~ubuntu-branches/ubuntu/natty/busybox/natty

« back to all changes in this revision

Viewing changes to util-linux/mdev.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2010-10-13 11:03:32 UTC
  • mfrom: (2.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20101013110332-epixayl40r7l8mpi
Tags: 1:1.17.1-4ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - [udeb] Enable chvt, getopt (and -l), killall, losetup, mktemp, NFS
    mount, od, ping, stat, and remote syslog.
  - [deb] Enable mdev.
  - [deb, static] Enable fractional sleep.
  - Enable 'mount -f' and mount helpers for all targets.
  - Add busybox-initramfs.
  - test-bin.patch: Move test and friends to /bin.
  - Add static-sh alias name for ash, and install /bin/static-sh symlink to
    busybox in busybox-static.
  - Use -marm on armel due to gcc thumb2 compilation issue.
  - grep-o-loop.patch: Fix infinite loop in 'grep -o' with a pattern that
    matches the zero-length string at the start of the line.
  - Add cross-compiling support.
  - applets-fallback.patch: Never execute busybox applets when chrooting.

Show diffs side-by-side

added added

removed removed

Lines of Context:
64
64
struct globals {
65
65
        int root_major, root_minor;
66
66
        char *subsystem;
67
 
};
 
67
} FIX_ALIASING;
68
68
#define G (*(struct globals*)&bb_common_bufsiz1)
69
 
#define root_major (G.root_major)
70
 
#define root_minor (G.root_minor)
71
 
#define subsystem  (G.subsystem )
72
69
 
73
70
/* Prevent infinite loops in /sys symlinks */
74
71
#define MAX_SYSFS_DEPTH 3
109
106
 */
110
107
static void make_device(char *path, int delete)
111
108
{
112
 
        char *device_name;
 
109
        char *device_name, *subsystem_slash_devname;
113
110
        int major, minor, type, len;
114
 
        int mode;
 
111
        mode_t mode;
115
112
        parser_t *parser;
116
113
 
117
114
        /* Try to read major/minor string.  Note that the kernel puts \n after
140
137
        device_name = (char*) bb_basename(path);
141
138
        /* http://kernel.org/doc/pending/hotplug.txt says that only
142
139
         * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
143
 
         * But since 2.6.25 block devices are also in /sys/class/block,
144
 
         * we use strstr("/block/") to forestall future surprises. */
 
140
         * But since 2.6.25 block devices are also in /sys/class/block.
 
141
         * We use strstr("/block/") to forestall future surprises. */
145
142
        type = S_IFCHR;
146
 
        if (strstr(path, "/block/"))
 
143
        if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0))
147
144
                type = S_IFBLK;
148
145
 
149
146
        /* Make path point to "subsystem/device_name" */
150
 
        if (path[5] == 'b') /* legacy /sys/block? */
 
147
        subsystem_slash_devname = NULL;
 
148
        /* Check for coldplug invocations first */
 
149
        if (strncmp(path, "/sys/block/", 11) == 0) /* legacy case */
151
150
                path += sizeof("/sys/") - 1;
152
 
        else
 
151
        else if (strncmp(path, "/sys/class/", 11) == 0)
153
152
                path += sizeof("/sys/class/") - 1;
 
153
        else {
 
154
                /* Example of a hotplug invocation:
 
155
                 * SUBSYSTEM="block"
 
156
                 * DEVPATH="/sys" + "/devices/virtual/mtd/mtd3/mtdblock3"
 
157
                 * ("/sys" is added by mdev_main)
 
158
                 * - path does not contain subsystem
 
159
                 */
 
160
                subsystem_slash_devname = concat_path_file(G.subsystem, device_name);
 
161
                path = subsystem_slash_devname;
 
162
        }
154
163
 
155
164
        /* If we have config file, look up user settings */
156
165
        if (ENABLE_FEATURE_MDEV_CONF)
195
204
                                if (major < 0)
196
205
                                        continue; /* no dev, no match */
197
206
                                sc = sscanf(val, "@%u,%u-%u", &cmaj, &cmin0, &cmin1);
198
 
                                if (sc < 1 || major != cmaj
 
207
                                if (sc < 1
 
208
                                 || major != cmaj
199
209
                                 || (sc == 2 && minor != cmin0)
200
210
                                 || (sc == 3 && (minor < cmin0 || minor > cmin1))
201
211
                                ) {
234
244
 
235
245
                                /* If no match, skip rest of line */
236
246
                                /* (regexec returns whole pattern as "range" 0) */
237
 
                                if (result || off[0].rm_so
 
247
                                if (result
 
248
                                 || off[0].rm_so
238
249
                                 || ((int)off[0].rm_eo != (int)strlen(str_to_match))
239
250
                                ) {
240
251
                                        continue; /* this line doesn't match */
246
257
 
247
258
                        /* 2nd field: uid:gid - device ownership */
248
259
                        if (get_uidgid(&ugid, tokens[1], 1) == 0)
249
 
                                bb_error_msg("unknown user/group %s", tokens[1]);
 
260
                                bb_error_msg("unknown user/group %s on line %d", tokens[1], parser->lineno);
250
261
 
251
262
                        /* 3rd field: mode - device permissions */
252
 
                        mode = strtoul(tokens[2], NULL, 8);
 
263
                        bb_parse_mode(tokens[2], &mode);
253
264
 
254
265
                        val = tokens[3];
255
 
                        /* 4th field (opt): >|=alias */
 
266
                        /* 4th field (opt): ">|=alias" or "!" to not create the node */
256
267
 
257
268
                        if (ENABLE_FEATURE_MDEV_RENAME && val) {
258
 
                                aliaslink = val[0];
259
 
                                if (aliaslink == '>' || aliaslink == '=') {
260
 
                                        char *a, *s, *st;
261
 
                                        char *p;
262
 
                                        unsigned i, n;
263
 
 
264
 
                                        a = val;
265
 
                                        s = strchrnul(val, ' ');
266
 
                                        st = strchrnul(val, '\t');
267
 
                                        if (st < s)
268
 
                                                s = st;
269
 
                                        val = (s[0] && s[1]) ? s+1 : NULL;
 
269
                                char *a, *s, *st;
 
270
 
 
271
                                a = val;
 
272
                                s = strchrnul(val, ' ');
 
273
                                st = strchrnul(val, '\t');
 
274
                                if (st < s)
 
275
                                        s = st;
 
276
                                st = (s[0] && s[1]) ? s+1 : NULL;
 
277
 
 
278
                                aliaslink = a[0];
 
279
                                if (aliaslink == '!' && s == a+1) {
 
280
                                        val = st;
 
281
                                        /* "!": suppress node creation/deletion */
 
282
                                        major = -1;
 
283
                                }
 
284
                                else if (aliaslink == '>' || aliaslink == '=') {
 
285
                                        val = st;
270
286
                                        s[0] = '\0';
271
 
 
272
287
                                        if (ENABLE_FEATURE_MDEV_RENAME_REGEXP) {
 
288
                                                char *p;
 
289
                                                unsigned i, n;
 
290
 
273
291
                                                /* substitute %1..9 with off[1..9], if any */
274
292
                                                n = 0;
275
293
                                                s = a;
313
331
                                /* Are we running this command now?
314
332
                                 * Run $cmd on delete, @cmd on create, *cmd on both
315
333
                                 */
316
 
                                if (s2-s != delete)
 
334
                                if (s2 - s != delete) {
 
335
                                        /* We are here if: '*',
 
336
                                         * or: '@' and delete = 0,
 
337
                                         * or: '$' and delete = 1
 
338
                                         */
317
339
                                        command = xstrdup(val + 1);
 
340
                                }
318
341
                        }
319
342
                }
320
343
 
330
353
 
331
354
                        if (!delete && major >= 0) {
332
355
                                if (mknod(node_name, mode | type, makedev(major, minor)) && errno != EEXIST)
333
 
                                        bb_perror_msg_and_die("mknod %s", node_name);
334
 
                                if (major == root_major && minor == root_minor)
 
356
                                        bb_perror_msg("can't create '%s'", node_name);
 
357
                                if (major == G.root_major && minor == G.root_minor)
335
358
                                        symlink(node_name, "root");
336
359
                                if (ENABLE_FEATURE_MDEV_CONF) {
337
360
                                        chmod(node_name, mode);
346
369
                        if (ENABLE_FEATURE_MDEV_EXEC && command) {
347
370
                                /* setenv will leak memory, use putenv/unsetenv/free */
348
371
                                char *s = xasprintf("%s=%s", "MDEV", node_name);
349
 
                                char *s1 = xasprintf("%s=%s", "SUBSYSTEM", subsystem);
 
372
                                char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem);
350
373
                                putenv(s);
351
374
                                putenv(s1);
352
375
                                if (system(command) == -1)
353
376
                                        bb_perror_msg("can't run '%s'", command);
354
 
                                unsetenv("SUBSYSTEM");
355
 
                                free(s1);
356
 
                                unsetenv("MDEV");
357
 
                                free(s);
 
377
                                bb_unsetenv_and_free(s1);
 
378
                                bb_unsetenv_and_free(s);
358
379
                                free(command);
359
380
                        }
360
381
 
361
 
                        if (delete) {
 
382
                        if (delete && major >= 0) {
362
383
                                if (ENABLE_FEATURE_MDEV_RENAME && alias) {
363
384
                                        if (aliaslink == '>')
364
385
                                                unlink(device_name);
380
401
 
381
402
        if (ENABLE_FEATURE_MDEV_CONF)
382
403
                config_close(parser);
 
404
        free(subsystem_slash_devname);
383
405
}
384
406
 
385
407
/* File callback for /sys/ traversal */
397
419
 
398
420
        strcpy(scratch, fileName);
399
421
        scratch[len] = '\0';
400
 
        make_device(scratch, 0);
 
422
        make_device(scratch, /*delete:*/ 0);
401
423
 
402
424
        return TRUE;
403
425
}
411
433
        /* Extract device subsystem -- the name of the directory
412
434
         * under /sys/class/ */
413
435
        if (1 == depth) {
414
 
                free(subsystem);
415
 
                subsystem = strrchr(fileName, '/');
416
 
                if (subsystem)
417
 
                        subsystem = xstrdup(subsystem + 1);
 
436
                free(G.subsystem);
 
437
                G.subsystem = strrchr(fileName, '/');
 
438
                if (G.subsystem)
 
439
                        G.subsystem = xstrdup(G.subsystem + 1);
418
440
        }
419
441
 
420
442
        return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
499
521
                struct stat st;
500
522
 
501
523
                xstat("/", &st);
502
 
                root_major = major(st.st_dev);
503
 
                root_minor = minor(st.st_dev);
 
524
                G.root_major = major(st.st_dev);
 
525
                G.root_minor = minor(st.st_dev);
504
526
 
505
527
                /* ACTION_FOLLOWLINKS is needed since in newer kernels
506
528
                 * /sys/block/loop* (for example) are symlinks to dirs,
526
548
                char *seq;
527
549
                char *action;
528
550
                char *env_path;
 
551
                static const char keywords[] ALIGN1 = "remove\0add\0";
 
552
                enum { OP_remove = 0, OP_add };
 
553
                smalluint op;
529
554
 
530
555
                /* Hotplug:
531
556
                 * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev
534
559
                 */
535
560
                action = getenv("ACTION");
536
561
                env_path = getenv("DEVPATH");
537
 
                subsystem = getenv("SUBSYSTEM");
538
 
                if (!action || !env_path /*|| !subsystem*/)
 
562
                G.subsystem = getenv("SUBSYSTEM");
 
563
                if (!action || !env_path /*|| !G.subsystem*/)
539
564
                        bb_show_usage();
540
565
                fw = getenv("FIRMWARE");
541
 
 
 
566
                op = index_in_strings(keywords, action);
542
567
                /* If it exists, does /dev/mdev.seq match $SEQNUM?
543
568
                 * If it does not match, earlier mdev is running
544
569
                 * in parallel, and we need to wait */
565
590
                }
566
591
 
567
592
                snprintf(temp, PATH_MAX, "/sys%s", env_path);
568
 
                if (strcmp(action, "remove") == 0) {
 
593
                if (op == OP_remove) {
569
594
                        /* Ignoring "remove firmware". It was reported
570
595
                         * to happen and to cause erroneous deletion
571
596
                         * of device nodes. */
572
597
                        if (!fw)
573
 
                                make_device(temp, 1);
 
598
                                make_device(temp, /*delete:*/ 1);
574
599
                }
575
 
                else if (strcmp(action, "add") == 0) {
576
 
                        make_device(temp, 0);
 
600
                else if (op == OP_add) {
 
601
                        make_device(temp, /*delete:*/ 0);
577
602
                        if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) {
578
603
                                if (fw)
579
604
                                        load_firmware(fw, temp);