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 printf(USAGE_HELP_OPTIONS(16));
63 printf(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 close_stdout_atexit();
113 while ((c
= getopt_long(argc
, argv
, "qaVh", longopts
, NULL
)) != -1)
122 print_version(EXIT_SUCCESS
);
126 errtryhelp(EXIT_FAILURE
);
130 * Check for, and open, the master raw device, /dev/raw
136 warnx(_("bad usage"));
137 errtryhelp(EXIT_FAILURE
);
139 for (i
= 1; i
< RAW_NR_MINORS
; i
++)
145 * It's a bind or a single query. Either way we need a raw device.
148 if (optind
>= argc
) {
149 warnx(_("bad usage"));
150 errtryhelp(EXIT_FAILURE
);
152 raw_name
= argv
[optind
++];
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
159 rc
= sscanf(raw_name
, _PATH_RAWDEVDIR
"raw%d", &raw_minor
);
161 warnx(_("bad usage"));
162 errtryhelp(EXIT_FAILURE
);
165 errx(EXIT_RAW_ACCESS
,
166 _("Device '%s' is the control raw device "
167 "(use raw<N> where <N> is greater than zero)"),
171 return query(raw_minor
, raw_name
, 0);
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?
177 switch (argc
- optind
) {
179 block_name
= argv
[optind
];
180 retval
= stat(block_name
, &statbuf
);
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"),
188 block_major
= major(statbuf
.st_rdev
);
189 block_minor
= minor(statbuf
.st_rdev
);
194 strtol_octal_or_err(argv
[optind
],
195 _("failed to parse argument"));
197 strtol_octal_or_err(argv
[optind
+ 1],
198 _("failed to parse argument"));
202 warnx(_("bad usage"));
203 errtryhelp(EXIT_FAILURE
);
206 return bind(raw_minor
, block_major
, block_minor
);
209 void open_raw_ctl(void)
211 master_fd
= open(_PATH_RAWDEVCTL
, O_RDWR
, 0);
213 master_fd
= open(_PATH_RAWDEVCTL_OLD
, O_RDWR
, 0);
216 _("Cannot open master raw device '%s'"),
221 static int query(int minor_raw
, const char *raw_name
, int quiet
)
223 struct raw_config_request rq
;
224 static int has_worked
= 0;
229 if (stat(raw_name
, &statbuf
) != 0)
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"),
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
);
242 rq
.raw_minor
= minor_raw
;
243 if (ioctl(master_fd
, RAW_GETBIND
, &rq
) < 0) {
244 if (quiet
&& errno
== ENODEV
)
246 if (has_worked
&& errno
== EINVAL
)
248 err(EXIT_RAW_IOCTL
, _("Error querying raw device"));
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. */
255 if (quiet
&& !rq
.block_major
&& !rq
.block_minor
)
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
);
263 static int bind(int minor_raw
, int block_major
, int block_minor
)
265 struct raw_config_request rq
;
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
);