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. |
