blob: b2838eb181f68e403e264b8c7a9634a725c376ed [file] [log] [blame]
Will Drewry80fbc6c2010-08-30 10:13:34 -05001/* 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
21static 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
42static int flag_help = 0;
43static int flag_use_slave = 0;
44static int flag_strip_partition = 0;
45static int flag_ignore = 0;
46static int flag_create = 0;
47static int flag_major = 0;
48static int flag_minor = 0;
49static const char *flag_path = "/";
Bertrand SIMONNET70c33492015-09-01 13:18:18 -070050static char *flag_block_path = NULL;
51static char *flag_dev_path = NULL;
Will Drewry80fbc6c2010-08-30 10:13:34 -050052
53static 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
113int 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
Mike Frysinger32979f62014-12-11 23:00:55 -0500134 path[0] = '\0';
Will Drewry80fbc6c2010-08-30 10:13:34 -0500135 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}