2 * raw.c: User mode tool to bind and query raw character devices.
4 * Stephen Tweedie, 1999, 2000
6 * This file may be redistributed under the terms of the GNU General
7 * Public License, version 2.
9 * Copyright Red Hat Software, 1999, 2000
16 #include <linux/major.h>
17 #include <linux/raw.h>
21 #include <sys/ioctl.h>
26 #include "closestream.h"
28 #include "pathnames.h"
30 #define EXIT_RAW_ACCESS 3
31 #define EXIT_RAW_IOCTL 4
33 #define RAW_NR_MINORS 8192
36 static int do_query_all
;
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
);
45 static void __attribute__((__noreturn__
)) usage(void)
48 fputs(USAGE_HEADER
, out
);
50 _(" %1$s %2$srawN <major> <minor>\n"
51 " %1$s %2$srawN /dev/<blockdevice>\n"
53 " %1$s -qa\n"), program_invocation_short_name
,
56 fputs(USAGE_SEPARATOR
, out
);
57 fputs(_("Bind a raw character device to a block device.\n"), out
);
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 print_usage_help_options(16);
63 fprintf(out
, USAGE_MAN_TAIL("raw(8)"));
67 static long strtol_octal_or_err(const char *str
, const char *errmesg
)
72 if (str
== NULL
|| *str
== '\0')
75 num
= strtol(str
, &end
, 0);
77 if (errno
|| str
== end
|| (end
&& *end
))
83 err(EXIT_FAILURE
, "%s: '%s'", errmesg
, str
);
85 errx(EXIT_FAILURE
, "%s: '%s'", errmesg
, str
);
89 int main(int argc
, char *argv
[])
95 int block_major
, block_minor
;
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'},
108 setlocale(LC_ALL
, "");
109 bindtextdomain(PACKAGE
, LOCALEDIR
);
111 atexit(close_stdout
);
113 while ((c
= getopt_long(argc
, argv
, "qaVh", longopts
, NULL
)) != -1)
122 printf(UTIL_LINUX_VERSION
);
127 errtryhelp(EXIT_FAILURE
);
131 * Check for, and open, the master raw device, /dev/raw
137 warnx(_("bad usage"));
138 errtryhelp(EXIT_FAILURE
);
140 for (i
= 1; i
< RAW_NR_MINORS
; i
++)
146 * It's a bind or a single query. Either way we need a raw device.
149 if (optind
>= argc
) {
150 warnx(_("bad usage"));
151 errtryhelp(EXIT_FAILURE
);
153 raw_name
= argv
[optind
++];
156 * try to check the device name before stat(), because on systems with
157 * udev the raw0 causes a create udev event for char 162/0, which
158 * causes udev to *remove* /dev/rawctl
160 rc
= sscanf(raw_name
, _PATH_RAWDEVDIR
"raw%d", &raw_minor
);
162 warnx(_("bad usage"));
163 errtryhelp(EXIT_FAILURE
);
166 errx(EXIT_RAW_ACCESS
,
167 _("Device '%s' is the control raw device "
168 "(use raw<N> where <N> is greater than zero)"),
172 return query(raw_minor
, raw_name
, 0);
175 * It's not a query, so we still have some parsing to do. Have we been
176 * given a block device filename or a major/minor pair?
178 switch (argc
- optind
) {
180 block_name
= argv
[optind
];
181 retval
= stat(block_name
, &statbuf
);
184 _("Cannot locate block device '%s'"), block_name
);
185 if (!S_ISBLK(statbuf
.st_mode
))
186 errx(EXIT_RAW_ACCESS
,
187 _("Device '%s' is not a block device"),
189 block_major
= major(statbuf
.st_rdev
);
190 block_minor
= minor(statbuf
.st_rdev
);
195 strtol_octal_or_err(argv
[optind
],
196 _("failed to parse argument"));
198 strtol_octal_or_err(argv
[optind
+ 1],
199 _("failed to parse argument"));
203 warnx(_("bad usage"));
204 errtryhelp(EXIT_FAILURE
);
207 return bind(raw_minor
, block_major
, block_minor
);
210 void open_raw_ctl(void)
212 master_fd
= open(_PATH_RAWDEVCTL
, O_RDWR
, 0);
214 master_fd
= open(_PATH_RAWDEVCTL_OLD
, O_RDWR
, 0);
217 _("Cannot open master raw device '%s'"),
222 static int query(int minor_raw
, const char *raw_name
, int quiet
)
224 struct raw_config_request rq
;
225 static int has_worked
= 0;
230 if (stat(raw_name
, &statbuf
) != 0)
232 _("Cannot locate raw device '%s'"), raw_name
);
233 if (!S_ISCHR(statbuf
.st_mode
))
234 errx(EXIT_RAW_ACCESS
,
235 _("Raw device '%s' is not a character dev"),
237 if (major(statbuf
.st_rdev
) != RAW_MAJOR
)
238 errx(EXIT_RAW_ACCESS
,
239 _("Device '%s' is not a raw dev"), raw_name
);
240 minor_raw
= minor(statbuf
.st_rdev
);
243 rq
.raw_minor
= minor_raw
;
244 if (ioctl(master_fd
, RAW_GETBIND
, &rq
) < 0) {
245 if (quiet
&& errno
== ENODEV
)
247 if (has_worked
&& errno
== EINVAL
)
249 err(EXIT_RAW_IOCTL
, _("Error querying raw device"));
252 /* If one query has worked, mark that fact so that we don't report
253 * spurious fatal errors if raw(8) has been built to support more raw
254 * minor numbers than the kernel has. */
256 if (quiet
&& !rq
.block_major
&& !rq
.block_minor
)
258 printf(_("%sraw%d: bound to major %d, minor %d\n"),
259 _PATH_RAWDEVDIR
, minor_raw
, (int)rq
.block_major
,
260 (int)rq
.block_minor
);
264 static int bind(int minor_raw
, int block_major
, int block_minor
)
266 struct raw_config_request rq
;
268 rq
.raw_minor
= minor_raw
;
269 rq
.block_major
= block_major
;
270 rq
.block_minor
= block_minor
;
271 if (ioctl(master_fd
, RAW_SETBIND
, &rq
) < 0)
272 err(EXIT_RAW_IOCTL
, _("Error setting raw device"));
273 printf(_("%sraw%d: bound to major %d, minor %d\n"),
274 _PATH_RAWDEVDIR
, raw_minor
, (int)rq
.block_major
,
275 (int)rq
.block_minor
);