diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:55:06 +0700 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:55:06 +0700 |
commit | 3f357a9c754805c4c38793749927aeda82797735 (patch) | |
tree | 65bb50517515714b6baaa4d5d2debed1e716bc83 | |
parent | 47a20f7daf954c90bbc77d2c108cb366171c650f (diff) | |
parent | 776509544123c68bbc128c0fdb2f699062d294cf (diff) | |
download | busybox-w32-3f357a9c754805c4c38793749927aeda82797735.tar.gz busybox-w32-3f357a9c754805c4c38793749927aeda82797735.tar.bz2 busybox-w32-3f357a9c754805c4c38793749927aeda82797735.zip |
Merge commit 'e4dcba1c103dc28e927e004791e331aaf604383d^'
36 files changed, 1744 insertions, 602 deletions
@@ -993,7 +993,7 @@ clean: archclean $(clean-dirs) | |||
993 | 993 | ||
994 | PHONY += doc-clean | 994 | PHONY += doc-clean |
995 | doc-clean: rm-files := docs/busybox.pod \ | 995 | doc-clean: rm-files := docs/busybox.pod \ |
996 | docs/BusyBox.html docs/BusyBox.1 docs/BusyBox.txt | 996 | docs/BusyBox.html docs/busybox.1 docs/BusyBox.txt |
997 | doc-clean: | 997 | doc-clean: |
998 | $(call cmd,rmfiles) | 998 | $(call cmd,rmfiles) |
999 | 999 | ||
diff --git a/Makefile.custom b/Makefile.custom index c6577a568..6da79e6e4 100644 --- a/Makefile.custom +++ b/Makefile.custom | |||
@@ -107,7 +107,7 @@ bigdata: busybox_unstripped | |||
107 | 107 | ||
108 | # Documentation Targets | 108 | # Documentation Targets |
109 | .PHONY: doc | 109 | .PHONY: doc |
110 | doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html | 110 | doc: docs/busybox.pod docs/BusyBox.txt docs/busybox.1 docs/BusyBox.html |
111 | 111 | ||
112 | # FIXME: Doesn't belong here | 112 | # FIXME: Doesn't belong here |
113 | cmd_doc = | 113 | cmd_doc = |
@@ -135,10 +135,10 @@ docs/BusyBox.txt: docs/busybox.pod | |||
135 | $(Q)-mkdir -p docs | 135 | $(Q)-mkdir -p docs |
136 | $(Q)-pod2text $< > $@ | 136 | $(Q)-pod2text $< > $@ |
137 | 137 | ||
138 | docs/BusyBox.1: docs/busybox.pod | 138 | docs/busybox.1: docs/busybox.pod |
139 | $(disp_doc) | 139 | $(disp_doc) |
140 | $(Q)-mkdir -p docs | 140 | $(Q)-mkdir -p docs |
141 | $(Q)-pod2man --center=BusyBox --release="version $(KERNELVERSION)" $< > $@ | 141 | $(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@ |
142 | 142 | ||
143 | docs/BusyBox.html: docs/busybox.net/BusyBox.html | 143 | docs/BusyBox.html: docs/busybox.net/BusyBox.html |
144 | $(disp_doc) | 144 | $(disp_doc) |
diff --git a/archival/gzip.c b/archival/gzip.c index e9f09730d..ffae9751b 100644 --- a/archival/gzip.c +++ b/archival/gzip.c | |||
@@ -340,7 +340,7 @@ struct globals { | |||
340 | ulg bits_sent; /* bit length of the compressed data */ | 340 | ulg bits_sent; /* bit length of the compressed data */ |
341 | #endif | 341 | #endif |
342 | 342 | ||
343 | uint32_t *crc_32_tab; | 343 | /*uint32_t *crc_32_tab;*/ |
344 | uint32_t crc; /* shift register contents */ | 344 | uint32_t crc; /* shift register contents */ |
345 | }; | 345 | }; |
346 | 346 | ||
@@ -393,15 +393,9 @@ static void put_32bit(ulg n) | |||
393 | * pointer, then initialize the crc shift register contents instead. | 393 | * pointer, then initialize the crc shift register contents instead. |
394 | * Return the current crc in either case. | 394 | * Return the current crc in either case. |
395 | */ | 395 | */ |
396 | static uint32_t updcrc(uch * s, unsigned n) | 396 | static void updcrc(uch * s, unsigned n) |
397 | { | 397 | { |
398 | uint32_t c = G1.crc; | 398 | G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); |
399 | while (n) { | ||
400 | c = G1.crc_32_tab[(uch)(c ^ *s++)] ^ (c >> 8); | ||
401 | n--; | ||
402 | } | ||
403 | G1.crc = c; | ||
404 | return c; | ||
405 | } | 399 | } |
406 | 400 | ||
407 | 401 | ||
@@ -2104,8 +2098,8 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) | |||
2104 | ALLOC(uch, G1.window, 2L * WSIZE); | 2098 | ALLOC(uch, G1.window, 2L * WSIZE); |
2105 | ALLOC(ush, G1.prev, 1L << BITS); | 2099 | ALLOC(ush, G1.prev, 1L << BITS); |
2106 | 2100 | ||
2107 | /* Initialise the CRC32 table */ | 2101 | /* Initialize the CRC32 table */ |
2108 | G1.crc_32_tab = crc32_filltable(NULL, 0); | 2102 | global_crc32_table = crc32_filltable(NULL, 0); |
2109 | 2103 | ||
2110 | return bbunpack(argv, pack_gzip, append_ext, "gz"); | 2104 | return bbunpack(argv, pack_gzip, append_ext, "gz"); |
2111 | } | 2105 | } |
diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index faba9ca82..ca427231e 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c | |||
@@ -22,17 +22,9 @@ | |||
22 | 22 | ||
23 | /* We use our own crc32 function */ | 23 | /* We use our own crc32 function */ |
24 | #define XZ_INTERNAL_CRC32 0 | 24 | #define XZ_INTERNAL_CRC32 0 |
25 | static uint32_t *crc32_table; | ||
26 | static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) | 25 | static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) |
27 | { | 26 | { |
28 | crc = ~crc; | 27 | return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); |
29 | |||
30 | while (size != 0) { | ||
31 | crc = crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); | ||
32 | --size; | ||
33 | } | ||
34 | |||
35 | return ~crc; | ||
36 | } | 28 | } |
37 | 29 | ||
38 | /* We use arch-optimized unaligned accessors */ | 30 | /* We use arch-optimized unaligned accessors */ |
@@ -53,8 +45,8 @@ unpack_xz_stream(int src_fd, int dst_fd) | |||
53 | unsigned char *membuf; | 45 | unsigned char *membuf; |
54 | IF_DESKTOP(long long) int total = 0; | 46 | IF_DESKTOP(long long) int total = 0; |
55 | 47 | ||
56 | if (!crc32_table) | 48 | if (!global_crc32_table) |
57 | crc32_table = crc32_filltable(NULL, /*endian:*/ 0); | 49 | global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); |
58 | 50 | ||
59 | memset(&iobuf, 0, sizeof(iobuf)); | 51 | memset(&iobuf, 0, sizeof(iobuf)); |
60 | /* Preload XZ file signature */ | 52 | /* Preload XZ file signature */ |
diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c index 20fda9d26..cb8a3d737 100644 --- a/archival/libunarchive/decompress_unzip.c +++ b/archival/libunarchive/decompress_unzip.c | |||
@@ -925,10 +925,7 @@ static int inflate_block(STATE_PARAM smallint *e) | |||
925 | /* Two callsites, both in inflate_get_next_window */ | 925 | /* Two callsites, both in inflate_get_next_window */ |
926 | static void calculate_gunzip_crc(STATE_PARAM_ONLY) | 926 | static void calculate_gunzip_crc(STATE_PARAM_ONLY) |
927 | { | 927 | { |
928 | unsigned n; | 928 | gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); |
929 | for (n = 0; n < gunzip_outbuf_count; n++) { | ||
930 | gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); | ||
931 | } | ||
932 | gunzip_bytes_out += gunzip_outbuf_count; | 929 | gunzip_bytes_out += gunzip_outbuf_count; |
933 | } | 930 | } |
934 | 931 | ||
diff --git a/archival/lzop.c b/archival/lzop.c index c6e718ad7..acb34fe14 100644 --- a/archival/lzop.c +++ b/archival/lzop.c | |||
@@ -393,7 +393,7 @@ typedef struct header_t { | |||
393 | } header_t; | 393 | } header_t; |
394 | 394 | ||
395 | struct globals { | 395 | struct globals { |
396 | const uint32_t *lzo_crc32_table; | 396 | /*const uint32_t *lzo_crc32_table;*/ |
397 | chksum_t chksum_in; | 397 | chksum_t chksum_in; |
398 | chksum_t chksum_out; | 398 | chksum_t chksum_out; |
399 | } FIX_ALIASING; | 399 | } FIX_ALIASING; |
@@ -468,19 +468,10 @@ lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len) | |||
468 | static FAST_FUNC uint32_t | 468 | static FAST_FUNC uint32_t |
469 | lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) | 469 | lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) |
470 | { | 470 | { |
471 | uint32_t crc; | 471 | //if (buf == NULL) - impossible |
472 | // return 0; | ||
472 | 473 | ||
473 | if (buf == NULL) | 474 | return ~crc32_block_endian0(~c, buf, len, global_crc32_table); |
474 | return 0; | ||
475 | |||
476 | crc = ~c; | ||
477 | if (len != 0) do { | ||
478 | crc = G.lzo_crc32_table[(uint8_t)((int)crc ^ *buf)] ^ (crc >> 8); | ||
479 | buf += 1; | ||
480 | len -= 1; | ||
481 | } while (len > 0); | ||
482 | |||
483 | return ~crc; | ||
484 | } | 475 | } |
485 | 476 | ||
486 | /**********************************************************************/ | 477 | /**********************************************************************/ |
@@ -679,8 +670,7 @@ static NOINLINE smallint lzo_compress(const header_t *h) | |||
679 | if (dst_len < src_len) { | 670 | if (dst_len < src_len) { |
680 | /* write checksum of compressed block */ | 671 | /* write checksum of compressed block */ |
681 | if (h->flags & F_ADLER32_C) | 672 | if (h->flags & F_ADLER32_C) |
682 | write32(lzo_adler32(ADLER32_INIT_VALUE, b2, | 673 | write32(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len)); |
683 | dst_len)); | ||
684 | if (h->flags & F_CRC32_C) | 674 | if (h->flags & F_CRC32_C) |
685 | write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len)); | 675 | write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len)); |
686 | /* write compressed block data */ | 676 | /* write compressed block data */ |
@@ -1080,6 +1070,6 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) | |||
1080 | if (applet_name[0] == 'u') | 1070 | if (applet_name[0] == 'u') |
1081 | option_mask32 |= OPT_DECOMPRESS; | 1071 | option_mask32 |= OPT_DECOMPRESS; |
1082 | 1072 | ||
1083 | G.lzo_crc32_table = crc32_filltable(NULL, 0); | 1073 | global_crc32_table = crc32_filltable(NULL, 0); |
1084 | return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); | 1074 | return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); |
1085 | } | 1075 | } |
diff --git a/coreutils/cksum.c b/coreutils/cksum.c index 7bf383e2d..7a37e6add 100644 --- a/coreutils/cksum.c +++ b/coreutils/cksum.c | |||
@@ -18,7 +18,6 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) | |||
18 | off_t length, filesize; | 18 | off_t length, filesize; |
19 | int bytes_read; | 19 | int bytes_read; |
20 | int exit_code = EXIT_SUCCESS; | 20 | int exit_code = EXIT_SUCCESS; |
21 | uint8_t *cp; | ||
22 | 21 | ||
23 | #if ENABLE_DESKTOP | 22 | #if ENABLE_DESKTOP |
24 | getopt32(argv, ""); /* coreutils 6.9 compat */ | 23 | getopt32(argv, ""); /* coreutils 6.9 compat */ |
@@ -39,11 +38,7 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) | |||
39 | 38 | ||
40 | #define read_buf bb_common_bufsiz1 | 39 | #define read_buf bb_common_bufsiz1 |
41 | while ((bytes_read = safe_read(fd, read_buf, sizeof(read_buf))) > 0) { | 40 | while ((bytes_read = safe_read(fd, read_buf, sizeof(read_buf))) > 0) { |
42 | cp = (uint8_t *) read_buf; | 41 | crc = crc32_block_endian1(crc, read_buf, bytes_read, crc32_table); |
43 | length += bytes_read; | ||
44 | do { | ||
45 | crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *cp++]; | ||
46 | } while (--bytes_read); | ||
47 | } | 42 | } |
48 | close(fd); | 43 | close(fd); |
49 | 44 | ||
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index e79210c0d..d3d294de9 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c | |||
@@ -10,13 +10,13 @@ | |||
10 | 10 | ||
11 | /* This is a NOEXEC applet. Be very careful! */ | 11 | /* This is a NOEXEC applet. Be very careful! */ |
12 | 12 | ||
13 | typedef enum { | 13 | enum { |
14 | /* 4th letter of applet_name is... */ | 14 | /* 4th letter of applet_name is... */ |
15 | HASH_MD5 = 's', /* "md5>s<um" */ | 15 | HASH_MD5 = 's', /* "md5>s<um" */ |
16 | HASH_SHA1 = '1', | 16 | HASH_SHA1 = '1', |
17 | HASH_SHA256 = '2', | 17 | HASH_SHA256 = '2', |
18 | HASH_SHA512 = '5', | 18 | HASH_SHA512 = '5', |
19 | } hash_algo_t; | 19 | }; |
20 | 20 | ||
21 | #define FLAG_SILENT 1 | 21 | #define FLAG_SILENT 1 |
22 | #define FLAG_CHECK 2 | 22 | #define FLAG_CHECK 2 |
@@ -32,7 +32,7 @@ static unsigned char *hash_bin_to_hex(unsigned char *hash_value, | |||
32 | return (unsigned char *)hex_value; | 32 | return (unsigned char *)hex_value; |
33 | } | 33 | } |
34 | 34 | ||
35 | static uint8_t *hash_file(const char *filename /*, hash_algo_t hash_algo*/) | 35 | static uint8_t *hash_file(const char *filename) |
36 | { | 36 | { |
37 | int src_fd, hash_len, count; | 37 | int src_fd, hash_len, count; |
38 | union _ctx_ { | 38 | union _ctx_ { |
@@ -45,13 +45,15 @@ static uint8_t *hash_file(const char *filename /*, hash_algo_t hash_algo*/) | |||
45 | RESERVE_CONFIG_UBUFFER(in_buf, 4096); | 45 | RESERVE_CONFIG_UBUFFER(in_buf, 4096); |
46 | void FAST_FUNC (*update)(void*, const void*, size_t); | 46 | void FAST_FUNC (*update)(void*, const void*, size_t); |
47 | void FAST_FUNC (*final)(void*, void*); | 47 | void FAST_FUNC (*final)(void*, void*); |
48 | hash_algo_t hash_algo = applet_name[3]; | 48 | char hash_algo; |
49 | 49 | ||
50 | src_fd = open_or_warn_stdin(filename); | 50 | src_fd = open_or_warn_stdin(filename); |
51 | if (src_fd < 0) { | 51 | if (src_fd < 0) { |
52 | return NULL; | 52 | return NULL; |
53 | } | 53 | } |
54 | 54 | ||
55 | hash_algo = applet_name[3]; | ||
56 | |||
55 | /* figure specific hash algorithims */ | 57 | /* figure specific hash algorithims */ |
56 | if (ENABLE_MD5SUM && hash_algo == HASH_MD5) { | 58 | if (ENABLE_MD5SUM && hash_algo == HASH_MD5) { |
57 | md5_begin(&context.md5); | 59 | md5_begin(&context.md5); |
@@ -74,10 +76,10 @@ static uint8_t *hash_file(const char *filename /*, hash_algo_t hash_algo*/) | |||
74 | final = (void*)sha512_end; | 76 | final = (void*)sha512_end; |
75 | hash_len = 64; | 77 | hash_len = 64; |
76 | } else { | 78 | } else { |
77 | bb_error_msg_and_die("algorithm not supported"); | 79 | xfunc_die(); /* can't reach this */ |
78 | } | 80 | } |
79 | 81 | ||
80 | while (0 < (count = safe_read(src_fd, in_buf, 4096))) { | 82 | while ((count = safe_read(src_fd, in_buf, 4096)) > 0) { |
81 | update(&context, in_buf, count); | 83 | update(&context, in_buf, count); |
82 | } | 84 | } |
83 | 85 | ||
@@ -99,27 +101,26 @@ int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
99 | int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) | 101 | int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) |
100 | { | 102 | { |
101 | int return_value = EXIT_SUCCESS; | 103 | int return_value = EXIT_SUCCESS; |
102 | uint8_t *hash_value; | ||
103 | unsigned flags; | 104 | unsigned flags; |
104 | /*hash_algo_t hash_algo = applet_name[3];*/ | ||
105 | 105 | ||
106 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { | 106 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { |
107 | /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ | 107 | /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ |
108 | flags = getopt32(argv, "scwbt"); | 108 | flags = getopt32(argv, "scwbt"); |
109 | argv += optind; | ||
110 | //argc -= optind; | ||
111 | } else { | ||
112 | argv += 1; | ||
113 | //argc -= 1; | ||
109 | } | 114 | } |
110 | else optind = 1; | ||
111 | argv += optind; | ||
112 | //argc -= optind; | ||
113 | if (!*argv) | 115 | if (!*argv) |
114 | *--argv = (char*)"-"; | 116 | *--argv = (char*)"-"; |
115 | 117 | ||
116 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) { | 118 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) { |
117 | if (flags & FLAG_SILENT) { | 119 | if (flags & FLAG_SILENT) { |
118 | bb_error_msg_and_die | 120 | bb_error_msg_and_die("-%c is meaningful only with -c", 's'); |
119 | ("-%c is meaningful only when verifying checksums", 's'); | 121 | } |
120 | } else if (flags & FLAG_WARN) { | 122 | if (flags & FLAG_WARN) { |
121 | bb_error_msg_and_die | 123 | bb_error_msg_and_die("-%c is meaningful only with -c", 'w'); |
122 | ("-%c is meaningful only when verifying checksums", 'w'); | ||
123 | } | 124 | } |
124 | } | 125 | } |
125 | 126 | ||
@@ -130,13 +131,13 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) | |||
130 | char *line; | 131 | char *line; |
131 | 132 | ||
132 | if (argv[1]) { | 133 | if (argv[1]) { |
133 | bb_error_msg_and_die | 134 | bb_error_msg_and_die("only one argument may be specified with -c"); |
134 | ("only one argument may be specified when using -c"); | ||
135 | } | 135 | } |
136 | 136 | ||
137 | pre_computed_stream = xfopen_stdin(argv[0]); | 137 | pre_computed_stream = xfopen_stdin(argv[0]); |
138 | 138 | ||
139 | while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { | 139 | while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { |
140 | uint8_t *hash_value; | ||
140 | char *filename_ptr; | 141 | char *filename_ptr; |
141 | 142 | ||
142 | count_total++; | 143 | count_total++; |
@@ -157,7 +158,7 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) | |||
157 | *filename_ptr = '\0'; | 158 | *filename_ptr = '\0'; |
158 | filename_ptr += 2; | 159 | filename_ptr += 2; |
159 | 160 | ||
160 | hash_value = hash_file(filename_ptr /*, hash_algo*/); | 161 | hash_value = hash_file(filename_ptr); |
161 | 162 | ||
162 | if (hash_value && (strcmp((char*)hash_value, line) == 0)) { | 163 | if (hash_value && (strcmp((char*)hash_value, line) == 0)) { |
163 | if (!(flags & FLAG_SILENT)) | 164 | if (!(flags & FLAG_SILENT)) |
@@ -183,7 +184,7 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) | |||
183 | */ | 184 | */ |
184 | } else { | 185 | } else { |
185 | do { | 186 | do { |
186 | hash_value = hash_file(*argv/*, hash_algo*/); | 187 | uint8_t *hash_value = hash_file(*argv); |
187 | if (hash_value == NULL) { | 188 | if (hash_value == NULL) { |
188 | return_value = EXIT_FAILURE; | 189 | return_value = EXIT_FAILURE; |
189 | } else { | 190 | } else { |
diff --git a/coreutils/mv.c b/coreutils/mv.c index 7f49d5bab..245639bd0 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c | |||
@@ -16,15 +16,30 @@ | |||
16 | #include "libbb.h" | 16 | #include "libbb.h" |
17 | #include "libcoreutils/coreutils.h" | 17 | #include "libcoreutils/coreutils.h" |
18 | 18 | ||
19 | //usage:#define mv_trivial_usage | ||
20 | //usage: "[-fin] SOURCE DEST\n" | ||
21 | //usage: "or: mv [-fin] SOURCE... DIRECTORY" | ||
22 | //usage:#define mv_full_usage "\n\n" | ||
23 | //usage: "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" | ||
24 | //usage: "\nOptions:" | ||
25 | //usage: "\n -f Don't prompt before overwriting" | ||
26 | //usage: "\n -i Interactive, prompt before overwrite" | ||
27 | //usage: "\n -n Don't overwrite an existing file" | ||
28 | //usage: | ||
29 | //usage:#define mv_example_usage | ||
30 | //usage: "$ mv /tmp/foo /bin/bar\n" | ||
31 | |||
19 | #if ENABLE_FEATURE_MV_LONG_OPTIONS | 32 | #if ENABLE_FEATURE_MV_LONG_OPTIONS |
20 | static const char mv_longopts[] ALIGN1 = | 33 | static const char mv_longopts[] ALIGN1 = |
21 | "interactive\0" No_argument "i" | 34 | "interactive\0" No_argument "i" |
22 | "force\0" No_argument "f" | 35 | "force\0" No_argument "f" |
36 | "no-clobber\0" No_argument "n" | ||
23 | ; | 37 | ; |
24 | #endif | 38 | #endif |
25 | 39 | ||
26 | #define OPT_FILEUTILS_FORCE 1 | 40 | #define OPT_FILEUTILS_FORCE 1 |
27 | #define OPT_FILEUTILS_INTERACTIVE 2 | 41 | #define OPT_FILEUTILS_INTERACTIVE 2 |
42 | #define OPT_FILEUTILS_NOCLOBBER 4 | ||
28 | 43 | ||
29 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 44 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
30 | int mv_main(int argc, char **argv) | 45 | int mv_main(int argc, char **argv) |
@@ -40,10 +55,11 @@ int mv_main(int argc, char **argv) | |||
40 | #if ENABLE_FEATURE_MV_LONG_OPTIONS | 55 | #if ENABLE_FEATURE_MV_LONG_OPTIONS |
41 | applet_long_options = mv_longopts; | 56 | applet_long_options = mv_longopts; |
42 | #endif | 57 | #endif |
43 | // Need at least two arguments | 58 | /* Need at least two arguments. |
44 | // -f unsets -i, -i unsets -f | 59 | * If more than one of -f, -i, -n is specified , only the final one |
45 | opt_complementary = "-2:f-i:i-f"; | 60 | * takes effect (it unsets previous options). */ |
46 | flags = getopt32(argv, "fi"); | 61 | opt_complementary = "-2:f-in:i-fn:n-fi"; |
62 | flags = getopt32(argv, "fin"); | ||
47 | argc -= optind; | 63 | argc -= optind; |
48 | argv += optind; | 64 | argv += optind; |
49 | last = argv[argc - 1]; | 65 | last = argv[argc - 1]; |
@@ -68,18 +84,22 @@ int mv_main(int argc, char **argv) | |||
68 | } | 84 | } |
69 | 85 | ||
70 | DO_MOVE: | 86 | DO_MOVE: |
71 | if (dest_exists | 87 | if (dest_exists) { |
72 | && !(flags & OPT_FILEUTILS_FORCE) | 88 | if (flags & OPT_FILEUTILS_NOCLOBBER) |
73 | && ((access(dest, W_OK) < 0 && isatty(0)) | ||
74 | || (flags & OPT_FILEUTILS_INTERACTIVE)) | ||
75 | ) { | ||
76 | if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { | ||
77 | goto RET_1; /* Ouch! fprintf failed! */ | ||
78 | } | ||
79 | if (!bb_ask_confirmation()) { | ||
80 | goto RET_0; | 89 | goto RET_0; |
90 | if (!(flags & OPT_FILEUTILS_FORCE) | ||
91 | && ((access(dest, W_OK) < 0 && isatty(0)) | ||
92 | || (flags & OPT_FILEUTILS_INTERACTIVE)) | ||
93 | ) { | ||
94 | if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { | ||
95 | goto RET_1; /* Ouch! fprintf failed! */ | ||
96 | } | ||
97 | if (!bb_ask_confirmation()) { | ||
98 | goto RET_0; | ||
99 | } | ||
81 | } | 100 | } |
82 | } | 101 | } |
102 | |||
83 | if (rename(*argv, dest) < 0) { | 103 | if (rename(*argv, dest) < 0) { |
84 | struct stat source_stat; | 104 | struct stat source_stat; |
85 | int source_exists; | 105 | int source_exists; |
diff --git a/coreutils/printf.c b/coreutils/printf.c index 2cc238439..c8395fa89 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c | |||
@@ -122,16 +122,14 @@ static double my_xstrtod(const char *arg) | |||
122 | return result; | 122 | return result; |
123 | } | 123 | } |
124 | 124 | ||
125 | static void print_esc_string(char *str) | 125 | static void print_esc_string(const char *str) |
126 | { | 126 | { |
127 | while (*str) { | 127 | char c; |
128 | if (*str == '\\') { | 128 | while ((c = *str) != '\0') { |
129 | str++; | 129 | str++; |
130 | bb_putchar(bb_process_escape_sequence((const char **)&str)); | 130 | if (c == '\\') |
131 | } else { | 131 | c = bb_process_escape_sequence(&str); |
132 | bb_putchar(*str); | 132 | putchar(c); |
133 | str++; | ||
134 | } | ||
135 | } | 133 | } |
136 | } | 134 | } |
137 | 135 | ||
@@ -344,7 +342,7 @@ static char **print_formatted(char *f, char **argv, int *conv_err) | |||
344 | f--; | 342 | f--; |
345 | break; | 343 | break; |
346 | default: | 344 | default: |
347 | bb_putchar(*f); | 345 | putchar(*f); |
348 | } | 346 | } |
349 | } | 347 | } |
350 | 348 | ||
diff --git a/docs/.gitignore b/docs/.gitignore index 9d1b7c227..11d616360 100644 --- a/docs/.gitignore +++ b/docs/.gitignore | |||
@@ -1,4 +1,4 @@ | |||
1 | /BusyBox.1 | 1 | /busybox.1 |
2 | /BusyBox.html | 2 | /BusyBox.html |
3 | /BusyBox.txt | 3 | /BusyBox.txt |
4 | /busybox.pod | 4 | /busybox.pod |
diff --git a/docs/smallint.txt b/docs/smallint.txt new file mode 100644 index 000000000..b57dfd775 --- /dev/null +++ b/docs/smallint.txt | |||
@@ -0,0 +1,39 @@ | |||
1 | smalluint i = index_in_str_array(params, name) + 1; | ||
2 | if (i == 0) | ||
3 | return 0; | ||
4 | if (!(i == 4 || i == 5)) | ||
5 | i |= 0x80; | ||
6 | |||
7 | return i; | ||
8 | |||
9 | I think that this optimization is wrong. | ||
10 | index_in_str_array returns int. At best, compiler will use it as-is. | ||
11 | At worst, compiler will try to make sure that it is properly cast | ||
12 | into a byte, which probably results in "n = n & 0xff" on many architectures. | ||
13 | |||
14 | You save nothing on space here because i is not stored on-stack, | ||
15 | gcc will keep it in register. And even if it *is* stored, | ||
16 | it is *stack* storage, which is cheap (unlike data/bss). | ||
17 | |||
18 | small[u]ints are useful _mostly_ for: | ||
19 | |||
20 | (a) flag variables | ||
21 | (a1) global flag variables - make data/bss smaller | ||
22 | (a2) local flag variables - "a = 5", "a |= 0x40" are smaller | ||
23 | for bytes than for full integers. | ||
24 | Example: | ||
25 | on i386, there is no widening constant store instruction | ||
26 | for some types of address modes, thus | ||
27 | movl $0x0,(%eax) is "c7 00 00 00 00 00" | ||
28 | movb $0x0,(%eax) is "c6 00 00" | ||
29 | (b) small integer structure members, when you have many such | ||
30 | structures allocated, | ||
31 | or when these are global objects of this structure type | ||
32 | |||
33 | small[u]ints are *NOT* useful for: | ||
34 | |||
35 | (a) function parameters and return values - | ||
36 | they are pushed on-stack or stored in registers, bytes here are *harder* | ||
37 | to deal with than ints | ||
38 | (b) "computational" variables - "a++", "a = b*3 + 7" may take more code to do | ||
39 | on bytes than on ints on some architectires. | ||
diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c index 524b84652..3a0743bb1 100644 --- a/e2fsprogs/old_e2fsprogs/fsck.c +++ b/e2fsprogs/old_e2fsprogs/fsck.c | |||
@@ -349,15 +349,7 @@ static void parse_escape(char *word) | |||
349 | if (!word) | 349 | if (!word) |
350 | return; | 350 | return; |
351 | 351 | ||
352 | for (p = q = word; *p; q++) { | 352 | strcpy_and_process_escape_sequences(word, word); |
353 | c = *p++; | ||
354 | if (c != '\\') { | ||
355 | *q = c; | ||
356 | } else { | ||
357 | *q = bb_process_escape_sequence(&p); | ||
358 | } | ||
359 | } | ||
360 | *q = 0; | ||
361 | } | 353 | } |
362 | 354 | ||
363 | static void free_instance(struct fsck_instance *i) | 355 | static void free_instance(struct fsck_instance *i) |
diff --git a/editors/awk.c b/editors/awk.c index 2245cad03..8bc56756c 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -283,88 +283,80 @@ enum { | |||
283 | #define OC_B OC_BUILTIN | 283 | #define OC_B OC_BUILTIN |
284 | 284 | ||
285 | static const char tokenlist[] ALIGN1 = | 285 | static const char tokenlist[] ALIGN1 = |
286 | "\1(" NTC | 286 | "\1(" NTC |
287 | "\1)" NTC | 287 | "\1)" NTC |
288 | "\1/" NTC /* REGEXP */ | 288 | "\1/" NTC /* REGEXP */ |
289 | "\2>>" "\1>" "\1|" NTC /* OUTRDR */ | 289 | "\2>>" "\1>" "\1|" NTC /* OUTRDR */ |
290 | "\2++" "\2--" NTC /* UOPPOST */ | 290 | "\2++" "\2--" NTC /* UOPPOST */ |
291 | "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ | 291 | "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ |
292 | "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ | 292 | "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ |
293 | "\2*=" "\2/=" "\2%=" "\2^=" | 293 | "\2*=" "\2/=" "\2%=" "\2^=" |
294 | "\1+" "\1-" "\3**=" "\2**" | 294 | "\1+" "\1-" "\3**=" "\2**" |
295 | "\1/" "\1%" "\1^" "\1*" | 295 | "\1/" "\1%" "\1^" "\1*" |
296 | "\2!=" "\2>=" "\2<=" "\1>" | 296 | "\2!=" "\2>=" "\2<=" "\1>" |
297 | "\1<" "\2!~" "\1~" "\2&&" | 297 | "\1<" "\2!~" "\1~" "\2&&" |
298 | "\2||" "\1?" "\1:" NTC | 298 | "\2||" "\1?" "\1:" NTC |
299 | "\2in" NTC | 299 | "\2in" NTC |
300 | "\1," NTC | 300 | "\1," NTC |
301 | "\1|" NTC | 301 | "\1|" NTC |
302 | "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ | 302 | "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ |
303 | "\1]" NTC | 303 | "\1]" NTC |
304 | "\1{" NTC | 304 | "\1{" NTC |
305 | "\1}" NTC | 305 | "\1}" NTC |
306 | "\1;" NTC | 306 | "\1;" NTC |
307 | "\1\n" NTC | 307 | "\1\n" NTC |
308 | "\2if" "\2do" "\3for" "\5break" /* STATX */ | 308 | "\2if" "\2do" "\3for" "\5break" /* STATX */ |
309 | "\10continue" "\6delete" "\5print" | 309 | "\10continue" "\6delete" "\5print" |
310 | "\6printf" "\4next" "\10nextfile" | 310 | "\6printf" "\4next" "\10nextfile" |
311 | "\6return" "\4exit" NTC | 311 | "\6return" "\4exit" NTC |
312 | "\5while" NTC | 312 | "\5while" NTC |
313 | "\4else" NTC | 313 | "\4else" NTC |
314 | 314 | ||
315 | "\3and" "\5compl" "\6lshift" "\2or" | 315 | "\3and" "\5compl" "\6lshift" "\2or" |
316 | "\6rshift" "\3xor" | 316 | "\6rshift" "\3xor" |
317 | "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ | 317 | "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ |
318 | "\3cos" "\3exp" "\3int" "\3log" | 318 | "\3cos" "\3exp" "\3int" "\3log" |
319 | "\4rand" "\3sin" "\4sqrt" "\5srand" | 319 | "\4rand" "\3sin" "\4sqrt" "\5srand" |
320 | "\6gensub" "\4gsub" "\5index" "\6length" | 320 | "\6gensub" "\4gsub" "\5index" "\6length" |
321 | "\5match" "\5split" "\7sprintf" "\3sub" | 321 | "\5match" "\5split" "\7sprintf" "\3sub" |
322 | "\6substr" "\7systime" "\10strftime" "\6mktime" | 322 | "\6substr" "\7systime" "\10strftime" "\6mktime" |
323 | "\7tolower" "\7toupper" NTC | 323 | "\7tolower" "\7toupper" NTC |
324 | "\7getline" NTC | 324 | "\7getline" NTC |
325 | "\4func" "\10function" NTC | 325 | "\4func" "\10function" NTC |
326 | "\5BEGIN" NTC | 326 | "\5BEGIN" NTC |
327 | "\3END" "\0" | 327 | "\3END" |
328 | /* compiler adds trailing "\0" */ | ||
328 | ; | 329 | ; |
329 | 330 | ||
330 | static const uint32_t tokeninfo[] = { | 331 | static const uint32_t tokeninfo[] = { |
331 | 0, | 332 | 0, |
332 | 0, | 333 | 0, |
333 | OC_REGEXP, | 334 | OC_REGEXP, |
334 | xS|'a', xS|'w', xS|'|', | 335 | xS|'a', xS|'w', xS|'|', |
335 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', | 336 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', |
336 | OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', | 337 | OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5), |
337 | OC_FIELD|xV|P(5), | 338 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', |
338 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), | 339 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', |
339 | OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', | 340 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', |
340 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', | 341 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', |
341 | OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', | 342 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, |
342 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', | 343 | OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), |
343 | OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', | 344 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', |
344 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', | 345 | OC_IN|SV|P(49), /* in */ |
345 | OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', | ||
346 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, | ||
347 | OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, | ||
348 | OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', | ||
349 | OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), | ||
350 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', | ||
351 | OC_COLON|xx|P(67)|':', | ||
352 | OC_IN|SV|P(49), | ||
353 | OC_COMMA|SS|P(80), | 346 | OC_COMMA|SS|P(80), |
354 | OC_PGETLINE|SV|P(37), | 347 | OC_PGETLINE|SV|P(37), |
355 | OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', | 348 | OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', |
356 | OC_UNARY|xV|P(19)|'!', | 349 | 0, /* ] */ |
357 | 0, | 350 | 0, |
358 | 0, | 351 | 0, |
359 | 0, | 352 | 0, |
360 | 0, | 353 | 0, /* \n */ |
361 | 0, | 354 | ST_IF, ST_DO, ST_FOR, OC_BREAK, |
362 | ST_IF, ST_DO, ST_FOR, OC_BREAK, | 355 | OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, |
363 | OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, | 356 | OC_PRINTF, OC_NEXT, OC_NEXTFILE, |
364 | OC_PRINTF, OC_NEXT, OC_NEXTFILE, | 357 | OC_RETURN|Vx, OC_EXIT|Nx, |
365 | OC_RETURN|Vx, OC_EXIT|Nx, | ||
366 | ST_WHILE, | 358 | ST_WHILE, |
367 | 0, | 359 | 0, /* else */ |
368 | 360 | ||
369 | OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), | 361 | OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), |
370 | OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), | 362 | OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), |
@@ -376,9 +368,9 @@ static const uint32_t tokeninfo[] = { | |||
376 | OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), | 368 | OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), |
377 | OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), | 369 | OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), |
378 | OC_GETLINE|SV|P(0), | 370 | OC_GETLINE|SV|P(0), |
379 | 0, 0, | 371 | 0, 0, |
380 | 0, | 372 | 0, |
381 | 0 | 373 | 0 /* END */ |
382 | }; | 374 | }; |
383 | 375 | ||
384 | /* internal variable names and their initial values */ | 376 | /* internal variable names and their initial values */ |
@@ -532,9 +524,7 @@ static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; | |||
532 | static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; | 524 | static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; |
533 | static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; | 525 | static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; |
534 | static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; | 526 | static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; |
535 | #if !ENABLE_FEATURE_AWK_LIBM | ||
536 | static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; | 527 | static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; |
537 | #endif | ||
538 | 528 | ||
539 | static void zero_out_var(var *vp) | 529 | static void zero_out_var(var *vp) |
540 | { | 530 | { |
@@ -692,8 +682,11 @@ static char nextchar(char **s) | |||
692 | pps = *s; | 682 | pps = *s; |
693 | if (c == '\\') | 683 | if (c == '\\') |
694 | c = bb_process_escape_sequence((const char**)s); | 684 | c = bb_process_escape_sequence((const char**)s); |
695 | if (c == '\\' && *s == pps) | 685 | if (c == '\\' && *s == pps) { /* unrecognized \z? */ |
696 | c = *(*s)++; | 686 | c = *(*s); /* yes, fetch z */ |
687 | if (c) | ||
688 | (*s)++; /* advance unless z = NUL */ | ||
689 | } | ||
697 | return c; | 690 | return c; |
698 | } | 691 | } |
699 | 692 | ||
@@ -705,8 +698,7 @@ static ALWAYS_INLINE int isalnum_(int c) | |||
705 | static double my_strtod(char **pp) | 698 | static double my_strtod(char **pp) |
706 | { | 699 | { |
707 | char *cp = *pp; | 700 | char *cp = *pp; |
708 | #if ENABLE_DESKTOP | 701 | if (ENABLE_DESKTOP && cp[0] == '0') { |
709 | if (cp[0] == '0') { | ||
710 | /* Might be hex or octal integer: 0x123abc or 07777 */ | 702 | /* Might be hex or octal integer: 0x123abc or 07777 */ |
711 | char c = (cp[1] | 0x20); | 703 | char c = (cp[1] | 0x20); |
712 | if (c == 'x' || isdigit(cp[1])) { | 704 | if (c == 'x' || isdigit(cp[1])) { |
@@ -723,7 +715,6 @@ static double my_strtod(char **pp) | |||
723 | */ | 715 | */ |
724 | } | 716 | } |
725 | } | 717 | } |
726 | #endif | ||
727 | return strtod(cp, pp); | 718 | return strtod(cp, pp); |
728 | } | 719 | } |
729 | 720 | ||
@@ -1015,9 +1006,10 @@ static uint32_t next_token(uint32_t expected) | |||
1015 | /* it's a string */ | 1006 | /* it's a string */ |
1016 | t_string = s = ++p; | 1007 | t_string = s = ++p; |
1017 | while (*p != '\"') { | 1008 | while (*p != '\"') { |
1018 | char *pp = p; | 1009 | char *pp; |
1019 | if (*p == '\0' || *p == '\n') | 1010 | if (*p == '\0' || *p == '\n') |
1020 | syntax_error(EMSG_UNEXP_EOS); | 1011 | syntax_error(EMSG_UNEXP_EOS); |
1012 | pp = p; | ||
1021 | *s++ = nextchar(&pp); | 1013 | *s++ = nextchar(&pp); |
1022 | p = pp; | 1014 | p = pp; |
1023 | } | 1015 | } |
@@ -1836,6 +1828,8 @@ static int awk_getline(rstream *rsm, var *v) | |||
1836 | int fd, so, eo, r, rp; | 1828 | int fd, so, eo, r, rp; |
1837 | char c, *m, *s; | 1829 | char c, *m, *s; |
1838 | 1830 | ||
1831 | debug_printf_eval("entered %s()\n", __func__); | ||
1832 | |||
1839 | /* we're using our own buffer since we need access to accumulating | 1833 | /* we're using our own buffer since we need access to accumulating |
1840 | * characters | 1834 | * characters |
1841 | */ | 1835 | */ |
@@ -1922,6 +1916,8 @@ static int awk_getline(rstream *rsm, var *v) | |||
1922 | rsm->pos = p - eo; | 1916 | rsm->pos = p - eo; |
1923 | rsm->size = size; | 1917 | rsm->size = size; |
1924 | 1918 | ||
1919 | debug_printf_eval("returning from %s(): %d\n", __func__, r); | ||
1920 | |||
1925 | return r; | 1921 | return r; |
1926 | } | 1922 | } |
1927 | 1923 | ||
@@ -2168,11 +2164,10 @@ static NOINLINE var *exec_builtin(node *op, var *res) | |||
2168 | switch (info) { | 2164 | switch (info) { |
2169 | 2165 | ||
2170 | case B_a2: | 2166 | case B_a2: |
2171 | #if ENABLE_FEATURE_AWK_LIBM | 2167 | if (ENABLE_FEATURE_AWK_LIBM) |
2172 | setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); | 2168 | setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); |
2173 | #else | 2169 | else |
2174 | syntax_error(EMSG_NO_MATH); | 2170 | syntax_error(EMSG_NO_MATH); |
2175 | #endif | ||
2176 | break; | 2171 | break; |
2177 | 2172 | ||
2178 | case B_sp: { | 2173 | case B_sp: { |
@@ -2347,6 +2342,8 @@ static var *evaluate(node *op, var *res) | |||
2347 | if (!op) | 2342 | if (!op) |
2348 | return setvar_s(res, NULL); | 2343 | return setvar_s(res, NULL); |
2349 | 2344 | ||
2345 | debug_printf_eval("entered %s()\n", __func__); | ||
2346 | |||
2350 | v1 = nvalloc(2); | 2347 | v1 = nvalloc(2); |
2351 | 2348 | ||
2352 | while (op) { | 2349 | while (op) { |
@@ -2367,7 +2364,7 @@ static var *evaluate(node *op, var *res) | |||
2367 | opn = (opinfo & OPNMASK); | 2364 | opn = (opinfo & OPNMASK); |
2368 | g_lineno = op->lineno; | 2365 | g_lineno = op->lineno; |
2369 | op1 = op->l.n; | 2366 | op1 = op->l.n; |
2370 | debug_printf_eval("opinfo:%08x opn:%08x XC:%x\n", opinfo, opn, XC(opinfo & OPCLSMASK)); | 2367 | debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); |
2371 | 2368 | ||
2372 | /* execute inevitable things */ | 2369 | /* execute inevitable things */ |
2373 | if (opinfo & OF_RES1) | 2370 | if (opinfo & OF_RES1) |
@@ -2387,6 +2384,7 @@ static var *evaluate(node *op, var *res) | |||
2387 | debug_printf_eval("L_d:%f\n", L_d); | 2384 | debug_printf_eval("L_d:%f\n", L_d); |
2388 | } | 2385 | } |
2389 | 2386 | ||
2387 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); | ||
2390 | switch (XC(opinfo & OPCLSMASK)) { | 2388 | switch (XC(opinfo & OPCLSMASK)) { |
2391 | 2389 | ||
2392 | /* -- iterative node type -- */ | 2390 | /* -- iterative node type -- */ |
@@ -2642,8 +2640,6 @@ static var *evaluate(node *op, var *res) | |||
2642 | 2640 | ||
2643 | /* simple builtins */ | 2641 | /* simple builtins */ |
2644 | case XC( OC_FBLTIN ): { | 2642 | case XC( OC_FBLTIN ): { |
2645 | int i; | ||
2646 | rstream *rsm; | ||
2647 | double R_d = R_d; /* for compiler */ | 2643 | double R_d = R_d; /* for compiler */ |
2648 | 2644 | ||
2649 | switch (opn) { | 2645 | switch (opn) { |
@@ -2654,35 +2650,40 @@ static var *evaluate(node *op, var *res) | |||
2654 | case F_rn: | 2650 | case F_rn: |
2655 | R_d = (double)rand() / (double)RAND_MAX; | 2651 | R_d = (double)rand() / (double)RAND_MAX; |
2656 | break; | 2652 | break; |
2657 | #if ENABLE_FEATURE_AWK_LIBM | 2653 | |
2658 | case F_co: | 2654 | case F_co: |
2659 | R_d = cos(L_d); | 2655 | if (ENABLE_FEATURE_AWK_LIBM) { |
2660 | break; | 2656 | R_d = cos(L_d); |
2657 | break; | ||
2658 | } | ||
2661 | 2659 | ||
2662 | case F_ex: | 2660 | case F_ex: |
2663 | R_d = exp(L_d); | 2661 | if (ENABLE_FEATURE_AWK_LIBM) { |
2664 | break; | 2662 | R_d = exp(L_d); |
2663 | break; | ||
2664 | } | ||
2665 | 2665 | ||
2666 | case F_lg: | 2666 | case F_lg: |
2667 | R_d = log(L_d); | 2667 | if (ENABLE_FEATURE_AWK_LIBM) { |
2668 | break; | 2668 | R_d = log(L_d); |
2669 | break; | ||
2670 | } | ||
2669 | 2671 | ||
2670 | case F_si: | 2672 | case F_si: |
2671 | R_d = sin(L_d); | 2673 | if (ENABLE_FEATURE_AWK_LIBM) { |
2672 | break; | 2674 | R_d = sin(L_d); |
2675 | break; | ||
2676 | } | ||
2673 | 2677 | ||
2674 | case F_sq: | 2678 | case F_sq: |
2675 | R_d = sqrt(L_d); | 2679 | if (ENABLE_FEATURE_AWK_LIBM) { |
2676 | break; | 2680 | R_d = sqrt(L_d); |
2677 | #else | 2681 | break; |
2678 | case F_co: | 2682 | } |
2679 | case F_ex: | 2683 | |
2680 | case F_lg: | ||
2681 | case F_si: | ||
2682 | case F_sq: | ||
2683 | syntax_error(EMSG_NO_MATH); | 2684 | syntax_error(EMSG_NO_MATH); |
2684 | break; | 2685 | break; |
2685 | #endif | 2686 | |
2686 | case F_sr: | 2687 | case F_sr: |
2687 | R_d = (double)seed; | 2688 | R_d = (double)seed; |
2688 | seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); | 2689 | seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); |
@@ -2709,26 +2710,37 @@ static var *evaluate(node *op, var *res) | |||
2709 | if (!op1) { | 2710 | if (!op1) { |
2710 | fflush(stdout); | 2711 | fflush(stdout); |
2711 | } else if (L.s && *L.s) { | 2712 | } else if (L.s && *L.s) { |
2712 | rsm = newfile(L.s); | 2713 | rstream *rsm = newfile(L.s); |
2713 | fflush(rsm->F); | 2714 | fflush(rsm->F); |
2714 | } else { | 2715 | } else { |
2715 | fflush_all(); | 2716 | fflush_all(); |
2716 | } | 2717 | } |
2717 | break; | 2718 | break; |
2718 | 2719 | ||
2719 | case F_cl: | 2720 | case F_cl: { |
2720 | i = 0; | 2721 | rstream *rsm; |
2722 | int err = 0; | ||
2721 | rsm = (rstream *)hash_search(fdhash, L.s); | 2723 | rsm = (rstream *)hash_search(fdhash, L.s); |
2724 | debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm); | ||
2722 | if (rsm) { | 2725 | if (rsm) { |
2723 | i = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); | 2726 | debug_printf_eval("OC_FBLTIN F_cl " |
2727 | "rsm->is_pipe:%d, ->F:%p\n", | ||
2728 | rsm->is_pipe, rsm->F); | ||
2729 | /* Can be NULL if open failed. Example: | ||
2730 | * getline line <"doesnt_exist"; | ||
2731 | * close("doesnt_exist"); <--- here rsm->F is NULL | ||
2732 | */ | ||
2733 | if (rsm->F) | ||
2734 | err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); | ||
2724 | free(rsm->buffer); | 2735 | free(rsm->buffer); |
2725 | hash_remove(fdhash, L.s); | 2736 | hash_remove(fdhash, L.s); |
2726 | } | 2737 | } |
2727 | if (i != 0) | 2738 | if (err) |
2728 | setvar_i(intvar[ERRNO], errno); | 2739 | setvar_i(intvar[ERRNO], errno); |
2729 | R_d = (double)i; | 2740 | R_d = (double)err; |
2730 | break; | 2741 | break; |
2731 | } | 2742 | } |
2743 | } /* switch */ | ||
2732 | setvar_i(res, R_d); | 2744 | setvar_i(res, R_d); |
2733 | break; | 2745 | break; |
2734 | } | 2746 | } |
@@ -2822,11 +2834,10 @@ static var *evaluate(node *op, var *res) | |||
2822 | L_d /= R_d; | 2834 | L_d /= R_d; |
2823 | break; | 2835 | break; |
2824 | case '&': | 2836 | case '&': |
2825 | #if ENABLE_FEATURE_AWK_LIBM | 2837 | if (ENABLE_FEATURE_AWK_LIBM) |
2826 | L_d = pow(L_d, R_d); | 2838 | L_d = pow(L_d, R_d); |
2827 | #else | 2839 | else |
2828 | syntax_error(EMSG_NO_MATH); | 2840 | syntax_error(EMSG_NO_MATH); |
2829 | #endif | ||
2830 | break; | 2841 | break; |
2831 | case '%': | 2842 | case '%': |
2832 | if (R_d == 0) | 2843 | if (R_d == 0) |
@@ -2877,6 +2888,7 @@ static var *evaluate(node *op, var *res) | |||
2877 | } /* while (op) */ | 2888 | } /* while (op) */ |
2878 | 2889 | ||
2879 | nvfree(v1); | 2890 | nvfree(v1); |
2891 | debug_printf_eval("returning from %s(): %p\n", __func__, res); | ||
2880 | return res; | 2892 | return res; |
2881 | #undef fnargs | 2893 | #undef fnargs |
2882 | #undef seed | 2894 | #undef seed |
@@ -2917,21 +2929,21 @@ static int awk_exit(int r) | |||
2917 | * otherwise return 0 */ | 2929 | * otherwise return 0 */ |
2918 | static int is_assignment(const char *expr) | 2930 | static int is_assignment(const char *expr) |
2919 | { | 2931 | { |
2920 | char *exprc, *s, *s0, *s1; | 2932 | char *exprc, *val, *s, *s1; |
2921 | 2933 | ||
2922 | exprc = xstrdup(expr); | 2934 | if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { |
2923 | if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { | ||
2924 | free(exprc); | ||
2925 | return FALSE; | 2935 | return FALSE; |
2926 | } | 2936 | } |
2927 | 2937 | ||
2928 | *s++ = '\0'; | 2938 | exprc = xstrdup(expr); |
2929 | s0 = s1 = s; | 2939 | val = exprc + (val - expr); |
2930 | while (*s) | 2940 | *val++ = '\0'; |
2931 | *s1++ = nextchar(&s); | 2941 | |
2942 | s = s1 = val; | ||
2943 | while ((*s1 = nextchar(&s)) != '\0') | ||
2944 | s1++; | ||
2932 | 2945 | ||
2933 | *s1 = '\0'; | 2946 | setvar_u(newvar(exprc), val); |
2934 | setvar_u(newvar(exprc), s0); | ||
2935 | free(exprc); | 2947 | free(exprc); |
2936 | return TRUE; | 2948 | return TRUE; |
2937 | } | 2949 | } |
diff --git a/include/libbb.h b/include/libbb.h index 325aae2a3..2936a8816 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -335,6 +335,7 @@ extern void bb_copyfd_exact_size(int fd1, int fd2, off_t size) FAST_FUNC; | |||
335 | /* this helper yells "short read!" if param is not -1 */ | 335 | /* this helper yells "short read!" if param is not -1 */ |
336 | extern void complain_copyfd_and_die(off_t sz) NORETURN FAST_FUNC; | 336 | extern void complain_copyfd_and_die(off_t sz) NORETURN FAST_FUNC; |
337 | extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC; | 337 | extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC; |
338 | char* strcpy_and_process_escape_sequences(char *dst, const char *src) FAST_FUNC; | ||
338 | /* xxxx_strip version can modify its parameter: | 339 | /* xxxx_strip version can modify its parameter: |
339 | * "/" -> "/" | 340 | * "/" -> "/" |
340 | * "abc" -> "abc" | 341 | * "abc" -> "abc" |
@@ -759,7 +760,7 @@ char *itoa(int n) FAST_FUNC; | |||
759 | char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; | 760 | char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; |
760 | char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; | 761 | char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; |
761 | /* Intelligent formatters of bignums */ | 762 | /* Intelligent formatters of bignums */ |
762 | void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; | 763 | void smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC; |
763 | void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; | 764 | void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; |
764 | /* If block_size == 0, display size without fractional part, | 765 | /* If block_size == 0, display size without fractional part, |
765 | * else display (size * block_size) with one decimal digit. | 766 | * else display (size * block_size) with one decimal digit. |
@@ -1559,8 +1560,10 @@ void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; | |||
1559 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 1560 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
1560 | void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; | 1561 | void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; |
1561 | 1562 | ||
1562 | 1563 | extern uint32_t *global_crc32_table; | |
1563 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; | 1564 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; |
1565 | uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; | ||
1566 | uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; | ||
1564 | 1567 | ||
1565 | typedef struct masks_labels_t { | 1568 | typedef struct masks_labels_t { |
1566 | const char *labels; | 1569 | const char *labels; |
@@ -1688,46 +1691,27 @@ extern const char bb_default_login_shell[]; | |||
1688 | # define VC_4 "/dev/tty4" | 1691 | # define VC_4 "/dev/tty4" |
1689 | # define VC_5 "/dev/tty5" | 1692 | # define VC_5 "/dev/tty5" |
1690 | # define VC_FORMAT "/dev/tty%d" | 1693 | # define VC_FORMAT "/dev/tty%d" |
1691 | #elif ENABLE_FEATURE_DEVFS /* from now on, assume Linux naming */ | 1694 | #elif ENABLE_FEATURE_DEVFS |
1695 | /*Linux, obsolete devfs names */ | ||
1692 | # define CURRENT_VC "/dev/vc/0" | 1696 | # define CURRENT_VC "/dev/vc/0" |
1693 | # define VC_1 "/dev/vc/1" | 1697 | # define VC_1 "/dev/vc/1" |
1694 | # define VC_2 "/dev/vc/2" | 1698 | # define VC_2 "/dev/vc/2" |
1695 | # define VC_3 "/dev/vc/3" | 1699 | # define VC_3 "/dev/vc/3" |
1696 | # define VC_4 "/dev/vc/4" | 1700 | # define VC_4 "/dev/vc/4" |
1697 | # define VC_5 "/dev/vc/5" | 1701 | # define VC_5 "/dev/vc/5" |
1698 | # if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) | ||
1699 | /* Yes, this sucks, but both SH (including sh64) and H8 have a SCI(F) for their | ||
1700 | respective serial ports .. as such, we can't use the common device paths for | ||
1701 | these. -- PFM */ | ||
1702 | # define SC_0 "/dev/ttsc/0" | ||
1703 | # define SC_1 "/dev/ttsc/1" | ||
1704 | # define SC_FORMAT "/dev/ttsc/%d" | ||
1705 | # else | ||
1706 | # define SC_0 "/dev/tts/0" | ||
1707 | # define SC_1 "/dev/tts/1" | ||
1708 | # define SC_FORMAT "/dev/tts/%d" | ||
1709 | # endif | ||
1710 | # define VC_FORMAT "/dev/vc/%d" | 1702 | # define VC_FORMAT "/dev/vc/%d" |
1711 | # define LOOP_FORMAT "/dev/loop/%d" | 1703 | # define LOOP_FORMAT "/dev/loop/%d" |
1712 | # define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) | 1704 | # define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) |
1713 | # define LOOP_NAME "/dev/loop/" | 1705 | # define LOOP_NAME "/dev/loop/" |
1714 | # define FB_0 "/dev/fb/0" | 1706 | # define FB_0 "/dev/fb/0" |
1715 | #else | 1707 | #else |
1708 | /*Linux, normal names */ | ||
1716 | # define CURRENT_VC "/dev/tty0" | 1709 | # define CURRENT_VC "/dev/tty0" |
1717 | # define VC_1 "/dev/tty1" | 1710 | # define VC_1 "/dev/tty1" |
1718 | # define VC_2 "/dev/tty2" | 1711 | # define VC_2 "/dev/tty2" |
1719 | # define VC_3 "/dev/tty3" | 1712 | # define VC_3 "/dev/tty3" |
1720 | # define VC_4 "/dev/tty4" | 1713 | # define VC_4 "/dev/tty4" |
1721 | # define VC_5 "/dev/tty5" | 1714 | # define VC_5 "/dev/tty5" |
1722 | # if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) | ||
1723 | # define SC_0 "/dev/ttySC0" | ||
1724 | # define SC_1 "/dev/ttySC1" | ||
1725 | # define SC_FORMAT "/dev/ttySC%d" | ||
1726 | # else | ||
1727 | # define SC_0 "/dev/ttyS0" | ||
1728 | # define SC_1 "/dev/ttyS1" | ||
1729 | # define SC_FORMAT "/dev/ttyS%d" | ||
1730 | # endif | ||
1731 | # define VC_FORMAT "/dev/tty%d" | 1715 | # define VC_FORMAT "/dev/tty%d" |
1732 | # define LOOP_FORMAT "/dev/loop%d" | 1716 | # define LOOP_FORMAT "/dev/loop%d" |
1733 | # define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) | 1717 | # define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) |
diff --git a/include/platform.h b/include/platform.h index c20d2aef6..3400fdfd5 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -283,15 +283,6 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; | |||
283 | 283 | ||
284 | /* ---- Miscellaneous --------------------------------------- */ | 284 | /* ---- Miscellaneous --------------------------------------- */ |
285 | 285 | ||
286 | #if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 5 && \ | ||
287 | !defined(__dietlibc__) && \ | ||
288 | !defined(_NEWLIB_VERSION) && \ | ||
289 | !(defined __digital__ && defined __unix__) | ||
290 | # error "Sorry, this libc version is not supported :(" | ||
291 | #endif | ||
292 | |||
293 | /* Don't perpetuate e2fsck crap into the headers. Clean up e2fsck instead. */ | ||
294 | |||
295 | #if defined __GLIBC__ || defined __UCLIBC__ \ | 286 | #if defined __GLIBC__ || defined __UCLIBC__ \ |
296 | || defined __dietlibc__ || defined _NEWLIB_VERSION | 287 | || defined __dietlibc__ || defined _NEWLIB_VERSION |
297 | # include <features.h> | 288 | # include <features.h> |
diff --git a/include/usage.src.h b/include/usage.src.h index f5ddd7ba5..6973c93ef 100644 --- a/include/usage.src.h +++ b/include/usage.src.h | |||
@@ -2695,18 +2695,6 @@ INSERT | |||
2695 | "ras3 reset retension rewind rewoffline seek setblk setdensity\n" \ | 2695 | "ras3 reset retension rewind rewoffline seek setblk setdensity\n" \ |
2696 | "setpart tell unload unlock weof wset" \ | 2696 | "setpart tell unload unlock weof wset" \ |
2697 | 2697 | ||
2698 | #define mv_trivial_usage \ | ||
2699 | "[-fi] SOURCE DEST\n" \ | ||
2700 | "or: mv [-fi] SOURCE... DIRECTORY" | ||
2701 | #define mv_full_usage "\n\n" \ | ||
2702 | "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" \ | ||
2703 | "\nOptions:" \ | ||
2704 | "\n -f Don't prompt before overwriting" \ | ||
2705 | "\n -i Interactive, prompt before overwrite" \ | ||
2706 | |||
2707 | #define mv_example_usage \ | ||
2708 | "$ mv /tmp/foo /bin/bar\n" | ||
2709 | |||
2710 | #define nameif_trivial_usage \ | 2698 | #define nameif_trivial_usage \ |
2711 | "[-s] [-c FILE] [{IFNAME MACADDR}]" | 2699 | "[-s] [-c FILE] [{IFNAME MACADDR}]" |
2712 | #define nameif_full_usage "\n\n" \ | 2700 | #define nameif_full_usage "\n\n" \ |
@@ -2721,27 +2709,6 @@ INSERT | |||
2721 | " or\n" \ | 2709 | " or\n" \ |
2722 | "$ nameif -c /etc/my_mactab_file\n" \ | 2710 | "$ nameif -c /etc/my_mactab_file\n" \ |
2723 | 2711 | ||
2724 | #define netstat_trivial_usage \ | ||
2725 | "[-laentuwxr"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" | ||
2726 | #define netstat_full_usage "\n\n" \ | ||
2727 | "Display networking information\n" \ | ||
2728 | "\nOptions:" \ | ||
2729 | "\n -l Display listening server sockets" \ | ||
2730 | "\n -a Display all sockets (default: connected)" \ | ||
2731 | "\n -e Display other/more information" \ | ||
2732 | "\n -n Don't resolve names" \ | ||
2733 | "\n -t Tcp sockets" \ | ||
2734 | "\n -u Udp sockets" \ | ||
2735 | "\n -w Raw sockets" \ | ||
2736 | "\n -x Unix sockets" \ | ||
2737 | "\n -r Display routing table" \ | ||
2738 | IF_FEATURE_NETSTAT_WIDE( \ | ||
2739 | "\n -W Display with no column truncation" \ | ||
2740 | ) \ | ||
2741 | IF_FEATURE_NETSTAT_PRG( \ | ||
2742 | "\n -p Display PID/Program name for sockets" \ | ||
2743 | ) | ||
2744 | |||
2745 | #define nmeter_trivial_usage \ | 2712 | #define nmeter_trivial_usage \ |
2746 | "format_string" | 2713 | "format_string" |
2747 | #define nmeter_full_usage "\n\n" \ | 2714 | #define nmeter_full_usage "\n\n" \ |
diff --git a/init/init.c b/init/init.c index 340731b8b..a7bbd5e64 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -463,7 +463,11 @@ static void set_sane_term(void) | |||
463 | #endif | 463 | #endif |
464 | 464 | ||
465 | /* Make it be sane */ | 465 | /* Make it be sane */ |
466 | tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; | 466 | #ifndef CRTSCTS |
467 | # define CRTSCTS 0 | ||
468 | #endif | ||
469 | /* added CRTSCTS to fix Debian bug 528560 */ | ||
470 | tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS; | ||
467 | tty.c_cflag |= CREAD | HUPCL | CLOCAL; | 471 | tty.c_cflag |= CREAD | HUPCL | CLOCAL; |
468 | 472 | ||
469 | /* input modes */ | 473 | /* input modes */ |
@@ -473,8 +477,7 @@ static void set_sane_term(void) | |||
473 | tty.c_oflag = OPOST | ONLCR; | 477 | tty.c_oflag = OPOST | ONLCR; |
474 | 478 | ||
475 | /* local modes */ | 479 | /* local modes */ |
476 | tty.c_lflag = | 480 | tty.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; |
477 | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; | ||
478 | 481 | ||
479 | tcsetattr_stdin_TCSANOW(&tty); | 482 | tcsetattr_stdin_TCSANOW(&tty); |
480 | } | 483 | } |
@@ -657,7 +660,9 @@ static struct init_action *mark_terminated(pid_t pid) | |||
657 | return a; | 660 | return a; |
658 | } | 661 | } |
659 | } | 662 | } |
660 | update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL); | 663 | update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, |
664 | /*username:*/ NULL, | ||
665 | /*hostname:*/ NULL); | ||
661 | } | 666 | } |
662 | return NULL; | 667 | return NULL; |
663 | } | 668 | } |
@@ -1083,8 +1088,6 @@ static int check_delayed_sigs(void) | |||
1083 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1088 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1084 | int init_main(int argc UNUSED_PARAM, char **argv) | 1089 | int init_main(int argc UNUSED_PARAM, char **argv) |
1085 | { | 1090 | { |
1086 | die_sleep = 30 * 24*60*60; /* if xmalloc would ever die... */ | ||
1087 | |||
1088 | if (argv[1] && strcmp(argv[1], "-q") == 0) { | 1091 | if (argv[1] && strcmp(argv[1], "-q") == 0) { |
1089 | return kill(1, SIGHUP); | 1092 | return kill(1, SIGHUP); |
1090 | } | 1093 | } |
@@ -1103,6 +1106,15 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1103 | #endif | 1106 | #endif |
1104 | } | 1107 | } |
1105 | 1108 | ||
1109 | /* If, say, xmalloc would ever die, we don't want to oops kernel | ||
1110 | * by exiting. | ||
1111 | * NB: we set die_sleep *after* PID 1 check and bb_show_usage. | ||
1112 | * Otherwise, for example, "init u" ("please rexec yourself" | ||
1113 | * command for sysvinit) will show help text (which isn't too bad), | ||
1114 | * *and sleep forever* (which is bad!) | ||
1115 | */ | ||
1116 | die_sleep = 30 * 24*60*60; | ||
1117 | |||
1106 | /* Figure out where the default console should be */ | 1118 | /* Figure out where the default console should be */ |
1107 | console_init(); | 1119 | console_init(); |
1108 | set_sane_term(); | 1120 | set_sane_term(); |
@@ -1170,7 +1182,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1170 | /* SELinux in enforcing mode but load_policy failed */ | 1182 | /* SELinux in enforcing mode but load_policy failed */ |
1171 | message(L_CONSOLE, "can't load SELinux Policy. " | 1183 | message(L_CONSOLE, "can't load SELinux Policy. " |
1172 | "Machine is in enforcing mode. Halting now."); | 1184 | "Machine is in enforcing mode. Halting now."); |
1173 | exit(EXIT_FAILURE); | 1185 | return EXIT_FAILURE; |
1174 | } | 1186 | } |
1175 | } | 1187 | } |
1176 | #endif | 1188 | #endif |
diff --git a/libbb/Config.src b/libbb/Config.src index 74dc9c549..f6c7a11ea 100644 --- a/libbb/Config.src +++ b/libbb/Config.src | |||
@@ -43,6 +43,17 @@ config FEATURE_ETC_NETWORKS | |||
43 | a rarely used feature which allows you to use names | 43 | a rarely used feature which allows you to use names |
44 | instead of IP/mask pairs in route command. | 44 | instead of IP/mask pairs in route command. |
45 | 45 | ||
46 | config FEATURE_USE_TERMIOS | ||
47 | bool "Use termios to manipulate the screen" | ||
48 | default y | ||
49 | depends on MORE || TOP || POWERTOP | ||
50 | help | ||
51 | This option allows utilities such as 'more' and 'top' to determine | ||
52 | the size of the screen. If you leave this disabled, your utilities | ||
53 | that display things on the screen will be especially primitive and | ||
54 | will be unable to determine the current screen size, and will be | ||
55 | unable to move the cursor. | ||
56 | |||
46 | config FEATURE_EDITING | 57 | config FEATURE_EDITING |
47 | bool "Command line editing" | 58 | bool "Command line editing" |
48 | default y | 59 | default y |
diff --git a/libbb/crc32.c b/libbb/crc32.c index 520b1ffb9..c63bf0772 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #include "libbb.h" | 19 | #include "libbb.h" |
20 | 20 | ||
21 | uint32_t *global_crc32_table; | ||
22 | |||
21 | uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) | 23 | uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) |
22 | { | 24 | { |
23 | uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320; | 25 | uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320; |
@@ -40,3 +42,25 @@ uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) | |||
40 | 42 | ||
41 | return crc_table - 256; | 43 | return crc_table - 256; |
42 | } | 44 | } |
45 | |||
46 | uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) | ||
47 | { | ||
48 | const void *end = (uint8_t*)buf + len; | ||
49 | |||
50 | while (buf != end) { | ||
51 | val = (val << 8) ^ crc_table[(val >> 24) ^ *(uint8_t*)buf]; | ||
52 | buf = (uint8_t*)buf + 1; | ||
53 | } | ||
54 | return val; | ||
55 | } | ||
56 | |||
57 | uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) | ||
58 | { | ||
59 | const void *end = (uint8_t*)buf + len; | ||
60 | |||
61 | while (buf != end) { | ||
62 | val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); | ||
63 | buf = (uint8_t*)buf + 1; | ||
64 | } | ||
65 | return val; | ||
66 | } | ||
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index aeacddef8..e427f6080 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
@@ -473,20 +473,13 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) | |||
473 | 473 | ||
474 | 474 | ||
475 | /* | 475 | /* |
476 | * Based on shasum from http://www.netsw.org/crypto/hash/ | 476 | * SHA1 part is: |
477 | * Majorly hacked up to use Dr Brian Gladman's sha1 code | 477 | * Copyright 2007 Rob Landley <rob@landley.net> |
478 | * | 478 | * |
479 | * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. | 479 | * Based on the public domain SHA-1 in C by Steve Reid <steve@edmweb.com> |
480 | * Copyright (C) 2003 Glenn L. McGrath | 480 | * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/ |
481 | * Copyright (C) 2003 Erik Andersen | ||
482 | * | ||
483 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
484 | * | ||
485 | * --------------------------------------------------------------------------- | ||
486 | * Issue Date: 10/11/2002 | ||
487 | * | 481 | * |
488 | * This is a byte oriented version of SHA1 that operates on arrays of bytes | 482 | * Licensed under GPLv2, see file LICENSE in this source tree. |
489 | * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor | ||
490 | * | 483 | * |
491 | * --------------------------------------------------------------------------- | 484 | * --------------------------------------------------------------------------- |
492 | * | 485 | * |
@@ -503,16 +496,18 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) | |||
503 | 496 | ||
504 | static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) | 497 | static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) |
505 | { | 498 | { |
506 | unsigned t; | 499 | static const uint32_t rconsts[] = { |
507 | uint32_t W[80], a, b, c, d, e; | 500 | 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 |
508 | const uint32_t *words = (uint32_t*) ctx->wbuffer; | 501 | }; |
502 | int i, j; | ||
503 | int cnt; | ||
504 | uint32_t W[16+16]; | ||
505 | uint32_t a, b, c, d, e; | ||
509 | 506 | ||
510 | for (t = 0; t < 16; ++t) | 507 | /* On-stack work buffer frees up one register in the main loop |
511 | W[t] = SWAP_BE32(words[t]); | 508 | * which otherwise will be needed to hold ctx pointer */ |
512 | for (/*t = 16*/; t < 80; ++t) { | 509 | for (i = 0; i < 16; i++) |
513 | uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; | 510 | W[i] = W[i+16] = SWAP_BE32(((uint32_t*)ctx->wbuffer)[i]); |
514 | W[t] = rotl32(T, 1); | ||
515 | } | ||
516 | 511 | ||
517 | a = ctx->hash[0]; | 512 | a = ctx->hash[0]; |
518 | b = ctx->hash[1]; | 513 | b = ctx->hash[1]; |
@@ -520,39 +515,41 @@ static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) | |||
520 | d = ctx->hash[3]; | 515 | d = ctx->hash[3]; |
521 | e = ctx->hash[4]; | 516 | e = ctx->hash[4]; |
522 | 517 | ||
523 | #undef ch | 518 | /* 4 rounds of 20 operations each */ |
524 | #undef parity | 519 | cnt = 0; |
525 | #undef maj | 520 | for (i = 0; i < 4; i++) { |
526 | #undef rnd | 521 | j = 19; |
527 | #define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) | 522 | do { |
528 | #define parity(x,y,z) ((x) ^ (y) ^ (z)) | 523 | uint32_t work; |
529 | #define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) | 524 | |
530 | /* A normal version as set out in the FIPS. */ | 525 | work = c ^ d; |
531 | #define rnd(f,k) \ | 526 | if (i == 0) { |
532 | do { \ | 527 | work = (work & b) ^ d; |
533 | uint32_t T = a; \ | 528 | if (j <= 3) |
534 | a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \ | 529 | goto ge16; |
535 | e = d; \ | 530 | /* Used to do SWAP_BE32 here, but this |
536 | d = c; \ | 531 | * requires ctx (see comment above) */ |
537 | c = rotl32(b, 30); \ | 532 | work += W[cnt]; |
538 | b = T; \ | 533 | } else { |
539 | } while (0) | 534 | if (i == 2) |
540 | 535 | work = ((b | c) & d) | (b & c); | |
541 | for (t = 0; t < 20; ++t) | 536 | else /* i = 1 or 3 */ |
542 | rnd(ch, 0x5a827999); | 537 | work ^= b; |
543 | 538 | ge16: | |
544 | for (/*t = 20*/; t < 40; ++t) | 539 | W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1); |
545 | rnd(parity, 0x6ed9eba1); | 540 | work += W[cnt]; |
546 | 541 | } | |
547 | for (/*t = 40*/; t < 60; ++t) | 542 | work += e + rotl32(a, 5) + rconsts[i]; |
548 | rnd(maj, 0x8f1bbcdc); | 543 | |
549 | 544 | /* Rotate by one for next time */ | |
550 | for (/*t = 60*/; t < 80; ++t) | 545 | e = d; |
551 | rnd(parity, 0xca62c1d6); | 546 | d = c; |
552 | #undef ch | 547 | c = /* b = */ rotl32(b, 30); |
553 | #undef parity | 548 | b = a; |
554 | #undef maj | 549 | a = work; |
555 | #undef rnd | 550 | cnt = (cnt + 1) & 15; |
551 | } while (--j >= 0); | ||
552 | } | ||
556 | 553 | ||
557 | ctx->hash[0] += a; | 554 | ctx->hash[0] += a; |
558 | ctx->hash[1] += b; | 555 | ctx->hash[1] += b; |
diff --git a/libbb/human_readable.c b/libbb/human_readable.c index 22dc5d23f..50cbe41bb 100644 --- a/libbb/human_readable.c +++ b/libbb/human_readable.c | |||
@@ -94,7 +94,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val, | |||
94 | 94 | ||
95 | /* Convert unsigned long long value into compact 5-char representation. | 95 | /* Convert unsigned long long value into compact 5-char representation. |
96 | * String is not terminated (buf[5] is untouched) */ | 96 | * String is not terminated (buf[5] is untouched) */ |
97 | void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) | 97 | void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) |
98 | { | 98 | { |
99 | const char *fmt; | 99 | const char *fmt; |
100 | char c; | 100 | char c; |
@@ -150,7 +150,7 @@ void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *sca | |||
150 | /* Convert unsigned long long value into compact 4-char | 150 | /* Convert unsigned long long value into compact 4-char |
151 | * representation. Examples: "1234", "1.2k", " 27M", "123T" | 151 | * representation. Examples: "1234", "1.2k", " 27M", "123T" |
152 | * String is not terminated (buf[4] is untouched) */ | 152 | * String is not terminated (buf[4] is untouched) */ |
153 | void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) | 153 | void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) |
154 | { | 154 | { |
155 | const char *fmt; | 155 | const char *fmt; |
156 | char c; | 156 | char c; |
diff --git a/libbb/parse_config.c b/libbb/parse_config.c index 3fff9f212..9dbfaf5d7 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c | |||
@@ -187,19 +187,7 @@ again: | |||
187 | 187 | ||
188 | #if 0 /* unused so far */ | 188 | #if 0 /* unused so far */ |
189 | if (flags & PARSE_ESCAPE) { | 189 | if (flags & PARSE_ESCAPE) { |
190 | const char *from; | 190 | strcpy_and_process_escape_sequences(tokens[t], tokens[t]); |
191 | char *to; | ||
192 | |||
193 | from = to = tokens[t]; | ||
194 | while (*from) { | ||
195 | if (*from == '\\') { | ||
196 | from++; | ||
197 | *to++ = bb_process_escape_sequence(&from); | ||
198 | } else { | ||
199 | *to++ = *from++; | ||
200 | } | ||
201 | } | ||
202 | *to = '\0'; | ||
203 | } | 191 | } |
204 | #endif | 192 | #endif |
205 | /* Skip possible delimiters */ | 193 | /* Skip possible delimiters */ |
diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index 82cbe10dc..346ecfa1e 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c | |||
@@ -18,52 +18,42 @@ | |||
18 | 18 | ||
19 | char FAST_FUNC bb_process_escape_sequence(const char **ptr) | 19 | char FAST_FUNC bb_process_escape_sequence(const char **ptr) |
20 | { | 20 | { |
21 | /* bash builtin "echo -e '\ec'" interprets \e as ESC, | ||
22 | * but coreutils "/bin/echo -e '\ec'" does not. | ||
23 | * manpages tend to support coreutils way. | ||
24 | * Update: coreutils added support for \e on 28 Oct 2009. */ | ||
25 | static const char charmap[] ALIGN1 = { | ||
26 | 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', 0, | ||
27 | '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; | ||
28 | |||
29 | const char *p; | ||
30 | const char *q; | 21 | const char *q; |
31 | unsigned num_digits; | 22 | unsigned num_digits; |
32 | unsigned r; | ||
33 | unsigned n; | 23 | unsigned n; |
34 | unsigned d; | ||
35 | unsigned base; | 24 | unsigned base; |
36 | 25 | ||
37 | num_digits = n = 0; | 26 | num_digits = n = 0; |
38 | base = 8; | 27 | base = 8; |
39 | q = *ptr; | 28 | q = *ptr; |
40 | 29 | ||
41 | #ifdef WANT_HEX_ESCAPES | 30 | if (WANT_HEX_ESCAPES && *q == 'x') { |
42 | if (*q == 'x') { | ||
43 | ++q; | 31 | ++q; |
44 | base = 16; | 32 | base = 16; |
45 | ++num_digits; | 33 | ++num_digits; |
46 | } | 34 | } |
47 | #endif | ||
48 | 35 | ||
49 | /* bash requires leading 0 in octal escapes: | 36 | /* bash requires leading 0 in octal escapes: |
50 | * \02 works, \2 does not (prints \ and 2). | 37 | * \02 works, \2 does not (prints \ and 2). |
51 | * We treat \2 as a valid octal escape sequence. */ | 38 | * We treat \2 as a valid octal escape sequence. */ |
52 | do { | 39 | do { |
53 | d = (unsigned char)(*q) - '0'; | 40 | unsigned r; |
54 | #ifdef WANT_HEX_ESCAPES | 41 | #if !WANT_HEX_ESCAPES |
55 | if (d >= 10) { | 42 | unsigned d = (unsigned char)(*q) - '0'; |
56 | d = (unsigned char)(_tolower(*q)) - 'a' + 10; | 43 | #else |
57 | } | 44 | unsigned d = (unsigned char)_tolower(*q) - '0'; |
45 | if (d >= 10) | ||
46 | d += ('0' - 'a' + 10); | ||
58 | #endif | 47 | #endif |
59 | |||
60 | if (d >= base) { | 48 | if (d >= base) { |
61 | #ifdef WANT_HEX_ESCAPES | 49 | if (WANT_HEX_ESCAPES && base == 16) { |
62 | if ((base == 16) && (!--num_digits)) { | 50 | --num_digits; |
63 | /* return '\\'; */ | 51 | if (num_digits == 0) { |
64 | --q; | 52 | /* \x<bad_char>: return '\', |
53 | * leave ptr pointing to x */ | ||
54 | return '\\'; | ||
55 | } | ||
65 | } | 56 | } |
66 | #endif | ||
67 | break; | 57 | break; |
68 | } | 58 | } |
69 | 59 | ||
@@ -76,21 +66,47 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) | |||
76 | ++q; | 66 | ++q; |
77 | } while (++num_digits < 3); | 67 | } while (++num_digits < 3); |
78 | 68 | ||
79 | if (num_digits == 0) { /* mnemonic escape sequence? */ | 69 | if (num_digits == 0) { |
80 | p = charmap; | 70 | /* Not octal or hex escape sequence. |
71 | * Is it one-letter one? */ | ||
72 | |||
73 | /* bash builtin "echo -e '\ec'" interprets \e as ESC, | ||
74 | * but coreutils "/bin/echo -e '\ec'" does not. | ||
75 | * Manpages tend to support coreutils way. | ||
76 | * Update: coreutils added support for \e on 28 Oct 2009. */ | ||
77 | static const char charmap[] ALIGN1 = { | ||
78 | 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', '\0', | ||
79 | '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\', | ||
80 | }; | ||
81 | const char *p = charmap; | ||
81 | do { | 82 | do { |
82 | if (*p == *q) { | 83 | if (*p == *q) { |
83 | q++; | 84 | q++; |
84 | break; | 85 | break; |
85 | } | 86 | } |
86 | } while (*++p); | 87 | } while (*++p != '\0'); |
87 | /* p points to found escape char or NUL, | 88 | /* p points to found escape char or NUL, |
88 | * advance it and find what it translates to */ | 89 | * advance it and find what it translates to. |
89 | p += sizeof(charmap) / 2; | 90 | * Note that \NUL and unrecognized sequence \z return '\' |
90 | n = *p; | 91 | * and leave ptr pointing to NUL or z. */ |
92 | n = p[sizeof(charmap) / 2]; | ||
91 | } | 93 | } |
92 | 94 | ||
93 | *ptr = q; | 95 | *ptr = q; |
94 | 96 | ||
95 | return (char) n; | 97 | return (char) n; |
96 | } | 98 | } |
99 | |||
100 | char* FAST_FUNC strcpy_and_process_escape_sequences(char *dst, const char *src) | ||
101 | { | ||
102 | while (1) { | ||
103 | char c, c1; | ||
104 | c = c1 = *src++; | ||
105 | if (c1 == '\\') | ||
106 | c1 = bb_process_escape_sequence(&src); | ||
107 | *dst = c1; | ||
108 | if (c == '\0') | ||
109 | return dst; | ||
110 | dst++; | ||
111 | } | ||
112 | } | ||
diff --git a/loginutils/getty.c b/loginutils/getty.c index b1cd235fb..ab55ea4b0 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c | |||
@@ -188,21 +188,9 @@ static void parse_args(char **argv, struct options *op, char **fakehost_p) | |||
188 | &(op->login), &op->timeout); | 188 | &(op->login), &op->timeout); |
189 | argv += optind; | 189 | argv += optind; |
190 | if (op->flags & F_INITSTRING) { | 190 | if (op->flags & F_INITSTRING) { |
191 | const char *p = op->initstring; | 191 | op->initstring = xstrdup(op->initstring); |
192 | char *q; | 192 | /* decode \ddd octal codes into chars */ |
193 | 193 | strcpy_and_process_escape_sequences((char*)op->initstring, op->initstring); | |
194 | op->initstring = q = xstrdup(p); | ||
195 | /* copy optarg into op->initstring decoding \ddd | ||
196 | octal codes into chars */ | ||
197 | while (*p) { | ||
198 | if (*p == '\\') { | ||
199 | p++; | ||
200 | *q++ = bb_process_escape_sequence(&p); | ||
201 | } else { | ||
202 | *q++ = *p++; | ||
203 | } | ||
204 | } | ||
205 | *q = '\0'; | ||
206 | } | 194 | } |
207 | op->flags ^= F_ISSUE; /* invert flag "show /etc/issue" */ | 195 | op->flags ^= F_ISSUE; /* invert flag "show /etc/issue" */ |
208 | debug("after getopt\n"); | 196 | debug("after getopt\n"); |
diff --git a/loginutils/login.c b/loginutils/login.c index e104fbb93..3065eaa5b 100644 --- a/loginutils/login.c +++ b/loginutils/login.c | |||
@@ -364,6 +364,10 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
364 | if (++count == 3) { | 364 | if (++count == 3) { |
365 | syslog(LOG_WARNING, "invalid password for '%s'%s", | 365 | syslog(LOG_WARNING, "invalid password for '%s'%s", |
366 | username, fromhost); | 366 | username, fromhost); |
367 | |||
368 | if (ENABLE_FEATURE_CLEAN_UP) | ||
369 | free(fromhost); | ||
370 | |||
367 | return EXIT_FAILURE; | 371 | return EXIT_FAILURE; |
368 | } | 372 | } |
369 | username[0] = '\0'; | 373 | username[0] = '\0'; |
@@ -401,6 +405,9 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
401 | if (pw->pw_uid == 0) | 405 | if (pw->pw_uid == 0) |
402 | syslog(LOG_INFO, "root login%s", fromhost); | 406 | syslog(LOG_INFO, "root login%s", fromhost); |
403 | 407 | ||
408 | if (ENABLE_FEATURE_CLEAN_UP) | ||
409 | free(fromhost); | ||
410 | |||
404 | /* well, a simple setexeccon() here would do the job as well, | 411 | /* well, a simple setexeccon() here would do the job as well, |
405 | * but let's play the game for now */ | 412 | * but let's play the game for now */ |
406 | IF_SELINUX(set_current_security_context(user_sid);) | 413 | IF_SELINUX(set_current_security_context(user_sid);) |
diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index 53aad3d52..b832cc1dd 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c | |||
@@ -42,15 +42,6 @@ but mtd/jffs2-user.h is gone now (at least 2.6.31.6 does not have it anymore) | |||
42 | #define cpu_to_je16(v) ((jint16_t){(v)}) | 42 | #define cpu_to_je16(v) ((jint16_t){(v)}) |
43 | #define cpu_to_je32(v) ((jint32_t){(v)}) | 43 | #define cpu_to_je32(v) ((jint32_t){(v)}) |
44 | 44 | ||
45 | static uint32_t crc32(uint32_t val, const void *ss, int len, | ||
46 | uint32_t *crc32_table) | ||
47 | { | ||
48 | const unsigned char *s = ss; | ||
49 | while (--len >= 0) | ||
50 | val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); | ||
51 | return val; | ||
52 | } | ||
53 | |||
54 | static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) | 45 | static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) |
55 | { | 46 | { |
56 | printf("\rErasing %u Kibyte @ %x - %2u%% complete.", | 47 | printf("\rErasing %u Kibyte @ %x - %2u%% complete.", |
@@ -131,8 +122,9 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) | |||
131 | cleanmarker.totlen = cpu_to_je32(8); | 122 | cleanmarker.totlen = cpu_to_je32(8); |
132 | } | 123 | } |
133 | 124 | ||
134 | cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, | 125 | cleanmarker.hdr_crc = cpu_to_je32( |
135 | crc32_table)); | 126 | crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table) |
127 | ); | ||
136 | } | 128 | } |
137 | 129 | ||
138 | /* Don't want to destroy progress indicator by bb_error_msg's */ | 130 | /* Don't want to destroy progress indicator by bb_error_msg's */ |
diff --git a/networking/netstat.c b/networking/netstat.c index 3114a3902..2a83af3ac 100644 --- a/networking/netstat.c +++ b/networking/netstat.c | |||
@@ -17,16 +17,37 @@ | |||
17 | #include "libbb.h" | 17 | #include "libbb.h" |
18 | #include "inet_common.h" | 18 | #include "inet_common.h" |
19 | 19 | ||
20 | //usage:#define netstat_trivial_usage | ||
21 | //usage: "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" | ||
22 | //usage:#define netstat_full_usage "\n\n" | ||
23 | //usage: "Display networking information\n" | ||
24 | //usage: "\nOptions:" | ||
25 | //usage: IF_ROUTE( | ||
26 | //usage: "\n -r Routing table" | ||
27 | //usage: ) | ||
28 | //usage: "\n -a All sockets" | ||
29 | //usage: "\n -l Listening sockets" | ||
30 | //usage: "\n Else: connected sockets" | ||
31 | //usage: "\n -t TCP sockets" | ||
32 | //usage: "\n -u UDP sockets" | ||
33 | //usage: "\n -w Raw sockets" | ||
34 | //usage: "\n -x Unix sockets" | ||
35 | //usage: "\n Else: all socket types" | ||
36 | //usage: "\n -e Other/more information" | ||
37 | //usage: "\n -n Don't resolve names" | ||
38 | //usage: IF_FEATURE_NETSTAT_WIDE( | ||
39 | //usage: "\n -W Wide display" | ||
40 | //usage: ) | ||
41 | //usage: IF_FEATURE_NETSTAT_PRG( | ||
42 | //usage: "\n -p Show PID/program name for sockets" | ||
43 | //usage: ) | ||
44 | |||
20 | #define NETSTAT_OPTS "laentuwx" \ | 45 | #define NETSTAT_OPTS "laentuwx" \ |
21 | IF_ROUTE( "r") \ | 46 | IF_ROUTE( "r") \ |
22 | IF_FEATURE_NETSTAT_WIDE("W") \ | 47 | IF_FEATURE_NETSTAT_WIDE("W") \ |
23 | IF_FEATURE_NETSTAT_PRG( "p") | 48 | IF_FEATURE_NETSTAT_PRG( "p") |
24 | 49 | ||
25 | enum { | 50 | enum { |
26 | OPTBIT_KEEP_OLD = 7, | ||
27 | IF_ROUTE( OPTBIT_ROUTE,) | ||
28 | IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) | ||
29 | IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG ,) | ||
30 | OPT_sock_listen = 1 << 0, // l | 51 | OPT_sock_listen = 1 << 0, // l |
31 | OPT_sock_all = 1 << 1, // a | 52 | OPT_sock_all = 1 << 1, // a |
32 | OPT_extended = 1 << 2, // e | 53 | OPT_extended = 1 << 2, // e |
@@ -35,6 +56,10 @@ enum { | |||
35 | OPT_sock_udp = 1 << 5, // u | 56 | OPT_sock_udp = 1 << 5, // u |
36 | OPT_sock_raw = 1 << 6, // w | 57 | OPT_sock_raw = 1 << 6, // w |
37 | OPT_sock_unix = 1 << 7, // x | 58 | OPT_sock_unix = 1 << 7, // x |
59 | OPTBIT_x = 7, | ||
60 | IF_ROUTE( OPTBIT_ROUTE,) | ||
61 | IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) | ||
62 | IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG ,) | ||
38 | OPT_route = IF_ROUTE( (1 << OPTBIT_ROUTE)) + 0, // r | 63 | OPT_route = IF_ROUTE( (1 << OPTBIT_ROUTE)) + 0, // r |
39 | OPT_wide = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W | 64 | OPT_wide = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W |
40 | OPT_prg = IF_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG )) + 0, // p | 65 | OPT_prg = IF_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG )) + 0, // p |
@@ -88,24 +113,25 @@ typedef enum { | |||
88 | SS_DISCONNECTING /* in process of disconnecting */ | 113 | SS_DISCONNECTING /* in process of disconnecting */ |
89 | } socket_state; | 114 | } socket_state; |
90 | 115 | ||
91 | #define SO_ACCEPTCON (1<<16) /* performed a listen */ | 116 | #define SO_ACCEPTCON (1<<16) /* performed a listen */ |
92 | #define SO_WAITDATA (1<<17) /* wait data to read */ | 117 | #define SO_WAITDATA (1<<17) /* wait data to read */ |
93 | #define SO_NOSPACE (1<<18) /* no space to write */ | 118 | #define SO_NOSPACE (1<<18) /* no space to write */ |
94 | |||
95 | /* Standard printout size */ | ||
96 | #define PRINT_IP_MAX_SIZE 23 | ||
97 | #define PRINT_NET_CONN "%s %6ld %6ld %-23s %-23s %-12s" | ||
98 | #define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State " | ||
99 | 119 | ||
120 | #define ADDR_NORMAL_WIDTH 23 | ||
100 | /* When there are IPv6 connections the IPv6 addresses will be | 121 | /* When there are IPv6 connections the IPv6 addresses will be |
101 | * truncated to none-recognition. The '-W' option makes the | 122 | * truncated to none-recognition. The '-W' option makes the |
102 | * address columns wide enough to accomodate for longest possible | 123 | * address columns wide enough to accomodate for longest possible |
103 | * IPv6 addresses, i.e. addresses of the form | 124 | * IPv6 addresses, i.e. addresses of the form |
104 | * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd | 125 | * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd |
105 | */ | 126 | */ |
106 | #define PRINT_IP_MAX_SIZE_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ | 127 | #define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ |
107 | #define PRINT_NET_CONN_WIDE "%s %6ld %6ld %-51s %-51s %-12s" | 128 | #if ENABLE_FEATURE_NETSTAT_WIDE |
108 | #define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State " | 129 | # define FMT_NET_CONN_DATA "%s %6ld %6ld %-*s %-*s %-12s" |
130 | # define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-*s %-*s State %s\n" | ||
131 | #else | ||
132 | # define FMT_NET_CONN_DATA "%s %6ld %6ld %-23s %-23s %-12s" | ||
133 | # define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State %s\n" | ||
134 | #endif | ||
109 | 135 | ||
110 | #define PROGNAME_WIDTH 20 | 136 | #define PROGNAME_WIDTH 20 |
111 | #define PROGNAME_WIDTH_STR "20" | 137 | #define PROGNAME_WIDTH_STR "20" |
@@ -121,22 +147,30 @@ struct prg_node { | |||
121 | #define PRG_HASH_SIZE 211 | 147 | #define PRG_HASH_SIZE 211 |
122 | 148 | ||
123 | struct globals { | 149 | struct globals { |
124 | const char *net_conn_line; | ||
125 | smallint flags; | 150 | smallint flags; |
126 | #if ENABLE_FEATURE_NETSTAT_PRG | 151 | #if ENABLE_FEATURE_NETSTAT_PRG |
127 | smallint prg_cache_loaded; | 152 | smallint prg_cache_loaded; |
128 | struct prg_node *prg_hash[PRG_HASH_SIZE]; | 153 | struct prg_node *prg_hash[PRG_HASH_SIZE]; |
129 | #endif | 154 | #endif |
155 | #if ENABLE_FEATURE_NETSTAT_PRG | ||
156 | const char *progname_banner; | ||
157 | #endif | ||
158 | #if ENABLE_FEATURE_NETSTAT_WIDE | ||
159 | unsigned addr_width; | ||
160 | #endif | ||
130 | }; | 161 | }; |
131 | #define G (*ptr_to_globals) | 162 | #define G (*ptr_to_globals) |
132 | #define flags (G.flags ) | 163 | #define flags (G.flags ) |
133 | #define net_conn_line (G.net_conn_line ) | ||
134 | #define prg_hash (G.prg_hash ) | ||
135 | #define prg_cache_loaded (G.prg_cache_loaded) | 164 | #define prg_cache_loaded (G.prg_cache_loaded) |
165 | #define prg_hash (G.prg_hash ) | ||
166 | #if ENABLE_FEATURE_NETSTAT_PRG | ||
167 | # define progname_banner (G.progname_banner ) | ||
168 | #else | ||
169 | # define progname_banner "" | ||
170 | #endif | ||
136 | #define INIT_G() do { \ | 171 | #define INIT_G() do { \ |
137 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 172 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
138 | flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ | 173 | flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ |
139 | net_conn_line = PRINT_NET_CONN; \ | ||
140 | } while (0) | 174 | } while (0) |
141 | 175 | ||
142 | 176 | ||
@@ -145,10 +179,6 @@ struct globals { | |||
145 | /* Deliberately truncating long to unsigned *int* */ | 179 | /* Deliberately truncating long to unsigned *int* */ |
146 | #define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) | 180 | #define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) |
147 | 181 | ||
148 | #define print_progname_banner() do { \ | ||
149 | if (option_mask32 & OPT_prg) printf(PROGNAME_BANNER); \ | ||
150 | } while (0) | ||
151 | |||
152 | static void prg_cache_add(long inode, char *name) | 182 | static void prg_cache_add(long inode, char *name) |
153 | { | 183 | { |
154 | unsigned hi = PRG_HASHIT(inode); | 184 | unsigned hi = PRG_HASHIT(inode); |
@@ -201,12 +231,12 @@ static long extract_socket_inode(const char *lname) | |||
201 | 231 | ||
202 | if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { | 232 | if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { |
203 | /* "socket:[12345]", extract the "12345" as inode */ | 233 | /* "socket:[12345]", extract the "12345" as inode */ |
204 | inode = bb_strtol(lname + sizeof("socket:[")-1, (char**)&lname, 0); | 234 | inode = bb_strtoul(lname + sizeof("socket:[")-1, (char**)&lname, 0); |
205 | if (*lname != ']') | 235 | if (*lname != ']') |
206 | inode = -1; | 236 | inode = -1; |
207 | } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { | 237 | } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { |
208 | /* "[0000]:12345", extract the "12345" as inode */ | 238 | /* "[0000]:12345", extract the "12345" as inode */ |
209 | inode = bb_strtol(lname + sizeof("[0000]:")-1, NULL, 0); | 239 | inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0); |
210 | if (errno) /* not NUL terminated? */ | 240 | if (errno) /* not NUL terminated? */ |
211 | inode = -1; | 241 | inode = -1; |
212 | } | 242 | } |
@@ -218,9 +248,9 @@ static long extract_socket_inode(const char *lname) | |||
218 | return inode; | 248 | return inode; |
219 | } | 249 | } |
220 | 250 | ||
221 | static int FAST_FUNC file_act(const char *fileName, | 251 | static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, |
222 | struct stat *statbuf UNUSED_PARAM, | 252 | struct stat *statbuf UNUSED_PARAM, |
223 | void *userData, | 253 | void *pid_slash_progname, |
224 | int depth UNUSED_PARAM) | 254 | int depth UNUSED_PARAM) |
225 | { | 255 | { |
226 | char *linkname; | 256 | char *linkname; |
@@ -231,7 +261,7 @@ static int FAST_FUNC file_act(const char *fileName, | |||
231 | inode = extract_socket_inode(linkname); | 261 | inode = extract_socket_inode(linkname); |
232 | free(linkname); | 262 | free(linkname); |
233 | if (inode >= 0) | 263 | if (inode >= 0) |
234 | prg_cache_add(inode, (char *)userData); | 264 | prg_cache_add(inode, (char *)pid_slash_progname); |
235 | } | 265 | } |
236 | return TRUE; | 266 | return TRUE; |
237 | } | 267 | } |
@@ -241,38 +271,40 @@ static int FAST_FUNC dir_act(const char *fileName, | |||
241 | void *userData UNUSED_PARAM, | 271 | void *userData UNUSED_PARAM, |
242 | int depth) | 272 | int depth) |
243 | { | 273 | { |
244 | const char *shortName; | 274 | const char *pid; |
245 | char *p, *q; | 275 | char *pid_slash_progname; |
276 | char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3]; | ||
246 | char cmdline_buf[512]; | 277 | char cmdline_buf[512]; |
247 | int i; | 278 | int n, len; |
248 | 279 | ||
249 | if (depth == 0) /* "/proc" itself */ | 280 | if (depth == 0) /* "/proc" itself */ |
250 | return TRUE; /* continue looking one level below /proc */ | 281 | return TRUE; /* continue looking one level below /proc */ |
251 | 282 | ||
252 | shortName = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ | 283 | pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ |
253 | if (!isdigit(shortName[0])) /* skip /proc entries whic aren't processes */ | 284 | if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */ |
254 | return SKIP; | 285 | return SKIP; |
255 | 286 | ||
256 | p = concat_path_file(fileName, "cmdline"); /* "/proc/PID/cmdline" */ | 287 | len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName); |
257 | i = open_read_close(p, cmdline_buf, sizeof(cmdline_buf) - 1); | 288 | n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1); |
258 | free(p); | 289 | if (n < 0) |
259 | if (i < 0) | ||
260 | return FALSE; | 290 | return FALSE; |
261 | cmdline_buf[i] = '\0'; | 291 | cmdline_buf[n] = '\0'; |
262 | q = concat_path_file(shortName, bb_basename(cmdline_buf)); /* "PID/argv0" */ | 292 | |
263 | 293 | /* go through all files in /proc/PID/fd and check whether they are sockets */ | |
264 | /* go through all files in /proc/PID/fd */ | 294 | strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd"); |
265 | p = concat_path_file(fileName, "fd"); | 295 | pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ |
266 | i = recursive_action(p, ACTION_RECURSE | ACTION_QUIET, | 296 | n = recursive_action(proc_pid_fname, |
267 | file_act, NULL, (void *)q, 0); | 297 | ACTION_RECURSE | ACTION_QUIET, |
268 | 298 | add_to_prg_cache_if_socket, | |
269 | free(p); | 299 | NULL, |
270 | free(q); | 300 | (void *)pid_slash_progname, |
271 | 301 | 0); | |
272 | if (!i) | 302 | free(pid_slash_progname); |
273 | return FALSE; /* signal permissions error to caller */ | 303 | |
274 | 304 | if (!n) | |
275 | return SKIP; /* caller should not recurse further into this dir. */ | 305 | return FALSE; /* signal permissions error to caller */ |
306 | |||
307 | return SKIP; /* caller should not recurse further into this dir */ | ||
276 | } | 308 | } |
277 | 309 | ||
278 | static void prg_cache_load(void) | 310 | static void prg_cache_load(void) |
@@ -294,7 +326,6 @@ static void prg_cache_load(void) | |||
294 | #else | 326 | #else |
295 | 327 | ||
296 | #define prg_cache_clear() ((void)0) | 328 | #define prg_cache_clear() ((void)0) |
297 | #define print_progname_banner() ((void)0) | ||
298 | 329 | ||
299 | #endif //ENABLE_FEATURE_NETSTAT_PRG | 330 | #endif //ENABLE_FEATURE_NETSTAT_PRG |
300 | 331 | ||
@@ -364,11 +395,14 @@ struct inet_params { | |||
364 | static int scan_inet_proc_line(struct inet_params *param, char *line) | 395 | static int scan_inet_proc_line(struct inet_params *param, char *line) |
365 | { | 396 | { |
366 | int num; | 397 | int num; |
367 | char local_addr[64], rem_addr[64]; | 398 | /* IPv6 /proc files use 32-char hex representation |
399 | * of IPv6 address, followed by :PORT_IN_HEX | ||
400 | */ | ||
401 | char local_addr[33], rem_addr[33]; /* 32 + 1 for NUL */ | ||
368 | 402 | ||
369 | num = sscanf(line, | 403 | num = sscanf(line, |
370 | "%*d: %64[0-9A-Fa-f]:%X " | 404 | "%*d: %32[0-9A-Fa-f]:%X " |
371 | "%64[0-9A-Fa-f]:%X %X " | 405 | "%32[0-9A-Fa-f]:%X %X " |
372 | "%lX:%lX %*X:%*X " | 406 | "%lX:%lX %*X:%*X " |
373 | "%*X %d %*d %ld ", | 407 | "%*X %d %*d %ld ", |
374 | local_addr, ¶m->local_port, | 408 | local_addr, ¶m->local_port, |
@@ -403,8 +437,11 @@ static void print_inet_line(struct inet_params *param, | |||
403 | char *r = ip_port_str( | 437 | char *r = ip_port_str( |
404 | ¶m->remaddr.sa, param->rem_port, | 438 | ¶m->remaddr.sa, param->rem_port, |
405 | proto, flags & NETSTAT_NUMERIC); | 439 | proto, flags & NETSTAT_NUMERIC); |
406 | printf(net_conn_line, | 440 | printf(FMT_NET_CONN_DATA, |
407 | proto, param->rxq, param->txq, l, r, state_str); | 441 | proto, param->rxq, param->txq, |
442 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l, | ||
443 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r, | ||
444 | state_str); | ||
408 | #if ENABLE_FEATURE_NETSTAT_PRG | 445 | #if ENABLE_FEATURE_NETSTAT_PRG |
409 | if (option_mask32 & OPT_prg) | 446 | if (option_mask32 & OPT_prg) |
410 | printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); | 447 | printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); |
@@ -419,6 +456,7 @@ static int FAST_FUNC tcp_do_one(char *line) | |||
419 | { | 456 | { |
420 | struct inet_params param; | 457 | struct inet_params param; |
421 | 458 | ||
459 | memset(¶m, 0, sizeof(param)); | ||
422 | if (scan_inet_proc_line(¶m, line)) | 460 | if (scan_inet_proc_line(¶m, line)) |
423 | return 1; | 461 | return 1; |
424 | 462 | ||
@@ -446,6 +484,7 @@ static int FAST_FUNC udp_do_one(char *line) | |||
446 | const char *state_str; | 484 | const char *state_str; |
447 | struct inet_params param; | 485 | struct inet_params param; |
448 | 486 | ||
487 | memset(¶m, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */ | ||
449 | if (scan_inet_proc_line(¶m, line)) | 488 | if (scan_inet_proc_line(¶m, line)) |
450 | return 1; | 489 | return 1; |
451 | 490 | ||
@@ -617,38 +656,39 @@ static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) | |||
617 | int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 656 | int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
618 | int netstat_main(int argc UNUSED_PARAM, char **argv) | 657 | int netstat_main(int argc UNUSED_PARAM, char **argv) |
619 | { | 658 | { |
620 | const char *net_conn_line_header = PRINT_NET_CONN_HEADER; | ||
621 | unsigned opt; | 659 | unsigned opt; |
622 | 660 | ||
623 | INIT_G(); | 661 | INIT_G(); |
624 | 662 | ||
625 | /* Option string must match NETSTAT_xxx constants */ | 663 | /* Option string must match NETSTAT_xxx constants */ |
626 | opt = getopt32(argv, NETSTAT_OPTS); | 664 | opt = getopt32(argv, NETSTAT_OPTS); |
627 | if (opt & 0x1) { // -l | 665 | if (opt & OPT_sock_listen) { // -l |
628 | flags &= ~NETSTAT_CONNECTED; | 666 | flags &= ~NETSTAT_CONNECTED; |
629 | flags |= NETSTAT_LISTENING; | 667 | flags |= NETSTAT_LISTENING; |
630 | } | 668 | } |
631 | if (opt & 0x2) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a | 669 | if (opt & OPT_sock_all) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a |
632 | //if (opt & 0x4) // -e | 670 | //if (opt & OPT_extended) // -e |
633 | if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n | 671 | if (opt & OPT_noresolve) flags |= NETSTAT_NUMERIC; // -n |
634 | //if (opt & 0x10) // -t: NETSTAT_TCP | 672 | //if (opt & OPT_sock_tcp) // -t: NETSTAT_TCP |
635 | //if (opt & 0x20) // -u: NETSTAT_UDP | 673 | //if (opt & OPT_sock_udp) // -u: NETSTAT_UDP |
636 | //if (opt & 0x40) // -w: NETSTAT_RAW | 674 | //if (opt & OPT_sock_raw) // -w: NETSTAT_RAW |
637 | //if (opt & 0x80) // -x: NETSTAT_UNIX | 675 | //if (opt & OPT_sock_unix) // -x: NETSTAT_UNIX |
638 | if (opt & OPT_route) { // -r | ||
639 | #if ENABLE_ROUTE | 676 | #if ENABLE_ROUTE |
677 | if (opt & OPT_route) { // -r | ||
640 | bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); | 678 | bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); |
641 | return 0; | 679 | return 0; |
642 | #else | ||
643 | bb_show_usage(); | ||
644 | #endif | ||
645 | } | 680 | } |
681 | #endif | ||
682 | #if ENABLE_FEATURE_NETSTAT_WIDE | ||
683 | G.addr_width = ADDR_NORMAL_WIDTH; | ||
646 | if (opt & OPT_wide) { // -W | 684 | if (opt & OPT_wide) { // -W |
647 | net_conn_line = PRINT_NET_CONN_WIDE; | 685 | G.addr_width = ADDR_WIDE; |
648 | net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; | ||
649 | } | 686 | } |
687 | #endif | ||
650 | #if ENABLE_FEATURE_NETSTAT_PRG | 688 | #if ENABLE_FEATURE_NETSTAT_PRG |
689 | progname_banner = ""; | ||
651 | if (opt & OPT_prg) { // -p | 690 | if (opt & OPT_prg) { // -p |
691 | progname_banner = PROGNAME_BANNER; | ||
652 | prg_cache_load(); | 692 | prg_cache_load(); |
653 | } | 693 | } |
654 | #endif | 694 | #endif |
@@ -667,9 +707,11 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |||
667 | printf("(only servers)"); | 707 | printf("(only servers)"); |
668 | else | 708 | else |
669 | printf("(w/o servers)"); | 709 | printf("(w/o servers)"); |
670 | printf(net_conn_line_header, "Local Address", "Foreign Address"); | 710 | printf(FMT_NET_CONN_HEADER, |
671 | print_progname_banner(); | 711 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address", |
672 | bb_putchar('\n'); | 712 | IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address", |
713 | progname_banner | ||
714 | ); | ||
673 | } | 715 | } |
674 | if (flags & NETSTAT_TCP) { | 716 | if (flags & NETSTAT_TCP) { |
675 | do_info("/proc/net/tcp", tcp_do_one); | 717 | do_info("/proc/net/tcp", tcp_do_one); |
@@ -697,9 +739,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) | |||
697 | printf("(only servers)"); | 739 | printf("(only servers)"); |
698 | else | 740 | else |
699 | printf("(w/o servers)"); | 741 | printf("(w/o servers)"); |
700 | printf("\nProto RefCnt Flags Type State I-Node "); | 742 | printf("\nProto RefCnt Flags Type State I-Node %sPath\n", progname_banner); |
701 | print_progname_banner(); | ||
702 | printf("Path\n"); | ||
703 | do_info("/proc/net/unix", unix_do_one); | 743 | do_info("/proc/net/unix", unix_do_one); |
704 | } | 744 | } |
705 | prg_cache_clear(); | 745 | prg_cache_clear(); |
diff --git a/procps/powertop.c b/procps/powertop.c new file mode 100644 index 000000000..5e028f074 --- /dev/null +++ b/procps/powertop.c | |||
@@ -0,0 +1,880 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * A mini 'powertop' utility: | ||
4 | * Analyze power consumption on Intel-based laptops. | ||
5 | * Based on powertop 1.11. | ||
6 | * | ||
7 | * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com> | ||
8 | * | ||
9 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
10 | */ | ||
11 | |||
12 | //applet:IF_POWERTOP(APPLET(powertop, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
13 | |||
14 | //kbuild:lib-$(CONFIG_POWERTOP) += powertop.o | ||
15 | |||
16 | //config:config POWERTOP | ||
17 | //config: bool "powertop" | ||
18 | //config: default y | ||
19 | //config: help | ||
20 | //config: Analyze power consumption on Intel-based laptops | ||
21 | |||
22 | // XXX This should be configurable | ||
23 | #define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 | ||
24 | |||
25 | #include "libbb.h" | ||
26 | |||
27 | |||
28 | //#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) | ||
29 | #define debug(fmt, ...) ((void)0) | ||
30 | |||
31 | |||
32 | #define BLOATY_HPET_IRQ_NUM_DETECTION 0 | ||
33 | #define MAX_CSTATE_COUNT 8 | ||
34 | #define IRQCOUNT 40 | ||
35 | |||
36 | |||
37 | #define DEFAULT_SLEEP 10 | ||
38 | #define DEFAULT_SLEEP_STR "10" | ||
39 | |||
40 | /* Frequency of the ACPI timer */ | ||
41 | #define FREQ_ACPI 3579.545 | ||
42 | #define FREQ_ACPI_1000 3579545 | ||
43 | |||
44 | /* Max filename length of entry in /sys/devices subsystem */ | ||
45 | #define BIG_SYSNAME_LEN 16 | ||
46 | |||
47 | typedef unsigned long long ullong; | ||
48 | |||
49 | struct line { | ||
50 | char *string; | ||
51 | int count; | ||
52 | /*int disk_count;*/ | ||
53 | }; | ||
54 | |||
55 | #if ENABLE_FEATURE_POWERTOP_PROCIRQ | ||
56 | struct irqdata { | ||
57 | smallint active; | ||
58 | int number; | ||
59 | ullong count; | ||
60 | char irq_desc[32]; | ||
61 | }; | ||
62 | #endif | ||
63 | |||
64 | struct globals { | ||
65 | struct line *lines; /* the most often used member */ | ||
66 | int lines_cnt; | ||
67 | int lines_cumulative_count; | ||
68 | int maxcstate; | ||
69 | unsigned total_cpus; | ||
70 | smallint cant_enable_timer_stats; | ||
71 | #if ENABLE_FEATURE_POWERTOP_PROCIRQ | ||
72 | # if BLOATY_HPET_IRQ_NUM_DETECTION | ||
73 | smallint scanned_timer_list; | ||
74 | int percpu_hpet_start; | ||
75 | int percpu_hpet_end; | ||
76 | # endif | ||
77 | int interrupt_0; | ||
78 | int total_interrupt; | ||
79 | struct irqdata interrupts[IRQCOUNT]; | ||
80 | #endif | ||
81 | ullong start_usage[MAX_CSTATE_COUNT]; | ||
82 | ullong last_usage[MAX_CSTATE_COUNT]; | ||
83 | ullong start_duration[MAX_CSTATE_COUNT]; | ||
84 | ullong last_duration[MAX_CSTATE_COUNT]; | ||
85 | #if ENABLE_FEATURE_USE_TERMIOS | ||
86 | struct termios init_settings; | ||
87 | #endif | ||
88 | }; | ||
89 | #define G (*ptr_to_globals) | ||
90 | #define INIT_G() do { \ | ||
91 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | ||
92 | } while (0) | ||
93 | |||
94 | #if ENABLE_FEATURE_USE_TERMIOS | ||
95 | static void reset_term(void) | ||
96 | { | ||
97 | tcsetattr_stdin_TCSANOW(&G.init_settings); | ||
98 | } | ||
99 | |||
100 | static void sig_handler(int signo UNUSED_PARAM) | ||
101 | { | ||
102 | reset_term(); | ||
103 | _exit(EXIT_FAILURE); | ||
104 | } | ||
105 | #endif | ||
106 | |||
107 | static int write_str_to_file(const char *fname, const char *str) | ||
108 | { | ||
109 | FILE *fp = fopen_for_write(fname); | ||
110 | if (!fp) | ||
111 | return 1; | ||
112 | fputs(str, fp); | ||
113 | fclose(fp); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | /* Make it more readable */ | ||
118 | #define start_timer() write_str_to_file("/proc/timer_stats", "1\n") | ||
119 | #define stop_timer() write_str_to_file("/proc/timer_stats", "0\n") | ||
120 | |||
121 | static NOINLINE void clear_lines(void) | ||
122 | { | ||
123 | int i; | ||
124 | if (G.lines) { | ||
125 | for (i = 0; i < G.lines_cnt; i++) | ||
126 | free(G.lines[i].string); | ||
127 | free(G.lines); | ||
128 | G.lines_cnt = 0; | ||
129 | G.lines = NULL; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void update_lines_cumulative_count(void) | ||
134 | { | ||
135 | int i; | ||
136 | for (i = 0; i < G.lines_cnt; i++) | ||
137 | G.lines_cumulative_count += G.lines[i].count; | ||
138 | } | ||
139 | |||
140 | static int line_compare(const void *p1, const void *p2) | ||
141 | { | ||
142 | const struct line *a = p1; | ||
143 | const struct line *b = p2; | ||
144 | return (b->count /*+ 50 * b->disk_count*/) - (a->count /*+ 50 * a->disk_count*/); | ||
145 | } | ||
146 | |||
147 | static void sort_lines(void) | ||
148 | { | ||
149 | qsort(G.lines, G.lines_cnt, sizeof(G.lines[0]), line_compare); | ||
150 | } | ||
151 | |||
152 | /* Save C-state usage and duration. Also update maxcstate. */ | ||
153 | static void read_cstate_counts(ullong *usage, ullong *duration) | ||
154 | { | ||
155 | DIR *dir; | ||
156 | struct dirent *d; | ||
157 | |||
158 | dir = opendir("/proc/acpi/processor"); | ||
159 | if (!dir) | ||
160 | return; | ||
161 | |||
162 | while ((d = readdir(dir)) != NULL) { | ||
163 | FILE *fp; | ||
164 | char buf[192]; | ||
165 | int level; | ||
166 | int len; | ||
167 | |||
168 | len = strlen(d->d_name); /* "CPUnn" */ | ||
169 | if (len < 3 || len > BIG_SYSNAME_LEN) | ||
170 | continue; | ||
171 | |||
172 | sprintf(buf, "/proc/acpi/processor/%s/power", d->d_name); | ||
173 | fp = fopen_for_read(buf); | ||
174 | if (!fp) | ||
175 | continue; | ||
176 | |||
177 | // Example file contents: | ||
178 | // active state: C0 | ||
179 | // max_cstate: C8 | ||
180 | // maximum allowed latency: 2000000000 usec | ||
181 | // states: | ||
182 | // C1: type[C1] promotion[--] demotion[--] latency[001] usage[00006173] duration[00000000000000000000] | ||
183 | // C2: type[C2] promotion[--] demotion[--] latency[001] usage[00085191] duration[00000000000083024907] | ||
184 | // C3: type[C3] promotion[--] demotion[--] latency[017] usage[01017622] duration[00000000017921327182] | ||
185 | level = 0; | ||
186 | while (fgets(buf, sizeof(buf), fp)) { | ||
187 | char *p = strstr(buf, "age["); | ||
188 | if (!p) | ||
189 | continue; | ||
190 | p += 4; | ||
191 | usage[level] += bb_strtoull(p, NULL, 10) + 1; | ||
192 | p = strstr(buf, "ation["); | ||
193 | if (!p) | ||
194 | continue; | ||
195 | p += 6; | ||
196 | duration[level] += bb_strtoull(p, NULL, 10); | ||
197 | |||
198 | if (level >= MAX_CSTATE_COUNT-1) | ||
199 | break; | ||
200 | level++; | ||
201 | if (level > G.maxcstate) /* update maxcstate */ | ||
202 | G.maxcstate = level; | ||
203 | } | ||
204 | fclose(fp); | ||
205 | } | ||
206 | closedir(dir); | ||
207 | } | ||
208 | |||
209 | /* Add line and/or update count */ | ||
210 | static void save_line(const char *string, int count) | ||
211 | { | ||
212 | int i; | ||
213 | for (i = 0; i < G.lines_cnt; i++) { | ||
214 | if (strcmp(string, G.lines[i].string) == 0) { | ||
215 | /* It's already there, only update count */ | ||
216 | G.lines[i].count += count; | ||
217 | return; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | /* Add new line */ | ||
222 | G.lines = xrealloc_vector(G.lines, 4, G.lines_cnt); | ||
223 | G.lines[G.lines_cnt].string = xstrdup(string); | ||
224 | G.lines[G.lines_cnt].count = count; | ||
225 | /*G.lines[G.lines_cnt].disk_count = 0;*/ | ||
226 | G.lines_cnt++; | ||
227 | } | ||
228 | |||
229 | #if ENABLE_FEATURE_POWERTOP_PROCIRQ | ||
230 | static int is_hpet_irq(const char *name) | ||
231 | { | ||
232 | char *p; | ||
233 | # if BLOATY_HPET_IRQ_NUM_DETECTION | ||
234 | long hpet_chan; | ||
235 | |||
236 | /* Learn the range of existing hpet timers. This is done once */ | ||
237 | if (!G.scanned_timer_list) { | ||
238 | FILE *fp; | ||
239 | char buf[80]; | ||
240 | |||
241 | G.scanned_timer_list = true; | ||
242 | fp = fopen_for_read("/proc/timer_list"); | ||
243 | if (!fp) | ||
244 | return 0; | ||
245 | |||
246 | while (fgets(buf, sizeof(buf), fp)) { | ||
247 | p = strstr(buf, "Clock Event Device: hpet"); | ||
248 | if (!p) | ||
249 | continue; | ||
250 | p += sizeof("Clock Event Device: hpet")-1; | ||
251 | if (!isdigit(*p)) | ||
252 | continue; | ||
253 | hpet_chan = xatoi_positive(p); | ||
254 | if (hpet_chan < G.percpu_hpet_start) | ||
255 | G.percpu_hpet_start = hpet_chan; | ||
256 | if (hpet_chan > G.percpu_hpet_end) | ||
257 | G.percpu_hpet_end = hpet_chan; | ||
258 | } | ||
259 | fclose(fp); | ||
260 | } | ||
261 | # endif | ||
262 | //TODO: optimize | ||
263 | p = strstr(name, "hpet"); | ||
264 | if (!p) | ||
265 | return 0; | ||
266 | p += 4; | ||
267 | if (!isdigit(*p)) | ||
268 | return 0; | ||
269 | # if BLOATY_HPET_IRQ_NUM_DETECTION | ||
270 | hpet_chan = xatoi_positive(p); | ||
271 | if (hpet_chan < G.percpu_hpet_start || hpet_chan > G.percpu_hpet_end) | ||
272 | return 0; | ||
273 | # endif | ||
274 | return 1; | ||
275 | } | ||
276 | |||
277 | /* Save new IRQ count, return delta from old one */ | ||
278 | static int save_irq_count(int irq, ullong count) | ||
279 | { | ||
280 | int unused = IRQCOUNT; | ||
281 | int i; | ||
282 | for (i = 0; i < IRQCOUNT; i++) { | ||
283 | if (G.interrupts[i].active && G.interrupts[i].number == irq) { | ||
284 | ullong old = G.interrupts[i].count; | ||
285 | G.interrupts[i].count = count; | ||
286 | return count - old; | ||
287 | } | ||
288 | if (!G.interrupts[i].active && unused > i) | ||
289 | unused = i; | ||
290 | } | ||
291 | if (unused < IRQCOUNT) { | ||
292 | G.interrupts[unused].active = 1; | ||
293 | G.interrupts[unused].count = count; | ||
294 | G.interrupts[unused].number = irq; | ||
295 | } | ||
296 | return count; | ||
297 | } | ||
298 | |||
299 | /* Read /proc/interrupts, save IRQ counts and IRQ description */ | ||
300 | static void process_irq_counts(void) | ||
301 | { | ||
302 | FILE *fp; | ||
303 | char buf[128]; | ||
304 | |||
305 | /* Reset values */ | ||
306 | G.interrupt_0 = 0; | ||
307 | G.total_interrupt = 0; | ||
308 | |||
309 | fp = xfopen_for_read("/proc/interrupts"); | ||
310 | while (fgets(buf, sizeof(buf), fp)) { | ||
311 | char irq_desc[sizeof(" <kernel IPI> : ") + sizeof(buf)]; | ||
312 | char *p; | ||
313 | const char *name; | ||
314 | int nr; | ||
315 | ullong count; | ||
316 | ullong delta; | ||
317 | |||
318 | p = strchr(buf, ':'); | ||
319 | if (!p) | ||
320 | continue; | ||
321 | /* 0: 143646045 153901007 IO-APIC-edge timer | ||
322 | * ^ | ||
323 | */ | ||
324 | /* Deal with non-maskable interrupts -- make up fake numbers */ | ||
325 | nr = -1; | ||
326 | if (buf[0] != ' ' && !isdigit(buf[0])) { | ||
327 | //TODO: optimize | ||
328 | if (strncmp(buf, "NMI:", 4) == 0) | ||
329 | nr = 20000; | ||
330 | if (strncmp(buf, "RES:", 4) == 0) | ||
331 | nr = 20001; | ||
332 | if (strncmp(buf, "CAL:", 4) == 0) | ||
333 | nr = 20002; | ||
334 | if (strncmp(buf, "TLB:", 4) == 0) | ||
335 | nr = 20003; | ||
336 | if (strncmp(buf, "TRM:", 4) == 0) | ||
337 | nr = 20004; | ||
338 | if (strncmp(buf, "THR:", 4) == 0) | ||
339 | nr = 20005; | ||
340 | if (strncmp(buf, "SPU:", 4) == 0) | ||
341 | nr = 20006; | ||
342 | } else { | ||
343 | /* bb_strtou doesn't eat leading spaces, using strtoul */ | ||
344 | nr = strtoul(buf, NULL, 10); | ||
345 | } | ||
346 | if (nr == -1) | ||
347 | continue; | ||
348 | |||
349 | p++; | ||
350 | /* 0: 143646045 153901007 IO-APIC-edge timer | ||
351 | * ^ | ||
352 | */ | ||
353 | /* Sum counts for this IRQ */ | ||
354 | count = 0; | ||
355 | while (1) { | ||
356 | char *tmp; | ||
357 | p = skip_whitespace(p); | ||
358 | if (!isdigit(*p)) | ||
359 | break; | ||
360 | count += bb_strtoull(p, &tmp, 10); | ||
361 | p = tmp; | ||
362 | } | ||
363 | /* 0: 143646045 153901007 IO-APIC-edge timer | ||
364 | * NMI: 1 2 Non-maskable interrupts | ||
365 | * ^ | ||
366 | */ | ||
367 | if (nr < 20000) { | ||
368 | /* Skip to the interrupt name, e.g. 'timer' */ | ||
369 | p = strchr(p, ' '); | ||
370 | if (!p) | ||
371 | continue; | ||
372 | p = skip_whitespace(p); | ||
373 | } | ||
374 | |||
375 | name = p; | ||
376 | strchrnul(name, '\n')[0] = '\0'; | ||
377 | /* Save description of the interrupt */ | ||
378 | if (nr >= 20000) | ||
379 | sprintf(irq_desc, " <kernel IPI> : %s", name); | ||
380 | else | ||
381 | sprintf(irq_desc, " <interrupt> : %s", name); | ||
382 | |||
383 | delta = save_irq_count(nr, count); | ||
384 | |||
385 | /* Skip per CPU timer interrupts */ | ||
386 | if (is_hpet_irq(name)) | ||
387 | continue; | ||
388 | |||
389 | if (nr != 0 && delta != 0) | ||
390 | save_line(irq_desc, delta); | ||
391 | |||
392 | if (nr == 0) | ||
393 | G.interrupt_0 = delta; | ||
394 | else | ||
395 | G.total_interrupt += delta; | ||
396 | } | ||
397 | |||
398 | fclose(fp); | ||
399 | } | ||
400 | #else /* !ENABLE_FEATURE_POWERTOP_PROCIRQ */ | ||
401 | # define process_irq_counts() ((void)0) | ||
402 | #endif | ||
403 | |||
404 | static NOINLINE int process_timer_stats(void) | ||
405 | { | ||
406 | char buf[128]; | ||
407 | char line[15 + 3 + 128]; | ||
408 | int n; | ||
409 | ullong totalticks; | ||
410 | FILE *fp; | ||
411 | |||
412 | buf[0] = '\0'; | ||
413 | totalticks = 0; | ||
414 | |||
415 | fp = NULL; | ||
416 | if (!G.cant_enable_timer_stats) | ||
417 | fp = fopen_for_read("/proc/timer_stats"); | ||
418 | if (fp) { | ||
419 | // Example file contents: | ||
420 | // Timer Stats Version: v0.2 | ||
421 | // Sample period: 1.329 s | ||
422 | // 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer) | ||
423 | // 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer) | ||
424 | // 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup) | ||
425 | // 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn) | ||
426 | // ... | ||
427 | // 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup) | ||
428 | // 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup) | ||
429 | // 331 total events, 249.059 events/sec | ||
430 | while (fgets(buf, sizeof(buf), fp)) { | ||
431 | const char *count, *process, *func; | ||
432 | char *p; | ||
433 | int cnt; | ||
434 | |||
435 | count = skip_whitespace(buf); | ||
436 | p = strchr(count, ','); | ||
437 | if (!p) | ||
438 | continue; | ||
439 | *p++ = '\0'; | ||
440 | if (strcmp(strchrnul(count, ' '), " total events") == 0) | ||
441 | break; | ||
442 | p = skip_whitespace(p); /* points to pid */ | ||
443 | |||
444 | /* Find char ' ', then eat remaining spaces */ | ||
445 | #define ADVANCE(p) do { \ | ||
446 | (p) = strchr((p), ' '); \ | ||
447 | if (!(p)) \ | ||
448 | continue; \ | ||
449 | *(p) = '\0'; \ | ||
450 | (p)++; \ | ||
451 | (p) = skip_whitespace(p); \ | ||
452 | } while (0) | ||
453 | /* Get process name */ | ||
454 | ADVANCE(p); | ||
455 | process = p; | ||
456 | /* Get function */ | ||
457 | ADVANCE(p); | ||
458 | func = p; | ||
459 | #undef ADVANCE | ||
460 | //if (strcmp(process, "swapper") == 0 | ||
461 | // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 | ||
462 | //) { | ||
463 | // process = "[kernel scheduler]"; | ||
464 | // func = "Load balancing tick"; | ||
465 | //} | ||
466 | |||
467 | if (strncmp(func, "tick_nohz_", 10) == 0) | ||
468 | continue; | ||
469 | if (strncmp(func, "tick_setup_sched_timer", 20) == 0) | ||
470 | continue; | ||
471 | //if (strcmp(process, "powertop") == 0) | ||
472 | // continue; | ||
473 | |||
474 | if (strcmp(process, "insmod") == 0) | ||
475 | process = "[kernel module]"; | ||
476 | if (strcmp(process, "modprobe") == 0) | ||
477 | process = "[kernel module]"; | ||
478 | if (strcmp(process, "swapper") == 0) | ||
479 | process = "<kernel core>"; | ||
480 | |||
481 | strchrnul(p, '\n')[0] = '\0'; | ||
482 | |||
483 | { | ||
484 | char *tmp; | ||
485 | cnt = bb_strtoull(count, &tmp, 10); | ||
486 | p = tmp; | ||
487 | } | ||
488 | while (*p != '\0') { | ||
489 | if (*p++ == 'D') /* deferred */ | ||
490 | goto skip; | ||
491 | } | ||
492 | |||
493 | //if (strchr(process, '[')) | ||
494 | sprintf(line, "%15.15s : %s", process, func); | ||
495 | //else | ||
496 | // sprintf(line, "%s", process); | ||
497 | save_line(line, cnt); | ||
498 | skip: ; | ||
499 | } | ||
500 | fclose(fp); | ||
501 | } | ||
502 | |||
503 | n = 0; | ||
504 | #if ENABLE_FEATURE_POWERTOP_PROCIRQ | ||
505 | if (strstr(buf, "total events")) { | ||
506 | n = bb_strtoull(buf, NULL, 10) / G.total_cpus; | ||
507 | if (n > 0 && n < G.interrupt_0) { | ||
508 | sprintf(line, " <interrupt> : %s", "extra timer interrupt"); | ||
509 | save_line(line, G.interrupt_0 - n); | ||
510 | } | ||
511 | } | ||
512 | #endif | ||
513 | return n; | ||
514 | } | ||
515 | |||
516 | #ifdef __i386__ | ||
517 | /* | ||
518 | * Get information about CPU using CPUID opcode. | ||
519 | */ | ||
520 | static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, | ||
521 | unsigned int *edx) | ||
522 | { | ||
523 | /* EAX value specifies what information to return */ | ||
524 | __asm__( | ||
525 | " pushl %%ebx\n" /* Save EBX */ | ||
526 | " cpuid\n" | ||
527 | " movl %%ebx, %1\n" /* Save content of EBX */ | ||
528 | " popl %%ebx\n" /* Restore EBX */ | ||
529 | : "=a"(*eax), /* Output */ | ||
530 | "=r"(*ebx), | ||
531 | "=c"(*ecx), | ||
532 | "=d"(*edx) | ||
533 | : "0"(*eax), /* Input */ | ||
534 | "1"(*ebx), | ||
535 | "2"(*ecx), | ||
536 | "3"(*edx) | ||
537 | /* No clobbered registers */ | ||
538 | ); | ||
539 | } | ||
540 | #endif | ||
541 | |||
542 | static NOINLINE void print_intel_cstates(void) | ||
543 | { | ||
544 | #ifdef __i386__ | ||
545 | int bios_table[8] = { 0 }; | ||
546 | int nbios = 0; | ||
547 | DIR *cpudir; | ||
548 | struct dirent *d; | ||
549 | int i; | ||
550 | unsigned eax, ebx, ecx, edx; | ||
551 | |||
552 | cpudir = opendir("/sys/devices/system/cpu"); | ||
553 | if (!cpudir) | ||
554 | return; | ||
555 | |||
556 | /* Loop over cpuN entries */ | ||
557 | while ((d = readdir(cpudir)) != NULL) { | ||
558 | DIR *dir; | ||
559 | int len; | ||
560 | char fname[sizeof("/sys/devices/system/cpu//cpuidle//desc") + 2*BIG_SYSNAME_LEN]; | ||
561 | |||
562 | len = strlen(d->d_name); | ||
563 | if (len < 3 || len > BIG_SYSNAME_LEN) | ||
564 | continue; | ||
565 | |||
566 | if (!isdigit(d->d_name[3])) | ||
567 | continue; | ||
568 | |||
569 | len = sprintf(fname, "/sys/devices/system/cpu/%s/cpuidle", d->d_name); | ||
570 | dir = opendir(fname); | ||
571 | if (!dir) | ||
572 | continue; | ||
573 | |||
574 | /* | ||
575 | * Every C-state has its own stateN directory, that | ||
576 | * contains a 'time' and a 'usage' file. | ||
577 | */ | ||
578 | while ((d = readdir(dir)) != NULL) { | ||
579 | FILE *fp; | ||
580 | char buf[64]; | ||
581 | int n; | ||
582 | |||
583 | n = strlen(d->d_name); | ||
584 | if (n < 3 || n > BIG_SYSNAME_LEN) | ||
585 | continue; | ||
586 | |||
587 | sprintf(fname + len, "/%s/desc", d->d_name); | ||
588 | fp = fopen_for_read(fname); | ||
589 | if (fp) { | ||
590 | char *p = fgets(buf, sizeof(buf), fp); | ||
591 | fclose(fp); | ||
592 | if (!p) | ||
593 | break; | ||
594 | p = strstr(p, "MWAIT "); | ||
595 | if (p) { | ||
596 | int pos; | ||
597 | p += sizeof("MWAIT ") - 1; | ||
598 | pos = (bb_strtoull(p, NULL, 16) >> 4) + 1; | ||
599 | if (pos >= ARRAY_SIZE(bios_table)) | ||
600 | continue; | ||
601 | bios_table[pos]++; | ||
602 | nbios++; | ||
603 | } | ||
604 | } | ||
605 | } | ||
606 | closedir(dir); | ||
607 | } | ||
608 | closedir(cpudir); | ||
609 | |||
610 | if (!nbios) | ||
611 | return; | ||
612 | |||
613 | eax = 5; | ||
614 | ebx = ecx = edx = 0; | ||
615 | cpuid(&eax, &ebx, &ecx, &edx); | ||
616 | if (!edx || !(ecx & 1)) | ||
617 | return; | ||
618 | |||
619 | printf("Your CPU supports the following C-states: "); | ||
620 | i = 0; | ||
621 | while (edx) { | ||
622 | if (edx & 7) | ||
623 | printf("C%u ", i); | ||
624 | edx >>= 4; | ||
625 | i++; | ||
626 | } | ||
627 | bb_putchar('\n'); | ||
628 | |||
629 | /* Print BIOS C-States */ | ||
630 | printf("Your BIOS reports the following C-states: "); | ||
631 | for (i = 0; i < 8; i++) | ||
632 | if (bios_table[i]) | ||
633 | printf("C%u ", i); | ||
634 | |||
635 | bb_putchar('\n'); | ||
636 | #endif | ||
637 | } | ||
638 | |||
639 | static void show_timerstats(void) | ||
640 | { | ||
641 | unsigned lines; | ||
642 | |||
643 | /* Get terminal height */ | ||
644 | get_terminal_width_height(STDOUT_FILENO, NULL, &lines); | ||
645 | |||
646 | /* We don't have whole terminal just for timerstats */ | ||
647 | lines -= 12; | ||
648 | |||
649 | if (!G.cant_enable_timer_stats) { | ||
650 | int i, n = 0; | ||
651 | char strbuf6[6]; | ||
652 | |||
653 | strbuf6[5] = '\0'; | ||
654 | puts("\nTop causes for wakeups:"); | ||
655 | for (i = 0; i < G.lines_cnt; i++) { | ||
656 | if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/) | ||
657 | && n++ < lines | ||
658 | ) { | ||
659 | /* NB: upstream powertop prints "(wakeups/sec)", | ||
660 | * we print just "(wakeup counts)". | ||
661 | */ | ||
662 | /*char c = ' '; | ||
663 | if (G.lines[i].disk_count) | ||
664 | c = 'D';*/ | ||
665 | smart_ulltoa5(G.lines[i].count, strbuf6, " KMGTPEZY"); | ||
666 | printf(/*" %5.1f%% (%s)%c %s\n"*/ | ||
667 | " %5.1f%% (%s) %s\n", | ||
668 | G.lines[i].count * 100.0 / G.lines_cumulative_count, | ||
669 | strbuf6, /*c,*/ | ||
670 | G.lines[i].string); | ||
671 | } | ||
672 | } | ||
673 | } else { | ||
674 | bb_putchar('\n'); | ||
675 | bb_error_msg("no stats available; run as root or" | ||
676 | " enable the cpufreq_stats module"); | ||
677 | } | ||
678 | } | ||
679 | |||
680 | // Example display from powertop version 1.11 | ||
681 | // Cn Avg residency P-states (frequencies) | ||
682 | // C0 (cpu running) ( 0.5%) 2.00 Ghz 0.0% | ||
683 | // polling 0.0ms ( 0.0%) 1.67 Ghz 0.0% | ||
684 | // C1 mwait 0.0ms ( 0.0%) 1333 Mhz 0.1% | ||
685 | // C2 mwait 0.1ms ( 0.1%) 1000 Mhz 99.9% | ||
686 | // C3 mwait 12.1ms (99.4%) | ||
687 | // | ||
688 | // Wakeups-from-idle per second : 93.6 interval: 15.0s | ||
689 | // no ACPI power usage estimate available | ||
690 | // | ||
691 | // Top causes for wakeups: | ||
692 | // 32.4% ( 26.7) <interrupt> : extra timer interrupt | ||
693 | // 29.0% ( 23.9) <kernel core> : hrtimer_start_range_ns (tick_sched_timer) | ||
694 | // 9.0% ( 7.5) <kernel core> : hrtimer_start (tick_sched_timer) | ||
695 | // 6.5% ( 5.3) <interrupt> : ata_piix | ||
696 | // 5.0% ( 4.1) inetd : hrtimer_start_range_ns (hrtimer_wakeup) | ||
697 | |||
698 | //usage:#define powertop_trivial_usage | ||
699 | //usage: "" | ||
700 | //usage:#define powertop_full_usage "\n\n" | ||
701 | //usage: "Analyze power consumption on Intel-based laptops\n" | ||
702 | |||
703 | int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
704 | int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) | ||
705 | { | ||
706 | ullong cur_usage[MAX_CSTATE_COUNT]; | ||
707 | ullong cur_duration[MAX_CSTATE_COUNT]; | ||
708 | char cstate_lines[MAX_CSTATE_COUNT + 2][64]; | ||
709 | #if ENABLE_FEATURE_USE_TERMIOS | ||
710 | struct termios new_settings; | ||
711 | struct pollfd pfd[1]; | ||
712 | |||
713 | pfd[0].fd = 0; | ||
714 | pfd[0].events = POLLIN; | ||
715 | #endif | ||
716 | |||
717 | INIT_G(); | ||
718 | |||
719 | #if ENABLE_FEATURE_POWERTOP_PROCIRQ && BLOATY_HPET_IRQ_NUM_DETECTION | ||
720 | G.percpu_hpet_start = INT_MAX; | ||
721 | G.percpu_hpet_end = INT_MIN; | ||
722 | #endif | ||
723 | |||
724 | /* Print warning when we don't have superuser privileges */ | ||
725 | if (geteuid() != 0) | ||
726 | bb_error_msg("run as root to collect enough information"); | ||
727 | |||
728 | /* Get number of CPUs */ | ||
729 | G.total_cpus = get_cpu_count(); | ||
730 | |||
731 | printf("Collecting data for "DEFAULT_SLEEP_STR" seconds\n"); | ||
732 | |||
733 | #if ENABLE_FEATURE_USE_TERMIOS | ||
734 | tcgetattr(0, (void *)&G.init_settings); | ||
735 | memcpy(&new_settings, &G.init_settings, sizeof(new_settings)); | ||
736 | /* Turn on unbuffered input, turn off echoing */ | ||
737 | new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); | ||
738 | /* So we don't forget to reset term settings */ | ||
739 | atexit(reset_term); | ||
740 | bb_signals(BB_FATAL_SIGS, sig_handler); | ||
741 | tcsetattr_stdin_TCSANOW(&new_settings); | ||
742 | #endif | ||
743 | |||
744 | /* Collect initial data */ | ||
745 | process_irq_counts(); | ||
746 | |||
747 | /* Read initial usage and duration */ | ||
748 | read_cstate_counts(G.start_usage, G.start_duration); | ||
749 | |||
750 | /* Copy them to "last" */ | ||
751 | memcpy(G.last_usage, G.start_usage, sizeof(G.last_usage)); | ||
752 | memcpy(G.last_duration, G.start_duration, sizeof(G.last_duration)); | ||
753 | |||
754 | /* Display C-states */ | ||
755 | print_intel_cstates(); | ||
756 | |||
757 | G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ | ||
758 | |||
759 | /* The main loop */ | ||
760 | for (;;) { | ||
761 | //double maxsleep = 0.0; | ||
762 | ullong totalticks, totalevents; | ||
763 | int i; | ||
764 | |||
765 | G.cant_enable_timer_stats |= start_timer(); /* 1 on error */ | ||
766 | #if !ENABLE_FEATURE_USE_TERMIOS | ||
767 | sleep(DEFAULT_SLEEP); | ||
768 | #else | ||
769 | if (safe_poll(pfd, 1, DEFAULT_SLEEP * 1000) > 0) { | ||
770 | unsigned char c; | ||
771 | if (safe_read(STDIN_FILENO, &c, 1) != 1) | ||
772 | break; /* EOF/error */ | ||
773 | if (c == G.init_settings.c_cc[VINTR]) | ||
774 | break; /* ^C */ | ||
775 | if ((c | 0x20) == 'q') | ||
776 | break; | ||
777 | } | ||
778 | #endif | ||
779 | G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ | ||
780 | |||
781 | clear_lines(); | ||
782 | process_irq_counts(); | ||
783 | |||
784 | /* Clear the stats */ | ||
785 | memset(cur_duration, 0, sizeof(cur_duration)); | ||
786 | memset(cur_usage, 0, sizeof(cur_usage)); | ||
787 | |||
788 | /* Read them */ | ||
789 | read_cstate_counts(cur_usage, cur_duration); | ||
790 | |||
791 | /* Count totalticks and totalevents */ | ||
792 | totalticks = totalevents = 0; | ||
793 | for (i = 0; i < MAX_CSTATE_COUNT; i++) { | ||
794 | if (cur_usage[i] != 0) { | ||
795 | totalticks += cur_duration[i] - G.last_duration[i]; | ||
796 | totalevents += cur_usage[i] - G.last_usage[i]; | ||
797 | } | ||
798 | } | ||
799 | |||
800 | /* Clear the screen */ | ||
801 | printf("\033[H\033[J"); | ||
802 | |||
803 | /* Clear C-state lines */ | ||
804 | memset(&cstate_lines, 0, sizeof(cstate_lines)); | ||
805 | |||
806 | if (totalevents == 0 && G.maxcstate <= 1) { | ||
807 | /* This should not happen */ | ||
808 | strcpy(cstate_lines[0], "C-state information is not available\n"); | ||
809 | } else { | ||
810 | double percentage; | ||
811 | unsigned newticks; | ||
812 | |||
813 | newticks = G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000 - totalticks; | ||
814 | /* Handle rounding errors: do not display negative values */ | ||
815 | if ((int)newticks < 0) | ||
816 | newticks = 0; | ||
817 | |||
818 | sprintf(cstate_lines[0], "Cn\t\t Avg residency\n"); | ||
819 | percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); | ||
820 | sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", percentage); | ||
821 | |||
822 | /* Compute values for individual C-states */ | ||
823 | for (i = 0; i < MAX_CSTATE_COUNT; i++) { | ||
824 | if (cur_usage[i] != 0) { | ||
825 | double slept; | ||
826 | slept = (cur_duration[i] - G.last_duration[i]) | ||
827 | / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; | ||
828 | percentage = (cur_duration[i] - G.last_duration[i]) * 100 | ||
829 | / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); | ||
830 | sprintf(cstate_lines[i + 2], "C%u\t\t%5.1fms (%4.1f%%)\n", | ||
831 | i + 1, slept, percentage); | ||
832 | //if (maxsleep < slept) | ||
833 | // maxsleep = slept; | ||
834 | } | ||
835 | } | ||
836 | } | ||
837 | |||
838 | for (i = 0; i < MAX_CSTATE_COUNT + 2; i++) | ||
839 | if (cstate_lines[i][0]) | ||
840 | fputs(cstate_lines[i], stdout); | ||
841 | |||
842 | i = process_timer_stats(); | ||
843 | #if ENABLE_FEATURE_POWERTOP_PROCIRQ | ||
844 | if (totalevents == 0) { | ||
845 | /* No C-state info available, use timerstats */ | ||
846 | totalevents = i * G.total_cpus + G.total_interrupt; | ||
847 | if (i < 0) | ||
848 | totalevents += G.interrupt_0 - i; | ||
849 | } | ||
850 | #endif | ||
851 | /* Upstream powertop prints wakeups per sec per CPU, | ||
852 | * we print just raw wakeup counts. | ||
853 | */ | ||
854 | //TODO: show real seconds (think about manual refresh) | ||
855 | printf("\nWakeups-from-idle in %u seconds: %llu\n", | ||
856 | DEFAULT_SLEEP, | ||
857 | totalevents | ||
858 | ); | ||
859 | |||
860 | update_lines_cumulative_count(); | ||
861 | sort_lines(); | ||
862 | show_timerstats(); | ||
863 | fflush(stdout); | ||
864 | |||
865 | /* Clear the stats */ | ||
866 | memset(cur_duration, 0, sizeof(cur_duration)); | ||
867 | memset(cur_usage, 0, sizeof(cur_usage)); | ||
868 | |||
869 | /* Get new values */ | ||
870 | read_cstate_counts(cur_usage, cur_duration); | ||
871 | |||
872 | /* Save them */ | ||
873 | memcpy(G.last_usage, cur_usage, sizeof(G.last_usage)); | ||
874 | memcpy(G.last_duration, cur_duration, sizeof(G.last_duration)); | ||
875 | } /* for (;;) */ | ||
876 | |||
877 | bb_putchar('\n'); | ||
878 | |||
879 | return EXIT_SUCCESS; | ||
880 | } | ||
diff --git a/procps/top.c b/procps/top.c index 4f37878de..f9106fac7 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -649,8 +649,9 @@ static void reset_term(void) | |||
649 | static void sig_catcher(int sig UNUSED_PARAM) | 649 | static void sig_catcher(int sig UNUSED_PARAM) |
650 | { | 650 | { |
651 | reset_term(); | 651 | reset_term(); |
652 | exit(EXIT_FAILURE); | 652 | _exit(EXIT_FAILURE); |
653 | } | 653 | } |
654 | |||
654 | #endif /* FEATURE_USE_TERMIOS */ | 655 | #endif /* FEATURE_USE_TERMIOS */ |
655 | 656 | ||
656 | /* | 657 | /* |
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 56b11ca46..0afe9b9e7 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -77,6 +77,12 @@ testing "awk string cast (bug 725)" \ | |||
77 | testing "awk handles whitespace before array subscript" \ | 77 | testing "awk handles whitespace before array subscript" \ |
78 | "awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" "" | 78 | "awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" "" |
79 | 79 | ||
80 | # GNU awk 3.1.5's "print ERRNO" prints "No such file or directory" instead of "2", | ||
81 | # do we need to emulate that as well? | ||
82 | testing "awk handles non-existing file correctly" \ | ||
83 | "awk 'BEGIN { getline line <\"doesnt_exist\"; print ERRNO; ERRNO=0; close(\"doesnt_exist\"); print ERRNO; print \"Ok\" }'" \ | ||
84 | "2\n0\nOk\n" "" "" | ||
85 | |||
80 | prg=' | 86 | prg=' |
81 | BEGIN { | 87 | BEGIN { |
82 | u["a"]=1 | 88 | u["a"]=1 |
diff --git a/util-linux/Config.src b/util-linux/Config.src index afa30923b..c71b4de38 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src | |||
@@ -181,6 +181,14 @@ config FEATURE_OSF_LABEL | |||
181 | Enabling this option allows you to create or change BSD disklabels | 181 | Enabling this option allows you to create or change BSD disklabels |
182 | and define and edit BSD disk slices. | 182 | and define and edit BSD disk slices. |
183 | 183 | ||
184 | config FEATURE_GPT_LABEL | ||
185 | bool "Support GPT disklabels" | ||
186 | default n | ||
187 | depends on FDISK && FEATURE_FDISK_WRITABLE | ||
188 | help | ||
189 | Enabling this option allows you to view GUID Partition Table | ||
190 | disklabels. | ||
191 | |||
184 | config FEATURE_FDISK_ADVANCED | 192 | config FEATURE_FDISK_ADVANCED |
185 | bool "Support expert mode" | 193 | bool "Support expert mode" |
186 | default y | 194 | default y |
@@ -478,17 +486,6 @@ config MORE | |||
478 | you will probably find this utility very helpful. If you don't have | 486 | you will probably find this utility very helpful. If you don't have |
479 | any need to reading text files, you can leave this disabled. | 487 | any need to reading text files, you can leave this disabled. |
480 | 488 | ||
481 | config FEATURE_USE_TERMIOS | ||
482 | bool "Use termios to manipulate the screen" | ||
483 | default y | ||
484 | depends on MORE || TOP | ||
485 | help | ||
486 | This option allows utilities such as 'more' and 'top' to determine | ||
487 | the size of the screen. If you leave this disabled, your utilities | ||
488 | that display things on the screen will be especially primitive and | ||
489 | will be unable to determine the current screen size, and will be | ||
490 | unable to move the cursor. | ||
491 | |||
492 | config MOUNT | 489 | config MOUNT |
493 | bool "mount" | 490 | bool "mount" |
494 | default y | 491 | default y |
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index b6417a355..3f2e0d3ae 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c | |||
@@ -107,12 +107,30 @@ struct partition { | |||
107 | unsigned char size4[4]; /* nr of sectors in partition */ | 107 | unsigned char size4[4]; /* nr of sectors in partition */ |
108 | } PACKED; | 108 | } PACKED; |
109 | 109 | ||
110 | /* | ||
111 | * per partition table entry data | ||
112 | * | ||
113 | * The four primary partitions have the same sectorbuffer (MBRbuffer) | ||
114 | * and have NULL ext_pointer. | ||
115 | * Each logical partition table entry has two pointers, one for the | ||
116 | * partition and one link to the next one. | ||
117 | */ | ||
118 | struct pte { | ||
119 | struct partition *part_table; /* points into sectorbuffer */ | ||
120 | struct partition *ext_pointer; /* points into sectorbuffer */ | ||
121 | sector_t offset_from_dev_start; /* disk sector number */ | ||
122 | char *sectorbuffer; /* disk sector contents */ | ||
123 | #if ENABLE_FEATURE_FDISK_WRITABLE | ||
124 | char changed; /* boolean */ | ||
125 | #endif | ||
126 | }; | ||
127 | |||
110 | #define unable_to_open "can't open '%s'" | 128 | #define unable_to_open "can't open '%s'" |
111 | #define unable_to_read "can't read from %s" | 129 | #define unable_to_read "can't read from %s" |
112 | #define unable_to_seek "can't seek on %s" | 130 | #define unable_to_seek "can't seek on %s" |
113 | 131 | ||
114 | enum label_type { | 132 | enum label_type { |
115 | LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF | 133 | LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT |
116 | }; | 134 | }; |
117 | 135 | ||
118 | #define LABEL_IS_DOS (LABEL_DOS == current_label_type) | 136 | #define LABEL_IS_DOS (LABEL_DOS == current_label_type) |
@@ -149,6 +167,14 @@ enum label_type { | |||
149 | #define STATIC_OSF extern | 167 | #define STATIC_OSF extern |
150 | #endif | 168 | #endif |
151 | 169 | ||
170 | #if ENABLE_FEATURE_GPT_LABEL | ||
171 | #define LABEL_IS_GPT (LABEL_GPT == current_label_type) | ||
172 | #define STATIC_GPT static | ||
173 | #else | ||
174 | #define LABEL_IS_GPT 0 | ||
175 | #define STATIC_GPT extern | ||
176 | #endif | ||
177 | |||
152 | enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; | 178 | enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; |
153 | 179 | ||
154 | static void update_units(void); | 180 | static void update_units(void); |
@@ -162,6 +188,7 @@ static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t ba | |||
162 | #endif | 188 | #endif |
163 | static const char *partition_type(unsigned char type); | 189 | static const char *partition_type(unsigned char type); |
164 | static void get_geometry(void); | 190 | static void get_geometry(void); |
191 | static void read_pte(struct pte *pe, sector_t offset); | ||
165 | #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE | 192 | #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE |
166 | static int get_boot(enum action what); | 193 | static int get_boot(enum action what); |
167 | #else | 194 | #else |
@@ -174,24 +201,6 @@ static int get_boot(void); | |||
174 | static sector_t get_start_sect(const struct partition *p); | 201 | static sector_t get_start_sect(const struct partition *p); |
175 | static sector_t get_nr_sects(const struct partition *p); | 202 | static sector_t get_nr_sects(const struct partition *p); |
176 | 203 | ||
177 | /* | ||
178 | * per partition table entry data | ||
179 | * | ||
180 | * The four primary partitions have the same sectorbuffer (MBRbuffer) | ||
181 | * and have NULL ext_pointer. | ||
182 | * Each logical partition table entry has two pointers, one for the | ||
183 | * partition and one link to the next one. | ||
184 | */ | ||
185 | struct pte { | ||
186 | struct partition *part_table; /* points into sectorbuffer */ | ||
187 | struct partition *ext_pointer; /* points into sectorbuffer */ | ||
188 | sector_t offset_from_dev_start; /* disk sector number */ | ||
189 | char *sectorbuffer; /* disk sector contents */ | ||
190 | #if ENABLE_FEATURE_FDISK_WRITABLE | ||
191 | char changed; /* boolean */ | ||
192 | #endif | ||
193 | }; | ||
194 | |||
195 | /* DOS partition types */ | 204 | /* DOS partition types */ |
196 | 205 | ||
197 | static const char *const i386_sys_types[] = { | 206 | static const char *const i386_sys_types[] = { |
@@ -653,6 +662,8 @@ STATIC_OSF void bsd_select(void); | |||
653 | STATIC_OSF void xbsd_print_disklabel(int); | 662 | STATIC_OSF void xbsd_print_disklabel(int); |
654 | #include "fdisk_osf.c" | 663 | #include "fdisk_osf.c" |
655 | 664 | ||
665 | #include "fdisk_gpt.c" | ||
666 | |||
656 | #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL | 667 | #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL |
657 | static uint16_t | 668 | static uint16_t |
658 | fdisk_swap16(uint16_t x) | 669 | fdisk_swap16(uint16_t x) |
@@ -833,6 +844,11 @@ menu(void) | |||
833 | puts("o\tcreate a new empty DOS partition table"); | 844 | puts("o\tcreate a new empty DOS partition table"); |
834 | puts("q\tquit without saving changes"); | 845 | puts("q\tquit without saving changes"); |
835 | puts("s\tcreate a new empty Sun disklabel"); /* sun */ | 846 | puts("s\tcreate a new empty Sun disklabel"); /* sun */ |
847 | } else if (LABEL_IS_GPT) { | ||
848 | puts("o\tcreate a new empty DOS partition table"); | ||
849 | puts("p\tprint the partition table"); | ||
850 | puts("q\tquit without saving changes"); | ||
851 | puts("s\tcreate a new empty Sun disklabel"); /* sun */ | ||
836 | } else { | 852 | } else { |
837 | puts("a\ttoggle a bootable flag"); | 853 | puts("a\ttoggle a bootable flag"); |
838 | puts("b\tedit bsd disklabel"); | 854 | puts("b\tedit bsd disklabel"); |
@@ -1308,7 +1324,18 @@ get_geometry(void) | |||
1308 | 1324 | ||
1309 | /* | 1325 | /* |
1310 | * Opens disk_device and optionally reads MBR. | 1326 | * Opens disk_device and optionally reads MBR. |
1311 | * FIXME: document what each 'what' value will do! | 1327 | * If what == OPEN_MAIN: |
1328 | * Open device, read MBR. Abort program on short read. Create empty | ||
1329 | * disklabel if the on-disk structure is invalid (WRITABLE mode). | ||
1330 | * If what == TRY_ONLY: | ||
1331 | * Open device, read MBR. Return an error if anything is out of place. | ||
1332 | * Do not create an empty disklabel. This is used for the "list" | ||
1333 | * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices). | ||
1334 | * If what == CREATE_EMPTY_*: | ||
1335 | * This means that get_boot() was called recursively from create_*label(). | ||
1336 | * Do not re-open the device; just set up the ptes array and print | ||
1337 | * geometry warnings. | ||
1338 | * | ||
1312 | * Returns: | 1339 | * Returns: |
1313 | * -1: no 0xaa55 flag present (possibly entire disk BSD) | 1340 | * -1: no 0xaa55 flag present (possibly entire disk BSD) |
1314 | * 0: found or created label | 1341 | * 0: found or created label |
@@ -1390,6 +1417,10 @@ static int get_boot(void) | |||
1390 | if (check_aix_label()) | 1417 | if (check_aix_label()) |
1391 | return 0; | 1418 | return 0; |
1392 | #endif | 1419 | #endif |
1420 | #if ENABLE_FEATURE_GPT_LABEL | ||
1421 | if (check_gpt_label()) | ||
1422 | return 0; | ||
1423 | #endif | ||
1393 | #if ENABLE_FEATURE_OSF_LABEL | 1424 | #if ENABLE_FEATURE_OSF_LABEL |
1394 | if (check_osf_label()) { | 1425 | if (check_osf_label()) { |
1395 | possibly_osf_label = 1; | 1426 | possibly_osf_label = 1; |
@@ -1409,7 +1440,7 @@ static int get_boot(void) | |||
1409 | if (!valid_part_table_flag(MBRbuffer)) { | 1440 | if (!valid_part_table_flag(MBRbuffer)) { |
1410 | if (what == OPEN_MAIN) { | 1441 | if (what == OPEN_MAIN) { |
1411 | printf("Device contains neither a valid DOS " | 1442 | printf("Device contains neither a valid DOS " |
1412 | "partition table, nor Sun, SGI or OSF " | 1443 | "partition table, nor Sun, SGI, OSF or GPT " |
1413 | "disklabel\n"); | 1444 | "disklabel\n"); |
1414 | #ifdef __sparc__ | 1445 | #ifdef __sparc__ |
1415 | IF_FEATURE_SUN_LABEL(create_sunlabel();) | 1446 | IF_FEATURE_SUN_LABEL(create_sunlabel();) |
@@ -2056,10 +2087,14 @@ list_table(int xtra) | |||
2056 | sun_list_table(xtra); | 2087 | sun_list_table(xtra); |
2057 | return; | 2088 | return; |
2058 | } | 2089 | } |
2059 | if (LABEL_IS_SUN) { | 2090 | if (LABEL_IS_SGI) { |
2060 | sgi_list_table(xtra); | 2091 | sgi_list_table(xtra); |
2061 | return; | 2092 | return; |
2062 | } | 2093 | } |
2094 | if (LABEL_IS_GPT) { | ||
2095 | gpt_list_table(xtra); | ||
2096 | return; | ||
2097 | } | ||
2063 | 2098 | ||
2064 | list_disk_geometry(); | 2099 | list_disk_geometry(); |
2065 | 2100 | ||
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c new file mode 100644 index 000000000..1ab1293de --- /dev/null +++ b/util-linux/fdisk_gpt.c | |||
@@ -0,0 +1,195 @@ | |||
1 | #if ENABLE_FEATURE_GPT_LABEL | ||
2 | /* | ||
3 | * Copyright (C) 2010 Kevin Cernekee <cernekee@gmail.com> | ||
4 | * | ||
5 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
6 | */ | ||
7 | |||
8 | #define GPT_MAGIC 0x5452415020494645ULL | ||
9 | enum { | ||
10 | LEGACY_GPT_TYPE = 0xee, | ||
11 | GPT_MAX_PARTS = 256, | ||
12 | GPT_MAX_PART_ENTRY_LEN = 4096, | ||
13 | GUID_LEN = 16, | ||
14 | }; | ||
15 | |||
16 | typedef struct { | ||
17 | uint64_t magic; | ||
18 | uint32_t revision; | ||
19 | uint32_t hdr_size; | ||
20 | uint32_t hdr_crc32; | ||
21 | uint32_t reserved; | ||
22 | uint64_t current_lba; | ||
23 | uint64_t backup_lba; | ||
24 | uint64_t first_usable_lba; | ||
25 | uint64_t last_usable_lba; | ||
26 | uint8_t disk_guid[GUID_LEN]; | ||
27 | uint64_t first_part_lba; | ||
28 | uint32_t n_parts; | ||
29 | uint32_t part_entry_len; | ||
30 | uint32_t part_array_crc32; | ||
31 | } gpt_header; | ||
32 | |||
33 | typedef struct { | ||
34 | uint8_t type_guid[GUID_LEN]; | ||
35 | uint8_t part_guid[GUID_LEN]; | ||
36 | uint64_t lba_start; | ||
37 | uint64_t lba_end; | ||
38 | uint64_t flags; | ||
39 | uint16_t name[36]; | ||
40 | } gpt_partition; | ||
41 | |||
42 | static gpt_header *gpt_hdr; | ||
43 | |||
44 | static char *part_array; | ||
45 | static unsigned int n_parts; | ||
46 | static unsigned int part_array_len; | ||
47 | static unsigned int part_entry_len; | ||
48 | |||
49 | static inline gpt_partition * | ||
50 | gpt_part(int i) | ||
51 | { | ||
52 | if (i >= n_parts) { | ||
53 | return NULL; | ||
54 | } | ||
55 | return (gpt_partition *)&part_array[i * part_entry_len]; | ||
56 | } | ||
57 | |||
58 | static uint32_t | ||
59 | gpt_crc32(void *buf, int len) | ||
60 | { | ||
61 | return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); | ||
62 | } | ||
63 | |||
64 | static void | ||
65 | gpt_print_guid(uint8_t *buf) | ||
66 | { | ||
67 | printf( | ||
68 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | ||
69 | buf[3], buf[2], buf[1], buf[0], | ||
70 | buf[5], buf[4], | ||
71 | buf[7], buf[6], | ||
72 | buf[8], buf[9], | ||
73 | buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); | ||
74 | } | ||
75 | |||
76 | /* TODO: real unicode support */ | ||
77 | static void | ||
78 | gpt_print_wide(uint16_t *s, int max_len) | ||
79 | { | ||
80 | int i = 0; | ||
81 | |||
82 | while (i < max_len) { | ||
83 | if (*s == 0) | ||
84 | return; | ||
85 | fputc(*s, stdout); | ||
86 | s++; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static void | ||
91 | gpt_list_table(int xtra UNUSED_PARAM) | ||
92 | { | ||
93 | int i; | ||
94 | char numstr6[6]; | ||
95 | |||
96 | numstr6[5] = '\0'; | ||
97 | |||
98 | smart_ulltoa5(total_number_of_sectors, numstr6, " KMGTPEZY"); | ||
99 | printf("Disk %s: %llu sectors, %s\n", disk_device, | ||
100 | (unsigned long long)total_number_of_sectors, | ||
101 | numstr6); | ||
102 | printf("Logical sector size: %u\n", sector_size); | ||
103 | printf("Disk identifier (GUID): "); | ||
104 | gpt_print_guid(gpt_hdr->disk_guid); | ||
105 | printf("\nPartition table holds up to %u entries\n", | ||
106 | (int)SWAP_LE32(gpt_hdr->n_parts)); | ||
107 | printf("First usable sector is %llu, last usable sector is %llu\n\n", | ||
108 | (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba), | ||
109 | (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba)); | ||
110 | |||
111 | printf("Number Start (sector) End (sector) Size Code Name\n"); | ||
112 | for (i = 0; i < n_parts; i++) { | ||
113 | gpt_partition *p = gpt_part(i); | ||
114 | if (p->lba_start) { | ||
115 | smart_ulltoa5(1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start), | ||
116 | numstr6, " KMGTPEZY"); | ||
117 | printf("%4u %15llu %15llu %11s %04x ", | ||
118 | i + 1, | ||
119 | (unsigned long long)SWAP_LE64(p->lba_start), | ||
120 | (unsigned long long)SWAP_LE64(p->lba_end), | ||
121 | numstr6, | ||
122 | 0x0700 /* FIXME */); | ||
123 | gpt_print_wide(p->name, 18); | ||
124 | printf("\n"); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static int | ||
130 | check_gpt_label(void) | ||
131 | { | ||
132 | struct partition *first = pt_offset(MBRbuffer, 0); | ||
133 | struct pte pe; | ||
134 | uint32_t crc; | ||
135 | |||
136 | /* LBA 0 contains the legacy MBR */ | ||
137 | |||
138 | if (!valid_part_table_flag(MBRbuffer) | ||
139 | || first->sys_ind != LEGACY_GPT_TYPE | ||
140 | ) { | ||
141 | current_label_type = 0; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /* LBA 1 contains the GPT header */ | ||
146 | |||
147 | read_pte(&pe, 1); | ||
148 | gpt_hdr = (void *)pe.sectorbuffer; | ||
149 | |||
150 | if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { | ||
151 | current_label_type = 0; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | if (!global_crc32_table) { | ||
156 | global_crc32_table = crc32_filltable(NULL, 0); | ||
157 | } | ||
158 | |||
159 | crc = SWAP_LE32(gpt_hdr->hdr_crc32); | ||
160 | gpt_hdr->hdr_crc32 = 0; | ||
161 | if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) { | ||
162 | /* FIXME: read the backup table */ | ||
163 | puts("\nwarning: GPT header CRC is invalid\n"); | ||
164 | } | ||
165 | |||
166 | n_parts = SWAP_LE32(gpt_hdr->n_parts); | ||
167 | part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len); | ||
168 | if (n_parts > GPT_MAX_PARTS | ||
169 | || part_entry_len > GPT_MAX_PART_ENTRY_LEN | ||
170 | || SWAP_LE32(gpt_hdr->hdr_size) > sector_size | ||
171 | ) { | ||
172 | puts("\nwarning: unable to parse GPT disklabel\n"); | ||
173 | current_label_type = 0; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | part_array_len = n_parts * part_entry_len; | ||
178 | part_array = xmalloc(part_array_len); | ||
179 | seek_sector(SWAP_LE64(gpt_hdr->first_part_lba)); | ||
180 | if (full_read(dev_fd, part_array, part_array_len) != part_array_len) { | ||
181 | fdisk_fatal(unable_to_read); | ||
182 | } | ||
183 | |||
184 | if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) { | ||
185 | /* FIXME: read the backup table */ | ||
186 | puts("\nwarning: GPT array CRC is invalid\n"); | ||
187 | } | ||
188 | |||
189 | puts("Found valid GPT with protective MBR; using GPT\n"); | ||
190 | |||
191 | current_label_type = LABEL_GPT; | ||
192 | return 1; | ||
193 | } | ||
194 | |||
195 | #endif /* GPT_LABEL */ | ||
diff --git a/util-linux/mount.c b/util-linux/mount.c index 5e85f9986..0f213bb30 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c | |||
@@ -332,7 +332,7 @@ static void append_mount_options(char **oldopts, const char *newopts) | |||
332 | } | 332 | } |
333 | 333 | ||
334 | // Use the mount_options list to parse options into flags. | 334 | // Use the mount_options list to parse options into flags. |
335 | // Also return list of unrecognized options if unrecognized != NULL | 335 | // Also update list of unrecognized options if unrecognized != NULL |
336 | static long parse_mount_options(char *options, char **unrecognized) | 336 | static long parse_mount_options(char *options, char **unrecognized) |
337 | { | 337 | { |
338 | long flags = MS_SILENT; | 338 | long flags = MS_SILENT; |
@@ -348,25 +348,35 @@ static long parse_mount_options(char *options, char **unrecognized) | |||
348 | // FIXME: use hasmntopt() | 348 | // FIXME: use hasmntopt() |
349 | // Find this option in mount_options | 349 | // Find this option in mount_options |
350 | for (i = 0; i < ARRAY_SIZE(mount_options); i++) { | 350 | for (i = 0; i < ARRAY_SIZE(mount_options); i++) { |
351 | if (!strcasecmp(option_str, options)) { | 351 | if (strcasecmp(option_str, options) == 0) { |
352 | long fl = mount_options[i]; | 352 | long fl = mount_options[i]; |
353 | if (fl < 0) flags &= fl; | 353 | if (fl < 0) |
354 | else flags |= fl; | 354 | flags &= fl; |
355 | break; | 355 | else |
356 | flags |= fl; | ||
357 | goto found; | ||
356 | } | 358 | } |
357 | option_str += strlen(option_str) + 1; | 359 | option_str += strlen(option_str) + 1; |
358 | } | 360 | } |
359 | // If unrecognized not NULL, append unrecognized mount options | 361 | // We did not recognize this option. |
360 | if (unrecognized && i == ARRAY_SIZE(mount_options)) { | 362 | // If "unrecognized" is not NULL, append option there. |
363 | // Note that we should not append *empty* option - | ||
364 | // in this case we want to pass NULL, not "", to "data" | ||
365 | // parameter of mount(2) syscall. | ||
366 | // This is crucial for filesystems that don't accept | ||
367 | // any arbitrary mount options, like cgroup fs: | ||
368 | // "mount -t cgroup none /mnt" | ||
369 | if (options[0] && unrecognized) { | ||
361 | // Add it to strflags, to pass on to kernel | 370 | // Add it to strflags, to pass on to kernel |
362 | i = *unrecognized ? strlen(*unrecognized) : 0; | 371 | char *p = *unrecognized; |
363 | *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2); | 372 | unsigned len = p ? strlen(p) : 0; |
373 | *unrecognized = p = xrealloc(p, len + strlen(options) + 2); | ||
364 | 374 | ||
365 | // Comma separated if it's not the first one | 375 | // Comma separated if it's not the first one |
366 | if (i) (*unrecognized)[i++] = ','; | 376 | if (len) p[len++] = ','; |
367 | strcpy((*unrecognized)+i, options); | 377 | strcpy(p + len, options); |
368 | } | 378 | } |
369 | 379 | found: | |
370 | if (!comma) | 380 | if (!comma) |
371 | break; | 381 | break; |
372 | // Advance to next option | 382 | // Advance to next option |
@@ -775,78 +785,52 @@ static char *nfs_strerror(int status) | |||
775 | 785 | ||
776 | static bool_t xdr_fhandle(XDR *xdrs, fhandle objp) | 786 | static bool_t xdr_fhandle(XDR *xdrs, fhandle objp) |
777 | { | 787 | { |
778 | if (!xdr_opaque(xdrs, objp, FHSIZE)) | 788 | return xdr_opaque(xdrs, objp, FHSIZE); |
779 | return FALSE; | ||
780 | return TRUE; | ||
781 | } | 789 | } |
782 | 790 | ||
783 | static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp) | 791 | static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp) |
784 | { | 792 | { |
785 | if (!xdr_u_int(xdrs, &objp->fhs_status)) | 793 | if (!xdr_u_int(xdrs, &objp->fhs_status)) |
786 | return FALSE; | 794 | return FALSE; |
787 | switch (objp->fhs_status) { | 795 | if (objp->fhs_status == 0) |
788 | case 0: | 796 | return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle); |
789 | if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) | ||
790 | return FALSE; | ||
791 | break; | ||
792 | default: | ||
793 | break; | ||
794 | } | ||
795 | return TRUE; | 797 | return TRUE; |
796 | } | 798 | } |
797 | 799 | ||
798 | static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp) | 800 | static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp) |
799 | { | 801 | { |
800 | if (!xdr_string(xdrs, objp, MNTPATHLEN)) | 802 | return xdr_string(xdrs, objp, MNTPATHLEN); |
801 | return FALSE; | ||
802 | return TRUE; | ||
803 | } | 803 | } |
804 | 804 | ||
805 | static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp) | 805 | static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp) |
806 | { | 806 | { |
807 | if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, | 807 | return xdr_bytes(xdrs, (char **)&objp->fhandle3_val, |
808 | (unsigned int *) &objp->fhandle3_len, | 808 | (unsigned int *) &objp->fhandle3_len, |
809 | FHSIZE3) | 809 | FHSIZE3); |
810 | ) { | ||
811 | return FALSE; | ||
812 | } | ||
813 | return TRUE; | ||
814 | } | 810 | } |
815 | 811 | ||
816 | static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp) | 812 | static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp) |
817 | { | 813 | { |
818 | if (!xdr_fhandle3(xdrs, &objp->fhandle)) | 814 | if (!xdr_fhandle3(xdrs, &objp->fhandle)) |
819 | return FALSE; | 815 | return FALSE; |
820 | if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), | 816 | return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), |
821 | &(objp->auth_flavours.auth_flavours_len), | 817 | &(objp->auth_flavours.auth_flavours_len), |
822 | ~0, | 818 | ~0, |
823 | sizeof(int), | 819 | sizeof(int), |
824 | (xdrproc_t) xdr_int) | 820 | (xdrproc_t) xdr_int); |
825 | ) { | ||
826 | return FALSE; | ||
827 | } | ||
828 | return TRUE; | ||
829 | } | 821 | } |
830 | 822 | ||
831 | static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp) | 823 | static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp) |
832 | { | 824 | { |
833 | if (!xdr_enum(xdrs, (enum_t *) objp)) | 825 | return xdr_enum(xdrs, (enum_t *) objp); |
834 | return FALSE; | ||
835 | return TRUE; | ||
836 | } | 826 | } |
837 | 827 | ||
838 | static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp) | 828 | static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp) |
839 | { | 829 | { |
840 | if (!xdr_mountstat3(xdrs, &objp->fhs_status)) | 830 | if (!xdr_mountstat3(xdrs, &objp->fhs_status)) |
841 | return FALSE; | 831 | return FALSE; |
842 | switch (objp->fhs_status) { | 832 | if (objp->fhs_status == MNT_OK) |
843 | case MNT_OK: | 833 | return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo); |
844 | if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo)) | ||
845 | return FALSE; | ||
846 | break; | ||
847 | default: | ||
848 | break; | ||
849 | } | ||
850 | return TRUE; | 834 | return TRUE; |
851 | } | 835 | } |
852 | 836 | ||
diff --git a/util-linux/umount.c b/util-linux/umount.c index 7ba46eeb0..78c603856 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c | |||
@@ -39,9 +39,6 @@ | |||
39 | # define MS_RELATIME (1 << 21) | 39 | # define MS_RELATIME (1 << 21) |
40 | #endif | 40 | #endif |
41 | #include "libbb.h" | 41 | #include "libbb.h" |
42 | #ifndef PATH_MAX | ||
43 | # define PATH_MAX (4*1024) | ||
44 | #endif | ||
45 | 42 | ||
46 | 43 | ||
47 | #if defined(__dietlibc__) | 44 | #if defined(__dietlibc__) |
@@ -73,7 +70,7 @@ int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
73 | int umount_main(int argc UNUSED_PARAM, char **argv) | 70 | int umount_main(int argc UNUSED_PARAM, char **argv) |
74 | { | 71 | { |
75 | int doForce; | 72 | int doForce; |
76 | char *const buf = xmalloc(PATH_MAX * 2 + 128); /* to save stack */ | 73 | char *const buf = xmalloc(4096); /* reducing stack usage */ |
77 | struct mntent me; | 74 | struct mntent me; |
78 | FILE *fp; | 75 | FILE *fp; |
79 | char *fstype = NULL; | 76 | char *fstype = NULL; |
@@ -104,7 +101,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv) | |||
104 | if (opt & OPT_ALL) | 101 | if (opt & OPT_ALL) |
105 | bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file); | 102 | bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file); |
106 | } else { | 103 | } else { |
107 | while (getmntent_r(fp, &me, buf, PATH_MAX * 2 + 128)) { | 104 | while (getmntent_r(fp, &me, buf, 4096)) { |
108 | /* Match fstype if passed */ | 105 | /* Match fstype if passed */ |
109 | if (!match_fstype(&me, fstype)) | 106 | if (!match_fstype(&me, fstype)) |
110 | continue; | 107 | continue; |