xref: /minix/usr.sbin/vnconfig/vnconfig.c (revision 6c8f7fc3)
1 /*	$NetBSD: vnconfig.c,v 1.41 2013/06/09 13:25:40 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1993 University of Utah.
34  * Copyright (c) 1990, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * the Systems Programming Group of the University of Utah Computer
39  * Science Department.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
66  *
67  *	@(#)vnconfig.c	8.1 (Berkeley) 12/15/93
68  */
69 
70 #include <sys/param.h>
71 #include <sys/ioctl.h>
72 #include <sys/mount.h>
73 #ifndef __minix
74 #include <sys/buf.h>
75 #include <sys/disklabel.h>
76 #include <sys/disk.h>
77 #include <sys/bitops.h>
78 #else
79 #include <sys/wait.h>
80 #endif
81 
82 #include <dev/vndvar.h>
83 
84 #include <disktab.h>
85 #include <err.h>
86 #include <dirent.h>
87 #include <errno.h>
88 #include <fcntl.h>
89 #include <stddef.h>
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <string.h>
93 #include <unistd.h>
94 #include <util.h>
95 #include <paths.h>
96 
97 #define VND_CONFIG	1
98 #define VND_UNCONFIG	2
99 #define VND_GET		3
100 
101 static int	verbose = 0;
102 static int	readonly = 0;
103 static int	force = 0;
104 static int	compressed = 0;
105 static char	*tabname;
106 #ifdef __minix
107 static int	service = 1;
108 #endif
109 
110 #ifndef __minix
111 static void	show(int, int);
112 #else
113 static void	show(const char *, int);
114 #endif
115 static int	config(char *, char *, char *, int);
116 static int	getgeom(struct vndgeom *, char *);
117 __dead static void	usage(void);
118 
119 #ifdef __minix
120 /*
121  * Start a driver instance for the given vnd name.  The return value indicates
122  * whether the instance has been started successfully.
123  */
124 static int
125 start_service(char *dev)
126 {
127 	char *p, *endp, cmd[PATH_MAX];
128 	int n, status;
129 
130 	p = strrchr(dev, '/');
131 	if (p == NULL) p = dev;
132 	else p++;
133 
134 	/*
135 	 * There are two alternatives to get the instance number for the
136 	 * driver: either we scan the given device name, or we obtain its major
137 	 * number.  We choose to scan the name, because major numbers are more
138 	 * likely to change in the future.
139 	 */
140 	if (strncmp(p, "vnd", 3) != 0)
141 		return 0;
142 	n = strtoul(p + 3, &endp, 10);
143 	if (endp[0])
144 		return 0;
145 
146 	if (verbose)
147 		printf("%s: starting driver\n", dev);
148 
149 	snprintf(cmd, sizeof(cmd),
150 	    "%s up %s/vnd -label vnd%u -args instance=%u -dev %s",
151 	    _PATH_SERVICE, _PATH_DRIVERS, n, n, dev);
152 
153 	status = system(cmd);
154 
155 	if (!WIFEXITED(status))
156 		return 0;
157 	return !WEXITSTATUS(status);
158 }
159 
160 /*
161  * Stop the driver instance responsible for the given file descriptor.
162  * The file descriptor is closed upon return.
163  */
164 static void
165 stop_service(int fd, char *dev)
166 {
167 	char cmd[PATH_MAX];
168 	struct vnd_user vnu;
169 	int openct, stop = 0;
170 
171 	/* Only shut down the driver if the device is opened once, by us. */
172 	if (ioctl(fd, DIOCOPENCT, &openct) == 0 && openct == 1) {
173 		/* We let the driver tell us what instance number it has. */
174 		if (ioctl(fd, VNDIOCGET, &vnu) == 0)
175 			stop = 1;
176 	}
177 
178 	/* Close the file descriptor before shutting down the driver! */
179 	(void) close(fd);
180 
181 	if (stop) {
182 		if (verbose)
183 			printf("%s: stopping driver\n", dev);
184 
185 		snprintf(cmd, sizeof(cmd), "%s down vnd%u", _PATH_SERVICE,
186 		    vnu.vnu_unit);
187 
188 		system(cmd);
189 	}
190 }
191 #endif
192 
193 int
194 main(int argc, char *argv[])
195 {
196 	int ch, rv, action = VND_CONFIG;
197 
198 #ifndef __minix
199 	while ((ch = getopt(argc, argv, "Fcf:lrt:uvz")) != -1) {
200 #else
201 	/* MINIX3: added -S; no support for -f, -t, -z at this time. */
202 	while ((ch = getopt(argc, argv, "SFclruv")) != -1) {
203 #endif
204 		switch (ch) {
205 #ifdef __minix
206 		case 'S':
207 			service = 0;
208 			break;
209 #endif
210 		case 'F':
211 			force = 1;
212 			break;
213 		case 'c':
214 			action = VND_CONFIG;
215 			break;
216 		case 'f':
217 #ifndef __minix
218 			if (setdisktab(optarg) == -1)
219 				usage();
220 #endif
221 			break;
222 		case 'l':
223 			action = VND_GET;
224 			break;
225 		case 'r':
226 			readonly = 1;
227 			break;
228 		case 't':
229 			tabname = optarg;
230 			break;
231 		case 'u':
232 			action = VND_UNCONFIG;
233 			break;
234 		case 'v':
235 			verbose = 1;
236 			break;
237 		case 'z':
238 			compressed = 1;
239 			readonly = 1;
240 			break;
241 		default:
242 		case '?':
243 			usage();
244 			/* NOTREACHED */
245 		}
246 	}
247 	argc -= optind;
248 	argv += optind;
249 
250 	if (action == VND_CONFIG) {
251 		if ((argc < 2 || argc > 3) ||
252 		    (argc == 3 && tabname != NULL))
253 			usage();
254 		rv = config(argv[0], argv[1], (argc == 3) ? argv[2] : NULL,
255 		    action);
256 	} else if (action == VND_UNCONFIG) {
257 		if (argc != 1 || tabname != NULL)
258 			usage();
259 		rv = config(argv[0], NULL, NULL, action);
260 	} else { /* VND_GET */
261 #ifndef __minix
262 		int n, v;
263 		const char *vn;
264 		char path[64];
265 #else
266 		int n;
267 #endif
268 
269 		if (argc != 0 && argc != 1)
270 			usage();
271 
272 #ifndef __minix
273 		vn = argc ? argv[0] : "vnd0";
274 
275 		v = opendisk(vn, O_RDONLY, path, sizeof(path), 0);
276 		if (v == -1)
277 			err(1, "open: %s", vn);
278 #endif
279 
280 		if (argc)
281 #ifndef __minix
282 			show(v, -1);
283 #else
284 			show(argv[0], -1);
285 #endif
286 		else {
287 			DIR *dirp;
288 			struct dirent *dp;
289 #ifndef __minix
290 			__BITMAP_TYPE(, uint32_t, 65536) bm;
291 
292 			__BITMAP_ZERO(&bm);
293 #else
294 			char *endp;
295 #endif
296 
297 			if ((dirp = opendir(_PATH_DEV)) == NULL)
298 				err(1, "opendir: %s", _PATH_DEV);
299 
300 			while ((dp = readdir(dirp)) != NULL) {
301 #ifndef __minix
302 				if (strncmp(dp->d_name, "rvnd", 4) != 0)
303 					continue;
304 				n = atoi(dp->d_name + 4);
305 				if (__BITMAP_ISSET(n, &bm))
306 					continue;
307 				__BITMAP_SET(n, &bm);
308 				show(v, n);
309 #else
310 				if (strncmp(dp->d_name, "vnd", 3) != 0)
311 					continue;
312 				n = strtoul(dp->d_name + 3, &endp, 10);
313 				if (endp[0])
314 					continue;
315 				show(dp->d_name, n);
316 #endif
317 			}
318 
319 			closedir(dirp);
320 		}
321 #ifndef __minix
322 		close(v);
323 #endif
324 		rv = 0;
325 	}
326 	return rv;
327 }
328 
329 static void
330 #ifndef __minix
331 show(int v, int n)
332 #else
333 show(const char *vn, int n)
334 #endif
335 {
336 	struct vnd_user vnu;
337 	char *dev;
338 	struct statvfs *mnt;
339 	int i, nmount;
340 #ifdef __minix
341 	int v;
342 	char path[PATH_MAX];
343 
344 	v = opendisk(vn, O_RDONLY, path, sizeof(path), 0);
345 	if (v == -1) {
346 		if (n == -1)
347 			err(1, "open: %s", vn);
348 		else
349 			printf("vnd%d: not in use\n", n);
350 		return;
351 	}
352 #endif
353 
354 	vnu.vnu_unit = n;
355 	if (ioctl(v, VNDIOCGET, &vnu) == -1)
356 		err(1, "VNDIOCGET");
357 
358 #ifdef __minix
359 	close(v);
360 #endif
361 
362 	if (vnu.vnu_ino == 0) {
363 		printf("vnd%d: not in use\n", vnu.vnu_unit);
364 		return;
365 	}
366 
367 	printf("vnd%d: ", vnu.vnu_unit);
368 
369 	dev = devname(vnu.vnu_dev, S_IFBLK);
370 	if (dev != NULL)
371 		nmount = getmntinfo(&mnt, MNT_NOWAIT);
372 	else {
373 		mnt = NULL;
374 		nmount = 0;
375 	}
376 
377 	if (mnt != NULL) {
378 		for (i = 0; i < nmount; i++) {
379 			if (strncmp(mnt[i].f_mntfromname, "/dev/", 5) == 0 &&
380 			    strcmp(mnt[i].f_mntfromname + 5, dev) == 0)
381 				break;
382 		}
383 		if (i < nmount)
384 			printf("%s (%s) ", mnt[i].f_mntonname,
385 			    mnt[i].f_mntfromname);
386 		else
387 			printf("%s ", dev);
388 	}
389 	else if (dev != NULL)
390 		printf("%s ", dev);
391 	else
392 		printf("dev %llu,%llu ",
393 		    (unsigned long long)major(vnu.vnu_dev),
394 		    (unsigned long long)minor(vnu.vnu_dev));
395 
396 	printf("inode %llu\n", (unsigned long long)vnu.vnu_ino);
397 }
398 
399 static int
400 config(char *dev, char *file, char *geom, int action)
401 {
402 	struct vnd_ioctl vndio;
403 #ifndef __minix
404 	struct disklabel *lp;
405 #else
406 	int stop = 0;
407 #endif
408 	char rdev[MAXPATHLEN + 1];
409 	int fd, rv;
410 
411 #ifdef __minix
412 	/*
413 	 * MINIX does not have the concept of raw devices.  As such, the access
414 	 * checks that apply to opening block devices, automatically apply here
415 	 * as well.  Therefore, we must open the device as read-only, or we
416 	 * would be unable to un-configure a device that was configured as
417 	 * read-only: opening such a device as read-write would fail.
418 	 */
419 	fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0);
420 
421 	if (fd < 0 && errno == ENXIO && action == VND_CONFIG && service) {
422 		stop = start_service(rdev);
423 
424 		fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0);
425 	}
426 #else
427 	fd = opendisk(dev, O_RDWR, rdev, sizeof(rdev), 0);
428 #endif
429 	if (fd < 0) {
430 		warn("%s: opendisk", rdev);
431 		return (1);
432 	}
433 
434 	memset(&vndio, 0, sizeof(vndio));
435 #ifdef __GNUC__
436 	rv = 0;			/* XXX */
437 #endif
438 
439 #ifndef __minix
440 	vndio.vnd_file = file;
441 #endif
442 	if (geom != NULL) {
443 		rv = getgeom(&vndio.vnd_geom, geom);
444 #ifdef __minix
445 		if (rv && stop)
446 			stop_service(fd, rdev);
447 #endif
448 		if (rv != 0)
449 			errx(1, "invalid geometry: %s", geom);
450 		vndio.vnd_flags = VNDIOF_HASGEOM;
451 #ifndef __minix
452 	} else if (tabname != NULL) {
453 		lp = getdiskbyname(tabname);
454 		if (lp == NULL)
455 			errx(1, "unknown disk type: %s", tabname);
456 		vndio.vnd_geom.vng_secsize = lp->d_secsize;
457 		vndio.vnd_geom.vng_nsectors = lp->d_nsectors;
458 		vndio.vnd_geom.vng_ntracks = lp->d_ntracks;
459 		vndio.vnd_geom.vng_ncylinders = lp->d_ncylinders;
460 		vndio.vnd_flags = VNDIOF_HASGEOM;
461 #endif
462 	}
463 
464 	if (readonly)
465 		vndio.vnd_flags |= VNDIOF_READONLY;
466 
467 #ifndef __minix
468 	if (compressed)
469 		vndio.vnd_flags |= VNF_COMP;
470 #endif
471 
472 	/*
473 	 * Clear (un-configure) the device
474 	 */
475 	if (action == VND_UNCONFIG) {
476 		if (force)
477 			vndio.vnd_flags |= VNDIOF_FORCE;
478 		rv = ioctl(fd, VNDIOCCLR, &vndio);
479 #ifdef VNDIOOCCLR
480 		if (rv && errno == ENOTTY)
481 			rv = ioctl(fd, VNDIOOCCLR, &vndio);
482 #endif
483 		if (rv)
484 			warn("%s: VNDIOCCLR", rdev);
485 		else if (verbose)
486 			printf("%s: cleared\n", rdev);
487 #ifdef __minix
488 		if (!rv && service)
489 			stop = 2;
490 #endif
491 	}
492 	/*
493 	 * Configure the device
494 	 */
495 	if (action == VND_CONFIG) {
496 		int	ffd;
497 
498 		ffd = open(file, readonly ? O_RDONLY : O_RDWR);
499 		if (ffd < 0)
500 			warn("%s", file);
501 		else {
502 #ifndef __minix
503 			(void) close(ffd);
504 #else
505 			vndio.vnd_fildes = ffd;
506 #endif
507 
508 			rv = ioctl(fd, VNDIOCSET, &vndio);
509 #ifdef VNDIOOCSET
510 			if (rv && errno == ENOTTY) {
511 				rv = ioctl(fd, VNDIOOCSET, &vndio);
512 				vndio.vnd_size = vndio.vnd_osize;
513 			}
514 #endif
515 #ifdef __minix
516 			(void) close(ffd);
517 #endif
518 			if (rv)
519 				warn("%s: VNDIOCSET", rdev);
520 			else if (verbose) {
521 				printf("%s: %" PRIu64 " bytes on %s", rdev,
522 				    vndio.vnd_size, file);
523 				if (vndio.vnd_flags & VNDIOF_HASGEOM)
524 					printf(" using geometry %d/%d/%d/%d",
525 					    vndio.vnd_geom.vng_secsize,
526 					    vndio.vnd_geom.vng_nsectors,
527 					    vndio.vnd_geom.vng_ntracks,
528 				    vndio.vnd_geom.vng_ncylinders);
529 				printf("\n");
530 			}
531 		}
532 #ifdef __minix
533 		if ((ffd < 0 || rv) && service)
534 			stop++;
535 #endif
536 	}
537 
538 #ifdef __minix
539 	if (stop >= 2)
540 		stop_service(fd, rdev);
541 	else
542 #endif
543 	(void) close(fd);
544 	fflush(stdout);
545 	return (rv < 0);
546 }
547 
548 static int
549 getgeom(struct vndgeom *vng, char *cp)
550 {
551 	char *secsize, *nsectors, *ntracks, *ncylinders;
552 
553 #define	GETARG(arg) \
554 	do { \
555 		if (cp == NULL || *cp == '\0') \
556 			return (1); \
557 		arg = strsep(&cp, "/"); \
558 		if (arg == NULL) \
559 			return (1); \
560 	} while (0)
561 
562 	GETARG(secsize);
563 	GETARG(nsectors);
564 	GETARG(ntracks);
565 	GETARG(ncylinders);
566 
567 #undef GETARG
568 
569 	/* Too many? */
570 	if (cp != NULL)
571 		return (1);
572 
573 #define	CVTARG(str, num) \
574 	do { \
575 		num = strtol(str, &cp, 10); \
576 		if (*cp != '\0') \
577 			return (1); \
578 	} while (0)
579 
580 	CVTARG(secsize, vng->vng_secsize);
581 	CVTARG(nsectors, vng->vng_nsectors);
582 	CVTARG(ntracks, vng->vng_ntracks);
583 	CVTARG(ncylinders, vng->vng_ncylinders);
584 
585 #undef CVTARG
586 
587 	return (0);
588 }
589 
590 static void
591 usage(void)
592 {
593 
594 	(void)fprintf(stderr, "%s%s",
595 #ifndef __minix
596 	    "usage: vnconfig [-crvz] [-f disktab] [-t typename] vnode_disk"
597 		" regular-file [geomspec]\n",
598 	    "       vnconfig -u [-Fv] vnode_disk\n"
599 #else
600 	    "usage: vnconfig [-Scrv] vnode_disk regular-file [geomspec]\n",
601 	    "       vnconfig -u [-SFv] vnode_disk\n"
602 #endif
603 	    "       vnconfig -l [vnode_disk]\n");
604 	exit(1);
605 }
606