Home | History | Annotate | Download | only in rootdev
      1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  *
      5  * Driver for using rootdev.c from the commandline
      6  */
      7 #include <err.h>
      8 #include <errno.h>
      9 #include <getopt.h>
     10 #include <linux/limits.h>
     11 #include <stdbool.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <sys/stat.h>
     16 #include <sys/types.h>
     17 #include <unistd.h>
     18 
     19 #include "rootdev.h"
     20 
     21 static void print_help(const char *progname) {
     22   fprintf(stderr,
     23     "%s [OPTIONS] [PATH]\n"
     24     "Outputs the containing device for the specified PATH.\n"
     25     "With no arguments, '/' is assumed.\n"
     26     "\n"
     27     "Options:\n"
     28     "  -h\tthis message.\n"
     29     "\n"
     30     "  -c\tcreate the /dev node if it cannot be found\n"
     31     "  -d\treturn the block device only if possible\n"
     32     "  -i\treturn path even if the node doesn't exist\n"
     33     "  -s\tif possible, return the first slave of the root device\n"
     34     "\n"
     35     "  --block [path]\tset the path to block under the sys mount point\n"
     36     "  --dev [path]\tset the path to dev mount point\n"
     37     "  --major [num]\tset the major number of the rootdev\n"
     38     "  --minor [num]\tset the minor number of the rootdev\n",
     39     progname);
     40 }
     41 
     42 static int flag_help = 0;
     43 static int flag_use_slave = 0;
     44 static int flag_strip_partition = 0;
     45 static int flag_ignore = 0;
     46 static int flag_create = 0;
     47 static int flag_major = 0;
     48 static int flag_minor = 0;
     49 static const char *flag_path = "/";
     50 static char *flag_block_path = NULL;
     51 static char *flag_dev_path = NULL;
     52 
     53 static void parse_args(int argc, char **argv) {
     54   while (1) {
     55     int c;
     56     int option_index = 0;
     57     static const struct option long_options[] = {
     58       {"c", no_argument, &flag_create, 1},
     59       {"d", no_argument, &flag_strip_partition, 1},
     60       {"h", no_argument, &flag_help, 1},
     61       {"i", no_argument, &flag_ignore, 1},
     62       {"s", no_argument, &flag_use_slave, 1},
     63       /* Long arguments for testing. */
     64       {"block", required_argument, NULL, 'b'},
     65       {"dev", required_argument, NULL, 'd'},
     66       {"major", required_argument, NULL, 'M'},
     67       {"minor", required_argument, NULL, 'm'},
     68       {0, 0, 0, 0}
     69     };
     70     c = getopt_long_only(argc, argv, "", long_options, &option_index);
     71 
     72     if (c == -1)
     73       break;
     74 
     75     if (c == '?') {
     76       flag_help = 1;
     77       break;
     78     }
     79 
     80     switch (c) {
     81     case 'b':
     82       flag_block_path = optarg;
     83       break;
     84     case 'd':
     85       flag_dev_path = optarg;
     86       break;
     87     case 'M':
     88       flag_major = atoi(optarg);
     89       break;
     90     case 'm':
     91       flag_minor = atoi(optarg);
     92       break;
     93     }
     94 
     95   }
     96 
     97   if (flag_create && flag_strip_partition) {
     98     flag_help = 1;
     99     warnx("-c and -d are incompatible at present.");
    100     return;
    101   }
    102 
    103   if (optind < argc) {
    104     flag_path = argv[optind++];
    105   }
    106 
    107   if (optind < argc) {
    108     fprintf(stderr, "Too many free arguments: %d\n", argc - optind);
    109     flag_help = 1;
    110    }
    111 }
    112 
    113 int main(int argc, char **argv) {
    114   struct stat path_stat;
    115   char path[PATH_MAX];
    116   int ret;
    117   dev_t root_dev;
    118   parse_args(argc, argv);
    119 
    120   if (flag_help) {
    121     print_help(argv[0]);
    122     return 1;
    123   }
    124 
    125   if (flag_major || flag_minor) {
    126     root_dev = makedev(flag_major, flag_minor);
    127   } else {
    128     /* Yields the containing dev_t in st_dev. */
    129     if (stat(flag_path, &path_stat) != 0)
    130       err(1, "Cannot stat(%s)", flag_path);
    131     root_dev = path_stat.st_dev;
    132   }
    133 
    134   path[0] = '\0';
    135   ret = rootdev_wrapper(path, sizeof(path),
    136                         flag_use_slave,
    137                         flag_strip_partition,
    138                         &root_dev,
    139                         flag_block_path,
    140                         flag_dev_path);
    141 
    142   if (ret == 1 && flag_create) {
    143     /* TODO(wad) add flag_force to allow replacement */
    144     ret = 0;
    145     if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR, root_dev) && errno != EEXIST) {
    146       warn("failed to create %s", path);
    147       ret = 1;
    148     }
    149   }
    150 
    151   if (flag_ignore && ret > 0)
    152     ret = 0;
    153 
    154   if (path[0] != '\0')
    155     printf("%s\n", path);
    156 
    157   return ret;
    158 }
    159