blob: 8473fa44b8d557a004922cd0a5d5531b010ce11d [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>
Yunlian Jiang8dc336a2018-07-18 20:57:29 -070016#include <sys/sysmacros.h>
Will Drewry80fbc6c2010-08-30 10:13:34 -050017#include <sys/types.h>
18#include <unistd.h>
19
20#include "rootdev.h"
21
22static void print_help(const char *progname) {
23 fprintf(stderr,
24 "%s [OPTIONS] [PATH]\n"
25 "Outputs the containing device for the specified PATH.\n"
26 "With no arguments, '/' is assumed.\n"
27 "\n"
28 "Options:\n"
29 " -h\tthis message.\n"
30 "\n"
31 " -c\tcreate the /dev node if it cannot be found\n"
32 " -d\treturn the block device only if possible\n"
33 " -i\treturn path even if the node doesn't exist\n"
34 " -s\tif possible, return the first slave of the root device\n"
35 "\n"
36 " --block [path]\tset the path to block under the sys mount point\n"
37 " --dev [path]\tset the path to dev mount point\n"
38 " --major [num]\tset the major number of the rootdev\n"
39 " --minor [num]\tset the minor number of the rootdev\n",
40 progname);
41}
42
43static int flag_help = 0;
44static int flag_use_slave = 0;
45static int flag_strip_partition = 0;
46static int flag_ignore = 0;
47static int flag_create = 0;
48static int flag_major = 0;
49static int flag_minor = 0;
50static const char *flag_path = "/";
51static char *flag_block_path = "/sys/block";
52static char *flag_dev_path = "/dev";
53
54static void parse_args(int argc, char **argv) {
55 while (1) {
56 int c;
57 int option_index = 0;
58 static const struct option long_options[] = {
59 {"c", no_argument, &flag_create, 1},
60 {"d", no_argument, &flag_strip_partition, 1},
61 {"h", no_argument, &flag_help, 1},
62 {"i", no_argument, &flag_ignore, 1},
63 {"s", no_argument, &flag_use_slave, 1},
64 /* Long arguments for testing. */
65 {"block", required_argument, NULL, 'b'},
66 {"dev", required_argument, NULL, 'd'},
67 {"major", required_argument, NULL, 'M'},
68 {"minor", required_argument, NULL, 'm'},
69 {0, 0, 0, 0}
70 };
71 c = getopt_long_only(argc, argv, "", long_options, &option_index);
72
73 if (c == -1)
74 break;
75
76 if (c == '?') {
77 flag_help = 1;
78 break;
79 }
80
81 switch (c) {
82 case 'b':
83 flag_block_path = optarg;
84 break;
85 case 'd':
86 flag_dev_path = optarg;
87 break;
88 case 'M':
89 flag_major = atoi(optarg);
90 break;
91 case 'm':
92 flag_minor = atoi(optarg);
93 break;
94 }
95
96 }
97
98 if (flag_create && flag_strip_partition) {
99 flag_help = 1;
100 warnx("-c and -d are incompatible at present.");
101 return;
102 }
103
104 if (optind < argc) {
105 flag_path = argv[optind++];
106 }
107
108 if (optind < argc) {
109 fprintf(stderr, "Too many free arguments: %d\n", argc - optind);
110 flag_help = 1;
111 }
112}
113
114int main(int argc, char **argv) {
115 struct stat path_stat;
116 char path[PATH_MAX];
117 int ret;
118 dev_t root_dev;
119 parse_args(argc, argv);
120
121 if (flag_help) {
122 print_help(argv[0]);
123 return 1;
124 }
125
126 if (flag_major || flag_minor) {
127 root_dev = makedev(flag_major, flag_minor);
128 } else {
129 /* Yields the containing dev_t in st_dev. */
130 if (stat(flag_path, &path_stat) != 0)
131 err(1, "Cannot stat(%s)", flag_path);
132 root_dev = path_stat.st_dev;
133 }
134
Mike Frysinger32979f62014-12-11 23:00:55 -0500135 path[0] = '\0';
Will Drewry80fbc6c2010-08-30 10:13:34 -0500136 ret = rootdev_wrapper(path, sizeof(path),
137 flag_use_slave,
138 flag_strip_partition,
139 &root_dev,
Xiaochu Liub9b8f1d2017-04-24 13:32:06 -0700140 flag_path,
Will Drewry80fbc6c2010-08-30 10:13:34 -0500141 flag_block_path,
142 flag_dev_path);
143
Xiaochu Liub9b8f1d2017-04-24 13:32:06 -0700144 /* root_dev can be zero-out by rootdev_wrapper when virtual
145 * device id is used (e.g. btrfs). */
146 if (root_dev != 0 && ret == 1 && flag_create) {
Will Drewry80fbc6c2010-08-30 10:13:34 -0500147 /* TODO(wad) add flag_force to allow replacement */
148 ret = 0;
149 if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR, root_dev) && errno != EEXIST) {
150 warn("failed to create %s", path);
151 ret = 1;
152 }
153 }
154
155 if (flag_ignore && ret > 0)
156 ret = 0;
157
158 if (path[0] != '\0')
159 printf("%s\n", path);
160
161 return ret;
162}