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