]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/raw.c
libblkid: make example more robust
[thirdparty/util-linux.git] / disk-utils / raw.c
1 /*
2 * raw.c: User mode tool to bind and query raw character devices.
3 *
4 * Stephen Tweedie, 1999, 2000
5 *
6 * This file may be redistributed under the terms of the GNU General
7 * Public License, version 2.
8 *
9 * Copyright Red Hat Software, 1999, 2000
10 *
11 */
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <getopt.h>
16 #include <linux/major.h>
17 #include <linux/raw.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "c.h"
26 #include "closestream.h"
27 #include "nls.h"
28 #include "pathnames.h"
29
30 #define EXIT_RAW_ACCESS 3
31 #define EXIT_RAW_IOCTL 4
32
33 #define RAW_NR_MINORS 8192
34
35 static int do_query;
36 static int do_query_all;
37
38 static int master_fd;
39 static int raw_minor;
40
41 void open_raw_ctl(void);
42 static int query(int minor_raw, const char *raw_name, int quiet);
43 static int bind(int minor_raw, int block_major, int block_minor);
44
45 static void __attribute__((__noreturn__)) usage(void)
46 {
47 FILE *out = stdout;
48 fputs(USAGE_HEADER, out);
49 fprintf(out,
50 _(" %1$s %2$srawN <major> <minor>\n"
51 " %1$s %2$srawN /dev/<blockdevice>\n"
52 " %1$s -q %2$srawN\n"
53 " %1$s -qa\n"), program_invocation_short_name,
54 _PATH_RAWDEVDIR);
55
56 fputs(USAGE_SEPARATOR, out);
57 fputs(_("Bind a raw character device to a block device.\n"), out);
58
59 fputs(USAGE_OPTIONS, out);
60 fputs(_(" -q, --query set query mode\n"), out);
61 fputs(_(" -a, --all query all raw devices\n"), out);
62 printf(USAGE_HELP_OPTIONS(16));
63 printf(USAGE_MAN_TAIL("raw(8)"));
64 exit(EXIT_SUCCESS);
65 }
66
67 static long strtol_octal_or_err(const char *str, const char *errmesg)
68 {
69 long num;
70 char *end = NULL;
71
72 if (str == NULL || *str == '\0')
73 goto err;
74 errno = 0;
75 num = strtol(str, &end, 0);
76
77 if (errno || str == end || (end && *end))
78 goto err;
79
80 return num;
81 err:
82 if (errno)
83 err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
84 else
85 errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
86 return 0;
87 }
88
89 int main(int argc, char *argv[])
90 {
91 int c;
92 char *raw_name;
93 char *block_name;
94 int retval;
95 int block_major, block_minor;
96 int i, rc;
97
98 struct stat statbuf;
99
100 static const struct option longopts[] = {
101 {"query", no_argument, NULL, 'q'},
102 {"all", no_argument, NULL, 'a'},
103 {"version", no_argument, NULL, 'V'},
104 {"help", no_argument, NULL, 'h'},
105 {NULL, 0, NULL, '0'},
106 };
107
108 setlocale(LC_ALL, "");
109 bindtextdomain(PACKAGE, LOCALEDIR);
110 textdomain(PACKAGE);
111 close_stdout_atexit();
112
113 while ((c = getopt_long(argc, argv, "qaVh", longopts, NULL)) != -1)
114 switch (c) {
115 case 'q':
116 do_query = 1;
117 break;
118 case 'a':
119 do_query_all = 1;
120 break;
121 case 'V':
122 print_version(EXIT_SUCCESS);
123 case 'h':
124 usage();
125 default:
126 errtryhelp(EXIT_FAILURE);
127 }
128
129 /*
130 * Check for, and open, the master raw device, /dev/raw
131 */
132 open_raw_ctl();
133
134 if (do_query_all) {
135 if (optind < argc) {
136 warnx(_("bad usage"));
137 errtryhelp(EXIT_FAILURE);
138 }
139 for (i = 1; i < RAW_NR_MINORS; i++)
140 query(i, NULL, 1);
141 exit(EXIT_SUCCESS);
142 }
143
144 /*
145 * It's a bind or a single query. Either way we need a raw device.
146 */
147
148 if (optind >= argc) {
149 warnx(_("bad usage"));
150 errtryhelp(EXIT_FAILURE);
151 }
152 raw_name = argv[optind++];
153
154 /*
155 * try to check the device name before stat(), because on systems with
156 * udev the raw0 causes a create udev event for char 162/0, which
157 * causes udev to *remove* /dev/rawctl
158 */
159 rc = sscanf(raw_name, _PATH_RAWDEVDIR "raw%d", &raw_minor);
160 if (rc != 1) {
161 warnx(_("bad usage"));
162 errtryhelp(EXIT_FAILURE);
163 }
164 if (raw_minor == 0)
165 errx(EXIT_RAW_ACCESS,
166 _("Device '%s' is the control raw device "
167 "(use raw<N> where <N> is greater than zero)"),
168 raw_name);
169
170 if (do_query)
171 return query(raw_minor, raw_name, 0);
172
173 /*
174 * It's not a query, so we still have some parsing to do. Have we been
175 * given a block device filename or a major/minor pair?
176 */
177 switch (argc - optind) {
178 case 1:
179 block_name = argv[optind];
180 retval = stat(block_name, &statbuf);
181 if (retval)
182 err(EXIT_RAW_ACCESS,
183 _("Cannot locate block device '%s'"), block_name);
184 if (!S_ISBLK(statbuf.st_mode))
185 errx(EXIT_RAW_ACCESS,
186 _("Device '%s' is not a block device"),
187 block_name);
188 block_major = major(statbuf.st_rdev);
189 block_minor = minor(statbuf.st_rdev);
190 break;
191
192 case 2:
193 block_major =
194 strtol_octal_or_err(argv[optind],
195 _("failed to parse argument"));
196 block_minor =
197 strtol_octal_or_err(argv[optind + 1],
198 _("failed to parse argument"));
199 break;
200
201 default:
202 warnx(_("bad usage"));
203 errtryhelp(EXIT_FAILURE);
204 }
205
206 return bind(raw_minor, block_major, block_minor);
207 }
208
209 void open_raw_ctl(void)
210 {
211 master_fd = open(_PATH_RAWDEVCTL, O_RDWR, 0);
212 if (master_fd < 0) {
213 master_fd = open(_PATH_RAWDEVCTL_OLD, O_RDWR, 0);
214 if (master_fd < 0)
215 err(EXIT_RAW_ACCESS,
216 _("Cannot open master raw device '%s'"),
217 _PATH_RAWDEVCTL);
218 }
219 }
220
221 static int query(int minor_raw, const char *raw_name, int quiet)
222 {
223 struct raw_config_request rq;
224 static int has_worked = 0;
225
226 if (raw_name) {
227 struct stat statbuf;
228
229 if (stat(raw_name, &statbuf) != 0)
230 err(EXIT_RAW_ACCESS,
231 _("Cannot locate raw device '%s'"), raw_name);
232 if (!S_ISCHR(statbuf.st_mode))
233 errx(EXIT_RAW_ACCESS,
234 _("Raw device '%s' is not a character dev"),
235 raw_name);
236 if (major(statbuf.st_rdev) != RAW_MAJOR)
237 errx(EXIT_RAW_ACCESS,
238 _("Device '%s' is not a raw dev"), raw_name);
239 minor_raw = minor(statbuf.st_rdev);
240 }
241
242 rq.raw_minor = minor_raw;
243 if (ioctl(master_fd, RAW_GETBIND, &rq) < 0) {
244 if (quiet && errno == ENODEV)
245 return 3;
246 if (has_worked && errno == EINVAL)
247 return 0;
248 err(EXIT_RAW_IOCTL, _("Error querying raw device"));
249 }
250
251 /* If one query has worked, mark that fact so that we don't report
252 * spurious fatal errors if raw(8) has been built to support more raw
253 * minor numbers than the kernel has. */
254 has_worked = 1;
255 if (quiet && !rq.block_major && !rq.block_minor)
256 return 0;
257 printf(_("%sraw%d: bound to major %d, minor %d\n"),
258 _PATH_RAWDEVDIR, minor_raw, (int)rq.block_major,
259 (int)rq.block_minor);
260 return 0;
261 }
262
263 static int bind(int minor_raw, int block_major, int block_minor)
264 {
265 struct raw_config_request rq;
266
267 rq.raw_minor = minor_raw;
268 rq.block_major = block_major;
269 rq.block_minor = block_minor;
270 if (ioctl(master_fd, RAW_SETBIND, &rq) < 0)
271 err(EXIT_RAW_IOCTL, _("Error setting raw device"));
272 printf(_("%sraw%d: bound to major %d, minor %d\n"),
273 _PATH_RAWDEVDIR, raw_minor, (int)rq.block_major,
274 (int)rq.block_minor);
275 return 0;
276 }