aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:55:06 +0700
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:55:06 +0700
commit3f357a9c754805c4c38793749927aeda82797735 (patch)
tree65bb50517515714b6baaa4d5d2debed1e716bc83
parent47a20f7daf954c90bbc77d2c108cb366171c650f (diff)
parent776509544123c68bbc128c0fdb2f699062d294cf (diff)
downloadbusybox-w32-3f357a9c754805c4c38793749927aeda82797735.tar.gz
busybox-w32-3f357a9c754805c4c38793749927aeda82797735.tar.bz2
busybox-w32-3f357a9c754805c4c38793749927aeda82797735.zip
Merge commit 'e4dcba1c103dc28e927e004791e331aaf604383d^'
-rw-r--r--Makefile2
-rw-r--r--Makefile.custom6
-rw-r--r--archival/gzip.c16
-rw-r--r--archival/libunarchive/decompress_unxz.c14
-rw-r--r--archival/libunarchive/decompress_unzip.c5
-rw-r--r--archival/lzop.c22
-rw-r--r--coreutils/cksum.c7
-rw-r--r--coreutils/md5_sha1_sum.c41
-rw-r--r--coreutils/mv.c46
-rw-r--r--coreutils/printf.c18
-rw-r--r--docs/.gitignore2
-rw-r--r--docs/smallint.txt39
-rw-r--r--e2fsprogs/old_e2fsprogs/fsck.c10
-rw-r--r--editors/awk.c266
-rw-r--r--include/libbb.h32
-rw-r--r--include/platform.h9
-rw-r--r--include/usage.src.h33
-rw-r--r--init/init.c26
-rw-r--r--libbb/Config.src11
-rw-r--r--libbb/crc32.c24
-rw-r--r--libbb/hash_md5_sha.c105
-rw-r--r--libbb/human_readable.c4
-rw-r--r--libbb/parse_config.c14
-rw-r--r--libbb/process_escape_sequence.c78
-rw-r--r--loginutils/getty.c18
-rw-r--r--loginutils/login.c7
-rw-r--r--miscutils/flash_eraseall.c14
-rw-r--r--networking/netstat.c198
-rw-r--r--procps/powertop.c880
-rw-r--r--procps/top.c3
-rwxr-xr-xtestsuite/awk.tests6
-rw-r--r--util-linux/Config.src19
-rw-r--r--util-linux/fdisk.c79
-rw-r--r--util-linux/fdisk_gpt.c195
-rw-r--r--util-linux/mount.c90
-rw-r--r--util-linux/umount.c7
36 files changed, 1744 insertions, 602 deletions
diff --git a/Makefile b/Makefile
index 60999dd4b..aff2a7a55 100644
--- a/Makefile
+++ b/Makefile
@@ -993,7 +993,7 @@ clean: archclean $(clean-dirs)
993 993
994PHONY += doc-clean 994PHONY += doc-clean
995doc-clean: rm-files := docs/busybox.pod \ 995doc-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
997doc-clean: 997doc-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
110doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html 110doc: 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
138docs/BusyBox.1: docs/busybox.pod 138docs/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
143docs/BusyBox.html: docs/busybox.net/BusyBox.html 143docs/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 */
396static uint32_t updcrc(uch * s, unsigned n) 396static 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
25static uint32_t *crc32_table;
26static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) 25static 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 */
926static void calculate_gunzip_crc(STATE_PARAM_ONLY) 926static 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
395struct globals { 395struct 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)
468static FAST_FUNC uint32_t 468static FAST_FUNC uint32_t
469lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) 469lzo_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
13typedef enum { 13enum {
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
35static uint8_t *hash_file(const char *filename /*, hash_algo_t hash_algo*/) 35static 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;
99int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) 101int 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
20static const char mv_longopts[] ALIGN1 = 33static 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
29int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 44int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
30int mv_main(int argc, char **argv) 45int 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
125static void print_esc_string(char *str) 125static 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
9I think that this optimization is wrong.
10index_in_str_array returns int. At best, compiler will use it as-is.
11At worst, compiler will try to make sure that it is properly cast
12into a byte, which probably results in "n = n & 0xff" on many architectures.
13
14You save nothing on space here because i is not stored on-stack,
15gcc will keep it in register. And even if it *is* stored,
16it is *stack* storage, which is cheap (unlike data/bss).
17
18small[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
33small[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
363static void free_instance(struct fsck_instance *i) 355static 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
285static const char tokenlist[] ALIGN1 = 285static 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
330static const uint32_t tokeninfo[] = { 331static 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";
532static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; 524static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
533static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; 525static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
534static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; 526static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
535#if !ENABLE_FEATURE_AWK_LIBM
536static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; 527static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
537#endif
538 528
539static void zero_out_var(var *vp) 529static 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)
705static double my_strtod(char **pp) 698static 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 */
2918static int is_assignment(const char *expr) 2930static 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 */
336extern void complain_copyfd_and_die(off_t sz) NORETURN FAST_FUNC; 336extern void complain_copyfd_and_die(off_t sz) NORETURN FAST_FUNC;
337extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC; 337extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC;
338char* 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;
759char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; 760char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
760char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; 761char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC;
761/* Intelligent formatters of bignums */ 762/* Intelligent formatters of bignums */
762void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; 763void smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC;
763void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; 764void 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;
1559void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; 1560void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
1560void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; 1561void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC;
1561 1562
1562 1563extern uint32_t *global_crc32_table;
1563uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; 1564uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC;
1565uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC;
1566uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC;
1564 1567
1565typedef struct masks_labels_t { 1568typedef 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)
1083int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1088int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1084int init_main(int argc UNUSED_PARAM, char **argv) 1089int 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
46config 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
46config FEATURE_EDITING 57config 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
21uint32_t *global_crc32_table;
22
21uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) 23uint32_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
46uint32_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
57uint32_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
504static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) 497static 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) */
97void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) 97void 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) */
153void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) 153void 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
19char FAST_FUNC bb_process_escape_sequence(const char **ptr) 19char 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
100char* 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
45static 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
54static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) 45static 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
25enum { 50enum {
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
123struct globals { 149struct 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
152static void prg_cache_add(long inode, char *name) 182static 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
221static int FAST_FUNC file_act(const char *fileName, 251static 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
278static void prg_cache_load(void) 310static 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 {
364static int scan_inet_proc_line(struct inet_params *param, char *line) 395static 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, &param->local_port, 408 local_addr, &param->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 &param->remaddr.sa, param->rem_port, 438 &param->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(&param, 0, sizeof(param));
422 if (scan_inet_proc_line(&param, line)) 460 if (scan_inet_proc_line(&param, 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(&param, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */
449 if (scan_inet_proc_line(&param, line)) 488 if (scan_inet_proc_line(&param, 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 *))
617int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 656int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
618int netstat_main(int argc UNUSED_PARAM, char **argv) 657int 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
47typedef unsigned long long ullong;
48
49struct line {
50 char *string;
51 int count;
52 /*int disk_count;*/
53};
54
55#if ENABLE_FEATURE_POWERTOP_PROCIRQ
56struct irqdata {
57 smallint active;
58 int number;
59 ullong count;
60 char irq_desc[32];
61};
62#endif
63
64struct 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
95static void reset_term(void)
96{
97 tcsetattr_stdin_TCSANOW(&G.init_settings);
98}
99
100static void sig_handler(int signo UNUSED_PARAM)
101{
102 reset_term();
103 _exit(EXIT_FAILURE);
104}
105#endif
106
107static 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
121static 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
133static 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
140static 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
147static 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. */
153static 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 */
210static 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
230static 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 */
278static 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 */
300static 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
404static 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 */
520static 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
542static 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
639static 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
703int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
704int 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)
649static void sig_catcher(int sig UNUSED_PARAM) 649static 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)" \
77testing "awk handles whitespace before array subscript" \ 77testing "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?
82testing "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
80prg=' 86prg='
81BEGIN { 87BEGIN {
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
184config 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
184config FEATURE_FDISK_ADVANCED 192config 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
481config 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
492config MOUNT 489config 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 */
118struct 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
114enum label_type { 132enum 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
152enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; 178enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
153 179
154static void update_units(void); 180static 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
163static const char *partition_type(unsigned char type); 189static const char *partition_type(unsigned char type);
164static void get_geometry(void); 190static void get_geometry(void);
191static 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
166static int get_boot(enum action what); 193static int get_boot(enum action what);
167#else 194#else
@@ -174,24 +201,6 @@ static int get_boot(void);
174static sector_t get_start_sect(const struct partition *p); 201static sector_t get_start_sect(const struct partition *p);
175static sector_t get_nr_sects(const struct partition *p); 202static 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 */
185struct 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
197static const char *const i386_sys_types[] = { 206static const char *const i386_sys_types[] = {
@@ -653,6 +662,8 @@ STATIC_OSF void bsd_select(void);
653STATIC_OSF void xbsd_print_disklabel(int); 662STATIC_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
657static uint16_t 668static uint16_t
658fdisk_swap16(uint16_t x) 669fdisk_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
9enum {
10 LEGACY_GPT_TYPE = 0xee,
11 GPT_MAX_PARTS = 256,
12 GPT_MAX_PART_ENTRY_LEN = 4096,
13 GUID_LEN = 16,
14};
15
16typedef 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
33typedef 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
42static gpt_header *gpt_hdr;
43
44static char *part_array;
45static unsigned int n_parts;
46static unsigned int part_array_len;
47static unsigned int part_entry_len;
48
49static inline gpt_partition *
50gpt_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
58static uint32_t
59gpt_crc32(void *buf, int len)
60{
61 return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table);
62}
63
64static void
65gpt_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 */
77static void
78gpt_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
90static void
91gpt_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
129static int
130check_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
336static long parse_mount_options(char *options, char **unrecognized) 336static 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
776static bool_t xdr_fhandle(XDR *xdrs, fhandle objp) 786static 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
783static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp) 791static 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
798static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp) 800static 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
805static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp) 805static 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
816static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp) 812static 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
831static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp) 823static 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
838static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp) 828static 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;
73int umount_main(int argc UNUSED_PARAM, char **argv) 70int 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;