]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/raw.c
include/c: add print_version() macro
[thirdparty/util-linux.git] / disk-utils / raw.c
CommitLineData
eb63b9b8
KZ
1/*
2 * raw.c: User mode tool to bind and query raw character devices.
3 *
22853e4a 4 * Stephen Tweedie, 1999, 2000
eb63b9b8
KZ
5 *
6 * This file may be redistributed under the terms of the GNU General
7 * Public License, version 2.
cd121363 8 *
22853e4a 9 * Copyright Red Hat Software, 1999, 2000
eb63b9b8
KZ
10 *
11 */
12
eb63b9b8 13#include <errno.h>
d5c28ebc 14#include <fcntl.h>
cd121363
SK
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>
eb63b9b8 21#include <sys/ioctl.h>
cd121363 22#include <sys/stat.h>
cd121363 23#include <unistd.h>
7c7c8bc5
SK
24
25#include "c.h"
45ca68ec 26#include "closestream.h"
5dd48fb2 27#include "nls.h"
16d8a9c9 28#include "pathnames.h"
eb63b9b8 29
44e53535
SK
30#define EXIT_RAW_ACCESS 3
31#define EXIT_RAW_IOCTL 4
6db46818 32
34ab1590 33#define RAW_NR_MINORS 8192
eb63b9b8 34
2ba641e5
SK
35static int do_query;
36static int do_query_all;
eb63b9b8 37
2ba641e5
SK
38static int master_fd;
39static int raw_minor;
eb63b9b8
KZ
40
41void open_raw_ctl(void);
89c50053 42static int query(int minor_raw, const char *raw_name, int quiet);
43static int bind(int minor_raw, int block_major, int block_minor);
eb63b9b8 44
5118d1be 45static void __attribute__((__noreturn__)) usage(void)
eb63b9b8 46{
5118d1be 47 FILE *out = stdout;
7c7c8bc5
SK
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"
16d8a9c9
SK
53 " %1$s -qa\n"), program_invocation_short_name,
54 _PATH_RAWDEVDIR);
451dbcfa
BS
55
56 fputs(USAGE_SEPARATOR, out);
57 fputs(_("Bind a raw character device to a block device.\n"), out);
58
7c7c8bc5 59 fputs(USAGE_OPTIONS, out);
1e0aef82
SK
60 fputs(_(" -q, --query set query mode\n"), out);
61 fputs(_(" -a, --all query all raw devices\n"), out);
f45f3ec3
RM
62 printf(USAGE_HELP_OPTIONS(16));
63 printf(USAGE_MAN_TAIL("raw(8)"));
5118d1be 64 exit(EXIT_SUCCESS);
eb63b9b8
KZ
65}
66
16bade89 67static long strtol_octal_or_err(const char *str, const char *errmesg)
d5fc1b15
SK
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
eb63b9b8
KZ
89int main(int argc, char *argv[])
90{
cd121363
SK
91 int c;
92 char *raw_name;
93 char *block_name;
94 int retval;
95 int block_major, block_minor;
96 int i, rc;
eb63b9b8
KZ
97
98 struct stat statbuf;
5dd48fb2 99
1e0aef82 100 static const struct option longopts[] = {
87918040
SK
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'},
1e0aef82
SK
106 };
107
9d2b339a 108 setlocale(LC_ALL, "");
5dd48fb2
PR
109 bindtextdomain(PACKAGE, LOCALEDIR);
110 textdomain(PACKAGE);
45ca68ec 111 atexit(close_stdout);
5dd48fb2 112
cd121363 113 while ((c = getopt_long(argc, argv, "qaVh", longopts, NULL)) != -1)
eb63b9b8 114 switch (c) {
1e0aef82
SK
115 case 'q':
116 do_query = 1;
117 break;
eb63b9b8
KZ
118 case 'a':
119 do_query_all = 1;
120 break;
1e0aef82
SK
121 case 'V':
122 printf(UTIL_LINUX_VERSION);
123 return EXIT_SUCCESS;
eb63b9b8 124 case 'h':
5118d1be 125 usage();
eb63b9b8 126 default:
677ec86c 127 errtryhelp(EXIT_FAILURE);
eb63b9b8 128 }
5dd48fb2 129
eb63b9b8
KZ
130 /*
131 * Check for, and open, the master raw device, /dev/raw
132 */
eb63b9b8 133 open_raw_ctl();
5dd48fb2 134
eb63b9b8 135 if (do_query_all) {
5118d1be
RM
136 if (optind < argc) {
137 warnx(_("bad usage"));
138 errtryhelp(EXIT_FAILURE);
139 }
34ab1590 140 for (i = 1; i < RAW_NR_MINORS; i++)
b41f637c 141 query(i, NULL, 1);
44e53535 142 exit(EXIT_SUCCESS);
eb63b9b8 143 }
5dd48fb2 144
eb63b9b8
KZ
145 /*
146 * It's a bind or a single query. Either way we need a raw device.
147 */
148
5118d1be
RM
149 if (optind >= argc) {
150 warnx(_("bad usage"));
151 errtryhelp(EXIT_FAILURE);
152 }
eb63b9b8
KZ
153 raw_name = argv[optind++];
154
34ab1590
KZ
155 /*
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
159 */
16d8a9c9 160 rc = sscanf(raw_name, _PATH_RAWDEVDIR "raw%d", &raw_minor);
5118d1be
RM
161 if (rc != 1) {
162 warnx(_("bad usage"));
163 errtryhelp(EXIT_FAILURE);
164 }
82b7ef36
SK
165 if (raw_minor == 0)
166 errx(EXIT_RAW_ACCESS,
167 _("Device '%s' is the control raw device "
168 "(use raw<N> where <N> is greater than zero)"),
169 raw_name);
34ab1590 170
eb63b9b8 171 if (do_query)
b41f637c 172 return query(raw_minor, raw_name, 0);
34ab1590 173
5dd48fb2 174 /*
cd121363
SK
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?
eb63b9b8 177 */
eb63b9b8
KZ
178 switch (argc - optind) {
179 case 1:
180 block_name = argv[optind];
82b7ef36
SK
181 retval = stat(block_name, &statbuf);
182 if (retval)
183 err(EXIT_RAW_ACCESS,
cd121363 184 _("Cannot locate block device '%s'"), block_name);
82b7ef36
SK
185 if (!S_ISBLK(statbuf.st_mode))
186 errx(EXIT_RAW_ACCESS,
187 _("Device '%s' is not a block device"),
188 block_name);
eb63b9b8
KZ
189 block_major = major(statbuf.st_rdev);
190 block_minor = minor(statbuf.st_rdev);
191 break;
5dd48fb2 192
eb63b9b8 193 case 2:
d5fc1b15
SK
194 block_major =
195 strtol_octal_or_err(argv[optind],
196 _("failed to parse argument"));
197 block_minor =
198 strtol_octal_or_err(argv[optind + 1],
199 _("failed to parse argument"));
eb63b9b8 200 break;
5dd48fb2 201
eb63b9b8 202 default:
5118d1be
RM
203 warnx(_("bad usage"));
204 errtryhelp(EXIT_FAILURE);
eb63b9b8 205 }
5dd48fb2 206
eb63b9b8 207 return bind(raw_minor, block_major, block_minor);
eb63b9b8
KZ
208}
209
eb63b9b8
KZ
210void open_raw_ctl(void)
211{
16d8a9c9 212 master_fd = open(_PATH_RAWDEVCTL, O_RDWR, 0);
eb63b9b8 213 if (master_fd < 0) {
16d8a9c9 214 master_fd = open(_PATH_RAWDEVCTL_OLD, O_RDWR, 0);
82b7ef36
SK
215 if (master_fd < 0)
216 err(EXIT_RAW_ACCESS,
16d8a9c9
SK
217 _("Cannot open master raw device '%s'"),
218 _PATH_RAWDEVCTL);
eb63b9b8
KZ
219 }
220}
221
89c50053 222static int query(int minor_raw, const char *raw_name, int quiet)
eb63b9b8
KZ
223{
224 struct raw_config_request rq;
34ab1590 225 static int has_worked = 0;
34ab1590 226
b41f637c
JM
227 if (raw_name) {
228 struct stat statbuf;
229
a434e239 230 if (stat(raw_name, &statbuf) != 0)
82b7ef36
SK
231 err(EXIT_RAW_ACCESS,
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"),
236 raw_name);
237 if (major(statbuf.st_rdev) != RAW_MAJOR)
238 errx(EXIT_RAW_ACCESS,
239 _("Device '%s' is not a raw dev"), raw_name);
89c50053 240 minor_raw = minor(statbuf.st_rdev);
b41f637c
JM
241 }
242
89c50053 243 rq.raw_minor = minor_raw;
cd121363 244 if (ioctl(master_fd, RAW_GETBIND, &rq) < 0) {
eb63b9b8
KZ
245 if (quiet && errno == ENODEV)
246 return 3;
34ab1590
KZ
247 if (has_worked && errno == EINVAL)
248 return 0;
82b7ef36 249 err(EXIT_RAW_IOCTL, _("Error querying raw device"));
eb63b9b8 250 }
82b7ef36 251
cd121363
SK
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. */
34ab1590 255 has_worked = 1;
eb63b9b8
KZ
256 if (quiet && !rq.block_major && !rq.block_minor)
257 return 0;
16d8a9c9
SK
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);
eb63b9b8
KZ
261 return 0;
262}
263
89c50053 264static int bind(int minor_raw, int block_major, int block_minor)
eb63b9b8
KZ
265{
266 struct raw_config_request rq;
5dd48fb2 267
cd121363 268 rq.raw_minor = minor_raw;
eb63b9b8
KZ
269 rq.block_major = block_major;
270 rq.block_minor = block_minor;
60d72321 271 if (ioctl(master_fd, RAW_SETBIND, &rq) < 0)
82b7ef36 272 err(EXIT_RAW_IOCTL, _("Error setting raw device"));
16d8a9c9
SK
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);
eb63b9b8
KZ
276 return 0;
277}