xref: /netbsd-src/usr.sbin/vnconfig/vnconfig.c (revision a8c74629f602faa0ccf8a463757d7baf858bbf3a)
1 /*	$NetBSD: vnconfig.c,v 1.48 2018/10/07 20:30:50 wiz 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 #include <sys/buf.h>
74 #include <sys/disklabel.h>
75 #include <sys/disk.h>
76 
77 #include <dev/vndvar.h>
78 
79 #include <disktab.h>
80 #include <err.h>
81 #include <errno.h>
82 #include <fcntl.h>
83 #include <stddef.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <unistd.h>
88 #include <util.h>
89 #include <paths.h>
90 #include <limits.h>
91 
92 #define VND_CONFIG	1
93 #define VND_UNCONFIG	2
94 #define VND_GET		3
95 
96 /* with -l we always print at least this many entries */
97 #define	DUMMY_FREE	4
98 
99 static int	verbose = 0;
100 static int	readonly = 0;
101 static int	fileio = 0;
102 static int	force = 0;
103 static int	compressed = 0;
104 static int	minimum = DUMMY_FREE;
105 static char	*tabname;
106 
107 static int	show(int, int, const char * const);
108 static int	config(char *, char *, char *, int);
109 static int	getgeom(struct vndgeom *, char *);
110 __dead static void	usage(void);
111 static void	show_unused(int);
112 
113 int
114 main(int argc, char *argv[])
115 {
116 	int ch, rv, action = VND_CONFIG;
117 	char *end;
118 	unsigned long cnt;
119 
120 	while ((ch = getopt(argc, argv, "Fcf:lm:rit:uvz")) != -1) {
121 		switch (ch) {
122 		case 'F':
123 			force = 1;
124 			break;
125 		case 'c':
126 			action = VND_CONFIG;
127 			break;
128 		case 'f':
129 			if (setdisktab(optarg) == -1)
130 				usage();
131 			break;
132 		case 'l':
133 			action = VND_GET;
134 			break;
135 		case 'm':
136 			cnt = strtoul(optarg, &end, 10);
137 			if (cnt >= INT_MAX || end == optarg || *end != '\0')
138 				usage();
139 			minimum = (int)cnt;
140 			break;
141 		case 'r':
142 			readonly = 1;
143 			break;
144 		case 'i':
145 			fileio = 1;
146 			break;
147 		case 't':
148 			tabname = optarg;
149 			break;
150 		case 'u':
151 			action = VND_UNCONFIG;
152 			break;
153 		case 'v':
154 			verbose = 1;
155 			break;
156 		case 'z':
157 			compressed = 1;
158 			readonly = 1;
159 			break;
160 		default:
161 		case '?':
162 			usage();
163 			/* NOTREACHED */
164 		}
165 	}
166 	argc -= optind;
167 	argv += optind;
168 
169 	if (action == VND_CONFIG) {
170 		if ((argc < 2 || argc > 3) ||
171 		    (argc == 3 && tabname != NULL))
172 			usage();
173 		rv = config(argv[0], argv[1], (argc == 3) ? argv[2] : NULL,
174 		    action);
175 	} else if (action == VND_UNCONFIG) {
176 		if (argc != 1 || tabname != NULL)
177 			usage();
178 		rv = config(argv[0], NULL, NULL, action);
179 	} else { /* VND_GET */
180 		int n, vdisk;
181 		const char *vn;
182 		char path[64];
183 
184 		if (argc == 0) {
185 			vn = "vnd0";
186 
187 			vdisk = opendisk(vn, O_RDONLY, path, sizeof(path), 0);
188 			if (vdisk == -1) {
189 				if (minimum == 0)
190 					return 1;
191 				err(1, "open: %s", vn);
192 			}
193 
194 			for (n = 0; show(vdisk, n, 0); n++)
195 				continue;
196 			while (n < minimum)
197 				show_unused(n++);
198 			close(vdisk);
199 			return 0;
200 		}
201 
202 		rv = 0;
203 		while (--argc >= 0) {
204 			vn = *argv++;
205 
206 			vdisk = opendisk(vn, O_RDONLY, path, sizeof(path), 0);
207 			if (vdisk == -1) {
208 				warn("open: %s", vn);
209 				rv = 1;
210 				continue;
211 			}
212 
213 			if (!show(vdisk, -1, vn))
214 				rv = 1;
215 			close(vdisk);
216 		}
217 	}
218 	return rv;
219 }
220 
221 static void
222 show_unused(int n)
223 {
224 	if (minimum == 0)
225 		return;
226 
227 	printf("vnd%d: not in use\n", n);
228 }
229 
230 static int
231 show(int v, int n, const char * const name)
232 {
233 	struct vnd_user vnu;
234 	char *dev;
235 	struct statvfs *mnt;
236 	int i, nmount;
237 
238 	vnu.vnu_unit = n;
239 	if (ioctl(v, VNDIOCGET, &vnu) == -1) {
240 		if (errno != ENXIO) {
241 			if (n != -1)
242 				err(1, "VNDIOCGET");
243 			warn("%s: VNDIOCGET", name);
244 		}
245 		return 0;
246 	}
247 
248 	if (vnu.vnu_ino == 0) {
249 		show_unused(vnu.vnu_unit);
250 		return -1;
251 	}
252 
253 	printf("vnd%d: ", vnu.vnu_unit);
254 
255 	dev = devname(vnu.vnu_dev, S_IFBLK);
256 	if (dev != NULL)
257 		nmount = getmntinfo(&mnt, MNT_NOWAIT);
258 	else {
259 		mnt = NULL;
260 		nmount = 0;
261 	}
262 
263 	if (mnt != NULL) {
264 		for (i = 0; i < nmount; i++) {
265 			if (strncmp(mnt[i].f_mntfromname, "/dev/", 5) == 0 &&
266 			    strcmp(mnt[i].f_mntfromname + 5, dev) == 0)
267 				break;
268 		}
269 		if (i < nmount)
270 			printf("%s (%s) ", mnt[i].f_mntonname,
271 			    mnt[i].f_mntfromname);
272 		else
273 			printf("%s ", dev);
274 	}
275 	else if (dev != NULL)
276 		printf("%s ", dev);
277 	else
278 		printf("dev %llu,%llu ",
279 		    (unsigned long long)major(vnu.vnu_dev),
280 		    (unsigned long long)minor(vnu.vnu_dev));
281 
282 	printf("inode %llu\n", (unsigned long long)vnu.vnu_ino);
283 	return 1;
284 }
285 
286 static int
287 config(char *dev, char *file, char *geom, int action)
288 {
289 	struct vnd_ioctl vndio;
290 	struct disklabel *lp;
291 	char rdev[MAXPATHLEN + 1];
292 	int fd, rv;
293 
294 	fd = opendisk(dev, O_RDWR, rdev, sizeof(rdev), 0);
295 	if (fd < 0) {
296 		warn("%s: opendisk", rdev);
297 		return (1);
298 	}
299 
300 	memset(&vndio, 0, sizeof(vndio));
301 #ifdef __GNUC__
302 	rv = 0;			/* XXX */
303 #endif
304 
305 	vndio.vnd_file = file;
306 	if (geom != NULL) {
307 		rv = getgeom(&vndio.vnd_geom, geom);
308 		if (rv != 0)
309 			errx(1, "invalid geometry: %s", geom);
310 		vndio.vnd_flags = VNDIOF_HASGEOM;
311 	} else if (tabname != NULL) {
312 		lp = getdiskbyname(tabname);
313 		if (lp == NULL)
314 			errx(1, "unknown disk type: %s", tabname);
315 		vndio.vnd_geom.vng_secsize = lp->d_secsize;
316 		vndio.vnd_geom.vng_nsectors = lp->d_nsectors;
317 		vndio.vnd_geom.vng_ntracks = lp->d_ntracks;
318 		vndio.vnd_geom.vng_ncylinders = lp->d_ncylinders;
319 		vndio.vnd_flags = VNDIOF_HASGEOM;
320 	}
321 
322 	if (readonly)
323 		vndio.vnd_flags |= VNDIOF_READONLY;
324 
325 	if (compressed)
326 		vndio.vnd_flags |= VNF_COMP;
327 
328 	if (fileio)
329 		vndio.vnd_flags |= VNDIOF_FILEIO;
330 
331 	/*
332 	 * Clear (un-configure) the device
333 	 */
334 	if (action == VND_UNCONFIG) {
335 		if (force)
336 			vndio.vnd_flags |= VNDIOF_FORCE;
337 		rv = ioctl(fd, VNDIOCCLR, &vndio);
338 #ifdef VNDIOOCCLR
339 		if (rv && errno == ENOTTY)
340 			rv = ioctl(fd, VNDIOOCCLR, &vndio);
341 #endif
342 		if (rv)
343 			warn("%s: VNDIOCCLR", rdev);
344 		else if (verbose)
345 			printf("%s: cleared\n", rdev);
346 	}
347 	/*
348 	 * Configure the device
349 	 */
350 	if (action == VND_CONFIG) {
351 		int	ffd;
352 
353 		ffd = open(file, readonly ? O_RDONLY : O_RDWR);
354 		if (ffd < 0) {
355 			warn("%s", file);
356 			rv = -1;
357 		} else {
358 			(void) close(ffd);
359 
360 			rv = ioctl(fd, VNDIOCSET, &vndio);
361 #ifdef VNDIOOCSET
362 			if (rv && errno == ENOTTY) {
363 				rv = ioctl(fd, VNDIOOCSET, &vndio);
364 				vndio.vnd_size = vndio.vnd_osize;
365 			}
366 #endif
367 			if (rv)
368 				warn("%s: VNDIOCSET", rdev);
369 			else if (verbose) {
370 				printf("%s: %" PRIu64 " bytes on %s", rdev,
371 				    vndio.vnd_size, file);
372 				if (vndio.vnd_flags & VNDIOF_HASGEOM)
373 					printf(" using geometry %d/%d/%d/%d",
374 					    vndio.vnd_geom.vng_secsize,
375 					    vndio.vnd_geom.vng_nsectors,
376 					    vndio.vnd_geom.vng_ntracks,
377 				    vndio.vnd_geom.vng_ncylinders);
378 				printf("\n");
379 			}
380 		}
381 	}
382 
383 	(void) close(fd);
384 	fflush(stdout);
385 	return (rv < 0);
386 }
387 
388 static int
389 getgeom(struct vndgeom *vng, char *cp)
390 {
391 	char *secsize, *nsectors, *ntracks, *ncylinders;
392 
393 #define	GETARG(arg) \
394 	do { \
395 		if (cp == NULL || *cp == '\0') \
396 			return (1); \
397 		arg = strsep(&cp, "/"); \
398 		if (arg == NULL) \
399 			return (1); \
400 	} while (0)
401 
402 	GETARG(secsize);
403 	GETARG(nsectors);
404 	GETARG(ntracks);
405 	GETARG(ncylinders);
406 
407 #undef GETARG
408 
409 	/* Too many? */
410 	if (cp != NULL)
411 		return (1);
412 
413 #define	CVTARG(str, num) \
414 	do { \
415 		num = strtol(str, &cp, 10); \
416 		if (*cp != '\0') \
417 			return (1); \
418 	} while (0)
419 
420 	CVTARG(secsize, vng->vng_secsize);
421 	CVTARG(nsectors, vng->vng_nsectors);
422 	CVTARG(ntracks, vng->vng_ntracks);
423 	CVTARG(ncylinders, vng->vng_ncylinders);
424 
425 #undef CVTARG
426 
427 	return (0);
428 }
429 
430 static void
431 usage(void)
432 {
433 	const char *p = getprogname();
434 	(void)fprintf(stderr,
435 	    "Usage: %s [-cirvz] [-f dsktab] [-t type] vnode_disk"
436 		" reg-file [geomspec]\n"
437 	    "       %s -u [-Fv] vnode_disk\n"
438 	    "       %s -l [-m num | vnode_disk...]\n", p, p, p);
439 	exit(1);
440 }
441