udftools

- Main Page
- Classes
- Files

- File List
- File Members

All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pktsetup.c
Go to the documentation of this file.
1 /*
2 * Copyright (c) 1999,2000 Jens Axboe <axboe@suse.de>
3 * Copyright (c) 2004 Peter Osterlund <petero2@telia.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <getopt.h>
29 #include <bits/types.h>
30 #include <sys/types.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <stdlib.h>
34 #include <errno.h>
35
36 #include <linux/cdrom.h>
37
38 /*
39 * if we don't have one, we probably have neither
40 */
41 #ifndef PACKET_SETUP_DEV
42 #define PACKET_SETUP_DEV _IOW('X', 1, unsigned int)
43 #define PACKET_TEARDOWN_DEV _IOW('X', 2, unsigned int)
44 #endif
45 #ifndef PACKET_CTRL_CMD
46 #define PACKET_CTRL_CMD _IOWR('X', 1, struct pkt_ctrl_command)
47 #endif
48
49 #define MAJOR(dev) ((dev & 0xfff00) >> 8)
50 #define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
51 #define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
52
53 #define MISC_MAJOR 10
54 #define CTL_DIR "/dev/pktcdvd"
55 #define CTL_DEV "control"
56
57 #define PKT_CTRL_CMD_SETUP 0
58 #define PKT_CTRL_CMD_TEARDOWN 1
59 #define PKT_CTRL_CMD_STATUS 2
60
61 struct pkt_ctrl_command {
62 __u32 command; /* in: Setup, teardown, status */
63 __u32 dev_index; /* in/out: Device index */
64 __u32 dev; /* in/out: Device nr for cdrw device */
65 __u32 pkt_dev; /* out: Device nr for packet device */
66 __u32 num_devices; /* out: Largest device index + 1 */
67 __u32 padding;
68 };
69
70
71 static int init_cdrom(int fd)
72 {
73 if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) < 0) {
74 perror("drive not ready\n");
75 return 1;
76 }
77
78 if (ioctl(fd, CDROM_DISC_STATUS, CDSL_CURRENT) < 0) {
79 perror("no disc inserted?\n");
80 return 1;
81 }
82
83 /*
84 * we don't care what disc type the uniform layer thinks it
85 * is, since it may get it wrong. what matters is that the above
86 * will force a TOC read.
87 */
88 return 0;
89 }
90
91 static int setup_dev(char *pkt_device, char *device, int rem)
92 {
93 int pkt_fd, dev_fd, cmd, arg, ret;
94
95 if ((pkt_fd = open(pkt_device, O_RDONLY)) == -1) {
96 perror("open packet device");
97 return 1;
98 }
99
100 if (!rem) {
101 cmd = PACKET_SETUP_DEV;
102 if ((dev_fd = open(device, O_RDONLY | O_NONBLOCK)) == -1) {
103 perror("open cd-rom");
104 close(pkt_fd);
105 return 1;
106 }
107 if (init_cdrom(dev_fd)) {
108 close(pkt_fd);
109 close(dev_fd);
110 return 1;
111 }
112 arg = dev_fd;
113 } else {
114 cmd = PACKET_TEARDOWN_DEV;
115 dev_fd = -1;
116 arg = 0;
117 }
118
119 ret = ioctl(pkt_fd, cmd, arg);
120 if (ret == -1)
121 perror("ioctl");
122
123 if (dev_fd >= 0)
124 close(dev_fd);
125 close(pkt_fd);
126
127 if (ret == -1)
128 return 1;
129
130 return 0;
131 }
132
133 static int usage(void)
134 {
135 printf("pktsetup from " PACKAGE_NAME " " PACKAGE_VERSION "\n");
136 printf("Set up and tear down packet device associations\n");
137 printf("For pktcdvd < 0.2.0:\n");
138 printf(" pktsetup /dev/pktcdvd0 /dev/cdrom setup device\n");
139 printf(" pktsetup -d /dev/pktcdvd0 tear down device\n");
140 printf("For pktcdvd >= 0.2.0:\n");
141 printf(" pktsetup dev_name /dev/cdrom setup device\n");
142 printf(" pktsetup -d dev_name tear down device\n");
143 printf(" pktsetup -d major:minor tear down device\n");
144 printf(" pktsetup -s show device mappings\n");
145 return 1;
146 }
147
148 /*
149 * Find the minor device number for the pktcdvd control device.
150 */
151 static int get_misc_minor(void)
152 {
153 int minor;
154 char name[64];
155 FILE *f;
156
157 if ((f = fopen("/proc/misc", "r")) == NULL)
158 return -1;
159 while (fscanf(f, " %d %63s", &minor, name) == 2) {
160 if (strcmp(name, "pktcdvd") == 0) {
161 fclose(f);
162 return minor;
163 }
164 }
165 fclose(f);
166 return -1;
167 }
168
169 static const char *pkt_dev_name(const char *dev)
170 {
171 static char buf[128];
172 snprintf(buf, sizeof(buf), "%s/%s", CTL_DIR, dev);
173 return buf;
174 }
175
176 static int create_ctl_dev(void)
177 {
178 int misc_minor;
179 struct stat stat_buf;
180 dev_t dev;
181
182 if ((misc_minor = get_misc_minor()) < 0) {
183 if (system("/sbin/modprobe pktcdvd") != 0) {
184 fprintf(stderr, "Can't load pktcdvd kernel module\n");
185 }
186 misc_minor = get_misc_minor();
187 }
188 if (misc_minor < 0) {
189 fprintf(stderr, "Can't find pktcdvd character device\n");
190 return -1;
191 }
192 dev = MKDEV(MISC_MAJOR, misc_minor);
193
194 if ((stat(pkt_dev_name(CTL_DEV), &stat_buf) >= 0) &&
195 S_ISCHR(stat_buf.st_mode) && (stat_buf.st_rdev == dev))
196 return 0; /* Already set up */
197
198 mkdir(CTL_DIR, 0755);
199 unlink(pkt_dev_name(CTL_DEV));
200
201 if (mknod(pkt_dev_name(CTL_DEV), S_IFCHR | 0644, dev) < 0) {
202 fprintf(stderr, "Can't create device %s: %s\n", pkt_dev_name(CTL_DEV), strerror(errno));
203 return -1;
204 }
205
206 return 0;
207 }
208
209 static int remove_stale_dev_node(int ctl_fd, char *devname)
210 {
211 struct stat stat_buf;
212 unsigned int i;
213 dev_t dev;
214 struct pkt_ctrl_command c;
215
216 if (stat(pkt_dev_name(devname), &stat_buf) < 0)
217 return 0;
218 if (!S_ISBLK(stat_buf.st_mode))
219 return 1;
220 dev = stat_buf.st_rdev;
221 memset(&c, 0, sizeof(struct pkt_ctrl_command));
222 for (i = 0; ; i++) {
223 c.command = PKT_CTRL_CMD_STATUS;
224 c.dev_index = i;
225 if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
226 perror("ioctl");
227 return 1;
228 }
229 if (i >= c.num_devices)
230 break;
231 if (c.pkt_dev == dev)
232 return 1; /* busy */
233 }
234 unlink(pkt_dev_name(devname));
235 return 0;
236 }
237
238 static int setup_dev_chardev(char *pkt_device, char *device, int rem)
239 {
240 struct pkt_ctrl_command c;
241 struct stat stat_buf;
242 int ctl_fd, dev_fd;
243 int ret = 1;
244
245 memset(&c, 0, sizeof(struct pkt_ctrl_command));
246
247 if (create_ctl_dev() < 0)
248 return 1;
249
250 if ((ctl_fd = open(pkt_dev_name(CTL_DEV), O_RDONLY)) < 0) {
251 perror("ctl open");
252 return 1;
253 }
254
255 if (!rem) {
256 if ((dev_fd = open(device, O_RDONLY | O_NONBLOCK)) == -1) {
257 perror("open cd-rom");
258 goto out_close;
259 }
260 if (init_cdrom(dev_fd)) {
261 close(dev_fd);
262 goto out_close;
263 }
264 close(dev_fd);
265
266 if (stat(device, &stat_buf) < 0) {
267 perror("stat cd-rom");
268 goto out_close;
269 }
270 if (!S_ISBLK(stat_buf.st_mode)) {
271 fprintf(stderr, "Not a block device\n");
272 goto out_close;
273 }
274 c.command = PKT_CTRL_CMD_SETUP;
275 c.dev = stat_buf.st_rdev;
276
277 if (remove_stale_dev_node(ctl_fd, pkt_device) != 0) {
278 fprintf(stderr, "Device node '%s' already in use\n", pkt_device);
279 goto out_close;
280 }
281 if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
282 perror("ioctl");
283 goto out_close;
284 }
285 if (mknod(pkt_dev_name(pkt_device), S_IFBLK | 0640, c.pkt_dev) < 0) {
286 fprintf(stderr, "Can't create device node '%s': %s\n", pkt_dev_name(pkt_device), strerror(errno));
287 goto out_close;
288 }
289 ret = 0;
290 } else {
291 int major, minor, remove_node;
292
293 if ((stat(pkt_dev_name(pkt_device), &stat_buf) >= 0) &&
294 S_ISBLK(stat_buf.st_mode)) {
295 major = MAJOR(stat_buf.st_rdev);
296 minor = MINOR(stat_buf.st_rdev);
297 remove_node = 1;
298 } else if (sscanf(pkt_device, "%d:%d", &major, &minor) == 2) {
299 remove_node = 0;
300 } else {
301 fprintf(stderr, "Can't find major/minor numbers\n");
302 goto out_close;
303 }
304
305 c.command = PKT_CTRL_CMD_TEARDOWN;
306 c.pkt_dev = MKDEV(major, minor);
307 if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
308 perror("ioctl");
309 goto out_close;
310 }
311 if (remove_node) {
312 if (unlink(pkt_dev_name(pkt_device)) == 0)
313 ret = 0;
314 } else {
315 ret = 0;
316 }
317 }
318
319 out_close:
320 close(ctl_fd);
321 return ret;
322 }
323
324 static void show_mappings(void)
325 {
326 struct pkt_ctrl_command c;
327 unsigned int i;
328 int ctl_fd;
329
330 memset(&c, 0, sizeof(struct pkt_ctrl_command));
331
332 if (create_ctl_dev() < 0)
333 return;
334
335 if ((ctl_fd = open(pkt_dev_name(CTL_DEV), O_RDONLY)) < 0) {
336 perror("ctl open");
337 return;
338 }
339
340 for (i = 0; ; i++) {
341 c.command = PKT_CTRL_CMD_STATUS;
342 c.dev_index = i;
343 if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
344 perror("ioctl");
345 goto out_close;
346 }
347 if (i >= c.num_devices)
348 break;
349 if (c.dev) {
350 printf("%2d : %d:%d -> %d:%d\n",
351 i, MAJOR(c.pkt_dev), MINOR(c.pkt_dev),
352 MAJOR(c.dev), MINOR(c.dev));
353 }
354 }
355
356 out_close:
357 close(ctl_fd);
358 }
359
360 int main(int argc, char **argv)
361 {
362 int rem = 0, c;
363 char *pkt_device;
364 char *device;
365
366 if (argc == 1)
367 return usage();
368
369 while ((c = getopt(argc, argv, "ds?")) != EOF) {
370 switch (c) {
371 case 'd':
372 rem = 1;
373 break;
374 case 's':
375 show_mappings();
376 return 0;
377 default:
378 return usage();
379 }
380 }
381 if (optind == argc || (!rem && optind+1 == argc) || (rem && optind+1 < argc) || (!rem && optind+2 < argc))
382 return usage();
383 pkt_device = argv[optind];
384 if (!rem)
385 device = argv[optind + 1];
386 else
387 device = NULL;
388 if (strchr(pkt_device, '/'))
389 return setup_dev(pkt_device, device, rem);
390 else
391 return setup_dev_chardev(pkt_device, device, rem);
392 }
device
int device
Definition: wrudf.c:18
show_mappings
static void show_mappings(void)
Definition: pktsetup.c:324
pkt_ctrl_command::dev_index
__u32 dev_index
Definition: pktsetup.c:63
remove_stale_dev_node
static int remove_stale_dev_node(int ctl_fd, char *devname)
Definition: pktsetup.c:209
pkt_ctrl_command::dev
__u32 dev
Definition: pktsetup.c:64
init_cdrom
static int init_cdrom(int fd)
Definition: pktsetup.c:71
MINOR
#define MINOR(dev)
Definition: pktsetup.c:50
MKDEV
#define MKDEV(ma, mi)
Definition: pktsetup.c:51
create_ctl_dev
static int create_ctl_dev(void)
Definition: pktsetup.c:176
pkt_ctrl_command::command
__u32 command
Definition: pktsetup.c:62
get_misc_minor
static int get_misc_minor(void)
Definition: pktsetup.c:151
pkt_ctrl_command
Definition: pktsetup.c:61
PKT_CTRL_CMD_TEARDOWN
#define PKT_CTRL_CMD_TEARDOWN
Definition: pktsetup.c:58
main
int main(int argc, char **argv)
Definition: pktsetup.c:360
pkt_ctrl_command::padding
__u32 padding
Definition: pktsetup.c:67
pkt_ctrl_command::num_devices
__u32 num_devices
Definition: pktsetup.c:66
pkt_ctrl_command::pkt_dev
__u32 pkt_dev
Definition: pktsetup.c:65
setup_dev
static int setup_dev(char *pkt_device, char *device, int rem)
Definition: pktsetup.c:91
pkt_dev_name
static const char * pkt_dev_name(const char *dev)
Definition: pktsetup.c:169
MISC_MAJOR
#define MISC_MAJOR
Definition: pktsetup.c:53
MAJOR
#define MAJOR(dev)
Definition: pktsetup.c:49
usage
static int usage(void)
Definition: pktsetup.c:133
PKT_CTRL_CMD_SETUP
#define PKT_CTRL_CMD_SETUP
Definition: pktsetup.c:57
CTL_DIR
#define CTL_DIR
Definition: pktsetup.c:54
PACKET_CTRL_CMD
#define PACKET_CTRL_CMD
Definition: pktsetup.c:46
PKT_CTRL_CMD_STATUS
#define PKT_CTRL_CMD_STATUS
Definition: pktsetup.c:59
CTL_DEV
#define CTL_DEV
Definition: pktsetup.c:55
PACKET_SETUP_DEV
#define PACKET_SETUP_DEV
Definition: pktsetup.c:42
setup_dev_chardev
static int setup_dev_chardev(char *pkt_device, char *device, int rem)
Definition: pktsetup.c:238
PACKET_TEARDOWN_DEV
#define PACKET_TEARDOWN_DEV
Definition: pktsetup.c:43