busybox/miscutils/makedevs.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
   4 *
   5 * makedevs
   6 * Make ranges of device files quickly.
   7 * known bugs: can't deal with alpha ranges
   8 */
   9
  10#include "libbb.h"
  11
  12#if ENABLE_FEATURE_MAKEDEVS_LEAF
  13/*
  14makedevs NAME TYPE MAJOR MINOR FIRST LAST [s]
  15TYPEs:
  16b       Block device
  17c       Character device
  18f       FIFO
  19
  20FIRST..LAST specify numbers appended to NAME.
  21If 's' is the last argument, the base device is created as well.
  22Examples:
  23        makedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63
  24        makedevs /dev/hda b 3 0 0 8 s    ->  hda,hda1-hda8
  25*/
  26int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  27int makedevs_main(int argc, char **argv)
  28{
  29        mode_t mode;
  30        char *basedev, *type, *nodname, *buf;
  31        int Smajor, Sminor, S, E;
  32
  33        if (argc < 7 || argv[1][0] == '-')
  34                bb_show_usage();
  35
  36        basedev = argv[1];
  37        buf = xasprintf("%s%u", argv[1], (unsigned)-1);
  38        type = argv[2];
  39        Smajor = xatoi_positive(argv[3]);
  40        Sminor = xatoi_positive(argv[4]);
  41        S = xatoi_positive(argv[5]);
  42        E = xatoi_positive(argv[6]);
  43        nodname = argv[7] ? basedev : buf;
  44
  45        mode = 0660;
  46        switch (type[0]) {
  47        case 'c':
  48                mode |= S_IFCHR;
  49                break;
  50        case 'b':
  51                mode |= S_IFBLK;
  52                break;
  53        case 'f':
  54                mode |= S_IFIFO;
  55                break;
  56        default:
  57                bb_show_usage();
  58        }
  59
  60        while (S <= E) {
  61                sprintf(buf, "%s%u", basedev, S);
  62
  63                /* if mode != S_IFCHR and != S_IFBLK,
  64                 * third param in mknod() ignored */
  65                if (mknod(nodname, mode, makedev(Smajor, Sminor)))
  66                        bb_perror_msg("can't create '%s'", nodname);
  67
  68                /*if (nodname == basedev)*/ /* ex. /dev/hda - to /dev/hda1 ... */
  69                        nodname = buf;
  70                S++;
  71                Sminor++;
  72        }
  73
  74        return 0;
  75}
  76
  77#elif ENABLE_FEATURE_MAKEDEVS_TABLE
  78
  79/* Licensed under GPLv2 or later, see file LICENSE in this source tree. */
  80
  81int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  82int makedevs_main(int argc UNUSED_PARAM, char **argv)
  83{
  84        parser_t *parser;
  85        char *line = (char *)"-";
  86        int ret = EXIT_SUCCESS;
  87
  88        opt_complementary = "=1"; /* exactly one param */
  89        getopt32(argv, "d:", &line);
  90        argv += optind;
  91
  92        xchdir(*argv); /* ensure root dir exists */
  93
  94        umask(0);
  95
  96        printf("rootdir=%s\ntable=", *argv);
  97        if (NOT_LONE_DASH(line)) {
  98                printf("'%s'\n", line);
  99        } else {
 100                puts("<stdin>");
 101        }
 102
 103        parser = config_open(line);
 104        while (config_read(parser, &line, 1, 1, "# \t", PARSE_NORMAL)) {
 105                int linenum;
 106                char type;
 107                unsigned mode = 0755;
 108                unsigned major = 0;
 109                unsigned minor = 0;
 110                unsigned count = 0;
 111                unsigned increment = 0;
 112                unsigned start = 0;
 113                char name[41];
 114                char user[41];
 115                char group[41];
 116                char *full_name = name;
 117                uid_t uid;
 118                gid_t gid;
 119
 120                linenum = parser->lineno;
 121
 122                if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u",
 123                                        name, &type, &mode, user, group,
 124                                        &major, &minor, &start, &increment, &count))
 125                 || ((unsigned)(major | minor | start | count | increment) > 255)
 126                ) {
 127                        bb_error_msg("invalid line %d: '%s'", linenum, line);
 128                        ret = EXIT_FAILURE;
 129                        continue;
 130                }
 131
 132                gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid();
 133                uid = (*user) ? get_ug_id(user, xuname2uid) : getuid();
 134                /* We are already in the right root dir,
 135                 * so make absolute paths relative */
 136                if ('/' == *full_name)
 137                        full_name++;
 138
 139                if (type == 'd') {
 140                        bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
 141                        if (chown(full_name, uid, gid) == -1) {
 142 chown_fail:
 143                                bb_perror_msg("line %d: can't chown %s", linenum, full_name);
 144                                ret = EXIT_FAILURE;
 145                                continue;
 146                        }
 147                        if (chmod(full_name, mode) < 0) {
 148 chmod_fail:
 149                                bb_perror_msg("line %d: can't chmod %s", linenum, full_name);
 150                                ret = EXIT_FAILURE;
 151                                continue;
 152                        }
 153                } else if (type == 'f') {
 154                        struct stat st;
 155                        if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) {
 156                                bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name);
 157                                ret = EXIT_FAILURE;
 158                                continue;
 159                        }
 160                        if (chown(full_name, uid, gid) < 0)
 161                                goto chown_fail;
 162                        if (chmod(full_name, mode) < 0)
 163                                goto chmod_fail;
 164                } else {
 165                        dev_t rdev;
 166                        unsigned i;
 167                        char *full_name_inc;
 168
 169                        if (type == 'p') {
 170                                mode |= S_IFIFO;
 171                        } else if (type == 'c') {
 172                                mode |= S_IFCHR;
 173                        } else if (type == 'b') {
 174                                mode |= S_IFBLK;
 175                        } else {
 176                                bb_error_msg("line %d: unsupported file type %c", linenum, type);
 177                                ret = EXIT_FAILURE;
 178                                continue;
 179                        }
 180
 181                        full_name_inc = xmalloc(strlen(full_name) + sizeof(int)*3 + 2);
 182                        if (count)
 183                                count--;
 184                        for (i = start; i <= start + count; i++) {
 185                                sprintf(full_name_inc, count ? "%s%u" : "%s", full_name, i);
 186                                rdev = makedev(major, minor + (i - start) * increment);
 187                                if (mknod(full_name_inc, mode, rdev) < 0) {
 188                                        bb_perror_msg("line %d: can't create node %s", linenum, full_name_inc);
 189                                        ret = EXIT_FAILURE;
 190                                } else if (chown(full_name_inc, uid, gid) < 0) {
 191                                        bb_perror_msg("line %d: can't chown %s", linenum, full_name_inc);
 192                                        ret = EXIT_FAILURE;
 193                                } else if (chmod(full_name_inc, mode) < 0) {
 194                                        bb_perror_msg("line %d: can't chmod %s", linenum, full_name_inc);
 195                                        ret = EXIT_FAILURE;
 196                                }
 197                        }
 198                        free(full_name_inc);
 199                }
 200        }
 201        if (ENABLE_FEATURE_CLEAN_UP)
 202                config_close(parser);
 203
 204        return ret;
 205}
 206
 207#else
 208# error makedevs configuration error, either leaf or table must be selected
 209#endif
 210