diff options
author | Ron Yorston <rmy@pobox.com> | 2020-01-08 12:30:49 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-01-08 12:30:49 +0000 |
commit | a9271a8e97e6e7be5285330d5f19352decabf807 (patch) | |
tree | bf3c4464c369a15a46454792dac167505f74769f | |
parent | b0b7ab792bc1f45963f4b84b94faaf05054e1613 (diff) | |
parent | 9ec836c033fc6e55e80f3309b3e05acdf09bb297 (diff) | |
download | busybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.tar.gz busybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.tar.bz2 busybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.zip |
Merge branch 'busybox' into merge
65 files changed, 1523 insertions, 716 deletions
@@ -170,12 +170,13 @@ config FEATURE_PIDFILE | |||
170 | config PID_FILE_PATH | 170 | config PID_FILE_PATH |
171 | string "Directory for pidfiles" | 171 | string "Directory for pidfiles" |
172 | default "/var/run" | 172 | default "/var/run" |
173 | depends on FEATURE_PIDFILE | 173 | depends on FEATURE_PIDFILE || FEATURE_CROND_SPECIAL_TIMES |
174 | help | 174 | help |
175 | This is the default path where pidfiles are created. Applets which | 175 | This is the default path where pidfiles are created. Applets which |
176 | allow you to set the pidfile path on the command line will override | 176 | allow you to set the pidfile path on the command line will override |
177 | this value. The option has no effect on applets that require you to | 177 | this value. The option has no effect on applets that require you to |
178 | specify a pidfile path. | 178 | specify a pidfile path. When crond has the 'Support special times' |
179 | option enabled, the 'crond.reboot' file is also stored here. | ||
179 | 180 | ||
180 | config BUSYBOX | 181 | config BUSYBOX |
181 | bool "Include busybox applet" | 182 | bool "Include busybox applet" |
diff --git a/Makefile.flags b/Makefile.flags index 6d4b2c3aa..66f28874e 100644 --- a/Makefile.flags +++ b/Makefile.flags | |||
@@ -47,12 +47,28 @@ endif | |||
47 | # gcc 3.x emits bogus "old style proto" warning on find.c:alloc_action() | 47 | # gcc 3.x emits bogus "old style proto" warning on find.c:alloc_action() |
48 | CFLAGS += $(call cc-ifversion, -ge, 0400, -Wold-style-definition) | 48 | CFLAGS += $(call cc-ifversion, -ge, 0400, -Wold-style-definition) |
49 | 49 | ||
50 | CFLAGS += $(call cc-option,-fno-builtin-strlen -finline-limit=0 -fomit-frame-pointer -ffunction-sections -fdata-sections,) | 50 | ifneq ($(CC),clang) |
51 | # "clang-9: warning: optimization flag '-finline-limit=0' is not supported | ||
52 | CFLAGS += $(call cc-option,-finline-limit=0,) | ||
53 | endif | ||
54 | |||
55 | CFLAGS += $(call cc-option,-fno-builtin-strlen -fomit-frame-pointer -ffunction-sections -fdata-sections,) | ||
51 | # -fno-guess-branch-probability: prohibit pseudo-random guessing | 56 | # -fno-guess-branch-probability: prohibit pseudo-random guessing |
52 | # of branch probabilities (hopefully makes bloatcheck more stable): | 57 | # of branch probabilities (hopefully makes bloatcheck more stable): |
53 | CFLAGS += $(call cc-option,-fno-guess-branch-probability,) | 58 | CFLAGS += $(call cc-option,-fno-guess-branch-probability,) |
54 | CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,) | 59 | CFLAGS += $(call cc-option,-funsigned-char,) |
55 | CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,) | 60 | |
61 | ifneq ($(CC),clang) | ||
62 | # "clang-9: warning: argument unused during compilation: '-static-libgcc'" | ||
63 | CFLAGS += $(call cc-option,-static-libgcc,) | ||
64 | endif | ||
65 | |||
66 | CFLAGS += $(call cc-option,-falign-functions=1,) | ||
67 | ifneq ($(CC),clang) | ||
68 | # "clang-9: warning: optimization flag '-falign-jumps=1' is not supported" (and same for other two) | ||
69 | CFLAGS += $(call cc-option,-falign-jumps=1 -falign-labels=1 -falign-loops=1,) | ||
70 | endif | ||
71 | |||
56 | # Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): | 72 | # Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): |
57 | CFLAGS += $(call cc-option,-fno-unwind-tables,) | 73 | CFLAGS += $(call cc-option,-fno-unwind-tables,) |
58 | CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) | 74 | CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) |
@@ -60,6 +76,9 @@ CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) | |||
60 | # (try disabling this and comparing assembly, it's instructive) | 76 | # (try disabling this and comparing assembly, it's instructive) |
61 | CFLAGS += $(call cc-option,-fno-builtin-printf,) | 77 | CFLAGS += $(call cc-option,-fno-builtin-printf,) |
62 | 78 | ||
79 | # clang-9 does not like "str" + N and "if (CONFIG_ITEM && cond)" constructs | ||
80 | CFLAGS += $(call cc-option,-Wno-string-plus-int -Wno-constant-logical-operand) | ||
81 | |||
63 | # FIXME: These warnings are at least partially to be concerned about and should | 82 | # FIXME: These warnings are at least partially to be concerned about and should |
64 | # be fixed.. | 83 | # be fixed.. |
65 | #CFLAGS += $(call cc-option,-Wconversion,) | 84 | #CFLAGS += $(call cc-option,-Wconversion,) |
@@ -135,10 +154,12 @@ endif | |||
135 | # fall back to using a temp file: | 154 | # fall back to using a temp file: |
136 | CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c) | 155 | CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c) |
137 | ifeq ($(CRYPT_AVAILABLE),y) | 156 | ifeq ($(CRYPT_AVAILABLE),y) |
138 | LDLIBS += m crypt | 157 | LDLIBS += m rt crypt |
139 | else | 158 | else |
140 | LDLIBS += m | 159 | LDLIBS += m rt |
141 | endif | 160 | endif |
161 | # libm may be needed for dc, awk, ntpd | ||
162 | # librt may be needed for clock_gettime() | ||
142 | 163 | ||
143 | # libpam may use libpthread, libdl and/or libaudit. | 164 | # libpam may use libpthread, libdl and/or libaudit. |
144 | # On some platforms that requires an explicit -lpthread, -ldl, -laudit. | 165 | # On some platforms that requires an explicit -lpthread, -ldl, -laudit. |
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 24033c9f5..da6f031e3 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -538,6 +538,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) | |||
538 | //usage: "\n -c Write to stdout" | 538 | //usage: "\n -c Write to stdout" |
539 | //usage: "\n -f Force" | 539 | //usage: "\n -f Force" |
540 | //usage: "\n -k Keep input files" | 540 | //usage: "\n -k Keep input files" |
541 | //usage: "\n -t Test file integrity" | ||
541 | //usage: | 542 | //usage: |
542 | //usage:#define xz_trivial_usage | 543 | //usage:#define xz_trivial_usage |
543 | //usage: "-d [-cfk] [FILE]..." | 544 | //usage: "-d [-cfk] [FILE]..." |
@@ -547,6 +548,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) | |||
547 | //usage: "\n -c Write to stdout" | 548 | //usage: "\n -c Write to stdout" |
548 | //usage: "\n -f Force" | 549 | //usage: "\n -f Force" |
549 | //usage: "\n -k Keep input files" | 550 | //usage: "\n -k Keep input files" |
551 | //usage: "\n -t Test file integrity" | ||
550 | //usage: | 552 | //usage: |
551 | //usage:#define xzcat_trivial_usage | 553 | //usage:#define xzcat_trivial_usage |
552 | //usage: "[FILE]..." | 554 | //usage: "[FILE]..." |
diff --git a/archival/gzip.c b/archival/gzip.c index 17341de45..d9c730f13 100644 --- a/archival/gzip.c +++ b/archival/gzip.c | |||
@@ -52,7 +52,7 @@ aa: 85.1% -- replaced with aa.gz | |||
52 | //config: help | 52 | //config: help |
53 | //config: Enable support for compression levels 4-9. The default level | 53 | //config: Enable support for compression levels 4-9. The default level |
54 | //config: is 6. If levels 1-3 are specified, 4 is used. | 54 | //config: is 6. If levels 1-3 are specified, 4 is used. |
55 | //config: If this option is not selected, -N options are ignored and -9 | 55 | //config: If this option is not selected, -N options are ignored and -6 |
56 | //config: is used. | 56 | //config: is used. |
57 | //config: | 57 | //config: |
58 | //config:config FEATURE_GZIP_DECOMPRESS | 58 | //config:config FEATURE_GZIP_DECOMPRESS |
@@ -259,12 +259,13 @@ enum { | |||
259 | 259 | ||
260 | #if !ENABLE_FEATURE_GZIP_LEVELS | 260 | #if !ENABLE_FEATURE_GZIP_LEVELS |
261 | 261 | ||
262 | max_chain_length = 4096, | 262 | comp_level_minus4 = 6 - 4, |
263 | max_chain_length = 128, | ||
263 | /* To speed up deflation, hash chains are never searched beyond this length. | 264 | /* To speed up deflation, hash chains are never searched beyond this length. |
264 | * A higher limit improves compression ratio but degrades the speed. | 265 | * A higher limit improves compression ratio but degrades the speed. |
265 | */ | 266 | */ |
266 | 267 | ||
267 | max_lazy_match = 258, | 268 | max_lazy_match = 16, |
268 | /* Attempt to find a better match only when the current match is strictly | 269 | /* Attempt to find a better match only when the current match is strictly |
269 | * smaller than this value. This mechanism is used only for compression | 270 | * smaller than this value. This mechanism is used only for compression |
270 | * levels >= 4. | 271 | * levels >= 4. |
@@ -276,7 +277,7 @@ enum { | |||
276 | * max_insert_length is used only for compression levels <= 3. | 277 | * max_insert_length is used only for compression levels <= 3. |
277 | */ | 278 | */ |
278 | 279 | ||
279 | good_match = 32, | 280 | good_match = 8, |
280 | /* Use a faster search when the previous match is longer than this */ | 281 | /* Use a faster search when the previous match is longer than this */ |
281 | 282 | ||
282 | /* Values for max_lazy_match, good_match and max_chain_length, depending on | 283 | /* Values for max_lazy_match, good_match and max_chain_length, depending on |
@@ -285,7 +286,7 @@ enum { | |||
285 | * found for specific files. | 286 | * found for specific files. |
286 | */ | 287 | */ |
287 | 288 | ||
288 | nice_match = 258, /* Stop searching when current match exceeds this */ | 289 | nice_match = 128, /* Stop searching when current match exceeds this */ |
289 | /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 | 290 | /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 |
290 | * For deflate_fast() (levels <= 3) good is ignored and lazy has a different | 291 | * For deflate_fast() (levels <= 3) good is ignored and lazy has a different |
291 | * meaning. | 292 | * meaning. |
@@ -334,14 +335,16 @@ struct globals { | |||
334 | #define head (G1.prev + WSIZE) /* hash head (see deflate.c) */ | 335 | #define head (G1.prev + WSIZE) /* hash head (see deflate.c) */ |
335 | 336 | ||
336 | #if ENABLE_FEATURE_GZIP_LEVELS | 337 | #if ENABLE_FEATURE_GZIP_LEVELS |
338 | unsigned comp_level_minus4; /* can be a byte */ | ||
337 | unsigned max_chain_length; | 339 | unsigned max_chain_length; |
338 | unsigned max_lazy_match; | 340 | unsigned max_lazy_match; |
339 | unsigned good_match; | 341 | unsigned good_match; |
340 | unsigned nice_match; | 342 | unsigned nice_match; |
341 | #define max_chain_length (G1.max_chain_length) | 343 | #define comp_level_minus4 (G1.comp_level_minus4) |
342 | #define max_lazy_match (G1.max_lazy_match) | 344 | #define max_chain_length (G1.max_chain_length) |
343 | #define good_match (G1.good_match) | 345 | #define max_lazy_match (G1.max_lazy_match) |
344 | #define nice_match (G1.nice_match) | 346 | #define good_match (G1.good_match) |
347 | #define nice_match (G1.nice_match) | ||
345 | #endif | 348 | #endif |
346 | 349 | ||
347 | /* =========================================================================== */ | 350 | /* =========================================================================== */ |
@@ -504,7 +507,7 @@ static ALWAYS_INLINE void flush_outbuf_if_32bit_optimized(void) | |||
504 | * pointer, then initialize the crc shift register contents instead. | 507 | * pointer, then initialize the crc shift register contents instead. |
505 | * Return the current crc in either case. | 508 | * Return the current crc in either case. |
506 | */ | 509 | */ |
507 | static void updcrc(uch * s, unsigned n) | 510 | static void updcrc(uch *s, unsigned n) |
508 | { | 511 | { |
509 | G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); | 512 | G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); |
510 | } | 513 | } |
@@ -607,7 +610,7 @@ static void bi_windup(void) | |||
607 | * Copy a stored block to the zip file, storing first the length and its | 610 | * Copy a stored block to the zip file, storing first the length and its |
608 | * one's complement if requested. | 611 | * one's complement if requested. |
609 | */ | 612 | */ |
610 | static void copy_block(char *buf, unsigned len, int header) | 613 | static void copy_block(const char *buf, unsigned len, int header) |
611 | { | 614 | { |
612 | bi_windup(); /* align on byte boundary */ | 615 | bi_windup(); /* align on byte boundary */ |
613 | 616 | ||
@@ -1007,7 +1010,8 @@ struct globals2 { | |||
1007 | tree_desc d_desc; | 1010 | tree_desc d_desc; |
1008 | tree_desc bl_desc; | 1011 | tree_desc bl_desc; |
1009 | 1012 | ||
1010 | ush bl_count[MAX_BITS + 1]; | 1013 | /* was "ush", but "unsigned" results in smaller code */ |
1014 | unsigned bl_count[MAX_BITS + 1]; | ||
1011 | 1015 | ||
1012 | /* The lengths of the bit length codes are sent in order of decreasing | 1016 | /* The lengths of the bit length codes are sent in order of decreasing |
1013 | * probability, to avoid transmitting the lengths for unused bit length codes. | 1017 | * probability, to avoid transmitting the lengths for unused bit length codes. |
@@ -1118,7 +1122,7 @@ static void init_block(void) | |||
1118 | (tree[n].Freq < tree[m].Freq \ | 1122 | (tree[n].Freq < tree[m].Freq \ |
1119 | || (tree[n].Freq == tree[m].Freq && G2.depth[n] <= G2.depth[m])) | 1123 | || (tree[n].Freq == tree[m].Freq && G2.depth[n] <= G2.depth[m])) |
1120 | 1124 | ||
1121 | static void pqdownheap(ct_data * tree, int k) | 1125 | static void pqdownheap(const ct_data *tree, int k) |
1122 | { | 1126 | { |
1123 | int v = G2.heap[k]; | 1127 | int v = G2.heap[k]; |
1124 | int j = k << 1; /* left son of k */ | 1128 | int j = k << 1; /* left son of k */ |
@@ -1152,22 +1156,15 @@ static void pqdownheap(ct_data * tree, int k) | |||
1152 | * The length opt_len is updated; static_len is also updated if stree is | 1156 | * The length opt_len is updated; static_len is also updated if stree is |
1153 | * not null. | 1157 | * not null. |
1154 | */ | 1158 | */ |
1155 | static void gen_bitlen(tree_desc * desc) | 1159 | static void gen_bitlen(const tree_desc *desc) |
1156 | { | 1160 | { |
1157 | ct_data *tree = desc->dyn_tree; | 1161 | #define tree desc->dyn_tree |
1158 | const uint8_t *extra = desc->extra_bits; | 1162 | int h; /* heap index */ |
1159 | int base = desc->extra_base; | 1163 | int n, m; /* iterate over the tree elements */ |
1160 | int max_code = desc->max_code; | 1164 | int bits; /* bit length */ |
1161 | int max_length = desc->max_length; | 1165 | int overflow; /* number of elements with bit length too large */ |
1162 | ct_data *stree = desc->static_tree; | 1166 | |
1163 | int h; /* heap index */ | 1167 | for (bits = 0; bits < ARRAY_SIZE(G2.bl_count); bits++) |
1164 | int n, m; /* iterate over the tree elements */ | ||
1165 | int bits; /* bit length */ | ||
1166 | int xbits; /* extra bits */ | ||
1167 | ush f; /* frequency */ | ||
1168 | int overflow = 0; /* number of elements with bit length too large */ | ||
1169 | |||
1170 | for (bits = 0; bits <= MAX_BITS; bits++) | ||
1171 | G2.bl_count[bits] = 0; | 1168 | G2.bl_count[bits] = 0; |
1172 | 1169 | ||
1173 | /* In a first pass, compute the optimal bit lengths (which may | 1170 | /* In a first pass, compute the optimal bit lengths (which may |
@@ -1175,28 +1172,32 @@ static void gen_bitlen(tree_desc * desc) | |||
1175 | */ | 1172 | */ |
1176 | tree[G2.heap[G2.heap_max]].Len = 0; /* root of the heap */ | 1173 | tree[G2.heap[G2.heap_max]].Len = 0; /* root of the heap */ |
1177 | 1174 | ||
1175 | overflow = 0; | ||
1178 | for (h = G2.heap_max + 1; h < HEAP_SIZE; h++) { | 1176 | for (h = G2.heap_max + 1; h < HEAP_SIZE; h++) { |
1177 | ulg f; /* frequency */ | ||
1178 | int xbits; /* extra bits */ | ||
1179 | |||
1179 | n = G2.heap[h]; | 1180 | n = G2.heap[h]; |
1180 | bits = tree[tree[n].Dad].Len + 1; | 1181 | bits = tree[tree[n].Dad].Len + 1; |
1181 | if (bits > max_length) { | 1182 | if (bits > desc->max_length) { |
1182 | bits = max_length; | 1183 | bits = desc->max_length; |
1183 | overflow++; | 1184 | overflow++; |
1184 | } | 1185 | } |
1185 | tree[n].Len = (ush) bits; | 1186 | tree[n].Len = (ush) bits; |
1186 | /* We overwrite tree[n].Dad which is no longer needed */ | 1187 | /* We overwrite tree[n].Dad which is no longer needed */ |
1187 | 1188 | ||
1188 | if (n > max_code) | 1189 | if (n > desc->max_code) |
1189 | continue; /* not a leaf node */ | 1190 | continue; /* not a leaf node */ |
1190 | 1191 | ||
1191 | G2.bl_count[bits]++; | 1192 | G2.bl_count[bits]++; |
1192 | xbits = 0; | 1193 | xbits = 0; |
1193 | if (n >= base) | 1194 | if (n >= desc->extra_base) |
1194 | xbits = extra[n - base]; | 1195 | xbits = desc->extra_bits[n - desc->extra_base]; |
1195 | f = tree[n].Freq; | 1196 | f = tree[n].Freq; |
1196 | G2.opt_len += (ulg) f *(bits + xbits); | 1197 | G2.opt_len += f * (bits + xbits); |
1197 | 1198 | ||
1198 | if (stree) | 1199 | if (desc->static_tree) |
1199 | G2.static_len += (ulg) f * (stree[n].Len + xbits); | 1200 | G2.static_len += f * (desc->static_tree[n].Len + xbits); |
1200 | } | 1201 | } |
1201 | if (overflow == 0) | 1202 | if (overflow == 0) |
1202 | return; | 1203 | return; |
@@ -1206,14 +1207,14 @@ static void gen_bitlen(tree_desc * desc) | |||
1206 | 1207 | ||
1207 | /* Find the first bit length which could increase: */ | 1208 | /* Find the first bit length which could increase: */ |
1208 | do { | 1209 | do { |
1209 | bits = max_length - 1; | 1210 | bits = desc->max_length - 1; |
1210 | while (G2.bl_count[bits] == 0) | 1211 | while (G2.bl_count[bits] == 0) |
1211 | bits--; | 1212 | bits--; |
1212 | G2.bl_count[bits]--; /* move one leaf down the tree */ | 1213 | G2.bl_count[bits]--; /* move one leaf down the tree */ |
1213 | G2.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ | 1214 | G2.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ |
1214 | G2.bl_count[max_length]--; | 1215 | G2.bl_count[desc->max_length]--; |
1215 | /* The brother of the overflow item also moves one step up, | 1216 | /* The brother of the overflow item also moves one step up, |
1216 | * but this does not affect bl_count[max_length] | 1217 | * but this does not affect bl_count[desc->max_length] |
1217 | */ | 1218 | */ |
1218 | overflow -= 2; | 1219 | overflow -= 2; |
1219 | } while (overflow > 0); | 1220 | } while (overflow > 0); |
@@ -1223,11 +1224,11 @@ static void gen_bitlen(tree_desc * desc) | |||
1223 | * lengths instead of fixing only the wrong ones. This idea is taken | 1224 | * lengths instead of fixing only the wrong ones. This idea is taken |
1224 | * from 'ar' written by Haruhiko Okumura.) | 1225 | * from 'ar' written by Haruhiko Okumura.) |
1225 | */ | 1226 | */ |
1226 | for (bits = max_length; bits != 0; bits--) { | 1227 | for (bits = desc->max_length; bits != 0; bits--) { |
1227 | n = G2.bl_count[bits]; | 1228 | n = G2.bl_count[bits]; |
1228 | while (n != 0) { | 1229 | while (n != 0) { |
1229 | m = G2.heap[--h]; | 1230 | m = G2.heap[--h]; |
1230 | if (m > max_code) | 1231 | if (m > desc->max_code) |
1231 | continue; | 1232 | continue; |
1232 | if (tree[m].Len != (unsigned) bits) { | 1233 | if (tree[m].Len != (unsigned) bits) { |
1233 | Trace((stderr, "code %d bits %d->%d\n", m, tree[m].Len, bits)); | 1234 | Trace((stderr, "code %d bits %d->%d\n", m, tree[m].Len, bits)); |
@@ -1237,6 +1238,7 @@ static void gen_bitlen(tree_desc * desc) | |||
1237 | n--; | 1238 | n--; |
1238 | } | 1239 | } |
1239 | } | 1240 | } |
1241 | #undef tree | ||
1240 | } | 1242 | } |
1241 | 1243 | ||
1242 | /* =========================================================================== | 1244 | /* =========================================================================== |
@@ -1247,12 +1249,13 @@ static void gen_bitlen(tree_desc * desc) | |||
1247 | * OUT assertion: the field code is set for all tree elements of non | 1249 | * OUT assertion: the field code is set for all tree elements of non |
1248 | * zero code length. | 1250 | * zero code length. |
1249 | */ | 1251 | */ |
1250 | static void gen_codes(ct_data * tree, int max_code) | 1252 | static void gen_codes(ct_data *tree, int max_code) |
1251 | { | 1253 | { |
1252 | ush next_code[MAX_BITS + 1]; /* next code value for each bit length */ | 1254 | /* next_code[] and code used to be "ush", but "unsigned" results in smaller code */ |
1253 | ush code = 0; /* running code value */ | 1255 | unsigned next_code[MAX_BITS + 1]; /* next code value for each bit length */ |
1254 | int bits; /* bit index */ | 1256 | unsigned code = 0; /* running code value */ |
1255 | int n; /* code index */ | 1257 | int bits; /* bit index */ |
1258 | int n; /* code index */ | ||
1256 | 1259 | ||
1257 | /* The distribution counts are first used to generate the code values | 1260 | /* The distribution counts are first used to generate the code values |
1258 | * without bit reversal. | 1261 | * without bit reversal. |
@@ -1304,7 +1307,7 @@ do { \ | |||
1304 | pqdownheap(tree, SMALLEST); \ | 1307 | pqdownheap(tree, SMALLEST); \ |
1305 | } while (0) | 1308 | } while (0) |
1306 | 1309 | ||
1307 | static void build_tree(tree_desc * desc) | 1310 | static void build_tree(tree_desc *desc) |
1308 | { | 1311 | { |
1309 | ct_data *tree = desc->dyn_tree; | 1312 | ct_data *tree = desc->dyn_tree; |
1310 | ct_data *stree = desc->static_tree; | 1313 | ct_data *stree = desc->static_tree; |
@@ -1382,10 +1385,10 @@ static void build_tree(tree_desc * desc) | |||
1382 | /* At this point, the fields freq and dad are set. We can now | 1385 | /* At this point, the fields freq and dad are set. We can now |
1383 | * generate the bit lengths. | 1386 | * generate the bit lengths. |
1384 | */ | 1387 | */ |
1385 | gen_bitlen((tree_desc *) desc); | 1388 | gen_bitlen(desc); |
1386 | 1389 | ||
1387 | /* The field len is now set, we can generate the bit codes */ | 1390 | /* The field len is now set, we can generate the bit codes */ |
1388 | gen_codes((ct_data *) tree, max_code); | 1391 | gen_codes(tree, max_code); |
1389 | } | 1392 | } |
1390 | 1393 | ||
1391 | /* =========================================================================== | 1394 | /* =========================================================================== |
@@ -1394,7 +1397,7 @@ static void build_tree(tree_desc * desc) | |||
1394 | * counts. (The contribution of the bit length codes will be added later | 1397 | * counts. (The contribution of the bit length codes will be added later |
1395 | * during the construction of bl_tree.) | 1398 | * during the construction of bl_tree.) |
1396 | */ | 1399 | */ |
1397 | static void scan_tree(ct_data * tree, int max_code) | 1400 | static void scan_tree(ct_data *tree, int max_code) |
1398 | { | 1401 | { |
1399 | int n; /* iterates over all tree elements */ | 1402 | int n; /* iterates over all tree elements */ |
1400 | int prevlen = -1; /* last emitted length */ | 1403 | int prevlen = -1; /* last emitted length */ |
@@ -1446,7 +1449,7 @@ static void scan_tree(ct_data * tree, int max_code) | |||
1446 | * Send a literal or distance tree in compressed form, using the codes in | 1449 | * Send a literal or distance tree in compressed form, using the codes in |
1447 | * bl_tree. | 1450 | * bl_tree. |
1448 | */ | 1451 | */ |
1449 | static void send_tree(ct_data * tree, int max_code) | 1452 | static void send_tree(const ct_data *tree, int max_code) |
1450 | { | 1453 | { |
1451 | int n; /* iterates over all tree elements */ | 1454 | int n; /* iterates over all tree elements */ |
1452 | int prevlen = -1; /* last emitted length */ | 1455 | int prevlen = -1; /* last emitted length */ |
@@ -1622,7 +1625,7 @@ static int ct_tally(int dist, int lc) | |||
1622 | /* =========================================================================== | 1625 | /* =========================================================================== |
1623 | * Send the block data compressed using the given Huffman trees | 1626 | * Send the block data compressed using the given Huffman trees |
1624 | */ | 1627 | */ |
1625 | static void compress_block(ct_data * ltree, ct_data * dtree) | 1628 | static void compress_block(const ct_data *ltree, const ct_data *dtree) |
1626 | { | 1629 | { |
1627 | unsigned dist; /* distance of matched string */ | 1630 | unsigned dist; /* distance of matched string */ |
1628 | int lc; /* match length or unmatched char (if dist == 0) */ | 1631 | int lc; /* match length or unmatched char (if dist == 0) */ |
@@ -1672,7 +1675,7 @@ static void compress_block(ct_data * ltree, ct_data * dtree) | |||
1672 | * trees or store, and output the encoded block to the zip file. This function | 1675 | * trees or store, and output the encoded block to the zip file. This function |
1673 | * returns the total compressed length for the file so far. | 1676 | * returns the total compressed length for the file so far. |
1674 | */ | 1677 | */ |
1675 | static void flush_block(char *buf, ulg stored_len, int eof) | 1678 | static void flush_block(const char *buf, ulg stored_len, int eof) |
1676 | { | 1679 | { |
1677 | ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ | 1680 | ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ |
1678 | int max_blindex; /* index of last bit length code of non zero freq */ | 1681 | int max_blindex; /* index of last bit length code of non zero freq */ |
@@ -1919,7 +1922,7 @@ static void bi_init(void) | |||
1919 | /* =========================================================================== | 1922 | /* =========================================================================== |
1920 | * Initialize the "longest match" routines for a new file | 1923 | * Initialize the "longest match" routines for a new file |
1921 | */ | 1924 | */ |
1922 | static void lm_init(unsigned *flags16p) | 1925 | static void lm_init(void) |
1923 | { | 1926 | { |
1924 | unsigned j; | 1927 | unsigned j; |
1925 | 1928 | ||
@@ -1927,8 +1930,6 @@ static void lm_init(unsigned *flags16p) | |||
1927 | memset(head, 0, HASH_SIZE * sizeof(*head)); | 1930 | memset(head, 0, HASH_SIZE * sizeof(*head)); |
1928 | /* prev will be initialized on the fly */ | 1931 | /* prev will be initialized on the fly */ |
1929 | 1932 | ||
1930 | /* speed options for the general purpose bit flag */ | ||
1931 | *flags16p |= 2; /* FAST 4, SLOW 2 */ | ||
1932 | /* ??? reduce max_chain_length for binary files */ | 1933 | /* ??? reduce max_chain_length for binary files */ |
1933 | 1934 | ||
1934 | //G1.strstart = 0; // globals are zeroed in pack_gzip() | 1935 | //G1.strstart = 0; // globals are zeroed in pack_gzip() |
@@ -2076,10 +2077,16 @@ static void zip(void) | |||
2076 | 2077 | ||
2077 | bi_init(); | 2078 | bi_init(); |
2078 | ct_init(); | 2079 | ct_init(); |
2079 | deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ | 2080 | lm_init(); |
2080 | lm_init(&deflate_flags); | ||
2081 | 2081 | ||
2082 | put_16bit(deflate_flags | 0x300); /* extra flags. OS id = 3 (Unix) */ | 2082 | deflate_flags = 0x300; /* extra flags. OS id = 3 (Unix) */ |
2083 | #if ENABLE_FEATURE_GZIP_LEVELS | ||
2084 | /* Note that comp_level < 4 do not exist in this version of gzip */ | ||
2085 | if (comp_level_minus4 == 9 - 4) { | ||
2086 | deflate_flags |= 0x02; /* SLOW flag */ | ||
2087 | } | ||
2088 | #endif | ||
2089 | put_16bit(deflate_flags); | ||
2083 | 2090 | ||
2084 | /* The above 32-bit misaligns outbuf (10 bytes are stored), flush it */ | 2091 | /* The above 32-bit misaligns outbuf (10 bytes are stored), flush it */ |
2085 | flush_outbuf_if_32bit_optimized(); | 2092 | flush_outbuf_if_32bit_optimized(); |
@@ -2222,8 +2229,11 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) | |||
2222 | #if ENABLE_FEATURE_GZIP_LEVELS | 2229 | #if ENABLE_FEATURE_GZIP_LEVELS |
2223 | opt >>= (BBUNPK_OPTSTRLEN IF_FEATURE_GZIP_DECOMPRESS(+ 2) + 1); /* drop cfkvq[dt]n bits */ | 2230 | opt >>= (BBUNPK_OPTSTRLEN IF_FEATURE_GZIP_DECOMPRESS(+ 2) + 1); /* drop cfkvq[dt]n bits */ |
2224 | if (opt == 0) | 2231 | if (opt == 0) |
2225 | opt = 1 << 6; /* default: 6 */ | 2232 | opt = 1 << 5; /* default: 6 */ |
2226 | opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ | 2233 | opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ |
2234 | |||
2235 | comp_level_minus4 = opt; | ||
2236 | |||
2227 | max_chain_length = 1 << gzip_level_config[opt].chain_shift; | 2237 | max_chain_length = 1 << gzip_level_config[opt].chain_shift; |
2228 | good_match = gzip_level_config[opt].good; | 2238 | good_match = gzip_level_config[opt].good; |
2229 | max_lazy_match = gzip_level_config[opt].lazy2 * 2; | 2239 | max_lazy_match = gzip_level_config[opt].lazy2 * 2; |
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c index cf07f71df..c0332d414 100644 --- a/archival/libarchive/decompress_gunzip.c +++ b/archival/libarchive/decompress_gunzip.c | |||
@@ -39,7 +39,8 @@ typedef struct huft_t { | |||
39 | unsigned char e; /* number of extra bits or operation */ | 39 | unsigned char e; /* number of extra bits or operation */ |
40 | unsigned char b; /* number of bits in this code or subcode */ | 40 | unsigned char b; /* number of bits in this code or subcode */ |
41 | union { | 41 | union { |
42 | unsigned short n; /* literal, length base, or distance base */ | 42 | unsigned n; /* literal, length base, or distance base */ |
43 | /* ^^^^^ was "unsigned short", but that results in larger code */ | ||
43 | struct huft_t *t; /* pointer to next level of table */ | 44 | struct huft_t *t; /* pointer to next level of table */ |
44 | } v; | 45 | } v; |
45 | } huft_t; | 46 | } huft_t; |
@@ -184,29 +185,26 @@ static const uint16_t mask_bits[] ALIGN2 = { | |||
184 | 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | 185 | 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff |
185 | }; | 186 | }; |
186 | 187 | ||
187 | /* Copy lengths for literal codes 257..285 */ | 188 | /* Put lengths/offsets and extra bits in a struct of arrays |
188 | static const uint16_t cplens[] ALIGN2 = { | 189 | * to make calls to huft_build() have one fewer parameter. |
189 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, | 190 | */ |
190 | 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 | 191 | struct cp_ext { |
192 | uint16_t cp[31]; | ||
193 | uint8_t ext[31]; | ||
191 | }; | 194 | }; |
192 | 195 | /* Copy lengths and extra bits for literal codes 257..285 */ | |
193 | /* note: see note #13 above about the 258 in this list. */ | 196 | /* note: see note #13 above about the 258 in this list. */ |
194 | /* Extra bits for literal codes 257..285 */ | 197 | static const struct cp_ext lit = { |
195 | static const uint8_t cplext[] ALIGN1 = { | 198 | /*257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 */ |
196 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, | 199 | /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 */ |
197 | 5, 5, 5, 0, 99, 99 | 200 | { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }, |
198 | }; /* 99 == invalid */ | 201 | { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 } /* 99 == invalid */ |
199 | |||
200 | /* Copy offsets for distance codes 0..29 */ | ||
201 | static const uint16_t cpdist[] ALIGN2 = { | ||
202 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, | ||
203 | 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 | ||
204 | }; | 202 | }; |
205 | 203 | /* Copy offsets and extra bits for distance codes 0..29 */ | |
206 | /* Extra bits for distance codes */ | 204 | static const struct cp_ext dist = { |
207 | static const uint8_t cpdext[] ALIGN1 = { | 205 | /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 */ |
208 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, | 206 | { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 }, |
209 | 11, 11, 12, 12, 13, 13 | 207 | { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 } |
210 | }; | 208 | }; |
211 | 209 | ||
212 | /* Tables for deflate from PKZIP's appnote.txt. */ | 210 | /* Tables for deflate from PKZIP's appnote.txt. */ |
@@ -277,22 +275,25 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current | |||
277 | 275 | ||
278 | 276 | ||
279 | /* Given a list of code lengths and a maximum table size, make a set of | 277 | /* Given a list of code lengths and a maximum table size, make a set of |
280 | * tables to decode that set of codes. Return zero on success, one if | 278 | * tables to decode that set of codes. |
281 | * the given code set is incomplete (the tables are still built in this | ||
282 | * case), two if the input is invalid (an oversubscribed set of lengths) | ||
283 | * - in this case stores NULL in *t. | ||
284 | * | 279 | * |
285 | * b: code lengths in bits (all assumed <= BMAX) | 280 | * b: code lengths in bits (all assumed <= BMAX) |
286 | * n: number of codes (assumed <= N_MAX) | 281 | * n: number of codes (assumed <= N_MAX) |
287 | * s: number of simple-valued codes (0..s-1) | 282 | * s: number of simple-valued codes (0..s-1) |
288 | * d: list of base values for non-simple codes | 283 | * cp_ext->cp,ext: list of base values/extra bits for non-simple codes |
289 | * e: list of extra bits for non-simple codes | ||
290 | * t: result: starting table | ||
291 | * m: maximum lookup bits, returns actual | 284 | * m: maximum lookup bits, returns actual |
285 | * result: starting table | ||
286 | * | ||
287 | * On error, returns a value with lowest-bit set on error. | ||
288 | * It can be just the value of 0x1, | ||
289 | * or a valid pointer to a Huffman table, ORed with 0x1 if incompete table | ||
290 | * is given: "fixed inflate" decoder feeds us such data. | ||
292 | */ | 291 | */ |
293 | static int huft_build(const unsigned *b, const unsigned n, | 292 | #define BAD_HUFT(p) ((uintptr_t)(p) & 1) |
294 | const unsigned s, const unsigned short *d, | 293 | #define ERR_RET ((huft_t*)(uintptr_t)1) |
295 | const unsigned char *e, huft_t **t, unsigned *m) | 294 | static huft_t* huft_build(const unsigned *b, const unsigned n, |
295 | const unsigned s, const struct cp_ext *cp_ext, | ||
296 | unsigned *m) | ||
296 | { | 297 | { |
297 | unsigned a; /* counter for codes of length k */ | 298 | unsigned a; /* counter for codes of length k */ |
298 | unsigned c[BMAX + 1]; /* bit length count table */ | 299 | unsigned c[BMAX + 1]; /* bit length count table */ |
@@ -314,12 +315,12 @@ static int huft_build(const unsigned *b, const unsigned n, | |||
314 | unsigned *xp; /* pointer into x */ | 315 | unsigned *xp; /* pointer into x */ |
315 | int y; /* number of dummy codes added */ | 316 | int y; /* number of dummy codes added */ |
316 | unsigned z; /* number of entries in current table */ | 317 | unsigned z; /* number of entries in current table */ |
318 | huft_t *result; | ||
319 | huft_t **t; | ||
317 | 320 | ||
318 | /* Length of EOB code, if any */ | 321 | /* Length of EOB code, if any */ |
319 | eob_len = n > 256 ? b[256] : BMAX; | 322 | eob_len = n > 256 ? b[256] : BMAX; |
320 | 323 | ||
321 | *t = NULL; | ||
322 | |||
323 | /* Generate counts for each bit length */ | 324 | /* Generate counts for each bit length */ |
324 | memset(c, 0, sizeof(c)); | 325 | memset(c, 0, sizeof(c)); |
325 | p = b; | 326 | p = b; |
@@ -335,9 +336,8 @@ static int huft_build(const unsigned *b, const unsigned n, | |||
335 | q[1].b = 1; | 336 | q[1].b = 1; |
336 | q[2].e = 99; /* invalid code marker */ | 337 | q[2].e = 99; /* invalid code marker */ |
337 | q[2].b = 1; | 338 | q[2].b = 1; |
338 | *t = q + 1; | ||
339 | *m = 1; | 339 | *m = 1; |
340 | return 0; | 340 | return q + 1; |
341 | } | 341 | } |
342 | 342 | ||
343 | /* Find minimum and maximum length, bound *m by those */ | 343 | /* Find minimum and maximum length, bound *m by those */ |
@@ -353,11 +353,11 @@ static int huft_build(const unsigned *b, const unsigned n, | |||
353 | for (y = 1 << j; j < i; j++, y <<= 1) { | 353 | for (y = 1 << j; j < i; j++, y <<= 1) { |
354 | y -= c[j]; | 354 | y -= c[j]; |
355 | if (y < 0) | 355 | if (y < 0) |
356 | return 2; /* bad input: more codes than bits */ | 356 | return ERR_RET; /* bad input: more codes than bits */ |
357 | } | 357 | } |
358 | y -= c[i]; | 358 | y -= c[i]; |
359 | if (y < 0) | 359 | if (y < 0) |
360 | return 2; | 360 | return ERR_RET; |
361 | c[i] += y; | 361 | c[i] += y; |
362 | 362 | ||
363 | /* Generate starting offsets into the value table for each length */ | 363 | /* Generate starting offsets into the value table for each length */ |
@@ -384,6 +384,8 @@ static int huft_build(const unsigned *b, const unsigned n, | |||
384 | } while (++i < n); | 384 | } while (++i < n); |
385 | 385 | ||
386 | /* Generate the Huffman codes and for each, make the table entries */ | 386 | /* Generate the Huffman codes and for each, make the table entries */ |
387 | result = ERR_RET; | ||
388 | t = &result; | ||
387 | x[0] = i = 0; /* first Huffman code is zero */ | 389 | x[0] = i = 0; /* first Huffman code is zero */ |
388 | p = v; /* grab values in bit order */ | 390 | p = v; /* grab values in bit order */ |
389 | htl = -1; /* no tables yet--level -1 */ | 391 | htl = -1; /* no tables yet--level -1 */ |
@@ -449,8 +451,8 @@ static int huft_build(const unsigned *b, const unsigned n, | |||
449 | r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ | 451 | r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ |
450 | r.v.n = (unsigned short) (*p++); /* simple code is just the value */ | 452 | r.v.n = (unsigned short) (*p++); /* simple code is just the value */ |
451 | } else { | 453 | } else { |
452 | r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ | 454 | r.e = (unsigned char) cp_ext->ext[*p - s]; /* non-simple--look up in lists */ |
453 | r.v.n = d[*p++ - s]; | 455 | r.v.n = cp_ext->cp[*p++ - s]; |
454 | } | 456 | } |
455 | 457 | ||
456 | /* fill code-like entries with r */ | 458 | /* fill code-like entries with r */ |
@@ -475,8 +477,11 @@ static int huft_build(const unsigned *b, const unsigned n, | |||
475 | /* return actual size of base table */ | 477 | /* return actual size of base table */ |
476 | *m = ws[1]; | 478 | *m = ws[1]; |
477 | 479 | ||
478 | /* Return 1 if we were given an incomplete table */ | 480 | if (y != 0 && g != 1) /* we were given an incomplete table */ |
479 | return y != 0 && g != 1; | 481 | /* return "result" ORed with 1 */ |
482 | return (void*)((uintptr_t)result | 1); | ||
483 | |||
484 | return result; | ||
480 | } | 485 | } |
481 | 486 | ||
482 | 487 | ||
@@ -777,14 +782,17 @@ static int inflate_block(STATE_PARAM smallint *e) | |||
777 | for (; i < 288; i++) /* make a complete, but wrong code set */ | 782 | for (; i < 288; i++) /* make a complete, but wrong code set */ |
778 | ll[i] = 8; | 783 | ll[i] = 8; |
779 | bl = 7; | 784 | bl = 7; |
780 | huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl); | 785 | inflate_codes_tl = huft_build(ll, 288, 257, &lit, &bl); |
781 | /* huft_build() never return nonzero - we use known data */ | 786 | /* ^^^ never returns error here - we use known data */ |
782 | 787 | ||
783 | /* set up distance table */ | 788 | /* set up distance table */ |
784 | for (i = 0; i < 30; i++) /* make an incomplete code set */ | 789 | for (i = 0; i < 30; i++) /* make an incomplete code set */ |
785 | ll[i] = 5; | 790 | ll[i] = 5; |
786 | bd = 5; | 791 | bd = 5; |
787 | huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd); | 792 | inflate_codes_td = huft_build(ll, 30, 0, &dist, &bd); |
793 | /* ^^^ does return error here! (lsb bit is set) - we gave it incomplete code set */ | ||
794 | /* clearing error bit: */ | ||
795 | inflate_codes_td = (void*)((uintptr_t)inflate_codes_td & ~(uintptr_t)1); | ||
788 | 796 | ||
789 | /* set up data for inflate_codes() */ | 797 | /* set up data for inflate_codes() */ |
790 | inflate_codes_setup(PASS_STATE bl, bd); | 798 | inflate_codes_setup(PASS_STATE bl, bd); |
@@ -850,9 +858,9 @@ static int inflate_block(STATE_PARAM smallint *e) | |||
850 | 858 | ||
851 | /* build decoding table for trees - single level, 7 bit lookup */ | 859 | /* build decoding table for trees - single level, 7 bit lookup */ |
852 | bl = 7; | 860 | bl = 7; |
853 | i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl); | 861 | inflate_codes_tl = huft_build(ll, 19, 19, NULL, &bl); |
854 | if (i != 0) { | 862 | if (BAD_HUFT(inflate_codes_tl)) { |
855 | abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */ | 863 | abort_unzip(PASS_STATE_ONLY); /* incomplete code set */ |
856 | } | 864 | } |
857 | 865 | ||
858 | /* read in literal and distance code lengths */ | 866 | /* read in literal and distance code lengths */ |
@@ -915,14 +923,13 @@ static int inflate_block(STATE_PARAM smallint *e) | |||
915 | 923 | ||
916 | /* build the decoding tables for literal/length and distance codes */ | 924 | /* build the decoding tables for literal/length and distance codes */ |
917 | bl = lbits; | 925 | bl = lbits; |
918 | 926 | inflate_codes_tl = huft_build(ll, nl, 257, &lit, &bl); | |
919 | i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl); | 927 | if (BAD_HUFT(inflate_codes_tl)) { |
920 | if (i != 0) { | ||
921 | abort_unzip(PASS_STATE_ONLY); | 928 | abort_unzip(PASS_STATE_ONLY); |
922 | } | 929 | } |
923 | bd = dbits; | 930 | bd = dbits; |
924 | i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd); | 931 | inflate_codes_td = huft_build(ll + nl, nd, 0, &dist, &bd); |
925 | if (i != 0) { | 932 | if (BAD_HUFT(inflate_codes_td)) { |
926 | abort_unzip(PASS_STATE_ONLY); | 933 | abort_unzip(PASS_STATE_ONLY); |
927 | } | 934 | } |
928 | 935 | ||
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index f03341384..3dd9bbf49 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c | |||
@@ -96,6 +96,24 @@ unpack_xz_stream(transformer_state_t *xstate) | |||
96 | */ | 96 | */ |
97 | do { | 97 | do { |
98 | if (membuf[iobuf.in_pos] != 0) { | 98 | if (membuf[iobuf.in_pos] != 0) { |
99 | /* There is more data, but is it XZ data? | ||
100 | * Example: dpkg-deb -f busybox_1.30.1-4_amd64.deb | ||
101 | * reads control.tar.xz "control" file | ||
102 | * inside the ar archive, but tar.xz | ||
103 | * extraction code reaches end of xz data, | ||
104 | * reached this code and reads the beginning | ||
105 | * of data.tar.xz's ar header, which isn't xz data, | ||
106 | * and prints "corrupted data". | ||
107 | * The correct solution is to not read | ||
108 | * past nested archive (to simulate EOF). | ||
109 | * This is a workaround: | ||
110 | */ | ||
111 | if (membuf[iobuf.in_pos] != 0xfd) { | ||
112 | /* It's definitely not a xz signature | ||
113 | * (which is 0xfd,"7zXZ",0x00). | ||
114 | */ | ||
115 | goto end; | ||
116 | } | ||
99 | xz_dec_reset(state); | 117 | xz_dec_reset(state); |
100 | goto do_run; | 118 | goto do_run; |
101 | } | 119 | } |
@@ -128,7 +146,7 @@ unpack_xz_stream(transformer_state_t *xstate) | |||
128 | break; | 146 | break; |
129 | } | 147 | } |
130 | } | 148 | } |
131 | 149 | end: | |
132 | xz_dec_end(state); | 150 | xz_dec_end(state); |
133 | free(membuf); | 151 | free(membuf); |
134 | 152 | ||
diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h index 66cb5a705..45056e42c 100644 --- a/archival/libarchive/unxz/xz_stream.h +++ b/archival/libarchive/unxz/xz_stream.h | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #define STREAM_HEADER_SIZE 12 | 26 | #define STREAM_HEADER_SIZE 12 |
27 | 27 | ||
28 | #define HEADER_MAGIC "\3757zXZ" | 28 | #define HEADER_MAGIC "\375""7zXZ" |
29 | #define HEADER_MAGIC_SIZE 6 | 29 | #define HEADER_MAGIC_SIZE 6 |
30 | 30 | ||
31 | #define FOOTER_MAGIC "YZ" | 31 | #define FOOTER_MAGIC "YZ" |
diff --git a/archival/tar.c b/archival/tar.c index 6618c9ecc..c57bff779 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1066,7 +1066,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1066 | IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive | 1066 | IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive |
1067 | IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive | 1067 | IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive |
1068 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS | 1068 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS |
1069 | ":\xf9+" // --strip-components=NUM | 1069 | ":\xf8+" // --strip-components=NUM |
1070 | #endif | 1070 | #endif |
1071 | LONGOPTS | 1071 | LONGOPTS |
1072 | , &base_dir // -C dir | 1072 | , &base_dir // -C dir |
diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c index ae216aa3f..4da43c45e 100644 --- a/coreutils/chgrp.c +++ b/coreutils/chgrp.c | |||
@@ -21,15 +21,15 @@ | |||
21 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/chgrp.html */ | 21 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/chgrp.html */ |
22 | 22 | ||
23 | //usage:#define chgrp_trivial_usage | 23 | //usage:#define chgrp_trivial_usage |
24 | //usage: "[-RhLHP"IF_DESKTOP("cvf")"]... GROUP FILE..." | 24 | //usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... GROUP FILE..." |
25 | //usage:#define chgrp_full_usage "\n\n" | 25 | //usage:#define chgrp_full_usage "\n\n" |
26 | //usage: "Change the group membership of each FILE to GROUP\n" | 26 | //usage: "Change the group membership of each FILE to GROUP\n" |
27 | //usage: "\n -R Recurse" | 27 | //usage: "\n -R Recurse" |
28 | //usage: "\n -h Affect symlinks instead of symlink targets" | 28 | //usage: "\n -h Affect symlinks instead of symlink targets" |
29 | //usage: IF_DESKTOP( | ||
29 | //usage: "\n -L Traverse all symlinks to directories" | 30 | //usage: "\n -L Traverse all symlinks to directories" |
30 | //usage: "\n -H Traverse symlinks on command line only" | 31 | //usage: "\n -H Traverse symlinks on command line only" |
31 | //usage: "\n -P Don't traverse symlinks (default)" | 32 | //usage: "\n -P Don't traverse symlinks (default)" |
32 | //usage: IF_DESKTOP( | ||
33 | //usage: "\n -c List changed files" | 33 | //usage: "\n -c List changed files" |
34 | //usage: "\n -v Verbose" | 34 | //usage: "\n -v Verbose" |
35 | //usage: "\n -f Hide errors" | 35 | //usage: "\n -f Hide errors" |
diff --git a/coreutils/date.c b/coreutils/date.c index feb400430..b9b7fd2cb 100644 --- a/coreutils/date.c +++ b/coreutils/date.c | |||
@@ -33,10 +33,9 @@ | |||
33 | //config: Enable option (-I) to output an ISO-8601 compliant | 33 | //config: Enable option (-I) to output an ISO-8601 compliant |
34 | //config: date/time string. | 34 | //config: date/time string. |
35 | //config: | 35 | //config: |
36 | //config:# defaults to "no": stat's nanosecond field is a bit non-portable | ||
37 | //config:config FEATURE_DATE_NANO | 36 | //config:config FEATURE_DATE_NANO |
38 | //config: bool "Support %[num]N nanosecond format specifier" | 37 | //config: bool "Support %[num]N nanosecond format specifier" |
39 | //config: default n # syscall(__NR_clock_gettime) | 38 | //config: default n # stat's nanosecond field is a bit non-portable |
40 | //config: depends on DATE | 39 | //config: depends on DATE |
41 | //config: select PLATFORM_LINUX | 40 | //config: select PLATFORM_LINUX |
42 | //config: help | 41 | //config: help |
@@ -272,13 +271,14 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
272 | #endif | 271 | #endif |
273 | } else { | 272 | } else { |
274 | #if ENABLE_FEATURE_DATE_NANO | 273 | #if ENABLE_FEATURE_DATE_NANO |
275 | /* libc has incredibly messy way of doing this, | 274 | clock_gettime(CLOCK_REALTIME, &ts); |
276 | * typically requiring -lrt. We just skip all this mess */ | ||
277 | syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts); | ||
278 | #else | 275 | #else |
279 | time(&ts.tv_sec); | 276 | time(&ts.tv_sec); |
280 | #endif | 277 | #endif |
281 | } | 278 | } |
279 | #if !ENABLE_FEATURE_DATE_NANO | ||
280 | ts.tv_nsec = 0; | ||
281 | #endif | ||
282 | localtime_r(&ts.tv_sec, &tm_time); | 282 | localtime_r(&ts.tv_sec, &tm_time); |
283 | 283 | ||
284 | /* If date string is given, update tm_time, and maybe set date */ | 284 | /* If date string is given, update tm_time, and maybe set date */ |
@@ -301,9 +301,10 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
301 | if (date_str[0] != '@') | 301 | if (date_str[0] != '@') |
302 | tm_time.tm_isdst = -1; | 302 | tm_time.tm_isdst = -1; |
303 | ts.tv_sec = validate_tm_time(date_str, &tm_time); | 303 | ts.tv_sec = validate_tm_time(date_str, &tm_time); |
304 | ts.tv_nsec = 0; | ||
304 | 305 | ||
305 | /* if setting time, set it */ | 306 | /* if setting time, set it */ |
306 | if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) { | 307 | if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { |
307 | bb_simple_perror_msg("can't set date"); | 308 | bb_simple_perror_msg("can't set date"); |
308 | } | 309 | } |
309 | } | 310 | } |
diff --git a/coreutils/ln.c b/coreutils/ln.c index ea2d10eab..5591e8335 100644 --- a/coreutils/ln.c +++ b/coreutils/ln.c | |||
@@ -41,7 +41,6 @@ | |||
41 | 41 | ||
42 | /* This is a NOEXEC applet. Be very careful! */ | 42 | /* This is a NOEXEC applet. Be very careful! */ |
43 | 43 | ||
44 | |||
45 | #define LN_SYMLINK (1 << 0) | 44 | #define LN_SYMLINK (1 << 0) |
46 | #define LN_FORCE (1 << 1) | 45 | #define LN_FORCE (1 << 1) |
47 | #define LN_NODEREFERENCE (1 << 2) | 46 | #define LN_NODEREFERENCE (1 << 2) |
@@ -63,7 +62,22 @@ int ln_main(int argc, char **argv) | |||
63 | int (*link_func)(const char *, const char *); | 62 | int (*link_func)(const char *, const char *); |
64 | 63 | ||
65 | opts = getopt32(argv, "^" "sfnbS:vT" "\0" "-1", &suffix); | 64 | opts = getopt32(argv, "^" "sfnbS:vT" "\0" "-1", &suffix); |
66 | 65 | /* | |
66 | -s, --symbolic make symbolic links instead of hard links | ||
67 | -f, --force remove existing destination files | ||
68 | -n, --no-dereference treat LINK_NAME as a normal file if it is a symbolic link to a directory | ||
69 | -b like --backup but does not accept an argument | ||
70 | --backup[=CONTROL] make a backup of each existing destination file | ||
71 | -S, --suffix=SUFFIX override the usual backup suffix | ||
72 | -v, --verbose | ||
73 | -T, --no-target-directory | ||
74 | -d, -F, --directory allow the superuser to attempt to hard link directories | ||
75 | -i, --interactive prompt whether to remove destinations | ||
76 | -L, --logical dereference TARGETs that are symbolic links | ||
77 | -P, --physical make hard links directly to symbolic links | ||
78 | -r, --relative create symbolic links relative to link location | ||
79 | -t, --target-directory=DIRECTORY specify the DIRECTORY in which to create the links | ||
80 | */ | ||
67 | last = argv[argc - 1]; | 81 | last = argv[argc - 1]; |
68 | argv += optind; | 82 | argv += optind; |
69 | argc -= optind; | 83 | argc -= optind; |
@@ -86,8 +100,11 @@ int ln_main(int argc, char **argv) | |||
86 | src = last; | 100 | src = last; |
87 | 101 | ||
88 | if (is_directory(src, | 102 | if (is_directory(src, |
89 | (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE | 103 | /*followlinks:*/ !(opts & (LN_NODEREFERENCE|LN_LINKFILE)) |
90 | ) | 104 | /* Why LN_LINKFILE does not follow links: |
105 | * -T/--no-target-directory implies -n/--no-dereference | ||
106 | */ | ||
107 | ) | ||
91 | ) { | 108 | ) { |
92 | if (opts & LN_LINKFILE) { | 109 | if (opts & LN_LINKFILE) { |
93 | bb_error_msg_and_die("'%s' is a directory", src); | 110 | bb_error_msg_and_die("'%s' is a directory", src); |
diff --git a/coreutils/tee.c b/coreutils/tee.c index fe5694331..e67296d43 100644 --- a/coreutils/tee.c +++ b/coreutils/tee.c | |||
@@ -39,6 +39,19 @@ | |||
39 | //usage: "$ cat /tmp/foo\n" | 39 | //usage: "$ cat /tmp/foo\n" |
40 | //usage: "Hello\n" | 40 | //usage: "Hello\n" |
41 | 41 | ||
42 | // Bare "tee" with no below options does not install SIGPIPE handler - just dies on it. | ||
43 | // TODO: | ||
44 | // --output-error[=MODE] | ||
45 | // 'warn' diagnose errors writing to any output | ||
46 | // 'warn-nopipe' diagnose errors writing to any output not a pipe | ||
47 | // 'exit' exit on error writing to any output | ||
48 | // 'exit-nopipe' exit on error writing to any output not a pipe | ||
49 | // ^^^ all of these should set SIGPIPE to SIG_IGN. | ||
50 | // Because "exit" mode should print error message and exit1(1) - not die on SIGPIPE. | ||
51 | // "exit-nopipe" does not exit on EPIPE and does not set exitcode to 1 too. | ||
52 | // -p diagnose errors writing to non pipes | ||
53 | // ^^^^ this should set SIGPIPE to SIG_IGN. EPIPE is ignored (same as "warn-nopipe") | ||
54 | |||
42 | #include "libbb.h" | 55 | #include "libbb.h" |
43 | #include "common_bufsiz.h" | 56 | #include "common_bufsiz.h" |
44 | 57 | ||
@@ -66,12 +79,12 @@ int tee_main(int argc, char **argv) | |||
66 | mode += (retval & 2); /* Since 'a' is the 2nd option... */ | 79 | mode += (retval & 2); /* Since 'a' is the 2nd option... */ |
67 | 80 | ||
68 | if (retval & 1) { | 81 | if (retval & 1) { |
69 | signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction. (why?) */ | 82 | signal(SIGINT, SIG_IGN); |
70 | } | 83 | } |
71 | retval = EXIT_SUCCESS; | 84 | retval = EXIT_SUCCESS; |
72 | /* gnu tee ignores SIGPIPE in case one of the output files is a pipe | 85 | /* if (opt_p || opt_output_error) |
73 | * that doesn't consume all its input. Good idea... */ | 86 | signal(SIGPIPE, SIG_IGN); |
74 | signal(SIGPIPE, SIG_IGN); | 87 | */ |
75 | 88 | ||
76 | /* Allocate an array of FILE *'s, with one extra for a sentinel. */ | 89 | /* Allocate an array of FILE *'s, with one extra for a sentinel. */ |
77 | fp = files = xzalloc(sizeof(FILE *) * (argc + 2)); | 90 | fp = files = xzalloc(sizeof(FILE *) * (argc + 2)); |
@@ -79,6 +92,7 @@ int tee_main(int argc, char **argv) | |||
79 | 92 | ||
80 | files[0] = stdout; | 93 | files[0] = stdout; |
81 | goto GOT_NEW_FILE; | 94 | goto GOT_NEW_FILE; |
95 | |||
82 | do { | 96 | do { |
83 | *fp = stdout; | 97 | *fp = stdout; |
84 | if (NOT_LONE_DASH(*argv)) { | 98 | if (NOT_LONE_DASH(*argv)) { |
@@ -102,6 +116,7 @@ int tee_main(int argc, char **argv) | |||
102 | fp = files; | 116 | fp = files; |
103 | do | 117 | do |
104 | fwrite(buf, 1, c, *fp); | 118 | fwrite(buf, 1, c, *fp); |
119 | /* if (opt_p && fwrite() != c && !EPIPE) bb_error_msg("..."); */ | ||
105 | while (*++fp); | 120 | while (*++fp); |
106 | } | 121 | } |
107 | if (c < 0) { /* Make sure read errors are signaled. */ | 122 | if (c < 0) { /* Make sure read errors are signaled. */ |
@@ -113,6 +128,7 @@ int tee_main(int argc, char **argv) | |||
113 | fp = files; | 128 | fp = files; |
114 | do | 129 | do |
115 | putc(c, *fp); | 130 | putc(c, *fp); |
131 | /* if (opt_p && putc() == EOF && !EPIPE) bb_error_msg("..."); */ | ||
116 | while (*++fp); | 132 | while (*++fp); |
117 | } | 133 | } |
118 | #endif | 134 | #endif |
diff --git a/coreutils/test.c b/coreutils/test.c index 868ffbecb..a08986130 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
@@ -411,7 +411,7 @@ extern struct test_statics *const test_ptr_to_statics; | |||
411 | #define leaving (S.leaving ) | 411 | #define leaving (S.leaving ) |
412 | 412 | ||
413 | #define INIT_S() do { \ | 413 | #define INIT_S() do { \ |
414 | (*(struct test_statics**)&test_ptr_to_statics) = xzalloc(sizeof(S)); \ | 414 | (*(struct test_statics**)not_const_pp(&test_ptr_to_statics)) = xzalloc(sizeof(S)); \ |
415 | barrier(); \ | 415 | barrier(); \ |
416 | } while (0) | 416 | } while (0) |
417 | #define DEINIT_S() do { \ | 417 | #define DEINIT_S() do { \ |
diff --git a/editors/vi.c b/editors/vi.c index 4676db2b2..948b95ae6 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -3556,7 +3556,7 @@ static void do_cmd(int c) | |||
3556 | } while (--cmdcnt > 0); | 3556 | } while (--cmdcnt > 0); |
3557 | break; | 3557 | break; |
3558 | case '{': // {- move backward paragraph | 3558 | case '{': // {- move backward paragraph |
3559 | q = char_search(dot, "\n\n", (BACK << 1) | FULL); | 3559 | q = char_search(dot, "\n\n", ((unsigned)BACK << 1) | FULL); |
3560 | if (q != NULL) { // found blank line | 3560 | if (q != NULL) { // found blank line |
3561 | dot = next_line(q); // move to next blank line | 3561 | dot = next_line(q); // move to next blank line |
3562 | } | 3562 | } |
diff --git a/examples/inittab b/examples/inittab index 01ceaef25..4761aa19c 100644 --- a/examples/inittab +++ b/examples/inittab | |||
@@ -19,30 +19,43 @@ | |||
19 | # | 19 | # |
20 | # <runlevels>: The runlevels field is completely ignored. | 20 | # <runlevels>: The runlevels field is completely ignored. |
21 | # | 21 | # |
22 | # <action>: Valid actions include: sysinit, respawn, askfirst, wait, once, | 22 | # <action>: Valid actions include: sysinit, wait, once, respawn, askfirst, |
23 | # restart, ctrlaltdel, and shutdown. | 23 | # shutdown, restart and ctrlaltdel. |
24 | # | 24 | # |
25 | # Note: askfirst acts just like respawn, but before running the specified | 25 | # sysinit actions are started first, and init waits for them to complete. |
26 | # process it displays the line "Please press Enter to activate this | 26 | # wait actions are started next, and init waits for them to complete. |
27 | # console." and then waits for the user to press enter before starting | 27 | # once actions are started next (and not waited for). |
28 | # the specified process. | ||
29 | # | 28 | # |
30 | # Note: unrecognized actions (like initdefault) will cause init to emit | 29 | # askfirst and respawn are started next. |
31 | # an error message, and then go along with its business. | 30 | # For askfirst, before running the specified process, init displays |
31 | # the line "Please press Enter to activate this console" | ||
32 | # and then waits for the user to press enter before starting it. | ||
33 | # | ||
34 | # shutdown actions are run on halt/reboot/poweroff, or on SIGQUIT. | ||
35 | # Then the machine is halted/rebooted/powered off, or for SIGQUIT, | ||
36 | # restart action is exec'ed (init process is replaced by that process). | ||
37 | # If no restart action specified, SIGQUIT has no effect. | ||
38 | # | ||
39 | # ctrlaltdel actions are run when SIGINT is received | ||
40 | # (this might be initiated by Ctrl-Alt-Del key combination). | ||
41 | # After they complete, normal processing of askfirst / respawn resumes. | ||
42 | # | ||
43 | # Note: unrecognized actions (like initdefault) will cause init to emit | ||
44 | # an error message, and then go along with its business. | ||
32 | # | 45 | # |
33 | # <process>: Specifies the process to be executed and it's command line. | 46 | # <process>: Specifies the process to be executed and it's command line. |
34 | # | 47 | # |
35 | # Note: BusyBox init works just fine without an inittab. If no inittab is | 48 | # Note: BusyBox init works just fine without an inittab. If no inittab is |
36 | # found, it has the following default behavior: | 49 | # found, it has the following default behavior: |
37 | # ::sysinit:/etc/init.d/rcS | 50 | # ::sysinit:/etc/init.d/rcS |
38 | # ::askfirst:/bin/sh | 51 | # ::askfirst:/bin/sh |
39 | # ::ctrlaltdel:/sbin/reboot | 52 | # ::ctrlaltdel:/sbin/reboot |
40 | # ::shutdown:/sbin/swapoff -a | 53 | # ::shutdown:/sbin/swapoff -a |
41 | # ::shutdown:/bin/umount -a -r | 54 | # ::shutdown:/bin/umount -a -r |
42 | # ::restart:/sbin/init | 55 | # ::restart:/sbin/init |
43 | # tty2::askfirst:/bin/sh | 56 | # tty2::askfirst:/bin/sh |
44 | # tty3::askfirst:/bin/sh | 57 | # tty3::askfirst:/bin/sh |
45 | # tty4::askfirst:/bin/sh | 58 | # tty4::askfirst:/bin/sh |
46 | # | 59 | # |
47 | # Boot-time system configuration/initialization script. | 60 | # Boot-time system configuration/initialization script. |
48 | # This is run first except when booting in single-user mode. | 61 | # This is run first except when booting in single-user mode. |
diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index 53974e6d6..6658fbeef 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script | |||
@@ -16,9 +16,10 @@ BROADCAST="broadcast +" | |||
16 | 16 | ||
17 | case "$1" in | 17 | case "$1" in |
18 | deconfig) | 18 | deconfig) |
19 | echo "Setting IP address 0.0.0.0 on $interface" | 19 | echo "Clearing IP addresses on $interface, upping it" |
20 | if command -v ip >/dev/null; then | 20 | if command -v ip >/dev/null; then |
21 | ip addr flush dev $interface | 21 | ip addr flush dev $interface |
22 | ip link set dev $interface up | ||
22 | else | 23 | else |
23 | ifconfig $interface 0.0.0.0 | 24 | ifconfig $interface 0.0.0.0 |
24 | fi | 25 | fi |
@@ -52,7 +53,6 @@ case "$1" in | |||
52 | done | 53 | done |
53 | fi | 54 | fi |
54 | 55 | ||
55 | echo "Recreating $RESOLV_CONF" | ||
56 | # If the file is a symlink somewhere (like /etc/resolv.conf | 56 | # If the file is a symlink somewhere (like /etc/resolv.conf |
57 | # pointing to /run/resolv.conf), make sure things work. | 57 | # pointing to /run/resolv.conf), make sure things work. |
58 | if test -L "$RESOLV_CONF"; then | 58 | if test -L "$RESOLV_CONF"; then |
@@ -60,6 +60,7 @@ case "$1" in | |||
60 | test -e "$RESOLV_CONF" || touch "$RESOLV_CONF" | 60 | test -e "$RESOLV_CONF" || touch "$RESOLV_CONF" |
61 | fi | 61 | fi |
62 | realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") | 62 | realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") |
63 | echo "Recreating $realconf" | ||
63 | tmpfile="$realconf-$$" | 64 | tmpfile="$realconf-$$" |
64 | > "$tmpfile" | 65 | > "$tmpfile" |
65 | [ -n "$domain" ] && echo "search $domain" >> "$tmpfile" | 66 | [ -n "$domain" ] && echo "search $domain" >> "$tmpfile" |
diff --git a/findutils/find.c b/findutils/find.c index 66ad36283..121f8fd03 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -203,6 +203,14 @@ | |||
203 | //config: WARNING: This option can do much harm if used wrong. Busybox will not | 203 | //config: WARNING: This option can do much harm if used wrong. Busybox will not |
204 | //config: try to protect the user from doing stupid things. Use with care. | 204 | //config: try to protect the user from doing stupid things. Use with care. |
205 | //config: | 205 | //config: |
206 | //config:config FEATURE_FIND_EMPTY | ||
207 | //config: bool "Enable -empty: match empty files or directories" | ||
208 | //config: default y | ||
209 | //config: depends on FIND | ||
210 | //config: help | ||
211 | //config: Support the 'find -empty' option to find empty regular files | ||
212 | //config: or directories. | ||
213 | //config: | ||
206 | //config:config FEATURE_FIND_PATH | 214 | //config:config FEATURE_FIND_PATH |
207 | //config: bool "Enable -path: match pathname with shell pattern" | 215 | //config: bool "Enable -path: match pathname with shell pattern" |
208 | //config: default y | 216 | //config: default y |
@@ -315,6 +323,9 @@ | |||
315 | //usage: IF_FEATURE_FIND_CONTEXT( | 323 | //usage: IF_FEATURE_FIND_CONTEXT( |
316 | //usage: "\n -context CTX File has specified security context" | 324 | //usage: "\n -context CTX File has specified security context" |
317 | //usage: ) | 325 | //usage: ) |
326 | //usage: IF_FEATURE_FIND_EMPTY( | ||
327 | //usage: "\n -empty Match empty file/directory" | ||
328 | //usage: ) | ||
318 | //usage: IF_FEATURE_FIND_PRUNE( | 329 | //usage: IF_FEATURE_FIND_PRUNE( |
319 | //usage: "\n -prune If current file is directory, don't descend into it" | 330 | //usage: "\n -prune If current file is directory, don't descend into it" |
320 | //usage: ) | 331 | //usage: ) |
@@ -396,6 +407,7 @@ IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) | |||
396 | IF_FEATURE_FIND_PRUNE( ACTS(prune)) | 407 | IF_FEATURE_FIND_PRUNE( ACTS(prune)) |
397 | IF_FEATURE_FIND_QUIT( ACTS(quit)) | 408 | IF_FEATURE_FIND_QUIT( ACTS(quit)) |
398 | IF_FEATURE_FIND_DELETE( ACTS(delete)) | 409 | IF_FEATURE_FIND_DELETE( ACTS(delete)) |
410 | IF_FEATURE_FIND_EMPTY( ACTS(empty)) | ||
399 | IF_FEATURE_FIND_EXEC( ACTS(exec, | 411 | IF_FEATURE_FIND_EXEC( ACTS(exec, |
400 | char **exec_argv; /* -exec ARGS */ | 412 | char **exec_argv; /* -exec ARGS */ |
401 | unsigned *subst_count; | 413 | unsigned *subst_count; |
@@ -824,6 +836,30 @@ ACTF(delete) | |||
824 | return TRUE; | 836 | return TRUE; |
825 | } | 837 | } |
826 | #endif | 838 | #endif |
839 | #if ENABLE_FEATURE_FIND_EMPTY | ||
840 | ACTF(empty) | ||
841 | { | ||
842 | if (S_ISDIR(statbuf->st_mode)) { | ||
843 | DIR *dir; | ||
844 | struct dirent *dent; | ||
845 | |||
846 | dir = opendir(fileName); | ||
847 | if (!dir) { | ||
848 | bb_simple_perror_msg(fileName); | ||
849 | return FALSE; | ||
850 | } | ||
851 | |||
852 | while ((dent = readdir(dir)) != NULL | ||
853 | && DOT_OR_DOTDOT(dent->d_name) | ||
854 | ) { | ||
855 | continue; | ||
856 | } | ||
857 | closedir(dir); | ||
858 | return dent == NULL; | ||
859 | } | ||
860 | return S_ISREG(statbuf->st_mode) && statbuf->st_size == 0; | ||
861 | } | ||
862 | #endif | ||
827 | #if ENABLE_FEATURE_FIND_CONTEXT | 863 | #if ENABLE_FEATURE_FIND_CONTEXT |
828 | ACTF(context) | 864 | ACTF(context) |
829 | { | 865 | { |
@@ -989,6 +1025,7 @@ static action*** parse_params(char **argv) | |||
989 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) | 1025 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) |
990 | IF_FEATURE_FIND_QUIT( PARM_quit ,) | 1026 | IF_FEATURE_FIND_QUIT( PARM_quit ,) |
991 | IF_FEATURE_FIND_DELETE( PARM_delete ,) | 1027 | IF_FEATURE_FIND_DELETE( PARM_delete ,) |
1028 | IF_FEATURE_FIND_EMPTY( PARM_empty ,) | ||
992 | IF_FEATURE_FIND_EXEC( PARM_exec ,) | 1029 | IF_FEATURE_FIND_EXEC( PARM_exec ,) |
993 | IF_FEATURE_FIND_EXECUTABLE(PARM_executable,) | 1030 | IF_FEATURE_FIND_EXECUTABLE(PARM_executable,) |
994 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) | 1031 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) |
@@ -1034,6 +1071,7 @@ static action*** parse_params(char **argv) | |||
1034 | IF_FEATURE_FIND_PRUNE( "-prune\0" ) | 1071 | IF_FEATURE_FIND_PRUNE( "-prune\0" ) |
1035 | IF_FEATURE_FIND_QUIT( "-quit\0" ) | 1072 | IF_FEATURE_FIND_QUIT( "-quit\0" ) |
1036 | IF_FEATURE_FIND_DELETE( "-delete\0" ) | 1073 | IF_FEATURE_FIND_DELETE( "-delete\0" ) |
1074 | IF_FEATURE_FIND_EMPTY( "-empty\0" ) | ||
1037 | IF_FEATURE_FIND_EXEC( "-exec\0" ) | 1075 | IF_FEATURE_FIND_EXEC( "-exec\0" ) |
1038 | IF_FEATURE_FIND_EXECUTABLE("-executable\0") | 1076 | IF_FEATURE_FIND_EXECUTABLE("-executable\0") |
1039 | IF_FEATURE_FIND_PAREN( "(\0" ) | 1077 | IF_FEATURE_FIND_PAREN( "(\0" ) |
@@ -1203,6 +1241,12 @@ static action*** parse_params(char **argv) | |||
1203 | (void) ALLOC_ACTION(delete); | 1241 | (void) ALLOC_ACTION(delete); |
1204 | } | 1242 | } |
1205 | #endif | 1243 | #endif |
1244 | #if ENABLE_FEATURE_FIND_EMPTY | ||
1245 | else if (parm == PARM_empty) { | ||
1246 | dbg("%d", __LINE__); | ||
1247 | (void) ALLOC_ACTION(empty); | ||
1248 | } | ||
1249 | #endif | ||
1206 | #if ENABLE_FEATURE_FIND_EXEC | 1250 | #if ENABLE_FEATURE_FIND_EXEC |
1207 | else if (parm == PARM_exec) { | 1251 | else if (parm == PARM_exec) { |
1208 | int i; | 1252 | int i; |
diff --git a/findutils/grep.c b/findutils/grep.c index 2cbe7ea91..5b8644c36 100644 --- a/findutils/grep.c +++ b/findutils/grep.c | |||
@@ -60,7 +60,7 @@ | |||
60 | 60 | ||
61 | /* options */ | 61 | /* options */ |
62 | //usage:#define grep_trivial_usage | 62 | //usage:#define grep_trivial_usage |
63 | //usage: "[-HhnlLoqvsriwFE" | 63 | //usage: "[-HhnlLoqvsrRiwFE" |
64 | //usage: IF_EXTRA_COMPAT("z") | 64 | //usage: IF_EXTRA_COMPAT("z") |
65 | //usage: "] [-m N] " | 65 | //usage: "] [-m N] " |
66 | //usage: IF_FEATURE_GREP_CONTEXT("[-A/B/C N] ") | 66 | //usage: IF_FEATURE_GREP_CONTEXT("[-A/B/C N] ") |
@@ -78,6 +78,7 @@ | |||
78 | //usage: "\n -v Select non-matching lines" | 78 | //usage: "\n -v Select non-matching lines" |
79 | //usage: "\n -s Suppress open and read errors" | 79 | //usage: "\n -s Suppress open and read errors" |
80 | //usage: "\n -r Recurse" | 80 | //usage: "\n -r Recurse" |
81 | //usage: "\n -R Recurse and dereference symlinks" | ||
81 | //usage: "\n -i Ignore case" | 82 | //usage: "\n -i Ignore case" |
82 | //usage: "\n -w Match whole words only" | 83 | //usage: "\n -w Match whole words only" |
83 | //usage: "\n -x Match whole lines only" | 84 | //usage: "\n -x Match whole lines only" |
@@ -108,7 +109,7 @@ | |||
108 | 109 | ||
109 | /* -e,-f are lists; -m,-A,-B,-C have numeric param */ | 110 | /* -e,-f are lists; -m,-A,-B,-C have numeric param */ |
110 | #define OPTSTR_GREP \ | 111 | #define OPTSTR_GREP \ |
111 | "lnqvscFiHhe:*f:*Lorm:+wx" \ | 112 | "lnqvscFiHhe:*f:*LorRm:+wx" \ |
112 | IF_FEATURE_GREP_CONTEXT("A:+B:+C:+") \ | 113 | IF_FEATURE_GREP_CONTEXT("A:+B:+C:+") \ |
113 | "E" \ | 114 | "E" \ |
114 | IF_EXTRA_COMPAT("z") \ | 115 | IF_EXTRA_COMPAT("z") \ |
@@ -131,6 +132,7 @@ enum { | |||
131 | OPTBIT_L, /* list unmatched file names only */ | 132 | OPTBIT_L, /* list unmatched file names only */ |
132 | OPTBIT_o, /* show only matching parts of lines */ | 133 | OPTBIT_o, /* show only matching parts of lines */ |
133 | OPTBIT_r, /* recurse dirs */ | 134 | OPTBIT_r, /* recurse dirs */ |
135 | OPTBIT_R, /* recurse dirs and symlinks to dirs */ | ||
134 | OPTBIT_m, /* -m MAX_MATCHES */ | 136 | OPTBIT_m, /* -m MAX_MATCHES */ |
135 | OPTBIT_w, /* -w whole word match */ | 137 | OPTBIT_w, /* -w whole word match */ |
136 | OPTBIT_x, /* -x whole line match */ | 138 | OPTBIT_x, /* -x whole line match */ |
@@ -154,6 +156,7 @@ enum { | |||
154 | OPT_L = 1 << OPTBIT_L, | 156 | OPT_L = 1 << OPTBIT_L, |
155 | OPT_o = 1 << OPTBIT_o, | 157 | OPT_o = 1 << OPTBIT_o, |
156 | OPT_r = 1 << OPTBIT_r, | 158 | OPT_r = 1 << OPTBIT_r, |
159 | OPT_R = 1 << OPTBIT_R, | ||
157 | OPT_m = 1 << OPTBIT_m, | 160 | OPT_m = 1 << OPTBIT_m, |
158 | OPT_w = 1 << OPTBIT_w, | 161 | OPT_w = 1 << OPTBIT_w, |
159 | OPT_x = 1 << OPTBIT_x, | 162 | OPT_x = 1 << OPTBIT_x, |
@@ -687,6 +690,7 @@ static int grep_dir(const char *dir) | |||
687 | int matched = 0; | 690 | int matched = 0; |
688 | recursive_action(dir, | 691 | recursive_action(dir, |
689 | /* recurse=yes */ ACTION_RECURSE | | 692 | /* recurse=yes */ ACTION_RECURSE | |
693 | /* followLinks=always */ ((option_mask32 & OPT_R) ? ACTION_FOLLOWLINKS : 0) | | ||
690 | /* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 | | 694 | /* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 | |
691 | /* depthFirst=yes */ ACTION_DEPTHFIRST, | 695 | /* depthFirst=yes */ ACTION_DEPTHFIRST, |
692 | /* fileAction= */ file_action_grep, | 696 | /* fileAction= */ file_action_grep, |
@@ -827,7 +831,7 @@ int grep_main(int argc UNUSED_PARAM, char **argv) | |||
827 | if (!cur_file || LONE_DASH(cur_file)) { | 831 | if (!cur_file || LONE_DASH(cur_file)) { |
828 | cur_file = "(standard input)"; | 832 | cur_file = "(standard input)"; |
829 | } else { | 833 | } else { |
830 | if (option_mask32 & OPT_r) { | 834 | if (option_mask32 & (OPT_r|OPT_R)) { |
831 | struct stat st; | 835 | struct stat st; |
832 | if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) { | 836 | if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) { |
833 | if (!(option_mask32 & OPT_h)) | 837 | if (!(option_mask32 & OPT_h)) |
diff --git a/include/libbb.h b/include/libbb.h index 84811c4f2..0aa44eb37 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -2218,12 +2218,32 @@ struct globals; | |||
2218 | * Magic prevents ptr_to_globals from going into rodata. | 2218 | * Magic prevents ptr_to_globals from going into rodata. |
2219 | * If you want to assign a value, use SET_PTR_TO_GLOBALS(x) */ | 2219 | * If you want to assign a value, use SET_PTR_TO_GLOBALS(x) */ |
2220 | extern struct globals *const ptr_to_globals; | 2220 | extern struct globals *const ptr_to_globals; |
2221 | |||
2222 | #if defined(__clang_major__) && __clang_major__ >= 9 | ||
2223 | /* Clang/llvm drops assignment to "constant" storage. Silently. | ||
2224 | * Needs serious convincing to not eliminate the store. | ||
2225 | */ | ||
2226 | static ALWAYS_INLINE void* not_const_pp(const void *p) | ||
2227 | { | ||
2228 | void *pp; | ||
2229 | __asm__ __volatile__( | ||
2230 | "# forget that p points to const" | ||
2231 | : /*outputs*/ "=r" (pp) | ||
2232 | : /*inputs*/ "0" (p) | ||
2233 | ); | ||
2234 | return pp; | ||
2235 | } | ||
2236 | #else | ||
2237 | static ALWAYS_INLINE void* not_const_pp(const void *p) { return (void*)p; } | ||
2238 | #endif | ||
2239 | |||
2221 | /* At least gcc 3.4.6 on mipsel system needs optimization barrier */ | 2240 | /* At least gcc 3.4.6 on mipsel system needs optimization barrier */ |
2222 | #define barrier() __asm__ __volatile__("":::"memory") | 2241 | #define barrier() __asm__ __volatile__("":::"memory") |
2223 | #define SET_PTR_TO_GLOBALS(x) do { \ | 2242 | #define SET_PTR_TO_GLOBALS(x) do { \ |
2224 | (*(struct globals**)&ptr_to_globals) = (void*)(x); \ | 2243 | (*(struct globals**)not_const_pp(&ptr_to_globals)) = (void*)(x); \ |
2225 | barrier(); \ | 2244 | barrier(); \ |
2226 | } while (0) | 2245 | } while (0) |
2246 | |||
2227 | #define FREE_PTR_TO_GLOBALS() do { \ | 2247 | #define FREE_PTR_TO_GLOBALS() do { \ |
2228 | if (ENABLE_FEATURE_CLEAN_UP) { \ | 2248 | if (ENABLE_FEATURE_CLEAN_UP) { \ |
2229 | free(ptr_to_globals); \ | 2249 | free(ptr_to_globals); \ |
diff --git a/init/init.c b/init/init.c index 0f3c5fa4d..28775a65c 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -145,13 +145,6 @@ | |||
145 | # include <sys/ucontext.h> | 145 | # include <sys/ucontext.h> |
146 | #endif | 146 | #endif |
147 | 147 | ||
148 | /* Used only for sanitizing purposes in set_sane_term() below. On systems where | ||
149 | * the baud rate is stored in a separate field, we can safely disable them. */ | ||
150 | #ifndef CBAUD | ||
151 | # define CBAUD 0 | ||
152 | # define CBAUDEX 0 | ||
153 | #endif | ||
154 | |||
155 | /* Was a CONFIG_xxx option. A lot of people were building | 148 | /* Was a CONFIG_xxx option. A lot of people were building |
156 | * not fully functional init by switching it on! */ | 149 | * not fully functional init by switching it on! */ |
157 | #define DEBUG_INIT 0 | 150 | #define DEBUG_INIT 0 |
@@ -217,6 +210,8 @@ struct globals { | |||
217 | #if !ENABLE_FEATURE_INIT_SYSLOG | 210 | #if !ENABLE_FEATURE_INIT_SYSLOG |
218 | const char *log_console; | 211 | const char *log_console; |
219 | #endif | 212 | #endif |
213 | sigset_t delayed_sigset; | ||
214 | struct timespec zero_ts; | ||
220 | } FIX_ALIASING; | 215 | } FIX_ALIASING; |
221 | #define G (*(struct globals*)bb_common_bufsiz1) | 216 | #define G (*(struct globals*)bb_common_bufsiz1) |
222 | #define INIT_G() do { \ | 217 | #define INIT_G() do { \ |
@@ -347,7 +342,8 @@ static void set_sane_term(void) | |||
347 | { | 342 | { |
348 | struct termios tty; | 343 | struct termios tty; |
349 | 344 | ||
350 | tcgetattr(STDIN_FILENO, &tty); | 345 | if (tcgetattr(STDIN_FILENO, &tty) != 0) |
346 | return; | ||
351 | 347 | ||
352 | /* set control chars */ | 348 | /* set control chars */ |
353 | tty.c_cc[VINTR] = 3; /* C-c */ | 349 | tty.c_cc[VINTR] = 3; /* C-c */ |
@@ -365,10 +361,15 @@ static void set_sane_term(void) | |||
365 | #endif | 361 | #endif |
366 | 362 | ||
367 | /* Make it be sane */ | 363 | /* Make it be sane */ |
364 | /* On systems where the baud rate is stored in a separate field, we can safely disable these. */ | ||
365 | #ifndef CBAUD | ||
366 | # define CBAUD 0 | ||
367 | # define CBAUDEX 0 | ||
368 | #endif | ||
369 | /* Added CRTSCTS to fix Debian bug 528560 */ | ||
368 | #ifndef CRTSCTS | 370 | #ifndef CRTSCTS |
369 | # define CRTSCTS 0 | 371 | # define CRTSCTS 0 |
370 | #endif | 372 | #endif |
371 | /* added CRTSCTS to fix Debian bug 528560 */ | ||
372 | tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS; | 373 | tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS; |
373 | tty.c_cflag |= CREAD | HUPCL | CLOCAL; | 374 | tty.c_cflag |= CREAD | HUPCL | CLOCAL; |
374 | 375 | ||
@@ -412,14 +413,8 @@ static int open_stdio_to_tty(const char* tty_name) | |||
412 | static void reset_sighandlers_and_unblock_sigs(void) | 413 | static void reset_sighandlers_and_unblock_sigs(void) |
413 | { | 414 | { |
414 | bb_signals(0 | 415 | bb_signals(0 |
415 | + (1 << SIGUSR1) | 416 | | (1 << SIGTSTP) |
416 | + (1 << SIGUSR2) | 417 | | (1 << SIGSTOP) |
417 | + (1 << SIGTERM) | ||
418 | + (1 << SIGQUIT) | ||
419 | + (1 << SIGINT) | ||
420 | + (1 << SIGHUP) | ||
421 | + (1 << SIGTSTP) | ||
422 | + (1 << SIGSTOP) | ||
423 | , SIG_DFL); | 418 | , SIG_DFL); |
424 | sigprocmask_allsigs(SIG_UNBLOCK); | 419 | sigprocmask_allsigs(SIG_UNBLOCK); |
425 | } | 420 | } |
@@ -485,16 +480,13 @@ static pid_t run(const struct init_action *a) | |||
485 | { | 480 | { |
486 | pid_t pid; | 481 | pid_t pid; |
487 | 482 | ||
488 | /* Careful: don't be affected by a signal in vforked child */ | ||
489 | sigprocmask_allsigs(SIG_BLOCK); | ||
490 | if (BB_MMU && (a->action_type & ASKFIRST)) | 483 | if (BB_MMU && (a->action_type & ASKFIRST)) |
491 | pid = fork(); | 484 | pid = fork(); |
492 | else | 485 | else |
493 | pid = vfork(); | 486 | pid = vfork(); |
494 | if (pid < 0) | ||
495 | message(L_LOG | L_CONSOLE, "can't fork"); | ||
496 | if (pid) { | 487 | if (pid) { |
497 | sigprocmask_allsigs(SIG_UNBLOCK); | 488 | if (pid < 0) |
489 | message(L_LOG | L_CONSOLE, "can't fork"); | ||
498 | return pid; /* Parent or error */ | 490 | return pid; /* Parent or error */ |
499 | } | 491 | } |
500 | 492 | ||
@@ -588,9 +580,11 @@ static void waitfor(pid_t pid) | |||
588 | while (1) { | 580 | while (1) { |
589 | pid_t wpid = wait(NULL); | 581 | pid_t wpid = wait(NULL); |
590 | mark_terminated(wpid); | 582 | mark_terminated(wpid); |
591 | /* Unsafe. SIGTSTP handler might have wait'ed it already */ | 583 | if (wpid == pid) /* this was the process we waited for */ |
592 | /*if (wpid == pid) break;*/ | 584 | break; |
593 | /* More reliable: */ | 585 | /* The above is not reliable enough: SIGTSTP handler might have |
586 | * wait'ed it already. Double check, exit if process is gone: | ||
587 | */ | ||
594 | if (kill(pid, 0)) | 588 | if (kill(pid, 0)) |
595 | break; | 589 | break; |
596 | } | 590 | } |
@@ -799,23 +793,17 @@ static void run_shutdown_and_kill_processes(void) | |||
799 | * Delayed handlers just set a flag variable. The variable is checked | 793 | * Delayed handlers just set a flag variable. The variable is checked |
800 | * in the main loop and acted upon. | 794 | * in the main loop and acted upon. |
801 | * | 795 | * |
802 | * halt/poweroff/reboot and restart have immediate handlers. | ||
803 | * They only traverse linked list of struct action's, never modify it, | ||
804 | * this should be safe to do even in signal handler. Also they | ||
805 | * never return. | ||
806 | * | ||
807 | * SIGSTOP and SIGTSTP have immediate handlers. They just wait | 796 | * SIGSTOP and SIGTSTP have immediate handlers. They just wait |
808 | * for SIGCONT to happen. | 797 | * for SIGCONT to happen. |
809 | * | 798 | * |
799 | * halt/poweroff/reboot and restart have delayed handlers. | ||
800 | * | ||
810 | * SIGHUP has a delayed handler, because modifying linked list | 801 | * SIGHUP has a delayed handler, because modifying linked list |
811 | * of struct action's from a signal handler while it is manipulated | 802 | * of struct action's from a signal handler while it is manipulated |
812 | * by the program may be disastrous. | 803 | * by the program may be disastrous. |
813 | * | 804 | * |
814 | * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing | 805 | * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing |
815 | * it to happen even somewhere inside "sysinit" would be a bit awkward. | 806 | * it to happen even somewhere inside "sysinit" would be a bit awkward. |
816 | * | ||
817 | * There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide | ||
818 | * and only one will be remembered and acted upon. | ||
819 | */ | 807 | */ |
820 | 808 | ||
821 | /* The SIGPWR/SIGUSR[12]/SIGTERM handler */ | 809 | /* The SIGPWR/SIGUSR[12]/SIGTERM handler */ |
@@ -899,11 +887,9 @@ static void exec_restart_action(void) | |||
899 | */ | 887 | */ |
900 | static void stop_handler(int sig UNUSED_PARAM) | 888 | static void stop_handler(int sig UNUSED_PARAM) |
901 | { | 889 | { |
902 | smallint saved_bb_got_signal; | 890 | int saved_errno = errno; |
903 | int saved_errno; | ||
904 | 891 | ||
905 | saved_bb_got_signal = bb_got_signal; | 892 | bb_got_signal = 0; |
906 | saved_errno = errno; | ||
907 | signal(SIGCONT, record_signo); | 893 | signal(SIGCONT, record_signo); |
908 | 894 | ||
909 | while (1) { | 895 | while (1) { |
@@ -917,12 +903,12 @@ static void stop_handler(int sig UNUSED_PARAM) | |||
917 | */ | 903 | */ |
918 | wpid = wait_any_nohang(NULL); | 904 | wpid = wait_any_nohang(NULL); |
919 | mark_terminated(wpid); | 905 | mark_terminated(wpid); |
920 | sleep(1); | 906 | if (wpid <= 0) /* no processes exited? sleep a bit */ |
907 | sleep(1); | ||
921 | } | 908 | } |
922 | 909 | ||
923 | signal(SIGCONT, SIG_DFL); | 910 | signal(SIGCONT, SIG_DFL); |
924 | errno = saved_errno; | 911 | errno = saved_errno; |
925 | bb_got_signal = saved_bb_got_signal; | ||
926 | } | 912 | } |
927 | 913 | ||
928 | #if ENABLE_FEATURE_USE_INITTAB | 914 | #if ENABLE_FEATURE_USE_INITTAB |
@@ -987,43 +973,39 @@ static void reload_inittab(void) | |||
987 | } | 973 | } |
988 | #endif | 974 | #endif |
989 | 975 | ||
990 | static int check_delayed_sigs(void) | 976 | static void check_delayed_sigs(struct timespec *ts) |
991 | { | 977 | { |
992 | int sigs_seen = 0; | 978 | int sig = sigtimedwait(&G.delayed_sigset, /* siginfo_t */ NULL, ts); |
979 | if (sig <= 0) | ||
980 | return; | ||
993 | 981 | ||
994 | while (1) { | 982 | /* The signal "sig" was caught */ |
995 | smallint sig = bb_got_signal; | ||
996 | 983 | ||
997 | if (!sig) | ||
998 | return sigs_seen; | ||
999 | bb_got_signal = 0; | ||
1000 | sigs_seen = 1; | ||
1001 | #if ENABLE_FEATURE_USE_INITTAB | 984 | #if ENABLE_FEATURE_USE_INITTAB |
1002 | if (sig == SIGHUP) | 985 | if (sig == SIGHUP) |
1003 | reload_inittab(); | 986 | reload_inittab(); |
1004 | #endif | 987 | #endif |
1005 | if (sig == SIGINT) | 988 | if (sig == SIGINT) |
1006 | run_actions(CTRLALTDEL); | 989 | run_actions(CTRLALTDEL); |
1007 | if (sig == SIGQUIT) { | 990 | if (sig == SIGQUIT) { |
1008 | exec_restart_action(); | 991 | exec_restart_action(); |
1009 | /* returns only if no restart action defined */ | 992 | /* returns only if no restart action defined */ |
1010 | } | 993 | } |
1011 | if ((1 << sig) & (0 | 994 | if ((1 << sig) & (0 |
1012 | #ifdef SIGPWR | 995 | #ifdef SIGPWR |
1013 | + (1 << SIGPWR) | 996 | | (1 << SIGPWR) |
1014 | #endif | 997 | #endif |
1015 | + (1 << SIGUSR1) | 998 | | (1 << SIGUSR1) |
1016 | + (1 << SIGUSR2) | 999 | | (1 << SIGUSR2) |
1017 | + (1 << SIGTERM) | 1000 | | (1 << SIGTERM) |
1018 | )) { | 1001 | )) { |
1019 | halt_reboot_pwoff(sig); | 1002 | halt_reboot_pwoff(sig); |
1020 | } | ||
1021 | } | 1003 | } |
1004 | /* if (sig == SIGCHLD) do nothing */ | ||
1022 | } | 1005 | } |
1023 | 1006 | ||
1024 | #if DEBUG_SEGV_HANDLER | 1007 | #if DEBUG_SEGV_HANDLER |
1025 | static | 1008 | static void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) |
1026 | void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) | ||
1027 | { | 1009 | { |
1028 | long ip; | 1010 | long ip; |
1029 | ucontext_t *uc; | 1011 | ucontext_t *uc; |
@@ -1050,50 +1032,62 @@ void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) | |||
1050 | 1032 | ||
1051 | static void sleep_much(void) | 1033 | static void sleep_much(void) |
1052 | { | 1034 | { |
1053 | sleep(30 * 24*60*60); | 1035 | sleep(30 * 24*60*60); |
1054 | } | 1036 | } |
1055 | 1037 | ||
1056 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1038 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1057 | int init_main(int argc UNUSED_PARAM, char **argv) | 1039 | int init_main(int argc UNUSED_PARAM, char **argv) |
1058 | { | 1040 | { |
1041 | struct sigaction sa; | ||
1042 | |||
1059 | INIT_G(); | 1043 | INIT_G(); |
1060 | 1044 | ||
1045 | /* Some users send poweroff signals to init VERY early. | ||
1046 | * To handle this, mask signals early. | ||
1047 | */ | ||
1048 | /* sigemptyset(&G.delayed_sigset); - done by INIT_G() */ | ||
1049 | sigaddset(&G.delayed_sigset, SIGINT); /* Ctrl-Alt-Del */ | ||
1050 | sigaddset(&G.delayed_sigset, SIGQUIT); /* re-exec another init */ | ||
1051 | #ifdef SIGPWR | ||
1052 | sigaddset(&G.delayed_sigset, SIGPWR); /* halt */ | ||
1053 | #endif | ||
1054 | sigaddset(&G.delayed_sigset, SIGUSR1); /* halt */ | ||
1055 | sigaddset(&G.delayed_sigset, SIGTERM); /* reboot */ | ||
1056 | sigaddset(&G.delayed_sigset, SIGUSR2); /* poweroff */ | ||
1057 | #if ENABLE_FEATURE_USE_INITTAB | ||
1058 | sigaddset(&G.delayed_sigset, SIGHUP); /* reread /etc/inittab */ | ||
1059 | #endif | ||
1060 | sigaddset(&G.delayed_sigset, SIGCHLD); /* make sigtimedwait() exit on SIGCHLD */ | ||
1061 | sigprocmask(SIG_BLOCK, &G.delayed_sigset, NULL); | ||
1062 | |||
1063 | #if DEBUG_SEGV_HANDLER | ||
1064 | memset(&sa, 0, sizeof(sa)); | ||
1065 | sa.sa_sigaction = handle_sigsegv; | ||
1066 | sa.sa_flags = SA_SIGINFO; | ||
1067 | sigaction_set(SIGSEGV, &sa); | ||
1068 | sigaction_set(SIGILL, &sa); | ||
1069 | sigaction_set(SIGFPE, &sa); | ||
1070 | sigaction_set(SIGBUS, &sa); | ||
1071 | #endif | ||
1072 | |||
1061 | if (argv[1] && strcmp(argv[1], "-q") == 0) { | 1073 | if (argv[1] && strcmp(argv[1], "-q") == 0) { |
1062 | return kill(1, SIGHUP); | 1074 | return kill(1, SIGHUP); |
1063 | } | 1075 | } |
1064 | 1076 | ||
1065 | #if DEBUG_SEGV_HANDLER | 1077 | #if !DEBUG_INIT |
1066 | { | 1078 | /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ |
1067 | struct sigaction sa; | 1079 | if (getpid() != 1 |
1068 | memset(&sa, 0, sizeof(sa)); | 1080 | && (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */ |
1069 | sa.sa_sigaction = handle_sigsegv; | 1081 | ) { |
1070 | sa.sa_flags = SA_SIGINFO; | 1082 | bb_simple_error_msg_and_die("must be run as PID 1"); |
1071 | sigaction(SIGSEGV, &sa, NULL); | ||
1072 | sigaction(SIGILL, &sa, NULL); | ||
1073 | sigaction(SIGFPE, &sa, NULL); | ||
1074 | sigaction(SIGBUS, &sa, NULL); | ||
1075 | } | 1083 | } |
1076 | #endif | ||
1077 | |||
1078 | if (!DEBUG_INIT) { | ||
1079 | /* Some users send poweroff signals to init VERY early. | ||
1080 | * To handle this, mask signals early, | ||
1081 | * and unmask them only after signal handlers are installed. | ||
1082 | */ | ||
1083 | sigprocmask_allsigs(SIG_BLOCK); | ||
1084 | 1084 | ||
1085 | /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ | 1085 | # ifdef RB_DISABLE_CAD |
1086 | if (getpid() != 1 | 1086 | /* Turn off rebooting via CTL-ALT-DEL - we get a |
1087 | && (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */ | 1087 | * SIGINT on CAD so we can shut things down gracefully... */ |
1088 | ) { | 1088 | reboot(RB_DISABLE_CAD); /* misnomer */ |
1089 | bb_simple_error_msg_and_die("must be run as PID 1"); | 1089 | # endif |
1090 | } | ||
1091 | #ifdef RB_DISABLE_CAD | ||
1092 | /* Turn off rebooting via CTL-ALT-DEL - we get a | ||
1093 | * SIGINT on CAD so we can shut things down gracefully... */ | ||
1094 | reboot(RB_DISABLE_CAD); /* misnomer */ | ||
1095 | #endif | 1090 | #endif |
1096 | } | ||
1097 | 1091 | ||
1098 | /* If, say, xmalloc would ever die, we don't want to oops kernel | 1092 | /* If, say, xmalloc would ever die, we don't want to oops kernel |
1099 | * by exiting. | 1093 | * by exiting. |
@@ -1157,106 +1151,65 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1157 | } | 1151 | } |
1158 | #endif | 1152 | #endif |
1159 | 1153 | ||
1160 | if (ENABLE_FEATURE_INIT_MODIFY_CMDLINE) { | 1154 | #if ENABLE_FEATURE_INIT_MODIFY_CMDLINE |
1161 | /* Make the command line just say "init" - that's all, nothing else */ | 1155 | /* Make the command line just say "init" - that's all, nothing else */ |
1162 | strncpy(argv[0], "init", strlen(argv[0])); | 1156 | strncpy(argv[0], "init", strlen(argv[0])); |
1163 | /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ | 1157 | /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ |
1164 | while (*++argv) | 1158 | while (*++argv) |
1165 | nuke_str(*argv); | 1159 | nuke_str(*argv); |
1166 | } | ||
1167 | |||
1168 | /* Set up signal handlers */ | ||
1169 | if (!DEBUG_INIT) { | ||
1170 | struct sigaction sa; | ||
1171 | |||
1172 | /* Stop handler must allow only SIGCONT inside itself */ | ||
1173 | memset(&sa, 0, sizeof(sa)); | ||
1174 | sigfillset(&sa.sa_mask); | ||
1175 | sigdelset(&sa.sa_mask, SIGCONT); | ||
1176 | sa.sa_handler = stop_handler; | ||
1177 | /* NB: sa_flags doesn't have SA_RESTART. | ||
1178 | * It must be able to interrupt wait(). | ||
1179 | */ | ||
1180 | sigaction_set(SIGTSTP, &sa); /* pause */ | ||
1181 | /* Does not work as intended, at least in 2.6.20. | ||
1182 | * SIGSTOP is simply ignored by init: | ||
1183 | */ | ||
1184 | sigaction_set(SIGSTOP, &sa); /* pause */ | ||
1185 | |||
1186 | /* These signals must interrupt wait(), | ||
1187 | * setting handler without SA_RESTART flag. | ||
1188 | */ | ||
1189 | bb_signals_recursive_norestart(0 | ||
1190 | + (1 << SIGINT) /* Ctrl-Alt-Del */ | ||
1191 | + (1 << SIGQUIT) /* re-exec another init */ | ||
1192 | #ifdef SIGPWR | ||
1193 | + (1 << SIGPWR) /* halt */ | ||
1194 | #endif | 1160 | #endif |
1195 | + (1 << SIGUSR1) /* halt */ | ||
1196 | + (1 << SIGTERM) /* reboot */ | ||
1197 | + (1 << SIGUSR2) /* poweroff */ | ||
1198 | #if ENABLE_FEATURE_USE_INITTAB | ||
1199 | + (1 << SIGHUP) /* reread /etc/inittab */ | ||
1200 | #endif | ||
1201 | , record_signo); | ||
1202 | 1161 | ||
1203 | sigprocmask_allsigs(SIG_UNBLOCK); | 1162 | /* Set up STOP signal handlers */ |
1204 | } | 1163 | /* Stop handler must allow only SIGCONT inside itself */ |
1164 | memset(&sa, 0, sizeof(sa)); | ||
1165 | sigfillset(&sa.sa_mask); | ||
1166 | sigdelset(&sa.sa_mask, SIGCONT); | ||
1167 | sa.sa_handler = stop_handler; | ||
1168 | sa.sa_flags = SA_RESTART; | ||
1169 | sigaction_set(SIGTSTP, &sa); /* pause */ | ||
1170 | /* Does not work as intended, at least in 2.6.20. | ||
1171 | * SIGSTOP is simply ignored by init | ||
1172 | * (NB: behavior might differ under strace): | ||
1173 | */ | ||
1174 | sigaction_set(SIGSTOP, &sa); /* pause */ | ||
1205 | 1175 | ||
1206 | /* Now run everything that needs to be run */ | 1176 | /* Now run everything that needs to be run */ |
1207 | /* First run the sysinit command */ | 1177 | /* First run the sysinit command */ |
1208 | run_actions(SYSINIT); | 1178 | run_actions(SYSINIT); |
1209 | check_delayed_sigs(); | 1179 | check_delayed_sigs(&G.zero_ts); |
1210 | /* Next run anything that wants to block */ | 1180 | /* Next run anything that wants to block */ |
1211 | run_actions(WAIT); | 1181 | run_actions(WAIT); |
1212 | check_delayed_sigs(); | 1182 | check_delayed_sigs(&G.zero_ts); |
1213 | /* Next run anything to be run only once */ | 1183 | /* Next run anything to be run only once */ |
1214 | run_actions(ONCE); | 1184 | run_actions(ONCE); |
1215 | 1185 | ||
1216 | /* Now run the looping stuff for the rest of forever. | 1186 | /* Now run the looping stuff for the rest of forever */ |
1217 | */ | ||
1218 | while (1) { | 1187 | while (1) { |
1219 | int maybe_WNOHANG; | ||
1220 | |||
1221 | maybe_WNOHANG = check_delayed_sigs(); | ||
1222 | |||
1223 | /* (Re)run the respawn/askfirst stuff */ | 1188 | /* (Re)run the respawn/askfirst stuff */ |
1224 | run_actions(RESPAWN | ASKFIRST); | 1189 | run_actions(RESPAWN | ASKFIRST); |
1225 | maybe_WNOHANG |= check_delayed_sigs(); | ||
1226 | 1190 | ||
1227 | /* Don't consume all CPU time - sleep a bit */ | 1191 | /* Wait for any signal (typically it's SIGCHLD) */ |
1228 | sleep(1); | 1192 | check_delayed_sigs(NULL); /* NULL timespec makes it wait */ |
1229 | maybe_WNOHANG |= check_delayed_sigs(); | 1193 | |
1230 | 1194 | /* Wait for any child process(es) to exit */ | |
1231 | /* Wait for any child process(es) to exit. | ||
1232 | * | ||
1233 | * If check_delayed_sigs above reported that a signal | ||
1234 | * was caught, wait will be nonblocking. This ensures | ||
1235 | * that if SIGHUP has reloaded inittab, respawn and askfirst | ||
1236 | * actions will not be delayed until next child death. | ||
1237 | */ | ||
1238 | if (maybe_WNOHANG) | ||
1239 | maybe_WNOHANG = WNOHANG; | ||
1240 | while (1) { | 1195 | while (1) { |
1241 | pid_t wpid; | 1196 | pid_t wpid; |
1242 | struct init_action *a; | 1197 | struct init_action *a; |
1243 | 1198 | ||
1244 | /* If signals happen _in_ the wait, they interrupt it, | 1199 | wpid = waitpid(-1, NULL, WNOHANG); |
1245 | * bb_signals_recursive_norestart set them up that way | ||
1246 | */ | ||
1247 | wpid = waitpid(-1, NULL, maybe_WNOHANG); | ||
1248 | if (wpid <= 0) | 1200 | if (wpid <= 0) |
1249 | break; | 1201 | break; |
1250 | 1202 | ||
1251 | a = mark_terminated(wpid); | 1203 | a = mark_terminated(wpid); |
1252 | if (a) { | 1204 | if (a) { |
1253 | message(L_LOG, "process '%s' (pid %d) exited. " | 1205 | message(L_LOG, "process '%s' (pid %u) exited. " |
1254 | "Scheduling for restart.", | 1206 | "Scheduling for restart.", |
1255 | a->command, wpid); | 1207 | a->command, (unsigned)wpid); |
1256 | } | 1208 | } |
1257 | /* See if anyone else is waiting to be reaped */ | ||
1258 | maybe_WNOHANG = WNOHANG; | ||
1259 | } | 1209 | } |
1210 | |||
1211 | /* Don't consume all CPU time - sleep a bit */ | ||
1212 | sleep(1); | ||
1260 | } /* while (1) */ | 1213 | } /* while (1) */ |
1261 | } | 1214 | } |
1262 | 1215 | ||
@@ -1269,11 +1222,17 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1269 | //usage: "Init is the first process started during boot. It never exits." | 1222 | //usage: "Init is the first process started during boot. It never exits." |
1270 | //usage: IF_FEATURE_USE_INITTAB( | 1223 | //usage: IF_FEATURE_USE_INITTAB( |
1271 | //usage: "\n""It (re)spawns children according to /etc/inittab." | 1224 | //usage: "\n""It (re)spawns children according to /etc/inittab." |
1225 | //usage: "\n""Signals:" | ||
1226 | //usage: "\n""HUP: reload /etc/inittab" | ||
1272 | //usage: ) | 1227 | //usage: ) |
1273 | //usage: IF_NOT_FEATURE_USE_INITTAB( | 1228 | //usage: IF_NOT_FEATURE_USE_INITTAB( |
1274 | //usage: "\n""This version of init doesn't use /etc/inittab," | 1229 | //usage: "\n""This version of init doesn't use /etc/inittab," |
1275 | //usage: "\n""has fixed set of processed to run." | 1230 | //usage: "\n""has fixed set of processed to run." |
1231 | //usage: "\n""Signals:" | ||
1276 | //usage: ) | 1232 | //usage: ) |
1233 | //usage: "\n""TSTP: stop respawning until CONT" | ||
1234 | //usage: "\n""QUIT: re-exec another init" | ||
1235 | //usage: "\n""USR1/TERM/USR2/INT: run halt/reboot/poweroff/Ctrl-Alt-Del script" | ||
1277 | //usage: | 1236 | //usage: |
1278 | //usage:#define init_notes_usage | 1237 | //usage:#define init_notes_usage |
1279 | //usage: "This version of init is designed to be run only by the kernel.\n" | 1238 | //usage: "This version of init is designed to be run only by the kernel.\n" |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index f7971daf4..17ce463ea 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -319,7 +319,7 @@ void lbb_prepare(const char *applet | |||
319 | IF_FEATURE_INDIVIDUAL(, char **argv)) | 319 | IF_FEATURE_INDIVIDUAL(, char **argv)) |
320 | { | 320 | { |
321 | #ifdef __GLIBC__ | 321 | #ifdef __GLIBC__ |
322 | (*(int **)&bb_errno) = __errno_location(); | 322 | (*(int **)not_const_pp(&bb_errno)) = __errno_location(); |
323 | barrier(); | 323 | barrier(); |
324 | #endif | 324 | #endif |
325 | applet_name = applet; | 325 | applet_name = applet; |
diff --git a/libbb/copyfd.c b/libbb/copyfd.c index ae5c26999..d41fd10f0 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * was seen to cause largish delays when user tries to ^C a file copy. | 18 | * was seen to cause largish delays when user tries to ^C a file copy. |
19 | * Let's use a saner size. | 19 | * Let's use a saner size. |
20 | * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB), | 20 | * Note: needs to be >= max(CONFIG_FEATURE_COPYBUF_KB), |
21 | * or else "copy to eof" code will use neddlesly short reads. | 21 | * or else "copy to eof" code will use needlesly short reads. |
22 | */ | 22 | */ |
23 | #define SENDFILE_BIGBUF (16*1024*1024) | 23 | #define SENDFILE_BIGBUF (16*1024*1024) |
24 | 24 | ||
@@ -60,10 +60,13 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | |||
60 | ssize_t rd; | 60 | ssize_t rd; |
61 | 61 | ||
62 | if (sendfile_sz) { | 62 | if (sendfile_sz) { |
63 | rd = sendfile(dst_fd, src_fd, NULL, | 63 | /* dst_fd == -1 is a fake, else... */ |
64 | size > sendfile_sz ? sendfile_sz : size); | 64 | if (dst_fd >= 0) { |
65 | if (rd >= 0) | 65 | rd = sendfile(dst_fd, src_fd, NULL, |
66 | goto read_ok; | 66 | size > sendfile_sz ? sendfile_sz : size); |
67 | if (rd >= 0) | ||
68 | goto read_ok; | ||
69 | } | ||
67 | sendfile_sz = 0; /* do not try sendfile anymore */ | 70 | sendfile_sz = 0; /* do not try sendfile anymore */ |
68 | } | 71 | } |
69 | #if CONFIG_FEATURE_COPYBUF_KB > 4 | 72 | #if CONFIG_FEATURE_COPYBUF_KB > 4 |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 9781b4a08..9bb3ea98b 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -203,7 +203,7 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; | |||
203 | #define delbuf (S.delbuf ) | 203 | #define delbuf (S.delbuf ) |
204 | 204 | ||
205 | #define INIT_S() do { \ | 205 | #define INIT_S() do { \ |
206 | (*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \ | 206 | (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \ |
207 | barrier(); \ | 207 | barrier(); \ |
208 | cmdedit_termw = 80; \ | 208 | cmdedit_termw = 80; \ |
209 | IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ | 209 | IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ |
diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c index 87cf59b3d..dc40d9155 100644 --- a/libbb/missing_syscalls.c +++ b/libbb/missing_syscalls.c | |||
@@ -15,14 +15,6 @@ pid_t getsid(pid_t pid) | |||
15 | return syscall(__NR_getsid, pid); | 15 | return syscall(__NR_getsid, pid); |
16 | } | 16 | } |
17 | 17 | ||
18 | int stime(const time_t *t) | ||
19 | { | ||
20 | struct timeval tv; | ||
21 | tv.tv_sec = *t; | ||
22 | tv.tv_usec = 0; | ||
23 | return settimeofday(&tv, NULL); | ||
24 | } | ||
25 | |||
26 | int sethostname(const char *name, size_t len) | 18 | int sethostname(const char *name, size_t len) |
27 | { | 19 | { |
28 | return syscall(__NR_sethostname, name, len); | 20 | return syscall(__NR_sethostname, name, len); |
diff --git a/libbb/read.c b/libbb/read.c index 5906bc225..a342506a8 100644 --- a/libbb/read.c +++ b/libbb/read.c | |||
@@ -12,9 +12,17 @@ ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) | |||
12 | { | 12 | { |
13 | ssize_t n; | 13 | ssize_t n; |
14 | 14 | ||
15 | do { | 15 | for (;;) { |
16 | n = read(fd, buf, count); | 16 | n = read(fd, buf, count); |
17 | } while (n < 0 && errno == EINTR); | 17 | if (n >= 0 || errno != EINTR) |
18 | break; | ||
19 | /* Some callers set errno=0, are upset when they see EINTR. | ||
20 | * Returning EINTR is wrong since we retry read(), | ||
21 | * the "error" was transient. | ||
22 | */ | ||
23 | errno = 0; | ||
24 | /* repeat the read() */ | ||
25 | } | ||
18 | 26 | ||
19 | return n; | 27 | return n; |
20 | } | 28 | } |
diff --git a/libbb/read_key.c b/libbb/read_key.c index 951786869..03b7da656 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c | |||
@@ -259,7 +259,8 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
259 | 259 | ||
260 | buffer[-1] = 0; | 260 | buffer[-1] = 0; |
261 | /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */ | 261 | /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */ |
262 | col |= (((-1 << 15) | row) << 16); | 262 | row |= ((unsigned)(-1) << 15); |
263 | col |= (row << 16); | ||
263 | /* Return it in high-order word */ | 264 | /* Return it in high-order word */ |
264 | return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS; | 265 | return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS; |
265 | } | 266 | } |
diff --git a/libbb/replace.c b/libbb/replace.c index a661d96e6..6183d3e6f 100644 --- a/libbb/replace.c +++ b/libbb/replace.c | |||
@@ -15,6 +15,10 @@ unsigned FAST_FUNC count_strstr(const char *str, const char *sub) | |||
15 | size_t sub_len = strlen(sub); | 15 | size_t sub_len = strlen(sub); |
16 | unsigned count = 0; | 16 | unsigned count = 0; |
17 | 17 | ||
18 | /* If sub is empty, avoid an infinite loop */ | ||
19 | if (sub_len == 0) | ||
20 | return strlen(str) + 1; | ||
21 | |||
18 | while ((str = strstr(str, sub)) != NULL) { | 22 | while ((str = strstr(str, sub)) != NULL) { |
19 | count++; | 23 | count++; |
20 | str += sub_len; | 24 | str += sub_len; |
diff --git a/libbb/time.c b/libbb/time.c index cab0ad602..e66a9cba8 100644 --- a/libbb/time.c +++ b/libbb/time.c | |||
@@ -253,11 +253,9 @@ char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) | |||
253 | #define CLOCK_MONOTONIC 1 | 253 | #define CLOCK_MONOTONIC 1 |
254 | #endif | 254 | #endif |
255 | 255 | ||
256 | /* libc has incredibly messy way of doing this, | ||
257 | * typically requiring -lrt. We just skip all this mess */ | ||
258 | static void get_mono(struct timespec *ts) | 256 | static void get_mono(struct timespec *ts) |
259 | { | 257 | { |
260 | if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts)) | 258 | if (clock_gettime(CLOCK_MONOTONIC, ts)) |
261 | bb_simple_error_msg_and_die("clock_gettime(MONOTONIC) failed"); | 259 | bb_simple_error_msg_and_die("clock_gettime(MONOTONIC) failed"); |
262 | } | 260 | } |
263 | unsigned long long FAST_FUNC monotonic_ns(void) | 261 | unsigned long long FAST_FUNC monotonic_ns(void) |
diff --git a/miscutils/bc.c b/miscutils/bc.c index 7ac30dd53..c7246ea1a 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -844,10 +844,10 @@ struct globals { | |||
844 | # error Strange INT_MAX | 844 | # error Strange INT_MAX |
845 | #endif | 845 | #endif |
846 | 846 | ||
847 | #if UINT_MAX == 4294967295 | 847 | #if UINT_MAX == 4294967295U |
848 | # define BC_MAX_SCALE_STR "4294967295" | 848 | # define BC_MAX_SCALE_STR "4294967295" |
849 | # define BC_MAX_STRING_STR "4294967294" | 849 | # define BC_MAX_STRING_STR "4294967294" |
850 | #elif UINT_MAX == 18446744073709551615 | 850 | #elif UINT_MAX == 18446744073709551615U |
851 | # define BC_MAX_SCALE_STR "18446744073709551615" | 851 | # define BC_MAX_SCALE_STR "18446744073709551615" |
852 | # define BC_MAX_STRING_STR "18446744073709551614" | 852 | # define BC_MAX_STRING_STR "18446744073709551614" |
853 | #else | 853 | #else |
@@ -1465,7 +1465,10 @@ static ssize_t bc_num_cmp(BcNum *a, BcNum *b) | |||
1465 | b_int = BC_NUM_INT(b); | 1465 | b_int = BC_NUM_INT(b); |
1466 | a_int -= b_int; | 1466 | a_int -= b_int; |
1467 | 1467 | ||
1468 | if (a_int != 0) return (ssize_t) a_int; | 1468 | if (a_int != 0) { |
1469 | if (neg) return - (ssize_t) a_int; | ||
1470 | return (ssize_t) a_int; | ||
1471 | } | ||
1469 | 1472 | ||
1470 | a_max = (a->rdx > b->rdx); | 1473 | a_max = (a->rdx > b->rdx); |
1471 | if (a_max) { | 1474 | if (a_max) { |
@@ -4973,7 +4976,9 @@ static void dc_parse_string(void) | |||
4973 | xc_parse_pushInst_and_Index(XC_INST_STR, len); | 4976 | xc_parse_pushInst_and_Index(XC_INST_STR, len); |
4974 | bc_vec_push(&G.prog.strs, &str); | 4977 | bc_vec_push(&G.prog.strs, &str); |
4975 | 4978 | ||
4976 | // Explanation needed here | 4979 | // Add an empty function so that if zdc_program_execStr ever needs to |
4980 | // parse the string into code (from the 'x' command) there's somewhere | ||
4981 | // to store the bytecode. | ||
4977 | xc_program_add_fn(); | 4982 | xc_program_add_fn(); |
4978 | p->func = xc_program_func(p->fidx); | 4983 | p->func = xc_program_func(p->fidx); |
4979 | 4984 | ||
@@ -5454,11 +5459,13 @@ static void xc_program_printString(const char *str) | |||
5454 | char *n; | 5459 | char *n; |
5455 | 5460 | ||
5456 | c = *str++; | 5461 | c = *str++; |
5457 | n = strchr(esc, c); // note: c can be NUL | 5462 | n = strchr(esc, c); // note: if c is NUL, n = \0 at end of esc |
5458 | if (!n) { | 5463 | if (!n || !c) { |
5459 | // Just print the backslash and following character | 5464 | // Just print the backslash and following character |
5460 | bb_putchar('\\'); | 5465 | bb_putchar('\\'); |
5461 | ++G.prog.nchars; | 5466 | ++G.prog.nchars; |
5467 | // But if we're at the end of the string, stop | ||
5468 | if (!c) break; | ||
5462 | } else { | 5469 | } else { |
5463 | if (n - esc == 0) // "\n" ? | 5470 | if (n - esc == 0) // "\n" ? |
5464 | G.prog.nchars = SIZE_MAX; | 5471 | G.prog.nchars = SIZE_MAX; |
@@ -6398,7 +6405,11 @@ static BC_STATUS zdc_program_asciify(void) | |||
6398 | str = xzalloc(2); | 6405 | str = xzalloc(2); |
6399 | str[0] = c; | 6406 | str[0] = c; |
6400 | //str[1] = '\0'; - already is | 6407 | //str[1] = '\0'; - already is |
6401 | bc_vec_push(&G.prog.strs, &str); | 6408 | idx = bc_vec_push(&G.prog.strs, &str); |
6409 | // Add an empty function so that if zdc_program_execStr ever needs to | ||
6410 | // parse the string into code (from the 'x' command) there's somewhere | ||
6411 | // to store the bytecode. | ||
6412 | xc_program_add_fn(); | ||
6402 | dup: | 6413 | dup: |
6403 | res.t = XC_RESULT_STR; | 6414 | res.t = XC_RESULT_STR; |
6404 | res.d.id.idx = idx; | 6415 | res.d.id.idx = idx; |
@@ -6521,7 +6532,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond) | |||
6521 | if (s || !BC_PROG_STR(n)) goto exit; | 6532 | if (s || !BC_PROG_STR(n)) goto exit; |
6522 | sidx = n->rdx; | 6533 | sidx = n->rdx; |
6523 | } else | 6534 | } else |
6524 | goto exit; | 6535 | goto exit_nopop; |
6525 | } | 6536 | } |
6526 | 6537 | ||
6527 | fidx = sidx + BC_PROG_REQ_FUNCS; | 6538 | fidx = sidx + BC_PROG_REQ_FUNCS; |
@@ -6561,6 +6572,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond) | |||
6561 | RETURN_STATUS(BC_STATUS_SUCCESS); | 6572 | RETURN_STATUS(BC_STATUS_SUCCESS); |
6562 | exit: | 6573 | exit: |
6563 | bc_vec_pop(&G.prog.results); | 6574 | bc_vec_pop(&G.prog.results); |
6575 | exit_nopop: | ||
6564 | RETURN_STATUS(s); | 6576 | RETURN_STATUS(s); |
6565 | } | 6577 | } |
6566 | #define zdc_program_execStr(...) (zdc_program_execStr(__VA_ARGS__) COMMA_SUCCESS) | 6578 | #define zdc_program_execStr(...) (zdc_program_execStr(__VA_ARGS__) COMMA_SUCCESS) |
diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c index b453efba9..beabb1ad5 100644 --- a/miscutils/hdparm.c +++ b/miscutils/hdparm.c | |||
@@ -996,7 +996,7 @@ static void identify(uint16_t *val) | |||
996 | /* check Endian of capacity bytes */ | 996 | /* check Endian of capacity bytes */ |
997 | nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR]; | 997 | nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR]; |
998 | oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB]; | 998 | oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB]; |
999 | if (abs(mm - nn) > abs(oo - nn)) | 999 | if (abs((int)(mm - nn)) > abs((int)(oo - nn))) |
1000 | mm = oo; | 1000 | mm = oo; |
1001 | } | 1001 | } |
1002 | printf("\tCHS current addressable sectors:%11u\n", mm); | 1002 | printf("\tCHS current addressable sectors:%11u\n", mm); |
diff --git a/networking/brctl.c b/networking/brctl.c index 586ca9b0c..25640246d 100644 --- a/networking/brctl.c +++ b/networking/brctl.c | |||
@@ -53,7 +53,9 @@ | |||
53 | //usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" | 53 | //usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" |
54 | //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" | 54 | //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" |
55 | //usage: IF_FEATURE_BRCTL_FANCY( | 55 | //usage: IF_FEATURE_BRCTL_FANCY( |
56 | //usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off" | 56 | //usage: "\n showmacs BRIDGE List MAC addresses" |
57 | //usage: "\n showstp BRIDGE Show STP info" | ||
58 | //usage: "\n stp BRIDGE 1/yes/on|0/no/off Set STP on/off" | ||
57 | //usage: "\n setageing BRIDGE SECONDS Set ageing time" | 59 | //usage: "\n setageing BRIDGE SECONDS Set ageing time" |
58 | //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" | 60 | //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" |
59 | //usage: "\n sethello BRIDGE SECONDS Set hello time" | 61 | //usage: "\n sethello BRIDGE SECONDS Set hello time" |
@@ -63,9 +65,7 @@ | |||
63 | //usage: "\n setpathcost BRIDGE IFACE COST Set path cost" | 65 | //usage: "\n setpathcost BRIDGE IFACE COST Set path cost" |
64 | //usage: ) | 66 | //usage: ) |
65 | // Not yet implemented: | 67 | // Not yet implemented: |
66 | // hairpin BRIDGE IFACE on|off Hairpin on/off | 68 | // hairpin BRIDGE IFACE on|off Set hairpin on/off |
67 | // showmacs BRIDGE List mac addrs | ||
68 | // showstp BRIDGE Show stp info | ||
69 | 69 | ||
70 | #include "libbb.h" | 70 | #include "libbb.h" |
71 | #include "common_bufsiz.h" | 71 | #include "common_bufsiz.h" |
@@ -129,7 +129,7 @@ static int show_bridge(const char *name, int need_hdr) | |||
129 | *bridge name bridge id STP enabled interfaces | 129 | *bridge name bridge id STP enabled interfaces |
130 | *br0 8000.000000000000 no eth0 | 130 | *br0 8000.000000000000 no eth0 |
131 | */ | 131 | */ |
132 | char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32]; | 132 | char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 8]; |
133 | int tabs; | 133 | int tabs; |
134 | DIR *ifaces; | 134 | DIR *ifaces; |
135 | struct dirent *ent; | 135 | struct dirent *ent; |
@@ -146,8 +146,7 @@ static int show_bridge(const char *name, int need_hdr) | |||
146 | 146 | ||
147 | if (need_hdr) | 147 | if (need_hdr) |
148 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); | 148 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); |
149 | printf("%s\t\t", name); | 149 | printf("%s\t\t%s\t", name, filedata); |
150 | printf("%s\t", filedata); | ||
151 | 150 | ||
152 | strcpy(sfx, "stp_state"); | 151 | strcpy(sfx, "stp_state"); |
153 | read_file(pathbuf); | 152 | read_file(pathbuf); |
@@ -158,7 +157,8 @@ static int show_bridge(const char *name, int need_hdr) | |||
158 | strcpy(filedata, "yes"); | 157 | strcpy(filedata, "yes"); |
159 | fputs(filedata, stdout); | 158 | fputs(filedata, stdout); |
160 | 159 | ||
161 | strcpy(sfx - (sizeof("bridge/")-1), "brif"); | 160 | /* sfx points past "BR/bridge/", turn it into "BR/brif": */ |
161 | sfx[-4] = 'f'; sfx[-3] = '\0'; | ||
162 | tabs = 0; | 162 | tabs = 0; |
163 | ifaces = opendir(pathbuf); | 163 | ifaces = opendir(pathbuf); |
164 | if (ifaces) { | 164 | if (ifaces) { |
@@ -194,7 +194,299 @@ static void write_uint(const char *name, const char *leaf, unsigned val) | |||
194 | n = sprintf(filedata, "%u\n", val); | 194 | n = sprintf(filedata, "%u\n", val); |
195 | if (write(fd, filedata, n) < 0) | 195 | if (write(fd, filedata, n) < 0) |
196 | bb_simple_perror_msg_and_die(name); | 196 | bb_simple_perror_msg_and_die(name); |
197 | close(fd); | 197 | /* So far all callers exit very soon after calling us. |
198 | * Do not bother closing fd (unless debugging): | ||
199 | */ | ||
200 | if (ENABLE_FEATURE_CLEAN_UP) | ||
201 | close(fd); | ||
202 | } | ||
203 | |||
204 | struct fdb_entry { | ||
205 | uint8_t mac_addr[6]; | ||
206 | uint8_t port_no; | ||
207 | uint8_t is_local; | ||
208 | uint32_t ageing_timer_value; | ||
209 | uint8_t port_hi; | ||
210 | uint8_t pad0; | ||
211 | uint16_t unused; | ||
212 | }; | ||
213 | |||
214 | static int compare_fdbs(const void *_f0, const void *_f1) | ||
215 | { | ||
216 | const struct fdb_entry *f0 = _f0; | ||
217 | const struct fdb_entry *f1 = _f1; | ||
218 | |||
219 | return memcmp(f0->mac_addr, f1->mac_addr, 6); | ||
220 | } | ||
221 | |||
222 | static size_t read_bridge_forward_db(const char *name, struct fdb_entry **_fdb) | ||
223 | { | ||
224 | char pathbuf[IFNAMSIZ + sizeof("/brforward") + 8]; | ||
225 | struct fdb_entry *fdb; | ||
226 | size_t nentries; | ||
227 | int fd; | ||
228 | ssize_t cc; | ||
229 | |||
230 | #if IFNAMSIZ == 16 | ||
231 | sprintf(pathbuf, "%.16s/brforward", name); | ||
232 | #else | ||
233 | sprintf(pathbuf, "%.*s/brforward", (int)IFNAMSIZ, name); | ||
234 | #endif | ||
235 | fd = open(pathbuf, O_RDONLY); | ||
236 | if (fd < 0) | ||
237 | bb_error_msg_and_die("bridge %s does not exist", name); | ||
238 | |||
239 | fdb = NULL; | ||
240 | nentries = 0; | ||
241 | for (;;) { | ||
242 | fdb = xrealloc_vector(fdb, 4, nentries); | ||
243 | cc = full_read(fd, &fdb[nentries], sizeof(*fdb)); | ||
244 | if (cc == 0) { | ||
245 | break; | ||
246 | } | ||
247 | if (cc != sizeof(*fdb)) { | ||
248 | bb_perror_msg_and_die("can't read bridge %s forward db", name); | ||
249 | } | ||
250 | ++nentries; | ||
251 | } | ||
252 | |||
253 | if (ENABLE_FEATURE_CLEAN_UP) | ||
254 | close(fd); | ||
255 | |||
256 | qsort(fdb, nentries, sizeof(*fdb), compare_fdbs); | ||
257 | |||
258 | *_fdb = fdb; | ||
259 | return nentries; | ||
260 | } | ||
261 | |||
262 | static void show_bridge_macs(const char *name) | ||
263 | { | ||
264 | struct fdb_entry *fdb; | ||
265 | size_t nentries; | ||
266 | size_t i; | ||
267 | |||
268 | nentries = read_bridge_forward_db(name, &fdb); | ||
269 | |||
270 | printf("port no\tmac addr\t\tis local?\tageing timer\n"); | ||
271 | for (i = 0; i < nentries; ++i) { | ||
272 | const struct fdb_entry *f = &fdb[i]; | ||
273 | unsigned tv_sec = f->ageing_timer_value / 100; | ||
274 | unsigned tv_csec = f->ageing_timer_value % 100; | ||
275 | printf("%3u\t" | ||
276 | "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t" | ||
277 | "%s\t\t" | ||
278 | "%4u.%.2u\n", | ||
279 | f->port_no, | ||
280 | f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], | ||
281 | f->mac_addr[3], f->mac_addr[4], f->mac_addr[5], | ||
282 | (f->is_local ? "yes" : "no"), | ||
283 | tv_sec, tv_csec | ||
284 | ); | ||
285 | } | ||
286 | |||
287 | if (ENABLE_FEATURE_CLEAN_UP) | ||
288 | free(fdb); | ||
289 | } | ||
290 | |||
291 | static void show_bridge_timer(const char *msg) | ||
292 | { | ||
293 | unsigned long long centisec = xstrtoull(filedata, 0); | ||
294 | unsigned tv_sec = centisec / 100; | ||
295 | unsigned tv_csec = centisec % 100; | ||
296 | printf("%s%4u.%.2u", msg, tv_sec, tv_csec); | ||
297 | } | ||
298 | |||
299 | static const char *show_bridge_state(unsigned state) | ||
300 | { | ||
301 | /* See linux/if_bridge.h, BR_STATE_ constants */ | ||
302 | static const char state_names[] ALIGN1 = | ||
303 | "disabled\0" //BR_STATE_DISABLED 0 | ||
304 | "listening\0" //BR_STATE_LISTENING 1 | ||
305 | "learning\0" //BR_STATE_LEARNING 2 | ||
306 | "forwarding\0" //BR_STATE_FORWARDING 3 | ||
307 | "blocking" //BR_STATE_BLOCKING 4 | ||
308 | ; | ||
309 | if (state < 5) | ||
310 | return nth_string(state_names, state); | ||
311 | return utoa(state); | ||
312 | } | ||
313 | |||
314 | static void printf_xstrtou(const char *fmt) | ||
315 | { | ||
316 | printf(fmt, xstrtou(filedata, 0)); | ||
317 | } | ||
318 | |||
319 | static void show_bridge_port(const char *name) | ||
320 | { | ||
321 | char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 8]; | ||
322 | char *sfx; | ||
323 | |||
324 | #if IFNAMSIZ == 16 | ||
325 | sfx = pathbuf + sprintf(pathbuf, "%.16s/brport/", name); | ||
326 | #else | ||
327 | sfx = pathbuf + sprintf(pathbuf, "%.*s/brport/", (int)IFNAMSIZ, name); | ||
328 | #endif | ||
329 | |||
330 | strcpy(sfx, "port_no"); | ||
331 | read_file(pathbuf); | ||
332 | printf("%s (%u)\n", name, xstrtou(filedata, 0)); | ||
333 | |||
334 | strcpy(sfx + 5, "id"); // "port_id" | ||
335 | read_file(pathbuf); | ||
336 | printf_xstrtou(" port id\t\t%.4x"); | ||
337 | |||
338 | strcpy(sfx, "state"); | ||
339 | read_file(pathbuf); | ||
340 | printf("\t\t\tstate\t\t%15s\n", show_bridge_state(xstrtou(filedata, 0))); | ||
341 | |||
342 | strcpy(sfx, "designated_root"); | ||
343 | read_file(pathbuf); | ||
344 | printf(" designated root\t%s", filedata); | ||
345 | |||
346 | strcpy(sfx, "path_cost"); | ||
347 | read_file(pathbuf); | ||
348 | printf_xstrtou("\tpath cost\t\t%4u\n"); | ||
349 | |||
350 | strcpy(sfx, "designated_bridge"); | ||
351 | read_file(pathbuf); | ||
352 | printf(" designated bridge\t%s", filedata); | ||
353 | |||
354 | strcpy(sfx, "message_age_timer"); | ||
355 | read_file(pathbuf); | ||
356 | show_bridge_timer("\tmessage age timer\t"); | ||
357 | |||
358 | strcpy(sfx, "designated_port"); | ||
359 | read_file(pathbuf); | ||
360 | printf_xstrtou("\n designated port\t%.4x"); | ||
361 | |||
362 | strcpy(sfx, "forward_delay_timer"); | ||
363 | read_file(pathbuf); | ||
364 | show_bridge_timer("\t\t\tforward delay timer\t"); | ||
365 | |||
366 | strcpy(sfx, "designated_cost"); | ||
367 | read_file(pathbuf); | ||
368 | printf_xstrtou("\n designated cost\t%4u"); | ||
369 | |||
370 | strcpy(sfx, "hold_timer"); | ||
371 | read_file(pathbuf); | ||
372 | show_bridge_timer("\t\t\thold timer\t\t"); | ||
373 | |||
374 | printf("\n flags\t\t\t"); | ||
375 | |||
376 | strcpy(sfx, "config_pending"); | ||
377 | read_file(pathbuf); | ||
378 | if (!LONE_CHAR(filedata, '0')) | ||
379 | printf("CONFIG_PENDING "); | ||
380 | |||
381 | strcpy(sfx, "change_ack"); | ||
382 | read_file(pathbuf); | ||
383 | if (!LONE_CHAR(filedata, '0')) | ||
384 | printf("TOPOLOGY_CHANGE_ACK "); | ||
385 | |||
386 | strcpy(sfx, "hairpin_mode"); | ||
387 | read_file(pathbuf); | ||
388 | if (!LONE_CHAR(filedata, '0')) | ||
389 | printf_xstrtou("\n hairpin mode\t\t%4u"); | ||
390 | |||
391 | printf("\n\n"); | ||
392 | } | ||
393 | |||
394 | static void show_bridge_stp(const char *name) | ||
395 | { | ||
396 | char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 8]; | ||
397 | char *sfx; | ||
398 | |||
399 | #if IFNAMSIZ == 16 | ||
400 | sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name); | ||
401 | #else | ||
402 | sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name); | ||
403 | #endif | ||
404 | |||
405 | strcpy(sfx, "bridge_id"); | ||
406 | if (read_file(pathbuf) < 0) | ||
407 | bb_error_msg_and_die("bridge %s does not exist", name); | ||
408 | |||
409 | printf("%s\n" | ||
410 | " bridge id\t\t%s", name, filedata); | ||
411 | |||
412 | strcpy(sfx, "root_id"); | ||
413 | read_file(pathbuf); | ||
414 | printf("\n designated root\t%s", filedata); | ||
415 | |||
416 | strcpy(sfx + 5, "port"); // "root_port" | ||
417 | read_file(pathbuf); | ||
418 | printf_xstrtou("\n root port\t\t%4u\t\t\t"); | ||
419 | |||
420 | strcpy(sfx + 6, "ath_cost"); // "root_path_cost" | ||
421 | read_file(pathbuf); | ||
422 | printf_xstrtou("path cost\t\t%4u\n"); | ||
423 | |||
424 | strcpy(sfx, "max_age"); | ||
425 | read_file(pathbuf); | ||
426 | show_bridge_timer(" max age\t\t"); | ||
427 | show_bridge_timer("\t\t\tbridge max age\t\t"); | ||
428 | |||
429 | strcpy(sfx, "hello_time"); | ||
430 | read_file(pathbuf); | ||
431 | show_bridge_timer("\n hello time\t\t"); | ||
432 | show_bridge_timer("\t\t\tbridge hello time\t"); | ||
433 | |||
434 | strcpy(sfx, "forward_delay"); | ||
435 | read_file(pathbuf); | ||
436 | show_bridge_timer("\n forward delay\t\t"); | ||
437 | show_bridge_timer("\t\t\tbridge forward delay\t"); | ||
438 | |||
439 | strcpy(sfx, "ageing_time"); | ||
440 | read_file(pathbuf); | ||
441 | show_bridge_timer("\n ageing time\t\t"); | ||
442 | |||
443 | strcpy(sfx, "hello_timer"); | ||
444 | read_file(pathbuf); | ||
445 | show_bridge_timer("\n hello timer\t\t"); | ||
446 | |||
447 | strcpy(sfx, "tcn_timer"); | ||
448 | read_file(pathbuf); | ||
449 | show_bridge_timer("\t\t\ttcn timer\t\t"); | ||
450 | |||
451 | strcpy(sfx, "topology_change_timer"); | ||
452 | read_file(pathbuf); | ||
453 | show_bridge_timer("\n topology change timer\t"); | ||
454 | |||
455 | strcpy(sfx, "gc_timer"); | ||
456 | read_file(pathbuf); | ||
457 | show_bridge_timer("\t\t\tgc timer\t\t"); | ||
458 | |||
459 | printf("\n flags\t\t\t"); | ||
460 | |||
461 | strcpy(sfx, "topology_change"); | ||
462 | read_file(pathbuf); | ||
463 | if (!LONE_CHAR(filedata, '0')) | ||
464 | printf("TOPOLOGY_CHANGE "); | ||
465 | |||
466 | strcpy(sfx, "topology_change_detected"); | ||
467 | read_file(pathbuf); | ||
468 | if (!LONE_CHAR(filedata, '0')) | ||
469 | printf("TOPOLOGY_CHANGE_DETECTED "); | ||
470 | printf("\n\n\n"); | ||
471 | |||
472 | /* Show bridge ports */ | ||
473 | { | ||
474 | DIR *ifaces; | ||
475 | |||
476 | /* sfx points past "BR/bridge/", turn it into "BR/brif": */ | ||
477 | sfx[-4] = 'f'; sfx[-3] = '\0'; | ||
478 | ifaces = opendir(pathbuf); | ||
479 | if (ifaces) { | ||
480 | struct dirent *ent; | ||
481 | while ((ent = readdir(ifaces)) != NULL) { | ||
482 | if (DOT_OR_DOTDOT(ent->d_name)) | ||
483 | continue; /* . or .. */ | ||
484 | show_bridge_port(ent->d_name); | ||
485 | } | ||
486 | if (ENABLE_FEATURE_CLEAN_UP) | ||
487 | closedir(ifaces); | ||
488 | } | ||
489 | } | ||
198 | } | 490 | } |
199 | #endif | 491 | #endif |
200 | 492 | ||
@@ -205,20 +497,26 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
205 | "addbr\0" "delbr\0" "addif\0" "delif\0" | 497 | "addbr\0" "delbr\0" "addif\0" "delif\0" |
206 | IF_FEATURE_BRCTL_FANCY( | 498 | IF_FEATURE_BRCTL_FANCY( |
207 | "stp\0" | 499 | "stp\0" |
500 | "showstp\0" | ||
208 | "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" | 501 | "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" |
209 | "setpathcost\0" "setportprio\0" | 502 | "setpathcost\0" "setportprio\0" |
210 | "setbridgeprio\0" | 503 | "setbridgeprio\0" |
504 | "showmacs\0" | ||
211 | ) | 505 | ) |
212 | IF_FEATURE_BRCTL_SHOW("show\0"); | 506 | IF_FEATURE_BRCTL_SHOW("show\0"); |
213 | enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif | 507 | enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif |
214 | IF_FEATURE_BRCTL_FANCY(, | 508 | IF_FEATURE_BRCTL_FANCY(, |
215 | ARG_stp, | 509 | ARG_stp, |
510 | ARG_showstp, | ||
216 | ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, | 511 | ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, |
217 | ARG_setpathcost, ARG_setportprio, | 512 | ARG_setpathcost, ARG_setportprio, |
218 | ARG_setbridgeprio | 513 | ARG_setbridgeprio, |
514 | ARG_showmacs | ||
219 | ) | 515 | ) |
220 | IF_FEATURE_BRCTL_SHOW(, ARG_show) | 516 | IF_FEATURE_BRCTL_SHOW(, ARG_show) |
221 | }; | 517 | }; |
518 | int key; | ||
519 | char *br; | ||
222 | 520 | ||
223 | argv++; | 521 | argv++; |
224 | if (!*argv) { | 522 | if (!*argv) { |
@@ -228,185 +526,157 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
228 | 526 | ||
229 | xchdir("/sys/class/net"); | 527 | xchdir("/sys/class/net"); |
230 | 528 | ||
231 | // while (*argv) | 529 | key = index_in_strings(keywords, *argv); |
232 | { | 530 | if (key == -1) /* no match found in keywords array, bail out. */ |
233 | smallint key; | 531 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
234 | char *br; | 532 | argv++; |
235 | |||
236 | key = index_in_strings(keywords, *argv); | ||
237 | if (key == -1) /* no match found in keywords array, bail out. */ | ||
238 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); | ||
239 | argv++; | ||
240 | 533 | ||
241 | #if ENABLE_FEATURE_BRCTL_SHOW | 534 | #if ENABLE_FEATURE_BRCTL_SHOW |
242 | if (key == ARG_show) { /* show [BR]... */ | 535 | if (key == ARG_show) { /* show [BR]... */ |
243 | DIR *net; | 536 | DIR *net; |
244 | struct dirent *ent; | 537 | struct dirent *ent; |
245 | int need_hdr = 1; | 538 | int need_hdr = 1; |
246 | int exitcode = EXIT_SUCCESS; | 539 | int exitcode = EXIT_SUCCESS; |
247 | 540 | ||
248 | if (*argv) { | 541 | if (*argv) { |
249 | /* "show BR1 BR2 BR3" */ | 542 | /* "show BR1 BR2 BR3" */ |
250 | do { | 543 | do { |
251 | if (show_bridge(*argv, need_hdr) >= 0) { | 544 | if (show_bridge(*argv, need_hdr) >= 0) { |
252 | need_hdr = 0; | 545 | need_hdr = 0; |
253 | } else { | 546 | } else { |
254 | bb_error_msg("bridge %s does not exist", *argv); | 547 | bb_error_msg("bridge %s does not exist", *argv); |
255 | //TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 | 548 | //TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 |
256 | //says this instead: "device eth0 is not a bridge" | 549 | //says this instead: "device eth0 is not a bridge" |
257 | exitcode = EXIT_FAILURE; | 550 | exitcode = EXIT_FAILURE; |
258 | } | 551 | } |
259 | } while (*++argv != NULL); | 552 | } while (*++argv != NULL); |
260 | return exitcode; | ||
261 | } | ||
262 | |||
263 | /* "show" (if no ifaces, shows nothing, not even header) */ | ||
264 | net = xopendir("."); | ||
265 | while ((ent = readdir(net)) != NULL) { | ||
266 | if (DOT_OR_DOTDOT(ent->d_name)) | ||
267 | continue; /* . or .. */ | ||
268 | if (show_bridge(ent->d_name, need_hdr) >= 0) | ||
269 | need_hdr = 0; | ||
270 | } | ||
271 | if (ENABLE_FEATURE_CLEAN_UP) | ||
272 | closedir(net); | ||
273 | return exitcode; | 553 | return exitcode; |
274 | } | 554 | } |
555 | |||
556 | /* "show" (if no ifaces, shows nothing, not even header) */ | ||
557 | net = xopendir("."); | ||
558 | while ((ent = readdir(net)) != NULL) { | ||
559 | if (DOT_OR_DOTDOT(ent->d_name)) | ||
560 | continue; /* . or .. */ | ||
561 | if (show_bridge(ent->d_name, need_hdr) >= 0) | ||
562 | need_hdr = 0; | ||
563 | } | ||
564 | if (ENABLE_FEATURE_CLEAN_UP) | ||
565 | closedir(net); | ||
566 | return exitcode; | ||
567 | } | ||
275 | #endif | 568 | #endif |
276 | 569 | ||
277 | if (!*argv) /* all but 'show' need at least one argument */ | 570 | if (!*argv) /* All of the below need at least one argument */ |
278 | bb_show_usage(); | 571 | bb_show_usage(); |
279 | 572 | ||
280 | br = *argv++; | 573 | br = *argv++; |
281 | 574 | ||
282 | if (key == ARG_addbr || key == ARG_delbr) { | 575 | if (key == ARG_addbr || key == ARG_delbr) { |
283 | /* addbr or delbr */ | 576 | /* brctl from bridge-utils 1.6 still uses ioctl |
284 | /* brctl from bridge-utils 1.6 still uses ioctl | 577 | * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses |
285 | * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses | 578 | */ |
286 | */ | 579 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); |
287 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); | 580 | ioctl_or_perror_and_die(fd, |
288 | ioctl_or_perror_and_die(fd, | 581 | key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, |
289 | key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, | 582 | br, "bridge %s", br |
290 | br, "bridge %s", br | 583 | ); |
291 | ); | 584 | //close(fd); |
292 | //close(fd); | 585 | //goto done; |
293 | //goto done; | 586 | /* bridge-utils 1.6 simply ignores trailing args: |
294 | /* bridge-utils 1.6 simply ignores trailing args: | 587 | * "brctl addbr BR1 ARGS" ignores ARGS |
295 | * "brctl addbr BR1 ARGS" ignores ARGS | 588 | */ |
296 | */ | 589 | if (ENABLE_FEATURE_CLEAN_UP) |
297 | if (ENABLE_FEATURE_CLEAN_UP) | 590 | close(fd); |
298 | close(fd); | 591 | return EXIT_SUCCESS; |
299 | return EXIT_SUCCESS; | 592 | } |
300 | } | ||
301 | 593 | ||
302 | if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ | 594 | if (key == ARG_showmacs) { |
303 | bb_show_usage(); | 595 | show_bridge_macs(br); |
596 | return EXIT_SUCCESS; | ||
597 | } | ||
598 | if (key == ARG_showstp) { | ||
599 | show_bridge_stp(br); | ||
600 | return EXIT_SUCCESS; | ||
601 | } | ||
304 | 602 | ||
305 | #if ENABLE_FEATURE_BRCTL_FANCY | 603 | if (!*argv) /* All of the below need at least two arguments */ |
306 | if (key == ARG_stp) { /* stp */ | 604 | bb_show_usage(); |
307 | static const char no_yes[] ALIGN1 = | ||
308 | "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */ | ||
309 | "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */ | ||
310 | int onoff = index_in_strings(no_yes, *argv); | ||
311 | if (onoff < 0) | ||
312 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); | ||
313 | onoff = (unsigned)onoff / 4; | ||
314 | write_uint(br, "bridge/stp_state", onoff); | ||
315 | //goto done_next_argv; | ||
316 | return EXIT_SUCCESS; | ||
317 | } | ||
318 | 605 | ||
319 | if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ | 606 | #if ENABLE_FEATURE_BRCTL_FANCY |
320 | /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time | 607 | if (key == ARG_stp) { |
321 | * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay | 608 | static const char no_yes[] ALIGN1 = |
322 | * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time | 609 | "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */ |
323 | * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age | 610 | "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */ |
324 | */ | 611 | int onoff = index_in_strings(no_yes, *argv); |
325 | write_uint(br, | 612 | if (onoff < 0) |
326 | nth_string( | 613 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
327 | "bridge/ageing_time" "\0" /* ARG_setageing */ | 614 | onoff = (unsigned)onoff / 4; |
328 | "bridge/forward_delay""\0" /* ARG_setfd */ | 615 | write_uint(br, "bridge/stp_state", onoff); |
329 | "bridge/hello_time" "\0" /* ARG_sethello */ | 616 | return EXIT_SUCCESS; |
330 | "bridge/max_age", /* ARG_setmaxage */ | 617 | } |
331 | key - ARG_setageing | ||
332 | ), | ||
333 | str_to_jiffies(*argv) | ||
334 | ); | ||
335 | //goto done_next_argv; | ||
336 | return EXIT_SUCCESS; | ||
337 | } | ||
338 | 618 | ||
339 | if (key == ARG_setbridgeprio) { | 619 | if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ |
340 | write_uint(br, "bridge/priority", xatoi_positive(*argv)); | 620 | /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time |
341 | //goto done_next_argv; | 621 | * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay |
342 | return EXIT_SUCCESS; | 622 | * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time |
343 | } | 623 | * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age |
624 | */ | ||
625 | write_uint(br, | ||
626 | nth_string( | ||
627 | "bridge/ageing_time" "\0" /* ARG_setageing */ | ||
628 | "bridge/forward_delay""\0" /* ARG_setfd */ | ||
629 | "bridge/hello_time" "\0" /* ARG_sethello */ | ||
630 | "bridge/max_age", /* ARG_setmaxage */ | ||
631 | key - ARG_setageing | ||
632 | ), | ||
633 | str_to_jiffies(*argv) | ||
634 | ); | ||
635 | return EXIT_SUCCESS; | ||
636 | } | ||
344 | 637 | ||
345 | if (key == ARG_setpathcost | 638 | if (key == ARG_setbridgeprio) { |
346 | || key == ARG_setportprio | 639 | write_uint(br, "bridge/priority", xatoi_positive(*argv)); |
347 | ) { | 640 | return EXIT_SUCCESS; |
348 | if (!argv[1]) | 641 | } |
349 | bb_show_usage(); | ||
350 | /* BR is not used (and ignored!) for these commands: | ||
351 | * "setpathcost BR PORT N" writes "N\n" to | ||
352 | * /sys/class/net/PORT/brport/path_cost | ||
353 | * "setportprio BR PORT N" writes "N\n" to | ||
354 | * /sys/class/net/PORT/brport/priority | ||
355 | */ | ||
356 | write_uint(argv[0], | ||
357 | nth_string( | ||
358 | "brport/path_cost" "\0" /* ARG_setpathcost */ | ||
359 | "brport/priority", /* ARG_setportprio */ | ||
360 | key - ARG_setpathcost | ||
361 | ), | ||
362 | xatoi_positive(argv[1]) | ||
363 | ); | ||
364 | //argv++; | ||
365 | //goto done_next_argv; | ||
366 | return EXIT_SUCCESS; | ||
367 | } | ||
368 | 642 | ||
369 | /* TODO: "showmacs BR" | 643 | if (key == ARG_setpathcost |
370 | * port no\tmac addr\t\tis local?\tageing timer | 644 | || key == ARG_setportprio |
371 | * <sp><sp>1\txx:xx:xx:xx:xx:xx\tno\t\t<sp><sp><sp>1.31 | 645 | ) { |
372 | * port no mac addr is local? ageing timer | 646 | if (!argv[1]) |
373 | * 1 xx:xx:xx:xx:xx:xx no 1.31 | 647 | bb_show_usage(); |
374 | * Read fixed-sized records from /sys/class/net/BR/brforward: | 648 | /* BR is not used (and ignored!) for these commands: |
375 | * struct __fdb_entry { | 649 | * "setpathcost BR PORT N" writes "N\n" to |
376 | * uint8_t mac_addr[ETH_ALEN]; | 650 | * /sys/class/net/PORT/brport/path_cost |
377 | * uint8_t port_no; //lsb | 651 | * "setportprio BR PORT N" writes "N\n" to |
378 | * uint8_t is_local; | 652 | * /sys/class/net/PORT/brport/priority |
379 | * uint32_t ageing_timer_value; | 653 | */ |
380 | * uint8_t port_hi; | 654 | write_uint(argv[0], |
381 | * uint8_t pad0; | 655 | nth_string( |
382 | * uint16_t unused; | 656 | "brport/path_cost" "\0" /* ARG_setpathcost */ |
383 | * }; | 657 | "brport/priority", /* ARG_setportprio */ |
384 | */ | 658 | key - ARG_setpathcost |
659 | ), | ||
660 | xatoi_positive(argv[1]) | ||
661 | ); | ||
662 | return EXIT_SUCCESS; | ||
663 | } | ||
385 | #endif | 664 | #endif |
386 | /* always true: if (key == ARG_addif || key == ARG_delif) */ { | 665 | /* always true: if (key == ARG_addif || key == ARG_delif) */ { |
387 | /* addif or delif */ | 666 | struct ifreq ifr; |
388 | struct ifreq ifr; | 667 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); |
389 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); | 668 | |
390 | 669 | strncpy_IFNAMSIZ(ifr.ifr_name, br); | |
391 | strncpy_IFNAMSIZ(ifr.ifr_name, br); | 670 | ifr.ifr_ifindex = if_nametoindex(*argv); |
392 | ifr.ifr_ifindex = if_nametoindex(*argv); | 671 | if (ifr.ifr_ifindex == 0) { |
393 | if (ifr.ifr_ifindex == 0) { | 672 | bb_perror_msg_and_die("iface %s", *argv); |
394 | bb_perror_msg_and_die("iface %s", *argv); | ||
395 | } | ||
396 | ioctl_or_perror_and_die(fd, | ||
397 | key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, | ||
398 | &ifr, "bridge %s", br | ||
399 | ); | ||
400 | //close(fd); | ||
401 | //goto done_next_argv; | ||
402 | if (ENABLE_FEATURE_CLEAN_UP) | ||
403 | close(fd); | ||
404 | return EXIT_SUCCESS; | ||
405 | } | 673 | } |
406 | 674 | ioctl_or_perror_and_die(fd, | |
407 | // done_next_argv: | 675 | key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, |
408 | // argv++; | 676 | &ifr, "bridge %s", br |
409 | // done: | 677 | ); |
678 | if (ENABLE_FEATURE_CLEAN_UP) | ||
679 | close(fd); | ||
410 | } | 680 | } |
411 | 681 | ||
412 | return EXIT_SUCCESS; | 682 | return EXIT_SUCCESS; |
diff --git a/networking/netstat.c b/networking/netstat.c index 29b891cdc..c7934423b 100644 --- a/networking/netstat.c +++ b/networking/netstat.c | |||
@@ -172,7 +172,7 @@ struct prg_node { | |||
172 | #define PRG_HASH_SIZE 211 | 172 | #define PRG_HASH_SIZE 211 |
173 | 173 | ||
174 | struct globals { | 174 | struct globals { |
175 | smallint flags; | 175 | smalluint flags; |
176 | #if ENABLE_FEATURE_NETSTAT_PRG | 176 | #if ENABLE_FEATURE_NETSTAT_PRG |
177 | smallint prg_cache_loaded; | 177 | smallint prg_cache_loaded; |
178 | struct prg_node *prg_hash[PRG_HASH_SIZE]; | 178 | struct prg_node *prg_hash[PRG_HASH_SIZE]; |
diff --git a/networking/nslookup.c b/networking/nslookup.c index 8adde14b8..c43e60558 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c | |||
@@ -283,6 +283,7 @@ static const struct { | |||
283 | { ns_t_cname, "CNAME" }, | 283 | { ns_t_cname, "CNAME" }, |
284 | { ns_t_mx, "MX" }, | 284 | { ns_t_mx, "MX" }, |
285 | { ns_t_txt, "TXT" }, | 285 | { ns_t_txt, "TXT" }, |
286 | { ns_t_srv, "SRV" }, | ||
286 | { ns_t_ptr, "PTR" }, | 287 | { ns_t_ptr, "PTR" }, |
287 | { ns_t_any, "ANY" }, | 288 | { ns_t_any, "ANY" }, |
288 | }; | 289 | }; |
@@ -435,6 +436,25 @@ static int parse_reply(const unsigned char *msg, size_t len) | |||
435 | } | 436 | } |
436 | break; | 437 | break; |
437 | 438 | ||
439 | case ns_t_srv: | ||
440 | if (rdlen < 6) { | ||
441 | //printf("SRV record too short\n"); | ||
442 | return -1; | ||
443 | } | ||
444 | |||
445 | cp = ns_rr_rdata(rr); | ||
446 | n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), | ||
447 | cp + 6, dname, sizeof(dname)); | ||
448 | |||
449 | if (n < 0) { | ||
450 | //printf("Unable to uncompress domain: %s\n", strerror(errno)); | ||
451 | return -1; | ||
452 | } | ||
453 | |||
454 | printf("%s\tservice = %u %u %u %s\n", ns_rr_name(rr), | ||
455 | ns_get16(cp), ns_get16(cp + 2), ns_get16(cp + 4), dname); | ||
456 | break; | ||
457 | |||
438 | case ns_t_soa: | 458 | case ns_t_soa: |
439 | if (rdlen < 20) { | 459 | if (rdlen < 20) { |
440 | dbg("SOA record too short:%d\n", rdlen); | 460 | dbg("SOA record too short:%d\n", rdlen); |
@@ -615,9 +635,15 @@ static int send_queries(struct ns *ns) | |||
615 | G.query[qn].name, rcodes[rcode]); | 635 | G.query[qn].name, rcodes[rcode]); |
616 | G.exitcode = EXIT_FAILURE; | 636 | G.exitcode = EXIT_FAILURE; |
617 | } else { | 637 | } else { |
618 | if (parse_reply(reply, recvlen) < 0) { | 638 | switch (parse_reply(reply, recvlen)) { |
639 | case -1: | ||
619 | printf("*** Can't find %s: Parse error\n", G.query[qn].name); | 640 | printf("*** Can't find %s: Parse error\n", G.query[qn].name); |
620 | G.exitcode = EXIT_FAILURE; | 641 | G.exitcode = EXIT_FAILURE; |
642 | break; | ||
643 | |||
644 | case 0: | ||
645 | printf("*** Can't find %s: No answer\n", G.query[qn].name); | ||
646 | break; | ||
621 | } | 647 | } |
622 | } | 648 | } |
623 | bb_putchar('\n'); | 649 | bb_putchar('\n'); |
diff --git a/networking/ntpd.c b/networking/ntpd.c index 48dc1c379..0f12409f9 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -164,7 +164,7 @@ | |||
164 | */ | 164 | */ |
165 | 165 | ||
166 | #define INITIAL_SAMPLES 4 /* how many samples do we want for init */ | 166 | #define INITIAL_SAMPLES 4 /* how many samples do we want for init */ |
167 | #define MIN_FREQHOLD 12 /* adjust offset, but not freq in this many first adjustments */ | 167 | #define MIN_FREQHOLD 10 /* adjust offset, but not freq in this many first adjustments */ |
168 | #define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this factor */ | 168 | #define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this factor */ |
169 | 169 | ||
170 | #define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */ | 170 | #define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */ |
@@ -504,12 +504,14 @@ static ALWAYS_INLINE double MAXD(double a, double b) | |||
504 | return a; | 504 | return a; |
505 | return b; | 505 | return b; |
506 | } | 506 | } |
507 | #if !USING_KERNEL_PLL_LOOP | ||
507 | static ALWAYS_INLINE double MIND(double a, double b) | 508 | static ALWAYS_INLINE double MIND(double a, double b) |
508 | { | 509 | { |
509 | if (a < b) | 510 | if (a < b) |
510 | return a; | 511 | return a; |
511 | return b; | 512 | return b; |
512 | } | 513 | } |
514 | #endif | ||
513 | static NOINLINE double my_SQRT(double X) | 515 | static NOINLINE double my_SQRT(double X) |
514 | { | 516 | { |
515 | union { | 517 | union { |
@@ -1874,9 +1876,11 @@ update_local_clock(peer_t *p) | |||
1874 | //15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6 | 1876 | //15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6 |
1875 | //15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6 | 1877 | //15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6 |
1876 | /* | 1878 | /* |
1877 | * This expression would choose MIN_FREQHOLD + 8 in the above example. | 1879 | * This expression would choose MIN_FREQHOLD + 14 in the above example |
1880 | * (off_032 is +1 for each 0.032768 seconds of offset). | ||
1878 | */ | 1881 | */ |
1879 | G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + ((unsigned)(abs(tmx.offset)) >> 16); | 1882 | unsigned off_032 = abs((int)(tmx.offset >> 15)); |
1883 | G.FREQHOLD_cnt = 1 + MIN_FREQHOLD + off_032; | ||
1880 | } | 1884 | } |
1881 | G.FREQHOLD_cnt--; | 1885 | G.FREQHOLD_cnt--; |
1882 | tmx.status |= STA_FREQHOLD; | 1886 | tmx.status |= STA_FREQHOLD; |
diff --git a/networking/route.c b/networking/route.c index a5d8d7cb9..e785b1da6 100644 --- a/networking/route.c +++ b/networking/route.c | |||
@@ -628,6 +628,7 @@ static void INET6_displayroutes(void) | |||
628 | 628 | ||
629 | r = 0; | 629 | r = 0; |
630 | while (1) { | 630 | while (1) { |
631 | memset(&snaddr6, 0, sizeof(snaddr6)); | ||
631 | inet_pton(AF_INET6, addr6x + r, | 632 | inet_pton(AF_INET6, addr6x + r, |
632 | (struct sockaddr *) &snaddr6.sin6_addr); | 633 | (struct sockaddr *) &snaddr6.sin6_addr); |
633 | snaddr6.sin6_family = AF_INET6; | 634 | snaddr6.sin6_family = AF_INET6; |
diff --git a/networking/tc.c b/networking/tc.c index 2e1078d31..510684443 100644 --- a/networking/tc.c +++ b/networking/tc.c | |||
@@ -215,8 +215,6 @@ static int prio_print_opt(struct rtattr *opt) | |||
215 | if (opt == NULL) | 215 | if (opt == NULL) |
216 | return 0; | 216 | return 0; |
217 | parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt)); | 217 | parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt)); |
218 | if (tb == NULL) | ||
219 | return 0; | ||
220 | printf("bands %u priomap ", qopt->bands); | 218 | printf("bands %u priomap ", qopt->bands); |
221 | for (i=0; i<=TC_PRIO_MAX; i++) | 219 | for (i=0; i<=TC_PRIO_MAX; i++) |
222 | printf(" %d", qopt->priomap[i]); | 220 | printf(" %d", qopt->priomap[i]); |
diff --git a/networking/telnet.c b/networking/telnet.c index fa1628723..9fc85050b 100644 --- a/networking/telnet.c +++ b/networking/telnet.c | |||
@@ -238,6 +238,18 @@ static void handle_net_output(int len) | |||
238 | *dst = '\r'; /* Enter -> CR LF */ | 238 | *dst = '\r'; /* Enter -> CR LF */ |
239 | *++dst = '\n'; | 239 | *++dst = '\n'; |
240 | } | 240 | } |
241 | #if 0 | ||
242 | /* putty's "special commands" mode does this: */ | ||
243 | /* Korenix 3005 switch needs at least the backspace tweak */ | ||
244 | if (c == 0x08 || c == 0x7f) { /* ctrl+h || backspace */ | ||
245 | *dst = IAC; | ||
246 | *++dst = EC; | ||
247 | } | ||
248 | if (c == 0x03) { /* ctrl+c */ | ||
249 | *dst = IAC; | ||
250 | *++dst = IP; | ||
251 | } | ||
252 | #endif | ||
241 | dst++; | 253 | dst++; |
242 | } | 254 | } |
243 | if (dst - outbuf != 0) | 255 | if (dst - outbuf != 0) |
@@ -248,7 +260,7 @@ static void handle_net_input(int len) | |||
248 | { | 260 | { |
249 | byte c; | 261 | byte c; |
250 | int i; | 262 | int i; |
251 | int cstart = cstart; /* for compiler */ | 263 | int cstart = 0; |
252 | 264 | ||
253 | i = 0; | 265 | i = 0; |
254 | //bb_error_msg("[%u,'%.*s']", G.telstate, len, G.buf); | 266 | //bb_error_msg("[%u,'%.*s']", G.telstate, len, G.buf); |
diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c index a4663cd79..5ddcdd2ad 100644 --- a/networking/tls_aesgcm.c +++ b/networking/tls_aesgcm.c | |||
@@ -13,6 +13,7 @@ typedef uint32_t word32; | |||
13 | 13 | ||
14 | /* from wolfssl-3.15.3/wolfcrypt/src/aes.c */ | 14 | /* from wolfssl-3.15.3/wolfcrypt/src/aes.c */ |
15 | 15 | ||
16 | #ifdef UNUSED | ||
16 | static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz) | 17 | static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz) |
17 | { | 18 | { |
18 | /* Multiply the sz by 8 */ | 19 | /* Multiply the sz by 8 */ |
@@ -32,6 +33,7 @@ static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz) | |||
32 | // buf[7] = sz & 0xff; | 33 | // buf[7] = sz & 0xff; |
33 | *(uint32_t*)(buf + 4) = SWAP_BE32(sz); | 34 | *(uint32_t*)(buf + 4) = SWAP_BE32(sz); |
34 | } | 35 | } |
36 | #endif | ||
35 | 37 | ||
36 | static void RIGHTSHIFTX(byte* x) | 38 | static void RIGHTSHIFTX(byte* x) |
37 | { | 39 | { |
diff --git a/networking/traceroute.c b/networking/traceroute.c index 0435d6ba6..06d3f19da 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -546,11 +546,11 @@ pr_type(unsigned char t) | |||
546 | }; | 546 | }; |
547 | # if ENABLE_TRACEROUTE6 | 547 | # if ENABLE_TRACEROUTE6 |
548 | static const char *const ttab6[] = { | 548 | static const char *const ttab6[] = { |
549 | [0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", | 549 | [0] = "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", |
550 | [4] "Param Problem", | 550 | [4] = "Param Problem", |
551 | [8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report", | 551 | [8] = "Echo Request", "Echo Reply", "Membership Query", "Membership Report", |
552 | [12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", | 552 | [12] = "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", |
553 | [16] "Neighbor Advert", "Redirect", | 553 | [16] = "Neighbor Advert", "Redirect", |
554 | }; | 554 | }; |
555 | 555 | ||
556 | if (dest_lsa->u.sa.sa_family == AF_INET6) { | 556 | if (dest_lsa->u.sa.sa_family == AF_INET6) { |
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 4a452cdb9..9ec752dfc 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c | |||
@@ -539,7 +539,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, | |||
539 | 539 | ||
540 | if (optflag->flags == OPTION_BIN) { | 540 | if (optflag->flags == OPTION_BIN) { |
541 | val = strtok(NULL, ""); /* do not split "'q w e'" */ | 541 | val = strtok(NULL, ""); /* do not split "'q w e'" */ |
542 | trim(val); | 542 | if (val) trim(val); |
543 | } else | 543 | } else |
544 | val = strtok(NULL, ", \t"); | 544 | val = strtok(NULL, ", \t"); |
545 | if (!val) | 545 | if (!val) |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 9d8e17c51..85c410a7c 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -123,6 +123,7 @@ static const char udhcpc6_longopts[] ALIGN1 = | |||
123 | "request-option\0" Required_argument "O" | 123 | "request-option\0" Required_argument "O" |
124 | "no-default-options\0" No_argument "o" | 124 | "no-default-options\0" No_argument "o" |
125 | "foreground\0" No_argument "f" | 125 | "foreground\0" No_argument "f" |
126 | "stateless\0" No_argument "l" | ||
126 | USE_FOR_MMU( | 127 | USE_FOR_MMU( |
127 | "background\0" No_argument "b" | 128 | "background\0" No_argument "b" |
128 | ) | 129 | ) |
@@ -147,9 +148,10 @@ enum { | |||
147 | OPT_o = 1 << 12, | 148 | OPT_o = 1 << 12, |
148 | OPT_x = 1 << 13, | 149 | OPT_x = 1 << 13, |
149 | OPT_f = 1 << 14, | 150 | OPT_f = 1 << 14, |
150 | OPT_d = 1 << 15, | 151 | OPT_l = 1 << 15, |
152 | OPT_d = 1 << 16, | ||
151 | /* The rest has variable bit positions, need to be clever */ | 153 | /* The rest has variable bit positions, need to be clever */ |
152 | OPTBIT_d = 15, | 154 | OPTBIT_d = 16, |
153 | USE_FOR_MMU( OPTBIT_b,) | 155 | USE_FOR_MMU( OPTBIT_b,) |
154 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | 156 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) |
155 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | 157 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) |
@@ -479,15 +481,31 @@ static ALWAYS_INLINE uint32_t random_xid(void) | |||
479 | /* Initialize the packet with the proper defaults */ | 481 | /* Initialize the packet with the proper defaults */ |
480 | static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) | 482 | static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) |
481 | { | 483 | { |
484 | uint8_t *ptr; | ||
482 | struct d6_option *clientid; | 485 | struct d6_option *clientid; |
486 | unsigned secs; | ||
483 | 487 | ||
484 | memset(packet, 0, sizeof(*packet)); | 488 | memset(packet, 0, sizeof(*packet)); |
485 | 489 | ||
486 | packet->d6_xid32 = xid; | 490 | packet->d6_xid32 = xid; |
487 | packet->d6_msg_type = type; | 491 | packet->d6_msg_type = type; |
488 | 492 | ||
493 | /* ELAPSED_TIME option is required to be present by the RFC, | ||
494 | * and some servers do check for its presense. [which?] | ||
495 | */ | ||
496 | ptr = packet->d6_options; /* NB: it is 32-bit aligned */ | ||
497 | *((uint32_t*)ptr) = htonl((D6_OPT_ELAPSED_TIME << 16) + 2); | ||
498 | ptr += 4; | ||
499 | client_data.last_secs = monotonic_sec(); | ||
500 | if (client_data.first_secs == 0) | ||
501 | client_data.first_secs = client_data.last_secs; | ||
502 | secs = client_data.last_secs - client_data.first_secs; | ||
503 | *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff; | ||
504 | ptr += 2; | ||
505 | |||
506 | /* add CLIENTID option */ | ||
489 | clientid = (void*)client_data.clientid; | 507 | clientid = (void*)client_data.clientid; |
490 | return mempcpy(packet->d6_options, clientid, clientid->len + 2+2); | 508 | return mempcpy(ptr, clientid, clientid->len + 2+2); |
491 | } | 509 | } |
492 | 510 | ||
493 | static uint8_t *add_d6_client_options(uint8_t *ptr) | 511 | static uint8_t *add_d6_client_options(uint8_t *ptr) |
@@ -544,6 +562,46 @@ static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t * | |||
544 | ); | 562 | ); |
545 | } | 563 | } |
546 | 564 | ||
565 | /* RFC 3315 18.1.5. Creation and Transmission of Information-request Messages | ||
566 | * | ||
567 | * The client uses an Information-request message to obtain | ||
568 | * configuration information without having addresses assigned to it. | ||
569 | * | ||
570 | * The client sets the "msg-type" field to INFORMATION-REQUEST. The | ||
571 | * client generates a transaction ID and inserts this value in the | ||
572 | * "transaction-id" field. | ||
573 | * | ||
574 | * The client SHOULD include a Client Identifier option to identify | ||
575 | * itself to the server. If the client does not include a Client | ||
576 | * Identifier option, the server will not be able to return any client- | ||
577 | * specific options to the client, or the server may choose not to | ||
578 | * respond to the message at all. The client MUST include a Client | ||
579 | * Identifier option if the Information-Request message will be | ||
580 | * authenticated. | ||
581 | * | ||
582 | * The client MUST include an Option Request option (see section 22.7) | ||
583 | * to indicate the options the client is interested in receiving. The | ||
584 | * client MAY include options with data values as hints to the server | ||
585 | * about parameter values the client would like to have returned. | ||
586 | */ | ||
587 | /* NOINLINE: limit stack usage in caller */ | ||
588 | static NOINLINE int send_d6_info_request(uint32_t xid) | ||
589 | { | ||
590 | struct d6_packet packet; | ||
591 | uint8_t *opt_ptr; | ||
592 | |||
593 | /* Fill in: msg type, client id */ | ||
594 | opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST, xid); | ||
595 | |||
596 | /* Add options: | ||
597 | * "param req" option according to -O, options specified with -x | ||
598 | */ | ||
599 | opt_ptr = add_d6_client_options(opt_ptr); | ||
600 | |||
601 | bb_error_msg("sending %s", "info request"); | ||
602 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); | ||
603 | } | ||
604 | |||
547 | /* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. | 605 | /* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. |
548 | * | 606 | * |
549 | * RFC 3315 17.1.1. Creation of Solicit Messages | 607 | * RFC 3315 17.1.1. Creation of Solicit Messages |
@@ -1129,6 +1187,8 @@ static void client_background(void) | |||
1129 | //usage: "\n -o Don't request any options (unless -O is given)" | 1187 | //usage: "\n -o Don't request any options (unless -O is given)" |
1130 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" | 1188 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" |
1131 | //usage: "\n -d Request prefix" | 1189 | //usage: "\n -d Request prefix" |
1190 | //usage: "\n -l Send 'information request' instead of 'solicit'" | ||
1191 | //usage: "\n (used for servers which do not assign IPv6 addresses)" | ||
1132 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" | 1192 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" |
1133 | //usage: "\n Examples of string, numeric, and hex byte opts:" | 1193 | //usage: "\n Examples of string, numeric, and hex byte opts:" |
1134 | //usage: "\n -x hostname:bbox - option 12" | 1194 | //usage: "\n -x hostname:bbox - option 12" |
@@ -1181,7 +1241,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1181 | /* Parse command line */ | 1241 | /* Parse command line */ |
1182 | opt = getopt32long(argv, "^" | 1242 | opt = getopt32long(argv, "^" |
1183 | /* O,x: list; -T,-t,-A take numeric param */ | 1243 | /* O,x: list; -T,-t,-A take numeric param */ |
1184 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd" | 1244 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" |
1185 | USE_FOR_MMU("b") | 1245 | USE_FOR_MMU("b") |
1186 | ///IF_FEATURE_UDHCPC_ARPING("a") | 1246 | ///IF_FEATURE_UDHCPC_ARPING("a") |
1187 | IF_FEATURE_UDHCP_PORT("P:") | 1247 | IF_FEATURE_UDHCP_PORT("P:") |
@@ -1198,15 +1258,20 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1198 | ); | 1258 | ); |
1199 | requested_ipv6 = NULL; | 1259 | requested_ipv6 = NULL; |
1200 | option_mask32 |= OPT_r; | 1260 | option_mask32 |= OPT_r; |
1201 | if (opt & OPT_r) { | 1261 | if (opt & OPT_l) { |
1262 | /* for -l, do not require IPv6 assignment from server */ | ||
1263 | option_mask32 &= ~OPT_r; | ||
1264 | } else if (opt & OPT_r) { | ||
1265 | /* explicit "-r ARG" given */ | ||
1202 | if (strcmp(str_r, "no") == 0) { | 1266 | if (strcmp(str_r, "no") == 0) { |
1203 | option_mask32 -= OPT_r; | 1267 | option_mask32 &= ~OPT_r; |
1204 | } else { | 1268 | } else { |
1205 | if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) | 1269 | if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) |
1206 | bb_error_msg_and_die("bad IPv6 address '%s'", str_r); | 1270 | bb_error_msg_and_die("bad IPv6 address '%s'", str_r); |
1207 | requested_ipv6 = &ipv6_buf; | 1271 | requested_ipv6 = &ipv6_buf; |
1208 | } | 1272 | } |
1209 | } | 1273 | } |
1274 | |||
1210 | #if ENABLE_FEATURE_UDHCP_PORT | 1275 | #if ENABLE_FEATURE_UDHCP_PORT |
1211 | if (opt & OPT_P) { | 1276 | if (opt & OPT_P) { |
1212 | CLIENT_PORT6 = xatou16(str_P); | 1277 | CLIENT_PORT6 = xatou16(str_P); |
@@ -1353,7 +1418,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1353 | if (packet_num == 0) | 1418 | if (packet_num == 0) |
1354 | xid = random_xid(); | 1419 | xid = random_xid(); |
1355 | /* multicast */ | 1420 | /* multicast */ |
1356 | send_d6_discover(xid, requested_ipv6); | 1421 | if (opt & OPT_l) |
1422 | send_d6_info_request(xid); | ||
1423 | else | ||
1424 | send_d6_discover(xid, requested_ipv6); | ||
1357 | timeout = discover_timeout; | 1425 | timeout = discover_timeout; |
1358 | packet_num++; | 1426 | packet_num++; |
1359 | continue; | 1427 | continue; |
@@ -1418,7 +1486,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1418 | * Anyway, it does recover by eventually failing through | 1486 | * Anyway, it does recover by eventually failing through |
1419 | * into INIT_SELECTING state. | 1487 | * into INIT_SELECTING state. |
1420 | */ | 1488 | */ |
1421 | send_d6_renew(xid, &srv6_buf, requested_ipv6); | 1489 | if (opt & OPT_l) |
1490 | send_d6_info_request(xid); | ||
1491 | else | ||
1492 | send_d6_renew(xid, &srv6_buf, requested_ipv6); | ||
1422 | timeout >>= 1; | 1493 | timeout >>= 1; |
1423 | continue; | 1494 | continue; |
1424 | } | 1495 | } |
@@ -1432,8 +1503,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1432 | /* Lease is *really* about to run out, | 1503 | /* Lease is *really* about to run out, |
1433 | * try to find DHCP server using broadcast */ | 1504 | * try to find DHCP server using broadcast */ |
1434 | if (timeout > 0) { | 1505 | if (timeout > 0) { |
1435 | /* send a broadcast renew request */ | 1506 | if (opt & OPT_l) |
1436 | send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); | 1507 | send_d6_info_request(xid); |
1508 | else /* send a broadcast renew request */ | ||
1509 | send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); | ||
1437 | timeout >>= 1; | 1510 | timeout >>= 1; |
1438 | continue; | 1511 | continue; |
1439 | } | 1512 | } |
@@ -1740,6 +1813,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1740 | prefix_timeout = address_timeout; | 1813 | prefix_timeout = address_timeout; |
1741 | /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ | 1814 | /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ |
1742 | timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; | 1815 | timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; |
1816 | if (opt & OPT_l) { | ||
1817 | /* TODO: request OPTION_INFORMATION_REFRESH_TIME (32) | ||
1818 | * and use its value instead of the default 1 day. | ||
1819 | */ | ||
1820 | timeout = 24 * 60 * 60; | ||
1821 | } | ||
1743 | /* paranoia: must not be too small */ | 1822 | /* paranoia: must not be too small */ |
1744 | /* timeout > 60 - ensures at least one unicast renew attempt */ | 1823 | /* timeout > 60 - ensures at least one unicast renew attempt */ |
1745 | if (timeout < 61) | 1824 | if (timeout < 61) |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 656295ff7..5a1f8fd7a 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -606,7 +606,7 @@ static ALWAYS_INLINE uint32_t random_xid(void) | |||
606 | /* Initialize the packet with the proper defaults */ | 606 | /* Initialize the packet with the proper defaults */ |
607 | static void init_packet(struct dhcp_packet *packet, char type) | 607 | static void init_packet(struct dhcp_packet *packet, char type) |
608 | { | 608 | { |
609 | uint16_t secs; | 609 | unsigned secs; |
610 | 610 | ||
611 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ | 611 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ |
612 | udhcp_init_header(packet, type); | 612 | udhcp_init_header(packet, type); |
@@ -617,7 +617,7 @@ static void init_packet(struct dhcp_packet *packet, char type) | |||
617 | if (client_data.first_secs == 0) | 617 | if (client_data.first_secs == 0) |
618 | client_data.first_secs = client_data.last_secs; | 618 | client_data.first_secs = client_data.last_secs; |
619 | secs = client_data.last_secs - client_data.first_secs; | 619 | secs = client_data.last_secs - client_data.first_secs; |
620 | packet->secs = htons(secs); | 620 | packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff; |
621 | 621 | ||
622 | memcpy(packet->chaddr, client_data.client_mac, 6); | 622 | memcpy(packet->chaddr, client_data.client_mac, 6); |
623 | if (client_data.clientid) | 623 | if (client_data.clientid) |
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index 42fe71a36..b407a6cdb 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h | |||
@@ -22,8 +22,8 @@ struct client_data_t { | |||
22 | uint8_t *hostname; /* Optional hostname to use */ | 22 | uint8_t *hostname; /* Optional hostname to use */ |
23 | uint8_t *fqdn; /* Optional fully qualified domain name to use */ | 23 | uint8_t *fqdn; /* Optional fully qualified domain name to use */ |
24 | 24 | ||
25 | uint16_t first_secs; | 25 | unsigned first_secs; |
26 | uint16_t last_secs; | 26 | unsigned last_secs; |
27 | 27 | ||
28 | int sockfd; | 28 | int sockfd; |
29 | smallint listen_mode; | 29 | smallint listen_mode; |
diff --git a/networking/wget.c b/networking/wget.c index 5b85cce1f..4365c76ce 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -1142,7 +1142,7 @@ static void download_one_url(const char *url) | |||
1142 | * We are not sure it exists on remote side */ | 1142 | * We are not sure it exists on remote side */ |
1143 | } | 1143 | } |
1144 | 1144 | ||
1145 | redir_limit = 5; | 1145 | redir_limit = 16; |
1146 | resolve_lsa: | 1146 | resolve_lsa: |
1147 | lsa = xhost2sockaddr(server.host, server.port); | 1147 | lsa = xhost2sockaddr(server.host, server.port); |
1148 | if (!(option_mask32 & WGET_OPT_QUIET)) { | 1148 | if (!(option_mask32 & WGET_OPT_QUIET)) { |
diff --git a/networking/whois.c b/networking/whois.c index 55e1de964..caa71ac51 100644 --- a/networking/whois.c +++ b/networking/whois.c | |||
@@ -53,7 +53,9 @@ static char *query(const char *host, int port, const char *domain) | |||
53 | fp = xfdopen_for_read(fd); | 53 | fp = xfdopen_for_read(fd); |
54 | 54 | ||
55 | success = 0; | 55 | success = 0; |
56 | while (fgets(linebuf, sizeof(linebuf)-1, fp)) { | 56 | while (bufpos < 32*1024 /* paranoia */ |
57 | && fgets(linebuf, sizeof(linebuf)-1, fp) | ||
58 | ) { | ||
57 | unsigned len; | 59 | unsigned len; |
58 | 60 | ||
59 | len = strcspn(linebuf, "\r\n"); | 61 | len = strcspn(linebuf, "\r\n"); |
diff --git a/procps/nmeter.c b/procps/nmeter.c index f0eb36740..ae16d8548 100644 --- a/procps/nmeter.c +++ b/procps/nmeter.c | |||
@@ -122,11 +122,6 @@ static inline void reset_outbuf(void) | |||
122 | cur_outbuf = outbuf; | 122 | cur_outbuf = outbuf; |
123 | } | 123 | } |
124 | 124 | ||
125 | static inline int outbuf_count(void) | ||
126 | { | ||
127 | return cur_outbuf - outbuf; | ||
128 | } | ||
129 | |||
130 | static void print_outbuf(void) | 125 | static void print_outbuf(void) |
131 | { | 126 | { |
132 | int sz = cur_outbuf - outbuf; | 127 | int sz = cur_outbuf - outbuf; |
diff --git a/runit/runsv.c b/runit/runsv.c index ccc762d78..36d85101e 100644 --- a/runit/runsv.c +++ b/runit/runsv.c | |||
@@ -51,11 +51,9 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
51 | #if ENABLE_MONOTONIC_SYSCALL | 51 | #if ENABLE_MONOTONIC_SYSCALL |
52 | #include <sys/syscall.h> | 52 | #include <sys/syscall.h> |
53 | 53 | ||
54 | /* libc has incredibly messy way of doing this, | ||
55 | * typically requiring -lrt. We just skip all this mess */ | ||
56 | static void gettimeofday_ns(struct timespec *ts) | 54 | static void gettimeofday_ns(struct timespec *ts) |
57 | { | 55 | { |
58 | syscall(__NR_clock_gettime, CLOCK_REALTIME, ts); | 56 | clock_gettime(CLOCK_REALTIME, ts); |
59 | } | 57 | } |
60 | #else | 58 | #else |
61 | static void gettimeofday_ns(struct timespec *ts) | 59 | static void gettimeofday_ns(struct timespec *ts) |
diff --git a/shell/ash.c b/shell/ash.c index 8a27d5cc3..95d0aebf0 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -638,7 +638,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
638 | #define random_gen (G_misc.random_gen ) | 638 | #define random_gen (G_misc.random_gen ) |
639 | #define backgndpid (G_misc.backgndpid ) | 639 | #define backgndpid (G_misc.backgndpid ) |
640 | #define INIT_G_misc() do { \ | 640 | #define INIT_G_misc() do { \ |
641 | (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ | 641 | (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \ |
642 | barrier(); \ | 642 | barrier(); \ |
643 | curdir = nullstr; \ | 643 | curdir = nullstr; \ |
644 | physdir = nullstr; \ | 644 | physdir = nullstr; \ |
@@ -1693,7 +1693,7 @@ extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack; | |||
1693 | #define g_stacknleft (G_memstack.g_stacknleft) | 1693 | #define g_stacknleft (G_memstack.g_stacknleft) |
1694 | #define stackbase (G_memstack.stackbase ) | 1694 | #define stackbase (G_memstack.stackbase ) |
1695 | #define INIT_G_memstack() do { \ | 1695 | #define INIT_G_memstack() do { \ |
1696 | (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ | 1696 | (*(struct globals_memstack**)not_const_pp(&ash_ptr_to_globals_memstack)) = xzalloc(sizeof(G_memstack)); \ |
1697 | barrier(); \ | 1697 | barrier(); \ |
1698 | g_stackp = &stackbase; \ | 1698 | g_stackp = &stackbase; \ |
1699 | g_stacknxt = stackbase.space; \ | 1699 | g_stacknxt = stackbase.space; \ |
@@ -2316,7 +2316,7 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | |||
2316 | #endif | 2316 | #endif |
2317 | #define INIT_G_var() do { \ | 2317 | #define INIT_G_var() do { \ |
2318 | unsigned i; \ | 2318 | unsigned i; \ |
2319 | (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ | 2319 | (*(struct globals_var**)not_const_pp(&ash_ptr_to_globals_var)) = xzalloc(sizeof(G_var)); \ |
2320 | barrier(); \ | 2320 | barrier(); \ |
2321 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ | 2321 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ |
2322 | varinit[i].flags = varinit_data[i].flags; \ | 2322 | varinit[i].flags = varinit_data[i].flags; \ |
@@ -13112,7 +13112,13 @@ checkend: { | |||
13112 | for (p = eofmark; STPUTC(c, out), *p; p++) { | 13112 | for (p = eofmark; STPUTC(c, out), *p; p++) { |
13113 | if (c != *p) | 13113 | if (c != *p) |
13114 | goto more_heredoc; | 13114 | goto more_heredoc; |
13115 | 13115 | /* FIXME: fails for backslash-newlined terminator: | |
13116 | * cat <<EOF | ||
13117 | * ... | ||
13118 | * EO\ | ||
13119 | * F | ||
13120 | * (see heredoc_bkslash_newline2.tests) | ||
13121 | */ | ||
13116 | c = pgetc_without_PEOA(); | 13122 | c = pgetc_without_PEOA(); |
13117 | } | 13123 | } |
13118 | 13124 | ||
diff --git a/shell/ash_test/ash-redir/redir_stdin1.right b/shell/ash_test/ash-redir/redir_stdin1.right new file mode 100644 index 000000000..1c6217e92 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_stdin1.right | |||
@@ -0,0 +1,3 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | read2 | ||
3 | Ok:0 | ||
diff --git a/shell/ash_test/ash-redir/redir_stdin1.tests b/shell/ash_test/ash-redir/redir_stdin1.tests new file mode 100755 index 000000000..f72253f9d --- /dev/null +++ b/shell/ash_test/ash-redir/redir_stdin1.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | echo read2 | $THIS_SH -c 'read r <redir_stdin1.tests | ||
3 | echo $r | ||
4 | read r | ||
5 | echo $r | ||
6 | ' | ||
7 | echo Ok:$? | ||
diff --git a/shell/hush.c b/shell/hush.c index 19b97e2a5..97202b953 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -573,7 +573,6 @@ typedef struct HFILE { | |||
573 | char *cur; | 573 | char *cur; |
574 | char *end; | 574 | char *end; |
575 | struct HFILE *next_hfile; | 575 | struct HFILE *next_hfile; |
576 | int is_stdin; | ||
577 | int fd; | 576 | int fd; |
578 | char buf[1024]; | 577 | char buf[1024]; |
579 | } HFILE; | 578 | } HFILE; |
@@ -973,6 +972,7 @@ struct globals { | |||
973 | unsigned execute_lineno; | 972 | unsigned execute_lineno; |
974 | #endif | 973 | #endif |
975 | HFILE *HFILE_list; | 974 | HFILE *HFILE_list; |
975 | HFILE *HFILE_stdin; | ||
976 | /* Which signals have non-DFL handler (even with no traps set)? | 976 | /* Which signals have non-DFL handler (even with no traps set)? |
977 | * Set at the start to: | 977 | * Set at the start to: |
978 | * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) | 978 | * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) |
@@ -1603,7 +1603,8 @@ static HFILE *hfopen(const char *name) | |||
1603 | } | 1603 | } |
1604 | 1604 | ||
1605 | fp = xmalloc(sizeof(*fp)); | 1605 | fp = xmalloc(sizeof(*fp)); |
1606 | fp->is_stdin = (name == NULL); | 1606 | if (name == NULL) |
1607 | G.HFILE_stdin = fp; | ||
1607 | fp->fd = fd; | 1608 | fp->fd = fd; |
1608 | fp->cur = fp->end = fp->buf; | 1609 | fp->cur = fp->end = fp->buf; |
1609 | fp->next_hfile = G.HFILE_list; | 1610 | fp->next_hfile = G.HFILE_list; |
@@ -2666,7 +2667,7 @@ static int fgetc_interactive(struct in_str *i) | |||
2666 | { | 2667 | { |
2667 | int ch; | 2668 | int ch; |
2668 | /* If it's interactive stdin, get new line. */ | 2669 | /* If it's interactive stdin, get new line. */ |
2669 | if (G_interactive_fd && i->file->is_stdin) { | 2670 | if (G_interactive_fd && i->file == G.HFILE_stdin) { |
2670 | /* Returns first char (or EOF), the rest is in i->p[] */ | 2671 | /* Returns first char (or EOF), the rest is in i->p[] */ |
2671 | ch = get_user_input(i); | 2672 | ch = get_user_input(i); |
2672 | G.promptmode = 1; /* PS2 */ | 2673 | G.promptmode = 1; /* PS2 */ |
@@ -3652,9 +3653,9 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
3652 | fdprintf(2, "%*s cmd %d assignment_cnt:%d", | 3653 | fdprintf(2, "%*s cmd %d assignment_cnt:%d", |
3653 | lvl*2, "", prn, | 3654 | lvl*2, "", prn, |
3654 | command->assignment_cnt); | 3655 | command->assignment_cnt); |
3655 | #if ENABLE_HUSH_LINENO_VAR | 3656 | # if ENABLE_HUSH_LINENO_VAR |
3656 | fdprintf(2, " LINENO:%u", command->lineno); | 3657 | fdprintf(2, " LINENO:%u", command->lineno); |
3657 | #endif | 3658 | # endif |
3658 | if (command->group) { | 3659 | if (command->group) { |
3659 | fdprintf(2, " group %s: (argv=%p)%s%s\n", | 3660 | fdprintf(2, " group %s: (argv=%p)%s%s\n", |
3660 | CMDTYPE[command->cmd_type], | 3661 | CMDTYPE[command->cmd_type], |
@@ -4770,9 +4771,9 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
4770 | # endif | 4771 | # endif |
4771 | end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); | 4772 | end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); |
4772 | 4773 | ||
4773 | #if ENABLE_HUSH_INTERACTIVE | 4774 | # if ENABLE_HUSH_INTERACTIVE |
4774 | G.promptmode = 1; /* PS2 */ | 4775 | G.promptmode = 1; /* PS2 */ |
4775 | #endif | 4776 | # endif |
4776 | debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); | 4777 | debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); |
4777 | 4778 | ||
4778 | while (1) { | 4779 | while (1) { |
@@ -4828,13 +4829,13 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
4828 | syntax_error_unterm_ch(end_ch); | 4829 | syntax_error_unterm_ch(end_ch); |
4829 | return 0; | 4830 | return 0; |
4830 | } | 4831 | } |
4831 | #if 0 | 4832 | # if 0 |
4832 | if (ch == '\n') { | 4833 | if (ch == '\n') { |
4833 | /* "backslash+newline", ignore both */ | 4834 | /* "backslash+newline", ignore both */ |
4834 | o_delchr(dest); /* undo insertion of '\' */ | 4835 | o_delchr(dest); /* undo insertion of '\' */ |
4835 | continue; | 4836 | continue; |
4836 | } | 4837 | } |
4837 | #endif | 4838 | # endif |
4838 | o_addchr(dest, ch); | 4839 | o_addchr(dest, ch); |
4839 | //bb_error_msg("%s:o_addchr('%c') after '\\'", __func__, ch); | 4840 | //bb_error_msg("%s:o_addchr('%c') after '\\'", __func__, ch); |
4840 | continue; | 4841 | continue; |
@@ -4991,7 +4992,7 @@ static int parse_dollar(o_string *as_string, | |||
4991 | if (last_ch == 0) /* error? */ | 4992 | if (last_ch == 0) /* error? */ |
4992 | return 0; | 4993 | return 0; |
4993 | #else | 4994 | #else |
4994 | #error Simple code to only allow ${var} is not implemented | 4995 | # error Simple code to only allow ${var} is not implemented |
4995 | #endif | 4996 | #endif |
4996 | if (as_string) { | 4997 | if (as_string) { |
4997 | o_addstr(as_string, dest->data + pos); | 4998 | o_addstr(as_string, dest->data + pos); |
@@ -7605,7 +7606,9 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | |||
7605 | avoid_fd = 9; | 7606 | avoid_fd = 9; |
7606 | 7607 | ||
7607 | #if ENABLE_HUSH_INTERACTIVE | 7608 | #if ENABLE_HUSH_INTERACTIVE |
7608 | if (fd == G_interactive_fd) { | 7609 | if (fd != 0 /* don't trigger for G_interactive_fd == 0 (that's "not interactive" flag) */ |
7610 | && fd == G_interactive_fd | ||
7611 | ) { | ||
7609 | /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ | 7612 | /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ |
7610 | G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd); | 7613 | G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd); |
7611 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd); | 7614 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd); |
@@ -7619,7 +7622,7 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | |||
7619 | /* No need to move script fds. | 7622 | /* No need to move script fds. |
7620 | * For NOMMU case, it's actively wrong: we'd change ->fd | 7623 | * For NOMMU case, it's actively wrong: we'd change ->fd |
7621 | * fields in memory for the parent, but parent's fds | 7624 | * fields in memory for the parent, but parent's fds |
7622 | * aren't be moved, it would use wrong fd! | 7625 | * aren't moved, it would use wrong fd! |
7623 | * Reproducer: "cmd 3>FILE" in script. | 7626 | * Reproducer: "cmd 3>FILE" in script. |
7624 | * If we would call move_HFILEs_on_redirect(), child would: | 7627 | * If we would call move_HFILEs_on_redirect(), child would: |
7625 | * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10 | 7628 | * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10 |
@@ -7683,6 +7686,20 @@ static void restore_redirects(struct squirrel *sq) | |||
7683 | } | 7686 | } |
7684 | free(sq); | 7687 | free(sq); |
7685 | } | 7688 | } |
7689 | if (G.HFILE_stdin | ||
7690 | && G.HFILE_stdin->fd != STDIN_FILENO | ||
7691 | ) { | ||
7692 | /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r". | ||
7693 | * Redirect moves ->fd to e.g. 10, | ||
7694 | * and it is not restored above (we do not restore script fds | ||
7695 | * after redirects, we just use new, "moved" fds). | ||
7696 | * However for stdin, get_user_input() -> read_line_input(), | ||
7697 | * and read builtin, depend on fd == STDIN_FILENO. | ||
7698 | */ | ||
7699 | debug_printf_redir("restoring %d to stdin\n", G.HFILE_stdin->fd); | ||
7700 | xmove_fd(G.HFILE_stdin->fd, STDIN_FILENO); | ||
7701 | G.HFILE_stdin->fd = STDIN_FILENO; | ||
7702 | } | ||
7686 | 7703 | ||
7687 | /* If moved, G_interactive_fd stays on new fd, not restoring it */ | 7704 | /* If moved, G_interactive_fd stays on new fd, not restoring it */ |
7688 | } | 7705 | } |
@@ -8684,9 +8701,9 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) | |||
8684 | pi->cmds[i].pid = 0; | 8701 | pi->cmds[i].pid = 0; |
8685 | pi->alive_cmds--; | 8702 | pi->alive_cmds--; |
8686 | if (!pi->alive_cmds) { | 8703 | if (!pi->alive_cmds) { |
8687 | #if ENABLE_HUSH_BASH_COMPAT | 8704 | # if ENABLE_HUSH_BASH_COMPAT |
8688 | G.dead_job_exitcode = job_exited_or_stopped(pi); | 8705 | G.dead_job_exitcode = job_exited_or_stopped(pi); |
8689 | #endif | 8706 | # endif |
8690 | if (G_interactive_fd) { | 8707 | if (G_interactive_fd) { |
8691 | printf(JOB_STATUS_FORMAT, pi->jobid, | 8708 | printf(JOB_STATUS_FORMAT, pi->jobid, |
8692 | "Done", pi->cmdtext); | 8709 | "Done", pi->cmdtext); |
@@ -9824,9 +9841,12 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
9824 | IF_HUSH_MODE_X(G_x_mode = state;) | 9841 | IF_HUSH_MODE_X(G_x_mode = state;) |
9825 | IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);) | 9842 | IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);) |
9826 | break; | 9843 | break; |
9844 | case 'e': | ||
9845 | G.o_opt[OPT_O_ERREXIT] = state; | ||
9846 | break; | ||
9827 | case 'o': | 9847 | case 'o': |
9828 | if (!o_opt) { | 9848 | if (!o_opt) { |
9829 | /* "set -+o" without parameter. | 9849 | /* "set -o" or "set +o" without parameter. |
9830 | * in bash, set -o produces this output: | 9850 | * in bash, set -o produces this output: |
9831 | * pipefail off | 9851 | * pipefail off |
9832 | * and set +o: | 9852 | * and set +o: |
@@ -9847,9 +9867,7 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
9847 | G.o_opt[idx] = state; | 9867 | G.o_opt[idx] = state; |
9848 | break; | 9868 | break; |
9849 | } | 9869 | } |
9850 | case 'e': | 9870 | /* fall through to error */ |
9851 | G.o_opt[OPT_O_ERREXIT] = state; | ||
9852 | break; | ||
9853 | default: | 9871 | default: |
9854 | return EXIT_FAILURE; | 9872 | return EXIT_FAILURE; |
9855 | } | 9873 | } |
@@ -10213,8 +10231,6 @@ int hush_main(int argc, char **argv) | |||
10213 | G_saved_tty_pgrp = 0; | 10231 | G_saved_tty_pgrp = 0; |
10214 | } | 10232 | } |
10215 | } | 10233 | } |
10216 | // TODO: track & disallow any attempts of user | ||
10217 | // to (inadvertently) close/redirect G_interactive_fd | ||
10218 | } | 10234 | } |
10219 | debug_printf("interactive_fd:%d\n", G_interactive_fd); | 10235 | debug_printf("interactive_fd:%d\n", G_interactive_fd); |
10220 | if (G_interactive_fd) { | 10236 | if (G_interactive_fd) { |
@@ -10536,10 +10552,10 @@ static int FAST_FUNC builtin_type(char **argv) | |||
10536 | if (0) {} /* make conditional compile easier below */ | 10552 | if (0) {} /* make conditional compile easier below */ |
10537 | /*else if (find_alias(*argv)) | 10553 | /*else if (find_alias(*argv)) |
10538 | type = "an alias";*/ | 10554 | type = "an alias";*/ |
10539 | #if ENABLE_HUSH_FUNCTIONS | 10555 | # if ENABLE_HUSH_FUNCTIONS |
10540 | else if (find_function(*argv)) | 10556 | else if (find_function(*argv)) |
10541 | type = "a function"; | 10557 | type = "a function"; |
10542 | #endif | 10558 | # endif |
10543 | else if (find_builtin(*argv)) | 10559 | else if (find_builtin(*argv)) |
10544 | type = "a shell builtin"; | 10560 | type = "a shell builtin"; |
10545 | else if ((path = find_in_path(*argv)) != NULL) | 10561 | else if ((path = find_in_path(*argv)) != NULL) |
@@ -10594,11 +10610,11 @@ static int FAST_FUNC builtin_read(char **argv) | |||
10594 | * Option string must start with "sr" to match BUILTIN_READ_xxx | 10610 | * Option string must start with "sr" to match BUILTIN_READ_xxx |
10595 | */ | 10611 | */ |
10596 | params.read_flags = getopt32(argv, | 10612 | params.read_flags = getopt32(argv, |
10597 | #if BASH_READ_D | 10613 | # if BASH_READ_D |
10598 | "!srn:p:t:u:d:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d | 10614 | "!srn:p:t:u:d:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d |
10599 | #else | 10615 | # else |
10600 | "!srn:p:t:u:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u | 10616 | "!srn:p:t:u:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u |
10601 | #endif | 10617 | # endif |
10602 | ); | 10618 | ); |
10603 | if ((uint32_t)params.read_flags == (uint32_t)-1) | 10619 | if ((uint32_t)params.read_flags == (uint32_t)-1) |
10604 | return EXIT_FAILURE; | 10620 | return EXIT_FAILURE; |
@@ -10771,24 +10787,24 @@ static int FAST_FUNC builtin_export(char **argv) | |||
10771 | { | 10787 | { |
10772 | unsigned opt_unexport; | 10788 | unsigned opt_unexport; |
10773 | 10789 | ||
10774 | #if ENABLE_HUSH_EXPORT_N | 10790 | # if ENABLE_HUSH_EXPORT_N |
10775 | /* "!": do not abort on errors */ | 10791 | /* "!": do not abort on errors */ |
10776 | opt_unexport = getopt32(argv, "!n"); | 10792 | opt_unexport = getopt32(argv, "!n"); |
10777 | if (opt_unexport == (uint32_t)-1) | 10793 | if (opt_unexport == (uint32_t)-1) |
10778 | return EXIT_FAILURE; | 10794 | return EXIT_FAILURE; |
10779 | argv += optind; | 10795 | argv += optind; |
10780 | #else | 10796 | # else |
10781 | opt_unexport = 0; | 10797 | opt_unexport = 0; |
10782 | argv++; | 10798 | argv++; |
10783 | #endif | 10799 | # endif |
10784 | 10800 | ||
10785 | if (argv[0] == NULL) { | 10801 | if (argv[0] == NULL) { |
10786 | char **e = environ; | 10802 | char **e = environ; |
10787 | if (e) { | 10803 | if (e) { |
10788 | while (*e) { | 10804 | while (*e) { |
10789 | #if 0 | 10805 | # if 0 |
10790 | puts(*e++); | 10806 | puts(*e++); |
10791 | #else | 10807 | # else |
10792 | /* ash emits: export VAR='VAL' | 10808 | /* ash emits: export VAR='VAL' |
10793 | * bash: declare -x VAR="VAL" | 10809 | * bash: declare -x VAR="VAL" |
10794 | * we follow ash example */ | 10810 | * we follow ash example */ |
@@ -10801,7 +10817,7 @@ static int FAST_FUNC builtin_export(char **argv) | |||
10801 | printf("export %.*s", (int)(p - s) + 1, s); | 10817 | printf("export %.*s", (int)(p - s) + 1, s); |
10802 | print_escaped(p + 1); | 10818 | print_escaped(p + 1); |
10803 | putchar('\n'); | 10819 | putchar('\n'); |
10804 | #endif | 10820 | # endif |
10805 | } | 10821 | } |
10806 | /*fflush_all(); - done after each builtin anyway */ | 10822 | /*fflush_all(); - done after each builtin anyway */ |
10807 | } | 10823 | } |
@@ -10931,8 +10947,10 @@ static int FAST_FUNC builtin_set(char **argv) | |||
10931 | if (arg[0] != '+' && arg[0] != '-') | 10947 | if (arg[0] != '+' && arg[0] != '-') |
10932 | break; | 10948 | break; |
10933 | for (n = 1; arg[n]; ++n) { | 10949 | for (n = 1; arg[n]; ++n) { |
10934 | if (set_mode((arg[0] == '-'), arg[n], argv[1])) | 10950 | if (set_mode((arg[0] == '-'), arg[n], argv[1])) { |
10935 | goto error; | 10951 | bb_error_msg("%s: %s: invalid option", "set", arg); |
10952 | return EXIT_FAILURE; | ||
10953 | } | ||
10936 | if (arg[n] == 'o' && argv[1]) | 10954 | if (arg[n] == 'o' && argv[1]) |
10937 | argv++; | 10955 | argv++; |
10938 | } | 10956 | } |
@@ -10962,11 +10980,6 @@ static int FAST_FUNC builtin_set(char **argv) | |||
10962 | G.global_argc = 1 + string_array_len(pp + 1); | 10980 | G.global_argc = 1 + string_array_len(pp + 1); |
10963 | 10981 | ||
10964 | return EXIT_SUCCESS; | 10982 | return EXIT_SUCCESS; |
10965 | |||
10966 | /* Nothing known, so abort */ | ||
10967 | error: | ||
10968 | bb_error_msg("%s: %s: invalid option", "set", arg); | ||
10969 | return EXIT_FAILURE; | ||
10970 | } | 10983 | } |
10971 | #endif | 10984 | #endif |
10972 | 10985 | ||
@@ -11459,9 +11472,9 @@ static int FAST_FUNC builtin_kill(char **argv) | |||
11459 | 11472 | ||
11460 | #if ENABLE_HUSH_WAIT | 11473 | #if ENABLE_HUSH_WAIT |
11461 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ | 11474 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ |
11462 | #if !ENABLE_HUSH_JOB | 11475 | # if !ENABLE_HUSH_JOB |
11463 | # define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid) | 11476 | # define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid) |
11464 | #endif | 11477 | # endif |
11465 | static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid) | 11478 | static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid) |
11466 | { | 11479 | { |
11467 | int ret = 0; | 11480 | int ret = 0; |
@@ -11493,7 +11506,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid | |||
11493 | /* Can't pass waitfor_pipe into checkjobs(): it won't be interruptible */ | 11506 | /* Can't pass waitfor_pipe into checkjobs(): it won't be interruptible */ |
11494 | ret = checkjobs(NULL, waitfor_pid); /* waitpid(WNOHANG) inside */ | 11507 | ret = checkjobs(NULL, waitfor_pid); /* waitpid(WNOHANG) inside */ |
11495 | debug_printf_exec("checkjobs:%d\n", ret); | 11508 | debug_printf_exec("checkjobs:%d\n", ret); |
11496 | #if ENABLE_HUSH_JOB | 11509 | # if ENABLE_HUSH_JOB |
11497 | if (waitfor_pipe) { | 11510 | if (waitfor_pipe) { |
11498 | int rcode = job_exited_or_stopped(waitfor_pipe); | 11511 | int rcode = job_exited_or_stopped(waitfor_pipe); |
11499 | debug_printf_exec("job_exited_or_stopped:%d\n", rcode); | 11512 | debug_printf_exec("job_exited_or_stopped:%d\n", rcode); |
@@ -11503,7 +11516,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid | |||
11503 | break; | 11516 | break; |
11504 | } | 11517 | } |
11505 | } | 11518 | } |
11506 | #endif | 11519 | # endif |
11507 | /* if ECHILD, there are no children (ret is -1 or 0) */ | 11520 | /* if ECHILD, there are no children (ret is -1 or 0) */ |
11508 | /* if ret == 0, no children changed state */ | 11521 | /* if ret == 0, no children changed state */ |
11509 | /* if ret != 0, it's exitcode+1 of exited waitfor_pid child */ | 11522 | /* if ret != 0, it's exitcode+1 of exited waitfor_pid child */ |
@@ -11511,12 +11524,12 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid | |||
11511 | ret--; | 11524 | ret--; |
11512 | if (ret < 0) /* if ECHILD, may need to fix "ret" */ | 11525 | if (ret < 0) /* if ECHILD, may need to fix "ret" */ |
11513 | ret = 0; | 11526 | ret = 0; |
11514 | #if ENABLE_HUSH_BASH_COMPAT | 11527 | # if ENABLE_HUSH_BASH_COMPAT |
11515 | if (waitfor_pid == -1 && errno == ECHILD) { | 11528 | if (waitfor_pid == -1 && errno == ECHILD) { |
11516 | /* exitcode of "wait -n" with no children is 127, not 0 */ | 11529 | /* exitcode of "wait -n" with no children is 127, not 0 */ |
11517 | ret = 127; | 11530 | ret = 127; |
11518 | } | 11531 | } |
11519 | #endif | 11532 | # endif |
11520 | sigprocmask(SIG_SETMASK, &oldset, NULL); | 11533 | sigprocmask(SIG_SETMASK, &oldset, NULL); |
11521 | break; | 11534 | break; |
11522 | } | 11535 | } |
@@ -11545,14 +11558,14 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
11545 | int status; | 11558 | int status; |
11546 | 11559 | ||
11547 | argv = skip_dash_dash(argv); | 11560 | argv = skip_dash_dash(argv); |
11548 | #if ENABLE_HUSH_BASH_COMPAT | 11561 | # if ENABLE_HUSH_BASH_COMPAT |
11549 | if (argv[0] && strcmp(argv[0], "-n") == 0) { | 11562 | if (argv[0] && strcmp(argv[0], "-n") == 0) { |
11550 | /* wait -n */ | 11563 | /* wait -n */ |
11551 | /* (bash accepts "wait -n PID" too and ignores PID) */ | 11564 | /* (bash accepts "wait -n PID" too and ignores PID) */ |
11552 | G.dead_job_exitcode = -1; | 11565 | G.dead_job_exitcode = -1; |
11553 | return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/); | 11566 | return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/); |
11554 | } | 11567 | } |
11555 | #endif | 11568 | # endif |
11556 | if (argv[0] == NULL) { | 11569 | if (argv[0] == NULL) { |
11557 | /* Don't care about wait results */ | 11570 | /* Don't care about wait results */ |
11558 | /* Note 1: must wait until there are no more children */ | 11571 | /* Note 1: must wait until there are no more children */ |
@@ -11576,7 +11589,7 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
11576 | do { | 11589 | do { |
11577 | pid_t pid = bb_strtou(*argv, NULL, 10); | 11590 | pid_t pid = bb_strtou(*argv, NULL, 10); |
11578 | if (errno || pid <= 0) { | 11591 | if (errno || pid <= 0) { |
11579 | #if ENABLE_HUSH_JOB | 11592 | # if ENABLE_HUSH_JOB |
11580 | if (argv[0][0] == '%') { | 11593 | if (argv[0][0] == '%') { |
11581 | struct pipe *wait_pipe; | 11594 | struct pipe *wait_pipe; |
11582 | ret = 127; /* bash compat for bad jobspecs */ | 11595 | ret = 127; /* bash compat for bad jobspecs */ |
@@ -11593,7 +11606,7 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
11593 | /* else: parse_jobspec() already emitted error msg */ | 11606 | /* else: parse_jobspec() already emitted error msg */ |
11594 | continue; | 11607 | continue; |
11595 | } | 11608 | } |
11596 | #endif | 11609 | # endif |
11597 | /* mimic bash message */ | 11610 | /* mimic bash message */ |
11598 | bb_error_msg("wait: '%s': not a pid or valid job spec", *argv); | 11611 | bb_error_msg("wait: '%s': not a pid or valid job spec", *argv); |
11599 | ret = EXIT_FAILURE; | 11612 | ret = EXIT_FAILURE; |
@@ -11615,7 +11628,7 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
11615 | ret = G.last_bg_pid_exitcode; | 11628 | ret = G.last_bg_pid_exitcode; |
11616 | } else { | 11629 | } else { |
11617 | /* Example: "wait 1". mimic bash message */ | 11630 | /* Example: "wait 1". mimic bash message */ |
11618 | bb_error_msg("wait: pid %d is not a child of this shell", (int)pid); | 11631 | bb_error_msg("wait: pid %u is not a child of this shell", (unsigned)pid); |
11619 | } | 11632 | } |
11620 | } else { | 11633 | } else { |
11621 | /* ??? */ | 11634 | /* ??? */ |
diff --git a/shell/hush_test/hush-redir/redir_stdin1.right b/shell/hush_test/hush-redir/redir_stdin1.right new file mode 100644 index 000000000..1c6217e92 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_stdin1.right | |||
@@ -0,0 +1,3 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | read2 | ||
3 | Ok:0 | ||
diff --git a/shell/hush_test/hush-redir/redir_stdin1.tests b/shell/hush_test/hush-redir/redir_stdin1.tests new file mode 100755 index 000000000..f72253f9d --- /dev/null +++ b/shell/hush_test/hush-redir/redir_stdin1.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | echo read2 | $THIS_SH -c 'read r <redir_stdin1.tests | ||
3 | echo $r | ||
4 | read r | ||
5 | echo $r | ||
6 | ' | ||
7 | echo Ok:$? | ||
diff --git a/shell/math.c b/shell/math.c index eaf4f2453..aac5017d0 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -537,11 +537,40 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) | |||
537 | base = (unsigned)n; | 537 | base = (unsigned)n; |
538 | n = 0; | 538 | n = 0; |
539 | nptr = *endptr + 1; | 539 | nptr = *endptr + 1; |
540 | /* bash allows "N#" (empty "nnnn" part) */ | 540 | for (;;) { |
541 | while (isdigit(*nptr)) { | 541 | unsigned digit = (unsigned)*nptr - '0'; |
542 | if (digit >= 10 /* not 0..9 */ | ||
543 | && digit <= 'z' - '0' /* needed to reject e.g. $((64#~)) */ | ||
544 | ) { | ||
545 | /* in bases up to 36, case does not matter for a-z */ | ||
546 | digit = (unsigned)(*nptr | 0x20) - ('a' - 10); | ||
547 | if (base > 36 && *nptr <= '_') { | ||
548 | /* otherwise, A-Z,@,_ are 36-61,62,63 */ | ||
549 | if (*nptr == '_') | ||
550 | digit = 63; | ||
551 | else if (*nptr == '@') | ||
552 | digit = 62; | ||
553 | else if (digit < 36) /* A-Z */ | ||
554 | digit += 36 - 10; | ||
555 | else | ||
556 | break; /* error: one of [\]^ */ | ||
557 | } | ||
558 | //bb_error_msg("ch:'%c'%d digit:%u", *nptr, *nptr, digit); | ||
559 | //if (digit < 10) - example where we need this? | ||
560 | // break; | ||
561 | } | ||
562 | if (digit >= base) | ||
563 | break; | ||
542 | /* bash does not check for overflows */ | 564 | /* bash does not check for overflows */ |
543 | n = n * base + (*nptr++ - '0'); | 565 | n = n * base + digit; |
566 | nptr++; | ||
544 | } | 567 | } |
568 | /* Note: we do not set errno on bad chars, we just set a pointer | ||
569 | * to the first invalid char. For example, this allows | ||
570 | * "N#" (empty "nnnn" part): 64#+1 is a valid expression, | ||
571 | * it means 64# + 1, whereas 64#~... is not, since ~ is not a valid | ||
572 | * operator. | ||
573 | */ | ||
545 | *endptr = (char*)nptr; | 574 | *endptr = (char*)nptr; |
546 | return n; | 575 | return n; |
547 | } | 576 | } |
diff --git a/shell/shell_common.c b/shell/shell_common.c index 06a6b6e5f..be69ff249 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -371,52 +371,91 @@ shell_builtin_read(struct builtin_read_params *params) | |||
371 | struct limits { | 371 | struct limits { |
372 | uint8_t cmd; /* RLIMIT_xxx fit into it */ | 372 | uint8_t cmd; /* RLIMIT_xxx fit into it */ |
373 | uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ | 373 | uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ |
374 | const char *name; | ||
375 | }; | 374 | }; |
376 | 375 | ||
377 | static const struct limits limits_tbl[] = { | 376 | static const struct limits limits_tbl[] = { |
378 | { RLIMIT_CORE, 9, "core file size (blocks)" }, // -c | 377 | { RLIMIT_CORE, 9, }, // -c |
379 | { RLIMIT_DATA, 10, "data seg size (kb)" }, // -d | 378 | { RLIMIT_DATA, 10, }, // -d |
380 | { RLIMIT_NICE, 0, "scheduling priority" }, // -e | 379 | { RLIMIT_NICE, 0, }, // -e |
381 | { RLIMIT_FSIZE, 9, "file size (blocks)" }, // -f | 380 | { RLIMIT_FSIZE, 9, }, // -f |
382 | #define LIMIT_F_IDX 3 | 381 | #define LIMIT_F_IDX 3 |
383 | #ifdef RLIMIT_SIGPENDING | 382 | #ifdef RLIMIT_SIGPENDING |
384 | { RLIMIT_SIGPENDING, 0, "pending signals" }, // -i | 383 | { RLIMIT_SIGPENDING, 0, }, // -i |
385 | #endif | 384 | #endif |
386 | #ifdef RLIMIT_MEMLOCK | 385 | #ifdef RLIMIT_MEMLOCK |
387 | { RLIMIT_MEMLOCK, 10, "max locked memory (kb)" }, // -l | 386 | { RLIMIT_MEMLOCK, 10, }, // -l |
388 | #endif | 387 | #endif |
389 | #ifdef RLIMIT_RSS | 388 | #ifdef RLIMIT_RSS |
390 | { RLIMIT_RSS, 10, "max memory size (kb)" }, // -m | 389 | { RLIMIT_RSS, 10, }, // -m |
391 | #endif | 390 | #endif |
392 | #ifdef RLIMIT_NOFILE | 391 | #ifdef RLIMIT_NOFILE |
393 | { RLIMIT_NOFILE, 0, "open files" }, // -n | 392 | { RLIMIT_NOFILE, 0, }, // -n |
394 | #endif | 393 | #endif |
395 | #ifdef RLIMIT_MSGQUEUE | 394 | #ifdef RLIMIT_MSGQUEUE |
396 | { RLIMIT_MSGQUEUE, 0, "POSIX message queues (bytes)" }, // -q | 395 | { RLIMIT_MSGQUEUE, 0, }, // -q |
397 | #endif | 396 | #endif |
398 | #ifdef RLIMIT_RTPRIO | 397 | #ifdef RLIMIT_RTPRIO |
399 | { RLIMIT_RTPRIO, 0, "real-time priority" }, // -r | 398 | { RLIMIT_RTPRIO, 0, }, // -r |
400 | #endif | 399 | #endif |
401 | #ifdef RLIMIT_STACK | 400 | #ifdef RLIMIT_STACK |
402 | { RLIMIT_STACK, 10, "stack size (kb)" }, // -s | 401 | { RLIMIT_STACK, 10, }, // -s |
403 | #endif | 402 | #endif |
404 | #ifdef RLIMIT_CPU | 403 | #ifdef RLIMIT_CPU |
405 | { RLIMIT_CPU, 0, "cpu time (seconds)" }, // -t | 404 | { RLIMIT_CPU, 0, }, // -t |
406 | #endif | 405 | #endif |
407 | #ifdef RLIMIT_NPROC | 406 | #ifdef RLIMIT_NPROC |
408 | { RLIMIT_NPROC, 0, "max user processes" }, // -u | 407 | { RLIMIT_NPROC, 0, }, // -u |
409 | #endif | 408 | #endif |
410 | #ifdef RLIMIT_AS | 409 | #ifdef RLIMIT_AS |
411 | { RLIMIT_AS, 10, "virtual memory (kb)" }, // -v | 410 | { RLIMIT_AS, 10, }, // -v |
412 | #endif | 411 | #endif |
413 | #ifdef RLIMIT_LOCKS | 412 | #ifdef RLIMIT_LOCKS |
414 | { RLIMIT_LOCKS, 0, "file locks" }, // -x | 413 | { RLIMIT_LOCKS, 0, }, // -x |
415 | #endif | 414 | #endif |
416 | }; | 415 | }; |
417 | // bash also shows: | 416 | // bash also shows: |
418 | //pipe size (512 bytes, -p) 8 | 417 | //pipe size (512 bytes, -p) 8 |
419 | 418 | ||
419 | static const char limits_help[] ALIGN1 = | ||
420 | "core file size (blocks)" // -c | ||
421 | "\0""data seg size (kb)" // -d | ||
422 | "\0""scheduling priority" // -e | ||
423 | "\0""file size (blocks)" // -f | ||
424 | #ifdef RLIMIT_SIGPENDING | ||
425 | "\0""pending signals" // -i | ||
426 | #endif | ||
427 | #ifdef RLIMIT_MEMLOCK | ||
428 | "\0""max locked memory (kb)" // -l | ||
429 | #endif | ||
430 | #ifdef RLIMIT_RSS | ||
431 | "\0""max memory size (kb)" // -m | ||
432 | #endif | ||
433 | #ifdef RLIMIT_NOFILE | ||
434 | "\0""open files" // -n | ||
435 | #endif | ||
436 | #ifdef RLIMIT_MSGQUEUE | ||
437 | "\0""POSIX message queues (bytes)" // -q | ||
438 | #endif | ||
439 | #ifdef RLIMIT_RTPRIO | ||
440 | "\0""real-time priority" // -r | ||
441 | #endif | ||
442 | #ifdef RLIMIT_STACK | ||
443 | "\0""stack size (kb)" // -s | ||
444 | #endif | ||
445 | #ifdef RLIMIT_CPU | ||
446 | "\0""cpu time (seconds)" // -t | ||
447 | #endif | ||
448 | #ifdef RLIMIT_NPROC | ||
449 | "\0""max user processes" // -u | ||
450 | #endif | ||
451 | #ifdef RLIMIT_AS | ||
452 | "\0""virtual memory (kb)" // -v | ||
453 | #endif | ||
454 | #ifdef RLIMIT_LOCKS | ||
455 | "\0""file locks" // -x | ||
456 | #endif | ||
457 | ; | ||
458 | |||
420 | static const char limit_chars[] ALIGN1 = | 459 | static const char limit_chars[] ALIGN1 = |
421 | "c" | 460 | "c" |
422 | "d" | 461 | "d" |
@@ -607,10 +646,12 @@ shell_builtin_ulimit(char **argv) | |||
607 | if (!(opts & (OPT_hard | OPT_soft))) | 646 | if (!(opts & (OPT_hard | OPT_soft))) |
608 | opts |= (OPT_hard | OPT_soft); | 647 | opts |= (OPT_hard | OPT_soft); |
609 | if (opts & OPT_all) { | 648 | if (opts & OPT_all) { |
649 | const char *help = limits_help; | ||
610 | for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) { | 650 | for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) { |
611 | getrlimit(limits_tbl[i].cmd, &limit); | 651 | getrlimit(limits_tbl[i].cmd, &limit); |
612 | printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]); | 652 | printf("%-32s(-%c) ", help, limit_chars[i]); |
613 | printlim(opts, &limit, &limits_tbl[i]); | 653 | printlim(opts, &limit, &limits_tbl[i]); |
654 | help += strlen(help) + 1; | ||
614 | } | 655 | } |
615 | return EXIT_SUCCESS; | 656 | return EXIT_SUCCESS; |
616 | } | 657 | } |
@@ -641,7 +682,7 @@ shell_builtin_ulimit(char **argv) | |||
641 | getrlimit(limits_tbl[i].cmd, &limit); | 682 | getrlimit(limits_tbl[i].cmd, &limit); |
642 | if (!val_str) { | 683 | if (!val_str) { |
643 | if (opt_cnt > 1) | 684 | if (opt_cnt > 1) |
644 | printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]); | 685 | printf("%-32s(-%c) ", nth_string(limits_help, i), limit_chars[i]); |
645 | printlim(opts, &limit, &limits_tbl[i]); | 686 | printlim(opts, &limit, &limits_tbl[i]); |
646 | } else { | 687 | } else { |
647 | rlim_t val = RLIM_INFINITY; | 688 | rlim_t val = RLIM_INFINITY; |
diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 3fde60a2c..179d5d2a2 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests | |||
@@ -187,6 +187,11 @@ testing "bc { print 1 }" \ | |||
187 | "1" \ | 187 | "1" \ |
188 | "" "{ print 1 }" | 188 | "" "{ print 1 }" |
189 | 189 | ||
190 | testing "bc comparison 1" \ | ||
191 | "bc" \ | ||
192 | "1\n" \ | ||
193 | "" "-10 < -9" | ||
194 | |||
190 | testing "bc nested loops and breaks" \ | 195 | testing "bc nested loops and breaks" \ |
191 | "bc" \ | 196 | "bc" \ |
192 | "\ | 197 | "\ |
diff --git a/testsuite/dc.tests b/testsuite/dc.tests index 8c3af4156..361bc8459 100755 --- a/testsuite/dc.tests +++ b/testsuite/dc.tests | |||
@@ -44,6 +44,41 @@ testing "dc complex without spaces (multiple args)" \ | |||
44 | optional FEATURE_DC_BIG | 44 | optional FEATURE_DC_BIG |
45 | # All tests below depend on FEATURE_DC_BIG | 45 | # All tests below depend on FEATURE_DC_BIG |
46 | 46 | ||
47 | testing "dc: x should execute strings" \ | ||
48 | "dc -e'[40 2 +] x f'" \ | ||
49 | "42\n" \ | ||
50 | "" "" | ||
51 | |||
52 | testing "dc: x should not execute or pop non-strings" \ | ||
53 | "dc -e'42 x f'" \ | ||
54 | "42\n" \ | ||
55 | "" "" | ||
56 | |||
57 | testing "dc: x should work with strings created from a" \ | ||
58 | "dc -e'42 112 a x'" \ | ||
59 | "42\n" \ | ||
60 | "" "" | ||
61 | |||
62 | testing "dc: p should print invalid escapes" \ | ||
63 | "dc -e '[\q] p'" \ | ||
64 | "\\q\n" \ | ||
65 | "" "" | ||
66 | |||
67 | testing "dc: p should print trailing backslashes" \ | ||
68 | "dc -e '[q\] p'" \ | ||
69 | "q\\\\\n" \ | ||
70 | "" "" | ||
71 | |||
72 | testing "dc: p should parse/print single backslashes" \ | ||
73 | "dc -e '[\] p'" \ | ||
74 | "\\\\\n" \ | ||
75 | "" "" | ||
76 | |||
77 | testing "dc: p should print single backslash strings" \ | ||
78 | "dc -e '92 a p'" \ | ||
79 | "\\\\\n" \ | ||
80 | "" "" | ||
81 | |||
47 | testing "dc read" \ | 82 | testing "dc read" \ |
48 | "dc -finput" \ | 83 | "dc -finput" \ |
49 | "2\n9\n1\n" \ | 84 | "2\n9\n1\n" \ |
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index f28d4fdd2..e58cb0fd1 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c | |||
@@ -299,9 +299,6 @@ static int get_boot(enum action what); | |||
299 | static int get_boot(void); | 299 | static int get_boot(void); |
300 | #endif | 300 | #endif |
301 | 301 | ||
302 | #define PLURAL 0 | ||
303 | #define SINGULAR 1 | ||
304 | |||
305 | static sector_t get_start_sect(const struct partition *p); | 302 | static sector_t get_start_sect(const struct partition *p); |
306 | static sector_t get_nr_sects(const struct partition *p); | 303 | static sector_t get_nr_sects(const struct partition *p); |
307 | 304 | ||
@@ -591,18 +588,18 @@ partname(const char *dev, int pno, int lth) | |||
591 | return bufp; | 588 | return bufp; |
592 | } | 589 | } |
593 | 590 | ||
591 | #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_OSF_LABEL | ||
594 | static ALWAYS_INLINE struct partition * | 592 | static ALWAYS_INLINE struct partition * |
595 | get_part_table(int i) | 593 | get_part_table(int i) |
596 | { | 594 | { |
597 | return ptes[i].part_table; | 595 | return ptes[i].part_table; |
598 | } | 596 | } |
597 | #endif | ||
599 | 598 | ||
600 | static const char * | 599 | static ALWAYS_INLINE const char * |
601 | str_units(int n) | 600 | str_units(void) |
602 | { /* n==1: use singular */ | 601 | { |
603 | if (n == 1) | 602 | return display_in_cyl_units ? "cylinder" : "sector"; |
604 | return display_in_cyl_units ? "cylinder" : "sector"; | ||
605 | return display_in_cyl_units ? "cylinders" : "sectors"; | ||
606 | } | 603 | } |
607 | 604 | ||
608 | static int | 605 | static int |
@@ -1778,8 +1775,8 @@ change_units(void) | |||
1778 | { | 1775 | { |
1779 | display_in_cyl_units = !display_in_cyl_units; | 1776 | display_in_cyl_units = !display_in_cyl_units; |
1780 | update_units(); | 1777 | update_units(); |
1781 | printf("Changing display/entry units to %s\n", | 1778 | printf("Changing display/entry units to %ss\n", |
1782 | str_units(PLURAL)); | 1779 | str_units()); |
1783 | } | 1780 | } |
1784 | 1781 | ||
1785 | static void | 1782 | static void |
@@ -2030,8 +2027,7 @@ check_consistency(const struct partition *p, int partition) | |||
2030 | static void | 2027 | static void |
2031 | list_disk_geometry(void) | 2028 | list_disk_geometry(void) |
2032 | { | 2029 | { |
2033 | ullong bytes = ((ullong)total_number_of_sectors << 9); | 2030 | ullong xbytes = total_number_of_sectors / (1024*1024 / 512); |
2034 | ullong xbytes = bytes / (1024*1024); | ||
2035 | char x = 'M'; | 2031 | char x = 'M'; |
2036 | 2032 | ||
2037 | if (xbytes >= 10000) { | 2033 | if (xbytes >= 10000) { |
@@ -2041,11 +2037,12 @@ list_disk_geometry(void) | |||
2041 | } | 2037 | } |
2042 | printf("Disk %s: %llu %cB, %llu bytes, %"SECT_FMT"u sectors\n" | 2038 | printf("Disk %s: %llu %cB, %llu bytes, %"SECT_FMT"u sectors\n" |
2043 | "%u cylinders, %u heads, %u sectors/track\n" | 2039 | "%u cylinders, %u heads, %u sectors/track\n" |
2044 | "Units: %s of %u * %u = %u bytes\n\n", | 2040 | "Units: %ss of %u * %u = %u bytes\n" |
2041 | "\n", | ||
2045 | disk_device, xbytes, x, | 2042 | disk_device, xbytes, x, |
2046 | bytes, total_number_of_sectors, | 2043 | ((ullong)total_number_of_sectors * 512), total_number_of_sectors, |
2047 | g_cylinders, g_heads, g_sectors, | 2044 | g_cylinders, g_heads, g_sectors, |
2048 | str_units(PLURAL), | 2045 | str_units(), |
2049 | units_per_sector, sector_size, units_per_sector * sector_size | 2046 | units_per_sector, sector_size, units_per_sector * sector_size |
2050 | ); | 2047 | ); |
2051 | } | 2048 | } |
@@ -2486,7 +2483,7 @@ add_partition(int n, int sys) | |||
2486 | for (i = 0; i < g_partitions; i++) | 2483 | for (i = 0; i < g_partitions; i++) |
2487 | first[i] = (cround(first[i]) - 1) * units_per_sector; | 2484 | first[i] = (cround(first[i]) - 1) * units_per_sector; |
2488 | 2485 | ||
2489 | snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); | 2486 | snprintf(mesg, sizeof(mesg), "First %s", str_units()); |
2490 | do { | 2487 | do { |
2491 | temp = start; | 2488 | temp = start; |
2492 | for (i = 0; i < g_partitions; i++) { | 2489 | for (i = 0; i < g_partitions; i++) { |
@@ -2548,7 +2545,7 @@ add_partition(int n, int sys) | |||
2548 | } else { | 2545 | } else { |
2549 | snprintf(mesg, sizeof(mesg), | 2546 | snprintf(mesg, sizeof(mesg), |
2550 | "Last %s or +size{,K,M,G,T}", | 2547 | "Last %s or +size{,K,M,G,T}", |
2551 | str_units(SINGULAR) | 2548 | str_units() |
2552 | ); | 2549 | ); |
2553 | stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg); | 2550 | stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg); |
2554 | if (display_in_cyl_units) { | 2551 | if (display_in_cyl_units) { |
diff --git a/util-linux/fdisk_aix.c b/util-linux/fdisk_aix.c index ee5df50e5..0a5e818fe 100644 --- a/util-linux/fdisk_aix.c +++ b/util-linux/fdisk_aix.c | |||
@@ -6,10 +6,10 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | typedef struct { | 8 | typedef struct { |
9 | unsigned int magic; /* expect AIX_LABEL_MAGIC */ | 9 | uint32_t magic; /* expect AIX_LABEL_MAGIC */ |
10 | unsigned int fillbytes1[124]; | 10 | uint32_t fillbytes1[124]; |
11 | unsigned int physical_volume_id; | 11 | uint32_t physical_volume_id; |
12 | unsigned int fillbytes2[124]; | 12 | uint32_t fillbytes2[124]; |
13 | } aix_partition; | 13 | } aix_partition; |
14 | 14 | ||
15 | #define AIX_LABEL_MAGIC 0xc9c2d4c1 | 15 | #define AIX_LABEL_MAGIC 0xc9c2d4c1 |
@@ -17,20 +17,18 @@ typedef struct { | |||
17 | #define AIX_INFO_MAGIC 0x00072959 | 17 | #define AIX_INFO_MAGIC 0x00072959 |
18 | #define AIX_INFO_MAGIC_SWAPPED 0x59290700 | 18 | #define AIX_INFO_MAGIC_SWAPPED 0x59290700 |
19 | 19 | ||
20 | #define aixlabel ((aix_partition *)MBRbuffer) | ||
21 | |||
22 | |||
23 | /* | 20 | /* |
24 | Changes: | 21 | * Changes: |
25 | * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 22 | * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
26 | * Internationalization | 23 | * Internationalization |
27 | * | 24 | * |
28 | * 2003-03-20 Phillip Kesling <pkesling@sgi.com> | 25 | * 2003-03-20 Phillip Kesling <pkesling@sgi.com> |
29 | * Some fixes | 26 | * Some fixes |
30 | */ | 27 | */ |
31 | 28 | ||
32 | static smallint aix_other_endian; /* bool */ | 29 | // Write-only vars, unfinished code? |
33 | static smallint aix_volumes = 1; /* max 15 */ | 30 | //static smallint aix_other_endian; /* bool */ |
31 | //static smallint aix_volumes = 1; /* max 15 */ | ||
34 | 32 | ||
35 | /* | 33 | /* |
36 | * only dealing with free blocks here | 34 | * only dealing with free blocks here |
@@ -54,18 +52,20 @@ aix_info(void) | |||
54 | static int | 52 | static int |
55 | check_aix_label(void) | 53 | check_aix_label(void) |
56 | { | 54 | { |
55 | aix_partition *aixlabel = (void*)MBRbuffer; | ||
56 | |||
57 | if (aixlabel->magic != AIX_LABEL_MAGIC | 57 | if (aixlabel->magic != AIX_LABEL_MAGIC |
58 | && aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED | 58 | && aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED |
59 | ) { | 59 | ) { |
60 | current_label_type = 0; | 60 | current_label_type = LABEL_DOS; |
61 | aix_other_endian = 0; | 61 | // aix_other_endian = 0; |
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED); | 64 | // aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED); |
65 | update_units(); | 65 | update_units(); |
66 | current_label_type = LABEL_AIX; | 66 | current_label_type = LABEL_AIX; |
67 | g_partitions = 1016; | 67 | g_partitions = 1016; |
68 | aix_volumes = 15; | 68 | // aix_volumes = 15; |
69 | aix_info(); | 69 | aix_info(); |
70 | /*aix_nolabel();*/ /* %% */ | 70 | /*aix_nolabel();*/ /* %% */ |
71 | /*aix_label = 1;*/ /* %% */ | 71 | /*aix_label = 1;*/ /* %% */ |
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c index dbe889f7c..e884e3dc1 100644 --- a/util-linux/fdisk_gpt.c +++ b/util-linux/fdisk_gpt.c | |||
@@ -161,7 +161,7 @@ check_gpt_label(void) | |||
161 | if (!valid_part_table_flag(MBRbuffer) | 161 | if (!valid_part_table_flag(MBRbuffer) |
162 | || first->sys_ind != LEGACY_GPT_TYPE | 162 | || first->sys_ind != LEGACY_GPT_TYPE |
163 | ) { | 163 | ) { |
164 | current_label_type = 0; | 164 | current_label_type = LABEL_DOS; |
165 | return 0; | 165 | return 0; |
166 | } | 166 | } |
167 | 167 | ||
@@ -171,7 +171,7 @@ check_gpt_label(void) | |||
171 | gpt_hdr = (void *)pe.sectorbuffer; | 171 | gpt_hdr = (void *)pe.sectorbuffer; |
172 | 172 | ||
173 | if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { | 173 | if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { |
174 | current_label_type = 0; | 174 | current_label_type = LABEL_DOS; |
175 | return 0; | 175 | return 0; |
176 | } | 176 | } |
177 | 177 | ||
@@ -194,7 +194,7 @@ check_gpt_label(void) | |||
194 | || SWAP_LE32(gpt_hdr->hdr_size) > sector_size | 194 | || SWAP_LE32(gpt_hdr->hdr_size) > sector_size |
195 | ) { | 195 | ) { |
196 | puts("\nwarning: unable to parse GPT disklabel\n"); | 196 | puts("\nwarning: unable to parse GPT disklabel\n"); |
197 | current_label_type = 0; | 197 | current_label_type = LABEL_DOS; |
198 | return 0; | 198 | return 0; |
199 | } | 199 | } |
200 | 200 | ||
diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c index 1328c1fcd..92180b2bc 100644 --- a/util-linux/fdisk_osf.c +++ b/util-linux/fdisk_osf.c | |||
@@ -470,7 +470,7 @@ xbsd_new_part(void) | |||
470 | end = xbsd_dlabel.d_secperunit - 1; | 470 | end = xbsd_dlabel.d_secperunit - 1; |
471 | #endif | 471 | #endif |
472 | 472 | ||
473 | snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); | 473 | snprintf(mesg, sizeof(mesg), "First %s", str_units()); |
474 | begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end), | 474 | begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end), |
475 | 0, mesg); | 475 | 0, mesg); |
476 | 476 | ||
@@ -478,7 +478,7 @@ xbsd_new_part(void) | |||
478 | begin = (begin - 1) * xbsd_dlabel.d_secpercyl; | 478 | begin = (begin - 1) * xbsd_dlabel.d_secpercyl; |
479 | 479 | ||
480 | snprintf(mesg, sizeof(mesg), "Last %s or +size or +sizeM or +sizeK", | 480 | snprintf(mesg, sizeof(mesg), "Last %s or +size or +sizeM or +sizeK", |
481 | str_units(SINGULAR)); | 481 | str_units()); |
482 | end = read_int(bsd_cround(begin), bsd_cround(end), bsd_cround(end), | 482 | end = read_int(bsd_cround(begin), bsd_cround(end), bsd_cround(end), |
483 | bsd_cround(begin), mesg); | 483 | bsd_cround(begin), mesg); |
484 | 484 | ||
diff --git a/util-linux/fdisk_sgi.c b/util-linux/fdisk_sgi.c index 0e5491a19..c90c801e2 100644 --- a/util-linux/fdisk_sgi.c +++ b/util-linux/fdisk_sgi.c | |||
@@ -295,19 +295,19 @@ sgi_list_table(int xtra) | |||
295 | "%u cylinders, %u physical cylinders\n" | 295 | "%u cylinders, %u physical cylinders\n" |
296 | "%u extra sects/cyl, interleave %u:1\n" | 296 | "%u extra sects/cyl, interleave %u:1\n" |
297 | "%s\n" | 297 | "%s\n" |
298 | "Units = %s of %u * 512 bytes\n\n", | 298 | "Units = %ss of %u * 512 bytes\n\n", |
299 | disk_device, g_heads, g_sectors, g_cylinders, | 299 | disk_device, g_heads, g_sectors, g_cylinders, |
300 | SGI_SSWAP16(sgiparam.pcylcount), | 300 | SGI_SSWAP16(sgiparam.pcylcount), |
301 | SGI_SSWAP16(sgiparam.sparecyl), | 301 | SGI_SSWAP16(sgiparam.sparecyl), |
302 | SGI_SSWAP16(sgiparam.ilfact), | 302 | SGI_SSWAP16(sgiparam.ilfact), |
303 | (char *)sgilabel, | 303 | (char *)sgilabel, |
304 | str_units(PLURAL), units_per_sector); | 304 | str_units(), units_per_sector); |
305 | } else { | 305 | } else { |
306 | printf("\nDisk %s (SGI disk label): " | 306 | printf("\nDisk %s (SGI disk label): " |
307 | "%u heads, %u sectors, %u cylinders\n" | 307 | "%u heads, %u sectors, %u cylinders\n" |
308 | "Units = %s of %u * 512 bytes\n\n", | 308 | "Units = %ss of %u * 512 bytes\n\n", |
309 | disk_device, g_heads, g_sectors, g_cylinders, | 309 | disk_device, g_heads, g_sectors, g_cylinders, |
310 | str_units(PLURAL), units_per_sector ); | 310 | str_units(), units_per_sector ); |
311 | } | 311 | } |
312 | 312 | ||
313 | w = strlen(disk_device); | 313 | w = strlen(disk_device); |
@@ -720,7 +720,7 @@ sgi_add_partition(int n, int sys) | |||
720 | printf("You got a partition overlap on the disk. Fix it first!\n"); | 720 | printf("You got a partition overlap on the disk. Fix it first!\n"); |
721 | return; | 721 | return; |
722 | } | 722 | } |
723 | snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); | 723 | snprintf(mesg, sizeof(mesg), "First %s", str_units()); |
724 | while (1) { | 724 | while (1) { |
725 | if (sys == SGI_VOLUME) { | 725 | if (sys == SGI_VOLUME) { |
726 | last = sgi_get_lastblock(); | 726 | last = sgi_get_lastblock(); |
@@ -746,7 +746,7 @@ sgi_add_partition(int n, int sys) | |||
746 | printf("You will get a partition overlap on the disk. " | 746 | printf("You will get a partition overlap on the disk. " |
747 | "Fix it first!\n"); | 747 | "Fix it first!\n"); |
748 | } | 748 | } |
749 | snprintf(mesg, sizeof(mesg), " Last %s", str_units(SINGULAR)); | 749 | snprintf(mesg, sizeof(mesg), " Last %s", str_units()); |
750 | last = read_int(scround(first), scround(last)-1, scround(last)-1, | 750 | last = read_int(scround(first), scround(last)-1, scround(last)-1, |
751 | scround(first), mesg)+1; | 751 | scround(first), mesg)+1; |
752 | if (display_in_cyl_units) | 752 | if (display_in_cyl_units) |
diff --git a/util-linux/fdisk_sun.c b/util-linux/fdisk_sun.c index 3697a69b9..29d7c283a 100644 --- a/util-linux/fdisk_sun.c +++ b/util-linux/fdisk_sun.c | |||
@@ -491,7 +491,7 @@ add_sun_partition(int n, int sys) | |||
491 | return; | 491 | return; |
492 | } | 492 | } |
493 | } | 493 | } |
494 | snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); | 494 | snprintf(mesg, sizeof(mesg), "First %s", str_units()); |
495 | while (1) { | 495 | while (1) { |
496 | if (whole_disk) | 496 | if (whole_disk) |
497 | first = read_int(0, 0, 0, 0, mesg); | 497 | first = read_int(0, 0, 0, 0, mesg); |
@@ -546,7 +546,7 @@ and is of type 'Whole disk'\n"); | |||
546 | } | 546 | } |
547 | snprintf(mesg, sizeof(mesg), | 547 | snprintf(mesg, sizeof(mesg), |
548 | "Last %s or +size or +sizeM or +sizeK", | 548 | "Last %s or +size or +sizeM or +sizeK", |
549 | str_units(SINGULAR)); | 549 | str_units()); |
550 | if (whole_disk) | 550 | if (whole_disk) |
551 | last = read_int(scround(stop2), scround(stop2), scround(stop2), | 551 | last = read_int(scround(stop2), scround(stop2), scround(stop2), |
552 | 0, mesg); | 552 | 0, mesg); |
@@ -567,8 +567,8 @@ and is of type 'Whole disk'\n"); | |||
567 | "You haven't covered the whole disk with the 3rd partition,\n" | 567 | "You haven't covered the whole disk with the 3rd partition,\n" |
568 | "but your value %u %s covers some other partition.\n" | 568 | "but your value %u %s covers some other partition.\n" |
569 | "Your entry has been changed to %u %s\n", | 569 | "Your entry has been changed to %u %s\n", |
570 | scround(last), str_units(SINGULAR), | 570 | scround(last), str_units(), |
571 | scround(stop), str_units(SINGULAR)); | 571 | scround(stop), str_units()); |
572 | last = stop; | 572 | last = stop; |
573 | } | 573 | } |
574 | } else if (!whole_disk && last > stop) | 574 | } else if (!whole_disk && last > stop) |
@@ -636,20 +636,20 @@ sun_list_table(int xtra) | |||
636 | "%u cylinders, %u alternate cylinders, %u physical cylinders\n" | 636 | "%u cylinders, %u alternate cylinders, %u physical cylinders\n" |
637 | "%u extra sects/cyl, interleave %u:1\n" | 637 | "%u extra sects/cyl, interleave %u:1\n" |
638 | "%s\n" | 638 | "%s\n" |
639 | "Units = %s of %u * 512 bytes\n\n", | 639 | "Units = %ss of %u * 512 bytes\n\n", |
640 | disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed), | 640 | disk_device, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed), |
641 | g_cylinders, SUN_SSWAP16(sunlabel->nacyl), | 641 | g_cylinders, SUN_SSWAP16(sunlabel->nacyl), |
642 | SUN_SSWAP16(sunlabel->pcylcount), | 642 | SUN_SSWAP16(sunlabel->pcylcount), |
643 | SUN_SSWAP16(sunlabel->sparecyl), | 643 | SUN_SSWAP16(sunlabel->sparecyl), |
644 | SUN_SSWAP16(sunlabel->ilfact), | 644 | SUN_SSWAP16(sunlabel->ilfact), |
645 | (char *)sunlabel, | 645 | (char *)sunlabel, |
646 | str_units(PLURAL), units_per_sector); | 646 | str_units(), units_per_sector); |
647 | else | 647 | else |
648 | printf( | 648 | printf( |
649 | "\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n" | 649 | "\nDisk %s (Sun disk label): %u heads, %u sectors, %u cylinders\n" |
650 | "Units = %s of %u * 512 bytes\n\n", | 650 | "Units = %ss of %u * 512 bytes\n\n", |
651 | disk_device, g_heads, g_sectors, g_cylinders, | 651 | disk_device, g_heads, g_sectors, g_cylinders, |
652 | str_units(PLURAL), units_per_sector); | 652 | str_units(), units_per_sector); |
653 | 653 | ||
654 | printf("%*s Flag Start End Blocks Id System\n", | 654 | printf("%*s Flag Start End Blocks Id System\n", |
655 | w + 1, "Device"); | 655 | w + 1, "Device"); |
diff --git a/util-linux/rdate.c b/util-linux/rdate.c index 41aade5ea..bb1dc519a 100644 --- a/util-linux/rdate.c +++ b/util-linux/rdate.c | |||
@@ -95,9 +95,13 @@ int rdate_main(int argc UNUSED_PARAM, char **argv) | |||
95 | if (!(flags & 2)) { /* no -p (-s may be present) */ | 95 | if (!(flags & 2)) { /* no -p (-s may be present) */ |
96 | if (time(NULL) == remote_time) | 96 | if (time(NULL) == remote_time) |
97 | bb_simple_error_msg("current time matches remote time"); | 97 | bb_simple_error_msg("current time matches remote time"); |
98 | else | 98 | else { |
99 | if (stime(&remote_time) < 0) | 99 | struct timespec ts; |
100 | ts.tv_sec = remote_time; | ||
101 | ts.tv_nsec = 0; | ||
102 | if (clock_settime(CLOCK_REALTIME, &ts) < 0) | ||
100 | bb_simple_perror_msg_and_die("can't set time of day"); | 103 | bb_simple_perror_msg_and_die("can't set time of day"); |
104 | } | ||
101 | } | 105 | } |
102 | 106 | ||
103 | if (flags != 1) /* not lone -s */ | 107 | if (flags != 1) /* not lone -s */ |
diff --git a/util-linux/taskset.c b/util-linux/taskset.c index ed8878ad4..b542f8c83 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c | |||
@@ -20,6 +20,14 @@ | |||
20 | //config: Needed for machines with more than 32-64 CPUs: | 20 | //config: Needed for machines with more than 32-64 CPUs: |
21 | //config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long | 21 | //config: affinity parameter 0xHHHHHHHHHHHHHHHHHHHH can be arbitrarily long |
22 | //config: in this case. Otherwise, it is limited to sizeof(long). | 22 | //config: in this case. Otherwise, it is limited to sizeof(long). |
23 | //config: | ||
24 | //config:config FEATURE_TASKSET_CPULIST | ||
25 | //config: bool "CPU list support (-c option)" | ||
26 | //config: default y | ||
27 | //config: depends on FEATURE_TASKSET_FANCY | ||
28 | //config: help | ||
29 | //config: Add support for taking/printing affinity as CPU list when '-c' | ||
30 | //config: option is used. For example, it prints '0-3,7' instead of mask '8f'. | ||
23 | 31 | ||
24 | //applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset)) | 32 | //applet:IF_TASKSET(APPLET_NOEXEC(taskset, taskset, BB_DIR_USR_BIN, BB_SUID_DROP, taskset)) |
25 | 33 | ||
@@ -108,26 +116,120 @@ static unsigned long *get_aff(int pid, unsigned *sz) | |||
108 | return mask; | 116 | return mask; |
109 | } | 117 | } |
110 | 118 | ||
119 | #if ENABLE_FEATURE_TASKSET_CPULIST | ||
120 | /* | ||
121 | * Parse the CPU list and set the mask accordingly. | ||
122 | * | ||
123 | * The list element can be either a CPU index or a range of CPU indices. | ||
124 | * Example: "1,3,5-7". Stride can be specified: "0-7:2" is "0,2,4,6". | ||
125 | * Note: leading and trailing whitespace is not allowed. | ||
126 | * util-linux 2.31 allows leading and sometimes trailing whitespace: | ||
127 | * ok: taskset -c ' 1, 2' | ||
128 | * ok: taskset -c ' 1 , 2' | ||
129 | * ok: taskset -c ' 1-7: 2 ,8' | ||
130 | * not ok: taskset -c ' 1 ' | ||
131 | * not ok: taskset -c ' 1-7: 2 ' | ||
132 | */ | ||
133 | static void parse_cpulist(ul *mask, unsigned max, char *s) | ||
134 | { | ||
135 | char *aff = s; | ||
136 | for (;;) { | ||
137 | unsigned bit, end; | ||
138 | unsigned stride = 1; | ||
139 | |||
140 | bit = end = bb_strtou(s, &s, 10); | ||
141 | if (*s == '-') { | ||
142 | s++; | ||
143 | end = bb_strtou(s, &s, 10); | ||
144 | if (*s == ':') { | ||
145 | s++; | ||
146 | stride = bb_strtou(s, &s, 10); | ||
147 | } | ||
148 | } | ||
149 | if ((*s != ',' && *s != '\0') | ||
150 | || bit > end | ||
151 | || end == UINT_MAX /* bb_strtou returns this on malformed / ERANGE numbers */ | ||
152 | || (stride - 1) > (UINT_MAX / 4) | ||
153 | /* disallow 0, malformed input, and too large stride prone to overflows */ | ||
154 | ) { | ||
155 | bb_error_msg_and_die("bad affinity '%s'", aff); | ||
156 | } | ||
157 | while (bit <= end && bit < max) { | ||
158 | mask[bit / BITS_UL] |= (1UL << (bit & MASK_UL)); | ||
159 | bit += stride; | ||
160 | } | ||
161 | if (*s == '\0') | ||
162 | break; | ||
163 | s++; | ||
164 | } | ||
165 | } | ||
166 | static void print_cpulist(const ul *mask, unsigned mask_size_in_bytes) | ||
167 | { | ||
168 | const ul *mask_end; | ||
169 | const char *delim; | ||
170 | unsigned pos; | ||
171 | ul bit; | ||
172 | |||
173 | mask_end = mask + mask_size_in_bytes / sizeof(mask[0]); | ||
174 | delim = ""; | ||
175 | pos = 0; | ||
176 | bit = 1; | ||
177 | for (;;) { | ||
178 | if (*mask & bit) { | ||
179 | unsigned onebit = pos + 1; | ||
180 | printf("%s%u", delim, pos); | ||
181 | do { | ||
182 | pos++; | ||
183 | bit <<= 1; | ||
184 | if (bit == 0) { | ||
185 | mask++; | ||
186 | if (mask >= mask_end) | ||
187 | break; | ||
188 | bit = 1; | ||
189 | } | ||
190 | } while (*mask & bit); | ||
191 | if (onebit != pos) | ||
192 | printf("-%u", pos - 1); | ||
193 | delim = ","; | ||
194 | } | ||
195 | pos++; | ||
196 | bit <<= 1; | ||
197 | if (bit == 0) { | ||
198 | mask++; | ||
199 | if (mask >= mask_end) | ||
200 | break; | ||
201 | bit = 1; | ||
202 | } | ||
203 | } | ||
204 | bb_putchar('\n'); | ||
205 | } | ||
206 | #endif | ||
207 | |||
111 | int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 208 | int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
112 | int taskset_main(int argc UNUSED_PARAM, char **argv) | 209 | int taskset_main(int argc UNUSED_PARAM, char **argv) |
113 | { | 210 | { |
114 | ul *mask; | 211 | ul *mask; |
115 | unsigned mask_size_in_bytes; | 212 | unsigned mask_size_in_bytes; |
116 | pid_t pid = 0; | 213 | pid_t pid = 0; |
117 | unsigned opt_p; | ||
118 | const char *current_new; | 214 | const char *current_new; |
119 | char *aff; | 215 | char *aff; |
216 | unsigned opts; | ||
217 | enum { | ||
218 | OPT_p = 1 << 0, | ||
219 | OPT_c = (1 << 1) * ENABLE_FEATURE_TASKSET_CPULIST, | ||
220 | }; | ||
120 | 221 | ||
121 | /* NB: we mimic util-linux's taskset: -p does not take | 222 | /* NB: we mimic util-linux's taskset: -p does not take |
122 | * an argument, i.e., "-pN" is NOT valid, only "-p N"! | 223 | * an argument, i.e., "-pN" is NOT valid, only "-p N"! |
123 | * Indeed, util-linux-2.13-pre7 uses: | 224 | * Indeed, util-linux-2.13-pre7 uses: |
124 | * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ | 225 | * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ |
125 | 226 | ||
126 | opt_p = getopt32(argv, "^+" "p" "\0" "-1" /* at least 1 arg */); | 227 | opts = getopt32(argv, "^+" "p"IF_FEATURE_TASKSET_CPULIST("c") |
228 | "\0" "-1" /* at least 1 arg */); | ||
127 | argv += optind; | 229 | argv += optind; |
128 | 230 | ||
129 | aff = *argv++; | 231 | aff = *argv++; |
130 | if (opt_p) { | 232 | if (opts & OPT_p) { |
131 | char *pid_str = aff; | 233 | char *pid_str = aff; |
132 | if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */ | 234 | if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */ |
133 | pid_str = *argv; /* NB: *argv != NULL in this case */ | 235 | pid_str = *argv; /* NB: *argv != NULL in this case */ |
@@ -144,8 +246,14 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) | |||
144 | current_new = "current"; | 246 | current_new = "current"; |
145 | print_aff: | 247 | print_aff: |
146 | mask = get_aff(pid, &mask_size_in_bytes); | 248 | mask = get_aff(pid, &mask_size_in_bytes); |
147 | if (opt_p) { | 249 | if (opts & OPT_p) { |
148 | printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", | 250 | #if ENABLE_FEATURE_TASKSET_CPULIST |
251 | if (opts & OPT_c) { | ||
252 | printf("pid %d's %s affinity list: ", pid, current_new); | ||
253 | print_cpulist(mask, mask_size_in_bytes); | ||
254 | } else | ||
255 | #endif | ||
256 | printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", | ||
149 | pid, current_new, from_mask(mask, mask_size_in_bytes)); | 257 | pid, current_new, from_mask(mask, mask_size_in_bytes)); |
150 | if (*argv == NULL) { | 258 | if (*argv == NULL) { |
151 | /* Either it was just "-p <pid>", | 259 | /* Either it was just "-p <pid>", |
@@ -158,17 +266,27 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) | |||
158 | } | 266 | } |
159 | memset(mask, 0, mask_size_in_bytes); | 267 | memset(mask, 0, mask_size_in_bytes); |
160 | 268 | ||
161 | /* Affinity was specified, translate it into mask */ | ||
162 | /* it is always in hex, skip "0x" if it exists */ | ||
163 | if (aff[0] == '0' && (aff[1]|0x20) == 'x') | ||
164 | aff += 2; | ||
165 | |||
166 | if (!ENABLE_FEATURE_TASKSET_FANCY) { | 269 | if (!ENABLE_FEATURE_TASKSET_FANCY) { |
270 | /* Affinity was specified, translate it into mask */ | ||
271 | /* it is always in hex, skip "0x" if it exists */ | ||
272 | if (aff[0] == '0' && (aff[1]|0x20) == 'x') | ||
273 | aff += 2; | ||
167 | mask[0] = xstrtoul(aff, 16); | 274 | mask[0] = xstrtoul(aff, 16); |
168 | } else { | 275 | } |
276 | #if ENABLE_FEATURE_TASKSET_CPULIST | ||
277 | else if (opts & OPT_c) { | ||
278 | parse_cpulist(mask, mask_size_in_bytes * 8, aff); | ||
279 | } | ||
280 | #endif | ||
281 | else { | ||
169 | unsigned i; | 282 | unsigned i; |
170 | char *last_char; | 283 | char *last_char; |
171 | 284 | ||
285 | /* Affinity was specified, translate it into mask */ | ||
286 | /* it is always in hex, skip "0x" if it exists */ | ||
287 | if (aff[0] == '0' && (aff[1]|0x20) == 'x') | ||
288 | aff += 2; | ||
289 | |||
172 | i = 0; /* bit pos in mask[] */ | 290 | i = 0; /* bit pos in mask[] */ |
173 | 291 | ||
174 | /* aff is ASCII hex string, accept very long masks in this form. | 292 | /* aff is ASCII hex string, accept very long masks in this form. |