aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--archival/libarchive/decompress_unxz.c47
-rw-r--r--include/platform.h2
-rw-r--r--util-linux/mdev.c402
-rw-r--r--util-linux/volume_id/ntfs.c2
5 files changed, 341 insertions, 114 deletions
diff --git a/Makefile b/Makefile
index c31ca899b..ca0644230 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 21 2PATCHLEVEL = 21
3SUBLEVEL = 0 3SUBLEVEL = 1
4EXTRAVERSION = 4EXTRAVERSION =
5NAME = Unnamed 5NAME = 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)
40IF_DESKTOP(long long) int FAST_FUNC 40IF_DESKTOP(long long) int FAST_FUNC
41unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) 41unpack_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
233static 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
252static const char keywords[] ALIGN1 = "add\0remove\0"; // "change\0"
234enum { OP_add, OP_remove }; 253enum { OP_add, OP_remove };
235 254
255struct envmatch {
256 struct envmatch *next;
257 char *envname;
258 regex_t match;
259};
260
236struct rule { 261struct 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
248struct globals { 274struct 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
289static void clean_up_cur_rule(void) 310static 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
330static
331const char* FAST_FUNC
332endofname(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
345static 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
299static void parse_next_rule(void) 371static 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
501static 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)
478static void make_device(char *device_name, char *path, int operation) 568static 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
939static 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
947static 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 */
962static int
963wait_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
1020static 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
822int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1033int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
823int mdev_main(int argc UNUSED_PARAM, char **argv) 1034int 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;