diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2013-06-29 17:00:22 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2013-06-29 17:00:22 +0200 |
commit | e73f3c1d3d83699b723251f7e6a981021ce75475 (patch) | |
tree | e0272460fb0dbbe33412a09534c088634fd3ed24 | |
parent | 64406a92a054f884747553011d4529103e2900e4 (diff) | |
download | busybox-w32-1_21_1.tar.gz busybox-w32-1_21_1.tar.bz2 busybox-w32-1_21_1.zip |
Apply post-1.21.0 patches, bump version to 1.21.11_21_1
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | archival/libarchive/decompress_unxz.c | 47 | ||||
-rw-r--r-- | include/platform.h | 2 | ||||
-rw-r--r-- | util-linux/mdev.c | 402 | ||||
-rw-r--r-- | util-linux/volume_id/ntfs.c | 2 |
5 files changed, 341 insertions, 114 deletions
@@ -1,6 +1,6 @@ | |||
1 | VERSION = 1 | 1 | VERSION = 1 |
2 | PATCHLEVEL = 21 | 2 | PATCHLEVEL = 21 |
3 | SUBLEVEL = 0 | 3 | SUBLEVEL = 1 |
4 | EXTRAVERSION = | 4 | EXTRAVERSION = |
5 | NAME = Unnamed | 5 | NAME = Unnamed |
6 | 6 | ||
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index 79b48a152..986b7b191 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c | |||
@@ -30,8 +30,8 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) | |||
30 | /* We use arch-optimized unaligned accessors */ | 30 | /* We use arch-optimized unaligned accessors */ |
31 | #define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) | 31 | #define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) |
32 | #define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) | 32 | #define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) |
33 | #define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) | 33 | #define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val)) |
34 | #define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) | 34 | #define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val)) |
35 | 35 | ||
36 | #include "unxz/xz_dec_bcj.c" | 36 | #include "unxz/xz_dec_bcj.c" |
37 | #include "unxz/xz_dec_lzma2.c" | 37 | #include "unxz/xz_dec_lzma2.c" |
@@ -40,6 +40,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) | |||
40 | IF_DESKTOP(long long) int FAST_FUNC | 40 | IF_DESKTOP(long long) int FAST_FUNC |
41 | unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) | 41 | unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) |
42 | { | 42 | { |
43 | enum xz_ret xz_result; | ||
43 | struct xz_buf iobuf; | 44 | struct xz_buf iobuf; |
44 | struct xz_dec *state; | 45 | struct xz_dec *state; |
45 | unsigned char *membuf; | 46 | unsigned char *membuf; |
@@ -63,9 +64,8 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) | |||
63 | /* Limit memory usage to about 64 MiB. */ | 64 | /* Limit memory usage to about 64 MiB. */ |
64 | state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); | 65 | state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); |
65 | 66 | ||
67 | xz_result = X_OK; | ||
66 | while (1) { | 68 | while (1) { |
67 | enum xz_ret r; | ||
68 | |||
69 | if (iobuf.in_pos == iobuf.in_size) { | 69 | if (iobuf.in_pos == iobuf.in_size) { |
70 | int rd = safe_read(src_fd, membuf, BUFSIZ); | 70 | int rd = safe_read(src_fd, membuf, BUFSIZ); |
71 | if (rd < 0) { | 71 | if (rd < 0) { |
@@ -73,28 +73,57 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) | |||
73 | total = -1; | 73 | total = -1; |
74 | break; | 74 | break; |
75 | } | 75 | } |
76 | if (rd == 0 && xz_result == XZ_STREAM_END) | ||
77 | break; | ||
76 | iobuf.in_size = rd; | 78 | iobuf.in_size = rd; |
77 | iobuf.in_pos = 0; | 79 | iobuf.in_pos = 0; |
78 | } | 80 | } |
81 | if (xz_result == XZ_STREAM_END) { | ||
82 | /* | ||
83 | * Try to start decoding next concatenated stream. | ||
84 | * Stream padding must always be a multiple of four | ||
85 | * bytes to preserve four-byte alignment. To keep the | ||
86 | * code slightly smaller, we aren't as strict here as | ||
87 | * the .xz spec requires. We just skip all zero-bytes | ||
88 | * without checking the alignment and thus can accept | ||
89 | * files that aren't valid, e.g. the XZ utils test | ||
90 | * files bad-0pad-empty.xz and bad-0catpad-empty.xz. | ||
91 | */ | ||
92 | do { | ||
93 | if (membuf[iobuf.in_pos] != 0) { | ||
94 | xz_dec_reset(state); | ||
95 | goto do_run; | ||
96 | } | ||
97 | iobuf.in_pos++; | ||
98 | } while (iobuf.in_pos < iobuf.in_size); | ||
99 | } | ||
100 | do_run: | ||
79 | // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", | 101 | // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", |
80 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); | 102 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); |
81 | r = xz_dec_run(state, &iobuf); | 103 | xz_result = xz_dec_run(state, &iobuf); |
82 | // bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", | 104 | // bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", |
83 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, r); | 105 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, xz_result); |
84 | if (iobuf.out_pos) { | 106 | if (iobuf.out_pos) { |
85 | xwrite(dst_fd, iobuf.out, iobuf.out_pos); | 107 | xwrite(dst_fd, iobuf.out, iobuf.out_pos); |
86 | IF_DESKTOP(total += iobuf.out_pos;) | 108 | IF_DESKTOP(total += iobuf.out_pos;) |
87 | iobuf.out_pos = 0; | 109 | iobuf.out_pos = 0; |
88 | } | 110 | } |
89 | if (r == XZ_STREAM_END) { | 111 | if (xz_result == XZ_STREAM_END) { |
90 | break; | 112 | /* |
113 | * Can just "break;" here, if not for concatenated | ||
114 | * .xz streams. | ||
115 | * Checking for padding may require buffer | ||
116 | * replenishment. Can't do it here. | ||
117 | */ | ||
118 | continue; | ||
91 | } | 119 | } |
92 | if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { | 120 | if (xz_result != XZ_OK && xz_result != XZ_UNSUPPORTED_CHECK) { |
93 | bb_error_msg("corrupted data"); | 121 | bb_error_msg("corrupted data"); |
94 | total = -1; | 122 | total = -1; |
95 | break; | 123 | break; |
96 | } | 124 | } |
97 | } | 125 | } |
126 | |||
98 | xz_dec_end(state); | 127 | xz_dec_end(state); |
99 | free(membuf); | 128 | free(membuf); |
100 | 129 | ||
diff --git a/include/platform.h b/include/platform.h index 128230658..f4deb30c0 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -228,7 +228,7 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; | |||
228 | # define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) | 228 | # define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) |
229 | # define move_to_unaligned16(u16p, v) do { \ | 229 | # define move_to_unaligned16(u16p, v) do { \ |
230 | uint16_t __t = (v); \ | 230 | uint16_t __t = (v); \ |
231 | memcpy((u16p), &__t, 4); \ | 231 | memcpy((u16p), &__t, 2); \ |
232 | } while (0) | 232 | } while (0) |
233 | # define move_to_unaligned32(u32p, v) do { \ | 233 | # define move_to_unaligned32(u32p, v) do { \ |
234 | uint32_t __t = (v); \ | 234 | uint32_t __t = (v); \ |
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 75de14ff1..3d4e135ba 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -80,7 +80,7 @@ | |||
80 | //usage: IF_FEATURE_MDEV_CONF( | 80 | //usage: IF_FEATURE_MDEV_CONF( |
81 | //usage: "\n" | 81 | //usage: "\n" |
82 | //usage: "It uses /etc/mdev.conf with lines\n" | 82 | //usage: "It uses /etc/mdev.conf with lines\n" |
83 | //usage: " [-]DEVNAME UID:GID PERM" | 83 | //usage: " [-][ENV=regex;]...DEVNAME UID:GID PERM" |
84 | //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") | 84 | //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") |
85 | //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") | 85 | //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") |
86 | //usage: "\n" | 86 | //usage: "\n" |
@@ -230,9 +230,34 @@ | |||
230 | * SUBSYSTEM=block | 230 | * SUBSYSTEM=block |
231 | */ | 231 | */ |
232 | 232 | ||
233 | static const char keywords[] ALIGN1 = "add\0remove\0change\0"; | 233 | #define DEBUG_LVL 2 |
234 | |||
235 | #if DEBUG_LVL >= 1 | ||
236 | # define dbg1(...) do { if (G.verbose) bb_error_msg(__VA_ARGS__); } while(0) | ||
237 | #else | ||
238 | # define dbg1(...) ((void)0) | ||
239 | #endif | ||
240 | #if DEBUG_LVL >= 2 | ||
241 | # define dbg2(...) do { if (G.verbose >= 2) bb_error_msg(__VA_ARGS__); } while(0) | ||
242 | #else | ||
243 | # define dbg2(...) ((void)0) | ||
244 | #endif | ||
245 | #if DEBUG_LVL >= 3 | ||
246 | # define dbg3(...) do { if (G.verbose >= 3) bb_error_msg(__VA_ARGS__); } while(0) | ||
247 | #else | ||
248 | # define dbg3(...) ((void)0) | ||
249 | #endif | ||
250 | |||
251 | |||
252 | static const char keywords[] ALIGN1 = "add\0remove\0"; // "change\0" | ||
234 | enum { OP_add, OP_remove }; | 253 | enum { OP_add, OP_remove }; |
235 | 254 | ||
255 | struct envmatch { | ||
256 | struct envmatch *next; | ||
257 | char *envname; | ||
258 | regex_t match; | ||
259 | }; | ||
260 | |||
236 | struct rule { | 261 | struct rule { |
237 | bool keep_matching; | 262 | bool keep_matching; |
238 | bool regex_compiled; | 263 | bool regex_compiled; |
@@ -243,12 +268,14 @@ struct rule { | |||
243 | char *ren_mov; | 268 | char *ren_mov; |
244 | IF_FEATURE_MDEV_EXEC(char *r_cmd;) | 269 | IF_FEATURE_MDEV_EXEC(char *r_cmd;) |
245 | regex_t match; | 270 | regex_t match; |
271 | struct envmatch *envmatch; | ||
246 | }; | 272 | }; |
247 | 273 | ||
248 | struct globals { | 274 | struct globals { |
249 | int root_major, root_minor; | 275 | int root_major, root_minor; |
250 | smallint verbose; | 276 | smallint verbose; |
251 | char *subsystem; | 277 | char *subsystem; |
278 | char *subsys_env; /* for putenv("SUBSYSTEM=subsystem") */ | ||
252 | #if ENABLE_FEATURE_MDEV_CONF | 279 | #if ENABLE_FEATURE_MDEV_CONF |
253 | const char *filename; | 280 | const char *filename; |
254 | parser_t *parser; | 281 | parser_t *parser; |
@@ -256,6 +283,7 @@ struct globals { | |||
256 | unsigned rule_idx; | 283 | unsigned rule_idx; |
257 | #endif | 284 | #endif |
258 | struct rule cur_rule; | 285 | struct rule cur_rule; |
286 | char timestr[sizeof("60.123456")]; | ||
259 | } FIX_ALIASING; | 287 | } FIX_ALIASING; |
260 | #define G (*(struct globals*)&bb_common_bufsiz1) | 288 | #define G (*(struct globals*)&bb_common_bufsiz1) |
261 | #define INIT_G() do { \ | 289 | #define INIT_G() do { \ |
@@ -267,15 +295,8 @@ struct globals { | |||
267 | /* Prevent infinite loops in /sys symlinks */ | 295 | /* Prevent infinite loops in /sys symlinks */ |
268 | #define MAX_SYSFS_DEPTH 3 | 296 | #define MAX_SYSFS_DEPTH 3 |
269 | 297 | ||
270 | /* We use additional 64+ bytes in make_device() */ | 298 | /* We use additional bytes in make_device() */ |
271 | #define SCRATCH_SIZE 80 | 299 | #define SCRATCH_SIZE 128 |
272 | |||
273 | #if 0 | ||
274 | # define dbg(...) bb_error_msg(__VA_ARGS__) | ||
275 | #else | ||
276 | # define dbg(...) ((void)0) | ||
277 | #endif | ||
278 | |||
279 | 300 | ||
280 | #if ENABLE_FEATURE_MDEV_CONF | 301 | #if ENABLE_FEATURE_MDEV_CONF |
281 | 302 | ||
@@ -288,14 +309,65 @@ static void make_default_cur_rule(void) | |||
288 | 309 | ||
289 | static void clean_up_cur_rule(void) | 310 | static void clean_up_cur_rule(void) |
290 | { | 311 | { |
312 | struct envmatch *e; | ||
313 | |||
291 | free(G.cur_rule.envvar); | 314 | free(G.cur_rule.envvar); |
315 | free(G.cur_rule.ren_mov); | ||
292 | if (G.cur_rule.regex_compiled) | 316 | if (G.cur_rule.regex_compiled) |
293 | regfree(&G.cur_rule.match); | 317 | regfree(&G.cur_rule.match); |
294 | free(G.cur_rule.ren_mov); | ||
295 | IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) | 318 | IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) |
319 | e = G.cur_rule.envmatch; | ||
320 | while (e) { | ||
321 | free(e->envname); | ||
322 | regfree(&e->match); | ||
323 | e = e->next; | ||
324 | } | ||
296 | make_default_cur_rule(); | 325 | make_default_cur_rule(); |
297 | } | 326 | } |
298 | 327 | ||
328 | /* In later versions, endofname is in libbb */ | ||
329 | #define endofname mdev_endofname | ||
330 | static | ||
331 | const char* FAST_FUNC | ||
332 | endofname(const char *name) | ||
333 | { | ||
334 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
335 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
336 | if (!is_name(*name)) | ||
337 | return name; | ||
338 | while (*++name) { | ||
339 | if (!is_in_name(*name)) | ||
340 | break; | ||
341 | } | ||
342 | return name; | ||
343 | } | ||
344 | |||
345 | static char *parse_envmatch_pfx(char *val) | ||
346 | { | ||
347 | struct envmatch **nextp = &G.cur_rule.envmatch; | ||
348 | |||
349 | for (;;) { | ||
350 | struct envmatch *e; | ||
351 | char *semicolon; | ||
352 | char *eq = strchr(val, '='); | ||
353 | if (!eq /* || eq == val? */) | ||
354 | return val; | ||
355 | if (endofname(val) != eq) | ||
356 | return val; | ||
357 | semicolon = strchr(eq, ';'); | ||
358 | if (!semicolon) | ||
359 | return val; | ||
360 | /* ENVVAR=regex;... */ | ||
361 | *nextp = e = xzalloc(sizeof(*e)); | ||
362 | nextp = &e->next; | ||
363 | e->envname = xstrndup(val, eq - val); | ||
364 | *semicolon = '\0'; | ||
365 | xregcomp(&e->match, eq + 1, REG_EXTENDED); | ||
366 | *semicolon = ';'; | ||
367 | val = semicolon + 1; | ||
368 | } | ||
369 | } | ||
370 | |||
299 | static void parse_next_rule(void) | 371 | static void parse_next_rule(void) |
300 | { | 372 | { |
301 | /* Note: on entry, G.cur_rule is set to default */ | 373 | /* Note: on entry, G.cur_rule is set to default */ |
@@ -308,12 +380,13 @@ static void parse_next_rule(void) | |||
308 | break; | 380 | break; |
309 | 381 | ||
310 | /* Fields: [-]regex uid:gid mode [alias] [cmd] */ | 382 | /* Fields: [-]regex uid:gid mode [alias] [cmd] */ |
311 | dbg("token1:'%s'", tokens[1]); | 383 | dbg3("token1:'%s'", tokens[1]); |
312 | 384 | ||
313 | /* 1st field */ | 385 | /* 1st field */ |
314 | val = tokens[0]; | 386 | val = tokens[0]; |
315 | G.cur_rule.keep_matching = ('-' == val[0]); | 387 | G.cur_rule.keep_matching = ('-' == val[0]); |
316 | val += G.cur_rule.keep_matching; /* swallow leading dash */ | 388 | val += G.cur_rule.keep_matching; /* swallow leading dash */ |
389 | val = parse_envmatch_pfx(val); | ||
317 | if (val[0] == '@') { | 390 | if (val[0] == '@') { |
318 | /* @major,minor[-minor2] */ | 391 | /* @major,minor[-minor2] */ |
319 | /* (useful when name is ambiguous: | 392 | /* (useful when name is ambiguous: |
@@ -328,8 +401,10 @@ static void parse_next_rule(void) | |||
328 | if (sc == 2) | 401 | if (sc == 2) |
329 | G.cur_rule.min1 = G.cur_rule.min0; | 402 | G.cur_rule.min1 = G.cur_rule.min0; |
330 | } else { | 403 | } else { |
404 | char *eq = strchr(val, '='); | ||
331 | if (val[0] == '$') { | 405 | if (val[0] == '$') { |
332 | char *eq = strchr(++val, '='); | 406 | /* $ENVVAR=regex ... */ |
407 | val++; | ||
333 | if (!eq) { | 408 | if (!eq) { |
334 | bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); | 409 | bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); |
335 | goto next_rule; | 410 | goto next_rule; |
@@ -373,7 +448,7 @@ static void parse_next_rule(void) | |||
373 | clean_up_cur_rule(); | 448 | clean_up_cur_rule(); |
374 | } /* while (config_read) */ | 449 | } /* while (config_read) */ |
375 | 450 | ||
376 | dbg("config_close(G.parser)"); | 451 | dbg3("config_close(G.parser)"); |
377 | config_close(G.parser); | 452 | config_close(G.parser); |
378 | G.parser = NULL; | 453 | G.parser = NULL; |
379 | 454 | ||
@@ -390,7 +465,7 @@ static const struct rule *next_rule(void) | |||
390 | 465 | ||
391 | /* Open conf file if we didn't do it yet */ | 466 | /* Open conf file if we didn't do it yet */ |
392 | if (!G.parser && G.filename) { | 467 | if (!G.parser && G.filename) { |
393 | dbg("config_open('%s')", G.filename); | 468 | dbg3("config_open('%s')", G.filename); |
394 | G.parser = config_open2(G.filename, fopen_for_read); | 469 | G.parser = config_open2(G.filename, fopen_for_read); |
395 | G.filename = NULL; | 470 | G.filename = NULL; |
396 | } | 471 | } |
@@ -399,7 +474,7 @@ static const struct rule *next_rule(void) | |||
399 | /* mdev -s */ | 474 | /* mdev -s */ |
400 | /* Do we have rule parsed already? */ | 475 | /* Do we have rule parsed already? */ |
401 | if (G.rule_vec[G.rule_idx]) { | 476 | if (G.rule_vec[G.rule_idx]) { |
402 | dbg("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); | 477 | dbg3("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); |
403 | return G.rule_vec[G.rule_idx++]; | 478 | return G.rule_vec[G.rule_idx++]; |
404 | } | 479 | } |
405 | make_default_cur_rule(); | 480 | make_default_cur_rule(); |
@@ -416,13 +491,28 @@ static const struct rule *next_rule(void) | |||
416 | rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule)); | 491 | rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule)); |
417 | G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx); | 492 | G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx); |
418 | G.rule_vec[G.rule_idx++] = rule; | 493 | G.rule_vec[G.rule_idx++] = rule; |
419 | dbg("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); | 494 | dbg3("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); |
420 | } | 495 | } |
421 | } | 496 | } |
422 | 497 | ||
423 | return rule; | 498 | return rule; |
424 | } | 499 | } |
425 | 500 | ||
501 | static int env_matches(struct envmatch *e) | ||
502 | { | ||
503 | while (e) { | ||
504 | int r; | ||
505 | char *val = getenv(e->envname); | ||
506 | if (!val) | ||
507 | return 0; | ||
508 | r = regexec(&e->match, val, /*size*/ 0, /*range[]*/ NULL, /*eflags*/ 0); | ||
509 | if (r != 0) /* no match */ | ||
510 | return 0; | ||
511 | e = e->next; | ||
512 | } | ||
513 | return 1; | ||
514 | } | ||
515 | |||
426 | #else | 516 | #else |
427 | 517 | ||
428 | # define next_rule() (&G.cur_rule) | 518 | # define next_rule() (&G.cur_rule) |
@@ -468,7 +558,7 @@ static char *build_alias(char *alias, const char *device_name) | |||
468 | 558 | ||
469 | /* mknod in /dev based on a path like "/sys/block/hda/hda1" | 559 | /* mknod in /dev based on a path like "/sys/block/hda/hda1" |
470 | * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes | 560 | * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes |
471 | * after NUL, but we promise to not mangle (IOW: to restore if needed) | 561 | * after NUL, but we promise to not mangle (IOW: to restore NUL if needed) |
472 | * path string. | 562 | * path string. |
473 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! | 563 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! |
474 | * | 564 | * |
@@ -478,9 +568,7 @@ static char *build_alias(char *alias, const char *device_name) | |||
478 | static void make_device(char *device_name, char *path, int operation) | 568 | static void make_device(char *device_name, char *path, int operation) |
479 | { | 569 | { |
480 | int major, minor, type, len; | 570 | int major, minor, type, len; |
481 | 571 | char *path_end = path + strlen(path); | |
482 | if (G.verbose) | ||
483 | bb_error_msg("device: %s, %s", device_name, path); | ||
484 | 572 | ||
485 | /* Try to read major/minor string. Note that the kernel puts \n after | 573 | /* Try to read major/minor string. Note that the kernel puts \n after |
486 | * the data, so we don't need to worry about null terminating the string | 574 | * the data, so we don't need to worry about null terminating the string |
@@ -489,29 +577,51 @@ static void make_device(char *device_name, char *path, int operation) | |||
489 | */ | 577 | */ |
490 | major = -1; | 578 | major = -1; |
491 | if (operation == OP_add) { | 579 | if (operation == OP_add) { |
492 | char *dev_maj_min = path + strlen(path); | 580 | strcpy(path_end, "/dev"); |
493 | 581 | len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1); | |
494 | strcpy(dev_maj_min, "/dev"); | 582 | *path_end = '\0'; |
495 | len = open_read_close(path, dev_maj_min + 1, 64); | ||
496 | *dev_maj_min = '\0'; | ||
497 | if (len < 1) { | 583 | if (len < 1) { |
498 | if (!ENABLE_FEATURE_MDEV_EXEC) | 584 | if (!ENABLE_FEATURE_MDEV_EXEC) |
499 | return; | 585 | return; |
500 | /* no "dev" file, but we can still run scripts | 586 | /* no "dev" file, but we can still run scripts |
501 | * based on device name */ | 587 | * based on device name */ |
502 | } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) { | 588 | } else if (sscanf(path_end + 1, "%u:%u", &major, &minor) == 2) { |
503 | if (G.verbose) | 589 | dbg1("dev %u,%u", major, minor); |
504 | bb_error_msg("maj,min: %u,%u", major, minor); | ||
505 | } else { | 590 | } else { |
506 | major = -1; | 591 | major = -1; |
507 | } | 592 | } |
508 | } | 593 | } |
509 | /* else: for delete, -1 still deletes the node, but < -1 suppresses that */ | 594 | /* else: for delete, -1 still deletes the node, but < -1 suppresses that */ |
510 | 595 | ||
511 | /* Determine device name, type, major and minor */ | 596 | /* Determine device name */ |
512 | if (!device_name) | 597 | if (!device_name) { |
513 | device_name = (char*) bb_basename(path); | 598 | /* |
514 | /* http://kernel.org/doc/pending/hotplug.txt says that only | 599 | * There was no $DEVNAME envvar (for example, mdev -s never has). |
600 | * But it is very useful: it contains the *path*, not only basename, | ||
601 | * Thankfully, uevent file has it. | ||
602 | * Example of .../sound/card0/controlC0/uevent file on Linux-3.7.7: | ||
603 | * MAJOR=116 | ||
604 | * MINOR=7 | ||
605 | * DEVNAME=snd/controlC0 | ||
606 | */ | ||
607 | strcpy(path_end, "/uevent"); | ||
608 | len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1); | ||
609 | if (len < 0) | ||
610 | len = 0; | ||
611 | *path_end = '\0'; | ||
612 | path_end[1 + len] = '\0'; | ||
613 | device_name = strstr(path_end + 1, "\nDEVNAME="); | ||
614 | if (device_name) { | ||
615 | device_name += sizeof("\nDEVNAME=")-1; | ||
616 | strchrnul(device_name, '\n')[0] = '\0'; | ||
617 | } else { | ||
618 | /* Fall back to just basename */ | ||
619 | device_name = (char*) bb_basename(path); | ||
620 | } | ||
621 | } | ||
622 | /* Determine device type */ | ||
623 | /* | ||
624 | * http://kernel.org/doc/pending/hotplug.txt says that only | ||
515 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. | 625 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. |
516 | * But since 2.6.25 block devices are also in /sys/class/block. | 626 | * But since 2.6.25 block devices are also in /sys/class/block. |
517 | * We use strstr("/block/") to forestall future surprises. | 627 | * We use strstr("/block/") to forestall future surprises. |
@@ -537,6 +647,8 @@ static void make_device(char *device_name, char *path, int operation) | |||
537 | rule = next_rule(); | 647 | rule = next_rule(); |
538 | 648 | ||
539 | #if ENABLE_FEATURE_MDEV_CONF | 649 | #if ENABLE_FEATURE_MDEV_CONF |
650 | if (!env_matches(rule->envmatch)) | ||
651 | continue; | ||
540 | if (rule->maj >= 0) { /* @maj,min rule */ | 652 | if (rule->maj >= 0) { /* @maj,min rule */ |
541 | if (major != rule->maj) | 653 | if (major != rule->maj) |
542 | continue; | 654 | continue; |
@@ -547,7 +659,7 @@ static void make_device(char *device_name, char *path, int operation) | |||
547 | } | 659 | } |
548 | if (rule->envvar) { /* $envvar=regex rule */ | 660 | if (rule->envvar) { /* $envvar=regex rule */ |
549 | str_to_match = getenv(rule->envvar); | 661 | str_to_match = getenv(rule->envvar); |
550 | dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); | 662 | dbg3("getenv('%s'):'%s'", rule->envvar, str_to_match); |
551 | if (!str_to_match) | 663 | if (!str_to_match) |
552 | continue; | 664 | continue; |
553 | } | 665 | } |
@@ -555,7 +667,7 @@ static void make_device(char *device_name, char *path, int operation) | |||
555 | 667 | ||
556 | if (rule->regex_compiled) { | 668 | if (rule->regex_compiled) { |
557 | int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); | 669 | int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); |
558 | dbg("regex_match for '%s':%d", str_to_match, regex_match); | 670 | dbg3("regex_match for '%s':%d", str_to_match, regex_match); |
559 | //bb_error_msg("matches:"); | 671 | //bb_error_msg("matches:"); |
560 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { | 672 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { |
561 | // if (off[i].rm_so < 0) continue; | 673 | // if (off[i].rm_so < 0) continue; |
@@ -574,9 +686,8 @@ static void make_device(char *device_name, char *path, int operation) | |||
574 | } | 686 | } |
575 | /* else: it's final implicit "match-all" rule */ | 687 | /* else: it's final implicit "match-all" rule */ |
576 | rule_matches: | 688 | rule_matches: |
689 | dbg2("rule matched, line %d", G.parser ? G.parser->lineno : -1); | ||
577 | #endif | 690 | #endif |
578 | dbg("rule matched"); | ||
579 | |||
580 | /* Build alias name */ | 691 | /* Build alias name */ |
581 | alias = NULL; | 692 | alias = NULL; |
582 | if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) { | 693 | if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) { |
@@ -619,34 +730,30 @@ static void make_device(char *device_name, char *path, int operation) | |||
619 | } | 730 | } |
620 | } | 731 | } |
621 | } | 732 | } |
622 | dbg("alias:'%s'", alias); | 733 | dbg3("alias:'%s'", alias); |
623 | 734 | ||
624 | command = NULL; | 735 | command = NULL; |
625 | IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;) | 736 | IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;) |
626 | if (command) { | 737 | if (command) { |
627 | const char *s = "$@*"; | ||
628 | const char *s2 = strchr(s, command[0]); | ||
629 | |||
630 | /* Are we running this command now? | 738 | /* Are we running this command now? |
631 | * Run $cmd on delete, @cmd on create, *cmd on both | 739 | * Run @cmd on create, $cmd on delete, *cmd on any |
632 | */ | 740 | */ |
633 | if (s2 - s != (operation == OP_remove) || *s2 == '*') { | 741 | if ((command[0] == '@' && operation == OP_add) |
634 | /* We are here if: '*', | 742 | || (command[0] == '$' && operation == OP_remove) |
635 | * or: '@' and delete = 0, | 743 | || (command[0] == '*') |
636 | * or: '$' and delete = 1 | 744 | ) { |
637 | */ | ||
638 | command++; | 745 | command++; |
639 | } else { | 746 | } else { |
640 | command = NULL; | 747 | command = NULL; |
641 | } | 748 | } |
642 | } | 749 | } |
643 | dbg("command:'%s'", command); | 750 | dbg3("command:'%s'", command); |
644 | 751 | ||
645 | /* "Execute" the line we found */ | 752 | /* "Execute" the line we found */ |
646 | node_name = device_name; | 753 | node_name = device_name; |
647 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 754 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
648 | node_name = alias = build_alias(alias, device_name); | 755 | node_name = alias = build_alias(alias, device_name); |
649 | dbg("alias2:'%s'", alias); | 756 | dbg3("alias2:'%s'", alias); |
650 | } | 757 | } |
651 | 758 | ||
652 | if (operation == OP_add && major >= 0) { | 759 | if (operation == OP_add && major >= 0) { |
@@ -656,8 +763,17 @@ static void make_device(char *device_name, char *path, int operation) | |||
656 | mkdir_recursive(node_name); | 763 | mkdir_recursive(node_name); |
657 | *slash = '/'; | 764 | *slash = '/'; |
658 | } | 765 | } |
659 | if (G.verbose) | 766 | if (ENABLE_FEATURE_MDEV_CONF) { |
660 | bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type); | 767 | dbg1("mknod %s (%d,%d) %o" |
768 | " %u:%u", | ||
769 | node_name, major, minor, rule->mode | type, | ||
770 | rule->ugid.uid, rule->ugid.gid | ||
771 | ); | ||
772 | } else { | ||
773 | dbg1("mknod %s (%d,%d) %o", | ||
774 | node_name, major, minor, rule->mode | type | ||
775 | ); | ||
776 | } | ||
661 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) | 777 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) |
662 | bb_perror_msg("can't create '%s'", node_name); | 778 | bb_perror_msg("can't create '%s'", node_name); |
663 | if (ENABLE_FEATURE_MDEV_CONF) { | 779 | if (ENABLE_FEATURE_MDEV_CONF) { |
@@ -671,8 +787,7 @@ static void make_device(char *device_name, char *path, int operation) | |||
671 | //TODO: on devtmpfs, device_name already exists and symlink() fails. | 787 | //TODO: on devtmpfs, device_name already exists and symlink() fails. |
672 | //End result is that instead of symlink, we have two nodes. | 788 | //End result is that instead of symlink, we have two nodes. |
673 | //What should be done? | 789 | //What should be done? |
674 | if (G.verbose) | 790 | dbg1("symlink: %s", device_name); |
675 | bb_error_msg("symlink: %s", device_name); | ||
676 | symlink(node_name, device_name); | 791 | symlink(node_name, device_name); |
677 | } | 792 | } |
678 | } | 793 | } |
@@ -681,27 +796,21 @@ static void make_device(char *device_name, char *path, int operation) | |||
681 | if (ENABLE_FEATURE_MDEV_EXEC && command) { | 796 | if (ENABLE_FEATURE_MDEV_EXEC && command) { |
682 | /* setenv will leak memory, use putenv/unsetenv/free */ | 797 | /* setenv will leak memory, use putenv/unsetenv/free */ |
683 | char *s = xasprintf("%s=%s", "MDEV", node_name); | 798 | char *s = xasprintf("%s=%s", "MDEV", node_name); |
684 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | ||
685 | putenv(s); | 799 | putenv(s); |
686 | putenv(s1); | 800 | dbg1("running: %s", command); |
687 | if (G.verbose) | ||
688 | bb_error_msg("running: %s", command); | ||
689 | if (system(command) == -1) | 801 | if (system(command) == -1) |
690 | bb_perror_msg("can't run '%s'", command); | 802 | bb_perror_msg("can't run '%s'", command); |
691 | bb_unsetenv_and_free(s1); | ||
692 | bb_unsetenv_and_free(s); | 803 | bb_unsetenv_and_free(s); |
693 | } | 804 | } |
694 | 805 | ||
695 | if (operation == OP_remove && major >= -1) { | 806 | if (operation == OP_remove && major >= -1) { |
696 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 807 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
697 | if (aliaslink == '>') { | 808 | if (aliaslink == '>') { |
698 | if (G.verbose) | 809 | dbg1("unlink: %s", device_name); |
699 | bb_error_msg("unlink: %s", device_name); | ||
700 | unlink(device_name); | 810 | unlink(device_name); |
701 | } | 811 | } |
702 | } | 812 | } |
703 | if (G.verbose) | 813 | dbg1("unlink: %s", node_name); |
704 | bb_error_msg("unlink: %s", node_name); | ||
705 | unlink(node_name); | 814 | unlink(node_name); |
706 | } | 815 | } |
707 | 816 | ||
@@ -746,9 +855,16 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | |||
746 | * under /sys/class/ */ | 855 | * under /sys/class/ */ |
747 | if (1 == depth) { | 856 | if (1 == depth) { |
748 | free(G.subsystem); | 857 | free(G.subsystem); |
858 | if (G.subsys_env) { | ||
859 | bb_unsetenv_and_free(G.subsys_env); | ||
860 | G.subsys_env = NULL; | ||
861 | } | ||
749 | G.subsystem = strrchr(fileName, '/'); | 862 | G.subsystem = strrchr(fileName, '/'); |
750 | if (G.subsystem) | 863 | if (G.subsystem) { |
751 | G.subsystem = xstrdup(G.subsystem + 1); | 864 | G.subsystem = xstrdup(G.subsystem + 1); |
865 | G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | ||
866 | putenv(G.subsys_env); | ||
867 | } | ||
752 | } | 868 | } |
753 | 869 | ||
754 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); | 870 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); |
@@ -813,12 +929,107 @@ static void load_firmware(const char *firmware, const char *sysfs_path) | |||
813 | full_write(loading_fd, "-1", 2); | 929 | full_write(loading_fd, "-1", 2); |
814 | 930 | ||
815 | out: | 931 | out: |
932 | xchdir("/dev"); | ||
816 | if (ENABLE_FEATURE_CLEAN_UP) { | 933 | if (ENABLE_FEATURE_CLEAN_UP) { |
817 | close(firmware_fd); | 934 | close(firmware_fd); |
818 | close(loading_fd); | 935 | close(loading_fd); |
819 | } | 936 | } |
820 | } | 937 | } |
821 | 938 | ||
939 | static char *curtime(void) | ||
940 | { | ||
941 | struct timeval tv; | ||
942 | gettimeofday(&tv, NULL); | ||
943 | sprintf(G.timestr, "%u.%06u", (unsigned)tv.tv_sec % 60, (unsigned)tv.tv_usec); | ||
944 | return G.timestr; | ||
945 | } | ||
946 | |||
947 | static void open_mdev_log(const char *seq, unsigned my_pid) | ||
948 | { | ||
949 | int logfd = open("mdev.log", O_WRONLY | O_APPEND); | ||
950 | if (logfd >= 0) { | ||
951 | xmove_fd(logfd, STDERR_FILENO); | ||
952 | G.verbose = 2; | ||
953 | applet_name = xasprintf("%s[%s]", applet_name, seq ? seq : utoa(my_pid)); | ||
954 | } | ||
955 | } | ||
956 | |||
957 | /* If it exists, does /dev/mdev.seq match $SEQNUM? | ||
958 | * If it does not match, earlier mdev is running | ||
959 | * in parallel, and we need to wait. | ||
960 | * Active mdev pokes us with SIGCHLD to check the new file. | ||
961 | */ | ||
962 | static int | ||
963 | wait_for_seqfile(const char *seq) | ||
964 | { | ||
965 | /* We time out after 2 sec */ | ||
966 | static const struct timespec ts = { 0, 32*1000*1000 }; | ||
967 | int timeout = 2000 / 32; | ||
968 | int seq_fd = -1; | ||
969 | int do_once = 1; | ||
970 | sigset_t set_CHLD; | ||
971 | |||
972 | sigemptyset(&set_CHLD); | ||
973 | sigaddset(&set_CHLD, SIGCHLD); | ||
974 | sigprocmask(SIG_BLOCK, &set_CHLD, NULL); | ||
975 | |||
976 | for (;;) { | ||
977 | int seqlen; | ||
978 | char seqbuf[sizeof(int)*3 + 2]; | ||
979 | |||
980 | if (seq_fd < 0) { | ||
981 | seq_fd = open("mdev.seq", O_RDWR); | ||
982 | if (seq_fd < 0) | ||
983 | break; | ||
984 | } | ||
985 | seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); | ||
986 | if (seqlen < 0) { | ||
987 | close(seq_fd); | ||
988 | seq_fd = -1; | ||
989 | break; | ||
990 | } | ||
991 | seqbuf[seqlen] = '\0'; | ||
992 | if (seqbuf[0] == '\n') { | ||
993 | /* seed file: write out seq ASAP */ | ||
994 | xwrite_str(seq_fd, seq); | ||
995 | xlseek(seq_fd, 0, SEEK_SET); | ||
996 | dbg2("first seq written"); | ||
997 | break; | ||
998 | } | ||
999 | if (strcmp(seq, seqbuf) == 0) { | ||
1000 | /* correct idx */ | ||
1001 | break; | ||
1002 | } | ||
1003 | if (do_once) { | ||
1004 | dbg2("%s waiting for '%s'", curtime(), seqbuf); | ||
1005 | do_once = 0; | ||
1006 | } | ||
1007 | if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { | ||
1008 | dbg3("woken up"); | ||
1009 | continue; /* don't decrement timeout! */ | ||
1010 | } | ||
1011 | if (--timeout == 0) { | ||
1012 | dbg1("%s waiting for '%s'", "timed out", seqbuf); | ||
1013 | break; | ||
1014 | } | ||
1015 | } | ||
1016 | sigprocmask(SIG_UNBLOCK, &set_CHLD, NULL); | ||
1017 | return seq_fd; | ||
1018 | } | ||
1019 | |||
1020 | static void signal_mdevs(unsigned my_pid) | ||
1021 | { | ||
1022 | procps_status_t* p = NULL; | ||
1023 | while ((p = procps_scan(p, PSSCAN_ARGV0)) != NULL) { | ||
1024 | if (p->pid != my_pid | ||
1025 | && p->argv0 | ||
1026 | && strcmp(bb_basename(p->argv0), "mdev") == 0 | ||
1027 | ) { | ||
1028 | kill(p->pid, SIGCHLD); | ||
1029 | } | ||
1030 | } | ||
1031 | } | ||
1032 | |||
822 | int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1033 | int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
823 | int mdev_main(int argc UNUSED_PARAM, char **argv) | 1034 | int mdev_main(int argc UNUSED_PARAM, char **argv) |
824 | { | 1035 | { |
@@ -840,8 +1051,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
840 | xchdir("/dev"); | 1051 | xchdir("/dev"); |
841 | 1052 | ||
842 | if (argv[1] && strcmp(argv[1], "-s") == 0) { | 1053 | if (argv[1] && strcmp(argv[1], "-s") == 0) { |
843 | /* Scan: | 1054 | /* |
844 | * mdev -s | 1055 | * Scan: mdev -s |
845 | */ | 1056 | */ |
846 | struct stat st; | 1057 | struct stat st; |
847 | 1058 | ||
@@ -853,6 +1064,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
853 | G.root_major = major(st.st_dev); | 1064 | G.root_major = major(st.st_dev); |
854 | G.root_minor = minor(st.st_dev); | 1065 | G.root_minor = minor(st.st_dev); |
855 | 1066 | ||
1067 | putenv((char*)"ACTION=add"); | ||
1068 | |||
856 | /* ACTION_FOLLOWLINKS is needed since in newer kernels | 1069 | /* ACTION_FOLLOWLINKS is needed since in newer kernels |
857 | * /sys/block/loop* (for example) are symlinks to dirs, | 1070 | * /sys/block/loop* (for example) are symlinks to dirs, |
858 | * not real directories. | 1071 | * not real directories. |
@@ -878,11 +1091,13 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
878 | char *action; | 1091 | char *action; |
879 | char *env_devname; | 1092 | char *env_devname; |
880 | char *env_devpath; | 1093 | char *env_devpath; |
1094 | unsigned my_pid; | ||
1095 | int seq_fd; | ||
881 | smalluint op; | 1096 | smalluint op; |
882 | 1097 | ||
883 | /* Hotplug: | 1098 | /* Hotplug: |
884 | * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev | 1099 | * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev |
885 | * ACTION can be "add" or "remove" | 1100 | * ACTION can be "add", "remove", "change" |
886 | * DEVPATH is like "/block/sda" or "/class/input/mice" | 1101 | * DEVPATH is like "/block/sda" or "/class/input/mice" |
887 | */ | 1102 | */ |
888 | action = getenv("ACTION"); | 1103 | action = getenv("ACTION"); |
@@ -893,39 +1108,20 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
893 | if (!action || !env_devpath /*|| !G.subsystem*/) | 1108 | if (!action || !env_devpath /*|| !G.subsystem*/) |
894 | bb_show_usage(); | 1109 | bb_show_usage(); |
895 | fw = getenv("FIRMWARE"); | 1110 | fw = getenv("FIRMWARE"); |
896 | /* If it exists, does /dev/mdev.seq match $SEQNUM? | ||
897 | * If it does not match, earlier mdev is running | ||
898 | * in parallel, and we need to wait */ | ||
899 | seq = getenv("SEQNUM"); | 1111 | seq = getenv("SEQNUM"); |
900 | if (seq) { | ||
901 | int timeout = 2000 / 32; /* 2000 msec */ | ||
902 | do { | ||
903 | int seqlen; | ||
904 | char seqbuf[sizeof(int)*3 + 2]; | ||
905 | |||
906 | seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf) - 1); | ||
907 | if (seqlen < 0) { | ||
908 | seq = NULL; | ||
909 | break; | ||
910 | } | ||
911 | seqbuf[seqlen] = '\0'; | ||
912 | if (seqbuf[0] == '\n' /* seed file? */ | ||
913 | || strcmp(seq, seqbuf) == 0 /* correct idx? */ | ||
914 | ) { | ||
915 | break; | ||
916 | } | ||
917 | usleep(32*1000); | ||
918 | } while (--timeout); | ||
919 | } | ||
920 | 1112 | ||
921 | { | 1113 | my_pid = getpid(); |
922 | int logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND); | 1114 | open_mdev_log(seq, my_pid); |
923 | if (logfd >= 0) { | 1115 | |
924 | xmove_fd(logfd, STDERR_FILENO); | 1116 | seq_fd = seq ? wait_for_seqfile(seq) : -1; |
925 | G.verbose = 1; | 1117 | |
926 | bb_error_msg("seq: %s action: %s", seq, action); | 1118 | dbg1("%s " |
927 | } | 1119 | "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" |
928 | } | 1120 | "%s%s", |
1121 | curtime(), | ||
1122 | action, G.subsystem, env_devname, env_devpath, | ||
1123 | fw ? " FW:" : "", fw ? fw : "" | ||
1124 | ); | ||
929 | 1125 | ||
930 | snprintf(temp, PATH_MAX, "/sys%s", env_devpath); | 1126 | snprintf(temp, PATH_MAX, "/sys%s", env_devpath); |
931 | if (op == OP_remove) { | 1127 | if (op == OP_remove) { |
@@ -935,16 +1131,18 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
935 | if (!fw) | 1131 | if (!fw) |
936 | make_device(env_devname, temp, op); | 1132 | make_device(env_devname, temp, op); |
937 | } | 1133 | } |
938 | else if (op == OP_add) { | 1134 | else { |
939 | make_device(env_devname, temp, op); | 1135 | make_device(env_devname, temp, op); |
940 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { | 1136 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { |
941 | if (fw) | 1137 | if (op == OP_add && fw) |
942 | load_firmware(fw, temp); | 1138 | load_firmware(fw, temp); |
943 | } | 1139 | } |
944 | } | 1140 | } |
945 | 1141 | ||
946 | if (seq) { | 1142 | dbg1("%s exiting", curtime()); |
947 | xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1)); | 1143 | if (seq_fd >= 0) { |
1144 | xwrite_str(seq_fd, utoa(xatou(seq) + 1)); | ||
1145 | signal_mdevs(my_pid); | ||
948 | } | 1146 | } |
949 | } | 1147 | } |
950 | 1148 | ||
diff --git a/util-linux/volume_id/ntfs.c b/util-linux/volume_id/ntfs.c index 7b2612f01..0444e546b 100644 --- a/util-linux/volume_id/ntfs.c +++ b/util-linux/volume_id/ntfs.c | |||
@@ -150,7 +150,7 @@ int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/) | |||
150 | 150 | ||
151 | attr = (struct file_attribute*) &buf[attr_off]; | 151 | attr = (struct file_attribute*) &buf[attr_off]; |
152 | attr_type = le32_to_cpu(attr->type); | 152 | attr_type = le32_to_cpu(attr->type); |
153 | attr_len = le16_to_cpu(attr->len); | 153 | attr_len = le32_to_cpu(attr->len); |
154 | val_off = le16_to_cpu(attr->value_offset); | 154 | val_off = le16_to_cpu(attr->value_offset); |
155 | val_len = le32_to_cpu(attr->value_len); | 155 | val_len = le32_to_cpu(attr->value_len); |
156 | attr_off += attr_len; | 156 | attr_off += attr_len; |