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
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(int err
)
47 FILE *out
= err
== EXIT_SUCCESS
? stdout
: stderr
;
49 fputs(USAGE_HEADER
, out
);
51 _(" %1$s %2$srawN <major> <minor>\n"
52 " %1$s %2$srawN /dev/<blockdevice>\n"
54 " %1$s -qa\n"), program_invocation_short_name
,
57 fputs(USAGE_SEPARATOR
, out
);
58 fputs(_("Bind a raw character device to a block device.\n"), out
);
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)"));
69 static long strtol_octal_or_err(const char *str
, const char *errmesg
)
74 if (str
== NULL
|| *str
== '\0')
77 num
= strtol(str
, &end
, 0);
79 if (errno
|| str
== end
|| (end
&& *end
))
85 err(EXIT_FAILURE
, "%s: '%s'", errmesg
, str
);
87 errx(EXIT_FAILURE
, "%s: '%s'", errmesg
, str
);
91 int main(int argc
, char *argv
[])
97 int block_major
, block_minor
;
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'},
110 setlocale(LC_ALL
, "");
111 bindtextdomain(PACKAGE
, LOCALEDIR
);
113 atexit(close_stdout
);
115 while ((c
= getopt_long(argc
, argv
, "qaVh", longopts
, NULL
)) != -1)
124 printf(UTIL_LINUX_VERSION
);
129 errtryhelp(EXIT_FAILURE
);
133 * Check for, and open, the master raw device, /dev/raw
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.
151 raw_name
= argv
[optind
++];
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
158 rc
= sscanf(raw_name
, _PATH_RAWDEVDIR
"raw%d", &raw_minor
);
163 errx(EXIT_RAW_ACCESS
,
164 _("Device '%s' is the control raw device "
165 "(use raw<N> where <N> is greater than zero)"),
169 return query(raw_minor
, raw_name
, 0);
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?
175 switch (argc
- optind
) {
177 block_name
= argv
[optind
];
178 retval
= stat(block_name
, &statbuf
);
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"),
186 block_major
= major(statbuf
.st_rdev
);
187 block_minor
= minor(statbuf
.st_rdev
);
192 strtol_octal_or_err(argv
[optind
],
193 _("failed to parse argument"));
195 strtol_octal_or_err(argv
[optind
+ 1],
196 _("failed to parse argument"));
203 return bind(raw_minor
, block_major
, block_minor
);
206 void open_raw_ctl(void)
208 master_fd
= open(_PATH_RAWDEVCTL
, O_RDWR
, 0);
210 master_fd
= open(_PATH_RAWDEVCTL_OLD
, O_RDWR
, 0);
213 _("Cannot open master raw device '%s'"),
218 static int query(int minor_raw
, const char *raw_name
, int quiet
)
220 struct raw_config_request rq
;
221 static int has_worked
= 0;
226 if (stat(raw_name
, &statbuf
) != 0)
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"),
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
);
239 rq
.raw_minor
= minor_raw
;
240 if (ioctl(master_fd
, RAW_GETBIND
, &rq
) < 0) {
241 if (quiet
&& errno
== ENODEV
)
243 if (has_worked
&& errno
== EINVAL
)
245 err(EXIT_RAW_IOCTL
, _("Error querying raw device"));
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. */
252 if (quiet
&& !rq
.block_major
&& !rq
.block_minor
)
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
);
260 static int bind(int minor_raw
, int block_major
, int block_minor
)
262 struct raw_config_request rq
;
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
);