xref: /dragonfly/usr.sbin/vnconfig/vnconfig.c (revision 63ab6604)
1 /*
2  * Copyright (c) 1993 University of Utah.
3  * Copyright (c) 1990, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department.
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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
39  *
40  * @(#)vnconfig.c	8.1 (Berkeley) 12/15/93
41  * $FreeBSD: src/usr.sbin/vnconfig/vnconfig.c,v 1.13.2.7 2003/06/02 09:10:27 maxim Exp $
42  * $DragonFly: src/usr.sbin/vnconfig/vnconfig.c,v 1.15 2008/07/27 22:36:01 thomas Exp $
43  */
44 
45 #include <ctype.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <paths.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <fcntl.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <sys/param.h>
55 #include <sys/ioctl.h>
56 #include <sys/linker.h>
57 #include <sys/mount.h>
58 #include <sys/module.h>
59 #include <sys/stat.h>
60 #include <sys/vnioctl.h>
61 #include <vfs/ufs/ufsmount.h>
62 
63 #define LINESIZE	1024
64 #define ZBUFSIZE	32768
65 
66 struct vndisk {
67 	char	*dev;
68 	char	*file;
69 	char	*autolabel;
70 	int	flags;
71 	int64_t	size;
72 	char	*oarg;
73 } *vndisks;
74 
75 #define VN_CONFIG	0x01
76 #define VN_UNCONFIG	0x02
77 #define VN_ENABLE	0x04
78 #define VN_DISABLE	0x08
79 #define	VN_SWAP		0x10
80 #define VN_MOUNTRO	0x20
81 #define VN_MOUNTRW	0x40
82 #define VN_IGNORE	0x80
83 #define VN_SET		0x100
84 #define VN_RESET	0x200
85 #define VN_TRUNCATE	0x400
86 #define VN_ZERO		0x800
87 
88 int nvndisks;
89 
90 int all = 0;
91 int verbose = 0;
92 int global = 0;
93 int listopt = 0;
94 u_long setopt = 0;
95 u_long resetopt = 0;
96 const char *configfile;
97 
98 int config(struct vndisk *);
99 void getoptions(struct vndisk *, const char *);
100 int getinfo(const char *vname);
101 char *rawdevice(const char *);
102 void readconfig(int);
103 static void usage(void);
104 static int64_t getsize(const char *arg);
105 static void do_autolabel(const char *dev, const char *label);
106 int what_opt(const char *, u_long *);
107 
108 int
109 main(int argc, char *argv[])
110 {
111 	int i, rv;
112 	int flags = 0;
113 	int64_t size = 0;
114 	char *autolabel = NULL;
115 	char *s;
116 
117 	configfile = _PATH_VNTAB;
118 	while ((i = getopt(argc, argv, "acdef:glr:s:S:TZL:uv")) != -1)
119 		switch (i) {
120 
121 		/* all -- use config file */
122 		case 'a':
123 			all++;
124 			break;
125 
126 		/* configure */
127 		case 'c':
128 			flags |= VN_CONFIG;
129 			flags &= ~VN_UNCONFIG;
130 			break;
131 
132 		/* disable */
133 		case 'd':
134 			flags |= VN_DISABLE;
135 			flags &= ~VN_ENABLE;
136 			break;
137 
138 		/* enable */
139 		case 'e':
140 			flags |= (VN_ENABLE|VN_CONFIG);
141 			flags &= ~(VN_DISABLE|VN_UNCONFIG);
142 			break;
143 
144 		/* alternate config file */
145 		case 'f':
146 			configfile = optarg;
147 			break;
148 
149 		/* fiddle global options */
150 		case 'g':
151 			global = 1 - global;
152 			break;
153 
154 		/* reset options */
155 		case 'r':
156 			for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
157 				if (what_opt(s, &resetopt))
158 					errx(1, "invalid options '%s'", s);
159 			}
160 			flags |= VN_RESET;
161 			break;
162 
163 		case 'l':
164 			listopt = 1;
165 			break;
166 
167 		/* set options */
168 		case 's':
169 			for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
170 				if (what_opt(s, &setopt))
171 					errx(1, "invalid options '%s'", s);
172 			}
173 			flags |= VN_SET;
174 			break;
175 
176 		/* unconfigure */
177 		case 'u':
178 			flags |= (VN_DISABLE|VN_UNCONFIG);
179 			flags &= ~(VN_ENABLE|VN_CONFIG);
180 			break;
181 
182 		/* verbose */
183 		case 'v':
184 			verbose++;
185 			break;
186 
187 		case 'S':
188 			size = getsize(optarg);
189 			flags |= VN_CONFIG;
190 			flags &= ~VN_UNCONFIG;
191 			break;
192 
193 		case 'T':
194 			flags |= VN_TRUNCATE;
195 			break;
196 
197 		case 'Z':
198 			flags |= VN_ZERO;
199 			break;
200 
201 		case 'L':
202 			autolabel = optarg;
203 			break;
204 
205 		default:
206 			usage();
207 		}
208 
209 	if (modfind("vn") < 0)
210 		if (kldload("vn") < 0 || modfind("vn") < 0)
211 			warnx( "cannot find or load \"vn\" kernel module");
212 
213 	rv = 0;
214 	if (listopt) {
215 		if(argc > optind)
216 			while(argc > optind)
217 				rv += getinfo( argv[optind++]);
218 		else {
219 			rv = getinfo( NULL );
220 		}
221 		exit(rv);
222 	}
223 
224 	if (flags == 0)
225 		flags = VN_CONFIG;
226 	if (all) {
227 		readconfig(flags);
228 	} else {
229 		vndisks = calloc(sizeof(struct vndisk), 1);
230 		if (argc < optind + 1)
231 			usage();
232 		vndisks[0].dev = argv[optind++];
233 		vndisks[0].file = argv[optind++];	/* may be NULL */
234 		vndisks[0].flags = flags;
235 		vndisks[0].size = size;
236 		vndisks[0].autolabel = autolabel;
237 		if (optind < argc)
238 			getoptions(&vndisks[0], argv[optind]);
239 		nvndisks = 1;
240 	}
241 	rv = 0;
242 	for (i = 0; i < nvndisks; i++)
243 		rv += config(&vndisks[i]);
244 	exit(rv);
245 }
246 
247 int
248 what_opt(const char *str, u_long *p)
249 {
250 	if (!strcmp(str,"reserve")) { *p |= VN_RESERVE; return 0; }
251 	if (!strcmp(str,"labels")) { *p |= VN_LABELS; return 0; }
252 	if (!strcmp(str,"follow")) { *p |= VN_FOLLOW; return 0; }
253 	if (!strcmp(str,"debug")) { *p |= VN_DEBUG; return 0; }
254 	if (!strcmp(str,"io")) { *p |= VN_IO; return 0; }
255 	if (!strcmp(str,"all")) { *p |= ~0; return 0; }
256 	if (!strcmp(str,"none")) { *p |= 0; return 0; }
257 	return 1;
258 }
259 
260 /*
261  *
262  * GETINFO
263  *
264  *	Print vnode disk information to stdout for the device at
265  *	path 'vname', or all existing 'vn' devices if none is given.
266  *	Any 'vn' devices must exist under /dev in order to be queried.
267  *
268  *	Todo: correctly use vm_secsize for swap-backed vn's ..
269  */
270 
271 int
272 getinfo( const char *vname )
273 {
274 	int i = 0, vd, printlim = 0;
275 	char vnpath[PATH_MAX];
276 	const char *tmp;
277 
278 	struct vn_user vnu;
279 	struct stat sb;
280 
281 	if (vname == NULL) {
282 		printlim = 1024;
283 	} else {
284 		tmp = vname;
285 		while (*tmp != 0) {
286 			if(isdigit(*tmp)){
287 				i = atoi(tmp);
288 				printlim = i + 1;
289 				break;
290 			}
291 			tmp++;
292 		}
293 		if (tmp == NULL) {
294 			printf("unknown vn device: %s", vname);
295 			return 1;
296 		}
297 	}
298 
299 	snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", i);
300 
301 	vd = open(vnpath, O_RDONLY);
302 	if (vd < 0) {
303 		err(1, "open: %s", vnpath);
304 		return 1;
305 	}
306 
307 	for (; i<printlim; i++) {
308 
309 		bzero((void *) &vnpath, sizeof(vnpath));
310 		bzero((void *) &sb, sizeof(struct stat));
311 		bzero((void *) &vnu, sizeof(struct vn_user));
312 
313 		vnu.vnu_unit = i;
314 
315 		snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", vnu.vnu_unit);
316 
317 		if(stat(vnpath, &sb) < 0) {
318 			break;
319 		}
320 		else {
321         		if (ioctl(vd, VNIOCGET, &vnu) == -1) {
322 				if (errno != ENXIO) {
323 					if (*vnu.vnu_file == '\0') {
324 						fprintf(stdout,
325 						    "vn%d: ioctl: can't access regular file\n",
326 						    vnu.vnu_unit);
327 						continue;
328 					}
329 					else {
330 						err(1, "ioctl: %s", vname);
331 						close(vd);
332 						return 1;
333 					}
334 				}
335         		}
336 
337 			fprintf(stdout, "vn%d: ", vnu.vnu_unit);
338 
339 			if (vnu.vnu_file[0] == 0)
340 				fprintf(stdout, "not in use\n");
341 			else if ((strcmp(vnu.vnu_file, _VN_USER_SWAP)) == 0)
342 				fprintf(stdout,
343 					"consuming %lld VM pages\n",
344 					vnu.vnu_size);
345 			else
346 				fprintf(stdout,
347 					"covering %s on %s, inode %ju\n",
348 					vnu.vnu_file,
349 					devname(vnu.vnu_dev, S_IFBLK),
350 					(uintmax_t)vnu.vnu_ino);
351 		}
352 	}
353 	close(vd);
354 	return 0;
355 }
356 
357 int
358 config(struct vndisk *vnp)
359 {
360 	char *dev, *file, *rdev, *oarg;
361 	FILE *f;
362 	struct vn_ioctl vnio;
363 	int flags, pgsize, rv, status;
364 	u_long l;
365 
366 	pgsize = getpagesize();
367 
368 	status = rv = 0;
369 
370 	/*
371 	 * Prepend "/dev/" to the specified device name, if necessary.
372 	 * Operate on vnp->dev because it is used later.
373 	 */
374 	if (vnp->dev[0] != '/' && vnp->dev[0] != '.')
375 		asprintf(&vnp->dev, "%s%s", _PATH_DEV, vnp->dev);
376 	dev = vnp->dev;
377 	file = vnp->file;
378 	flags = vnp->flags;
379 	oarg = vnp->oarg;
380 
381 	if (flags & VN_IGNORE)
382 		return(0);
383 
384 	/*
385 	 * When a regular file has been specified, do any requested setup
386 	 * of the file.  Truncation (also creates the file if necessary),
387 	 * sizing, and zeroing.
388 	 */
389 
390 	if (file && vnp->size != 0 && (flags & VN_CONFIG)) {
391 		int  fd;
392 		struct stat st;
393 
394 		if (flags & VN_TRUNCATE)
395 			fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600);
396 		else
397 			fd = open(file, O_RDWR);
398 		if (fd >= 0 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
399 			if (st.st_size < vnp->size * pgsize)
400 				ftruncate(fd, vnp->size * pgsize);
401 			if (vnp->size != 0)
402 				st.st_size = vnp->size * pgsize;
403 
404 			if (flags & VN_ZERO) {
405 				char *buf = malloc(ZBUFSIZE);
406 				bzero(buf, ZBUFSIZE);
407 				while (st.st_size > 0) {
408 					int n = (st.st_size > ZBUFSIZE) ?
409 					    ZBUFSIZE : (int)st.st_size;
410 					if (write(fd, buf, n) != n) {
411 						ftruncate(fd, 0);
412 						printf("Unable to ZERO file %s\n", file);
413 						return(0);
414 					}
415 					st.st_size -= (off_t)n;
416 				}
417 			}
418 			close(fd);
419 		} else {
420 			printf("Unable to open file %s\n", file);
421 			return(0);
422 		}
423 	} else if (file == NULL && vnp->size == 0 && (flags & VN_CONFIG)) {
424 		warnx("specify regular filename or swap size");
425 		return (0);
426 	}
427 
428 	rdev = rawdevice(dev);
429 	f = fopen(rdev, "rw");
430 	if (f == NULL) {
431 		warn("%s", dev);
432 		return(1);
433 	}
434 	vnio.vn_file = file;
435 	vnio.vn_size = vnp->size;	/* non-zero only if swap backed */
436 
437 	/*
438 	 * Disable the device
439 	 */
440 	if (flags & VN_DISABLE) {
441 		if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
442 			rv = unmount(oarg, 0);
443 			if (rv) {
444 				status--;
445 				if (errno == EBUSY)
446 					flags &= ~VN_UNCONFIG;
447 				if ((flags & VN_UNCONFIG) == 0)
448 					warn("umount");
449 			} else if (verbose)
450 				printf("%s: unmounted\n", dev);
451 		}
452 	}
453 	/*
454 	 * Clear (un-configure) the device
455 	 */
456 	if (flags & VN_UNCONFIG) {
457 		rv = ioctl(fileno(f), VNIOCDETACH, &vnio);
458 		if (rv) {
459 			if (errno == ENODEV) {
460 				if (verbose)
461 					printf("%s: not configured\n", dev);
462 				rv = 0;
463 			} else {
464 				status--;
465 				warn("VNIOCDETACH");
466 			}
467 		} else if (verbose)
468 			printf("%s: cleared\n", dev);
469 	}
470 	/*
471 	 * Set specified options
472 	 */
473 	if (flags & VN_SET) {
474 		l = setopt;
475 		if (global)
476 			rv = ioctl(fileno(f), VNIOCGSET, &l);
477 		else
478 			rv = ioctl(fileno(f), VNIOCUSET, &l);
479 		if (rv) {
480 			status--;
481 			warn("VNIO[GU]SET");
482 		} else if (verbose)
483 			printf("%s: flags now=%08lx\n",dev,l);
484 	}
485 	/*
486 	 * Reset specified options
487 	 */
488 	if (flags & VN_RESET) {
489 		l = resetopt;
490 		if (global)
491 			rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
492 		else
493 			rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
494 		if (rv) {
495 			status--;
496 			warn("VNIO[GU]CLEAR");
497 		} else if (verbose)
498 			printf("%s: flags now=%08lx\n",dev,l);
499 	}
500 	/*
501 	 * Configure the device
502 	 */
503 	if (flags & VN_CONFIG) {
504 		rv = ioctl(fileno(f), VNIOCATTACH, &vnio);
505 		if (rv) {
506 			status--;
507 			warn("VNIOCATTACH");
508 			flags &= ~VN_ENABLE;
509 		} else {
510 			if (verbose) {
511 				printf("%s: %s, ", dev, file);
512 				if (vnp->size != 0) {
513 				    printf("%lld bytes mapped\n", vnio.vn_size);
514 				} else {
515 				    printf("complete file mapped\n");
516 				}
517 			}
518 			/*
519 			 * autolabel
520 			 */
521 			if (vnp->autolabel) {
522 				do_autolabel(vnp->dev, vnp->autolabel);
523 			}
524 		}
525 	}
526 	/*
527 	 * Set an option
528 	 */
529 	if (flags & VN_SET) {
530 		l = setopt;
531 		if (global)
532 			rv = ioctl(fileno(f), VNIOCGSET, &l);
533 		else
534 			rv = ioctl(fileno(f), VNIOCUSET, &l);
535 		if (rv) {
536 			status--;
537 			warn("VNIO[GU]SET");
538 		} else if (verbose)
539 			printf("%s: flags now=%08lx\n",dev,l);
540 	}
541 	/*
542 	 * Reset an option
543 	 */
544 	if (flags & VN_RESET) {
545 		l = resetopt;
546 		if (global)
547 			rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
548 		else
549 			rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
550 		if (rv) {
551 			status--;
552 			warn("VNIO[GU]CLEAR");
553 		} else if (verbose)
554 			printf("%s: flags now=%08lx\n",dev,l);
555 	}
556 
557 	/*
558 	 * Close the device now, as we may want to mount it.
559 	 */
560 	fclose(f);
561 
562 	/*
563 	 * Enable special functions on the device
564 	 */
565 	if (flags & VN_ENABLE) {
566 		if (flags & VN_SWAP) {
567 			rv = swapon(dev);
568 			if (rv) {
569 				status--;
570 				warn("swapon");
571 			}
572 			else if (verbose)
573 				printf("%s: swapping enabled\n", dev);
574 		}
575 		if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
576 			struct ufs_args args;
577 			int mflags;
578 
579 			args.fspec = dev;
580 			mflags = (flags & VN_MOUNTRO) ? MNT_RDONLY : 0;
581 			rv = mount("ufs", oarg, mflags, &args);
582 			if (rv) {
583 				status--;
584 				warn("mount");
585 			}
586 			else if (verbose)
587 				printf("%s: mounted on %s\n", dev, oarg);
588 		}
589 	}
590 /* done: */
591 	fflush(stdout);
592 	return(status < 0);
593 }
594 
595 #define EOL(c)		((c) == '\0' || (c) == '\n')
596 #define WHITE(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
597 
598 void
599 readconfig(int flags)
600 {
601 	char buf[LINESIZE];
602 	FILE *f;
603 	char *cp, *sp;
604 	int ix;
605 	int ax;
606 
607 	f = fopen(configfile, "r");
608 	if (f == NULL)
609 		err(1, "%s", configfile);
610 	ix = 0;		/* number of elements */
611 	ax = 0;		/* allocated elements */
612 	while (fgets(buf, LINESIZE, f) != NULL) {
613 		cp = buf;
614 		if (*cp == '#')
615 			continue;
616 		while (!EOL(*cp) && WHITE(*cp))
617 			cp++;
618 		if (EOL(*cp))
619 			continue;
620 		sp = cp;
621 		while (!EOL(*cp) && !WHITE(*cp))
622 			cp++;
623 		if (EOL(*cp))
624 			continue;
625 		*cp++ = '\0';
626 
627 		if (ix == ax) {
628 			ax = ax + 16;
629 			vndisks = realloc(vndisks, ax * sizeof(struct vndisk));
630 			bzero(&vndisks[ix], (ax - ix) * sizeof(struct vndisk));
631 		}
632 		vndisks[ix].dev = malloc(cp - sp);
633 		strcpy(vndisks[ix].dev, sp);
634 		while (!EOL(*cp) && WHITE(*cp))
635 			cp++;
636 		if (EOL(*cp))
637 			continue;
638 		sp = cp;
639 		while (!EOL(*cp) && !WHITE(*cp))
640 			cp++;
641 		*cp++ = '\0';
642 
643 		if (*sp == '%' && strtol(sp + 1, NULL, 0) > 0) {
644 			vndisks[ix].size = getsize(sp + 1);
645 		} else {
646 			vndisks[ix].file = malloc(cp - sp);
647 			strcpy(vndisks[ix].file, sp);
648 		}
649 
650 		while (!EOL(*cp) && WHITE(*cp))
651 			cp++;
652 		vndisks[ix].flags = flags;
653 		if (!EOL(*cp)) {
654 			sp = cp;
655 			while (!EOL(*cp) && !WHITE(*cp))
656 				cp++;
657 			*cp++ = '\0';
658 			getoptions(&vndisks[ix], sp);
659 		}
660 		nvndisks++;
661 		ix++;
662 	}
663 }
664 
665 void
666 getoptions(struct vndisk *vnp, const char *fstr)
667 {
668 	int flags = 0;
669 	const char *oarg = NULL;
670 
671 	if (strcmp(fstr, "swap") == 0)
672 		flags |= VN_SWAP;
673 	else if (strncmp(fstr, "mount=", 6) == 0) {
674 		flags |= VN_MOUNTRW;
675 		oarg = &fstr[6];
676 	} else if (strncmp(fstr, "mountrw=", 8) == 0) {
677 		flags |= VN_MOUNTRW;
678 		oarg = &fstr[8];
679 	} else if (strncmp(fstr, "mountro=", 8) == 0) {
680 		flags |= VN_MOUNTRO;
681 		oarg = &fstr[8];
682 	} else if (strcmp(fstr, "ignore") == 0)
683 		flags |= VN_IGNORE;
684 	vnp->flags |= flags;
685 	if (oarg) {
686 		vnp->oarg = malloc(strlen(oarg) + 1);
687 		strcpy(vnp->oarg, oarg);
688 	} else
689 		vnp->oarg = NULL;
690 }
691 
692 char *
693 rawdevice(const char *dev)
694 {
695 	char *rawbuf, *dp, *ep;
696 	struct stat sb;
697 	int len;
698 
699 	len = strlen(dev);
700 	rawbuf = malloc(len + 2);
701 	strcpy(rawbuf, dev);
702 	if (stat(rawbuf, &sb) != 0 || !S_ISCHR(sb.st_mode)) {
703 		dp = strrchr(rawbuf, '/');
704 		if (dp) {
705 			for (ep = &rawbuf[len]; ep > dp; --ep)
706 				*(ep+1) = *ep;
707 			*++ep = 'r';
708 		}
709 	}
710 	return (rawbuf);
711 }
712 
713 static void
714 usage(void)
715 {
716 	fprintf(stderr, "%s\n%s\n%s\n%s\n",
717 		"usage: vnconfig [-cdeguvTZ] [-s options] [-r options]",
718 		"                [-S value] special_file [regular_file] [feature]",
719 		"       vnconfig -a [-cdeguv] [-s options] [-r options] [-f config_file]",
720 		"       vnconfig -l [special_file ...]");
721 	exit(1);
722 }
723 
724 static int64_t
725 getsize(const char *arg)
726 {
727 	char *ptr;
728 	int pgsize = getpagesize();
729 	int64_t size = strtoq(arg, &ptr, 0);
730 
731 	switch(tolower(*ptr)) {
732 	case 't':
733 		/*
734 		 * GULP!  Terabytes.  It's actually possible to create
735 		 * a 7.9 TB VN device, though newfs can't handle any single
736 		 * filesystem larger then 1 TB.
737 		 */
738 		size *= 1024;
739 		/* fall through */
740 	case 'g':
741 		size *= 1024;
742 		/* fall through */
743 	default:
744 	case 'm':
745 		size *= 1024;
746 		/* fall through */
747 	case 'k':
748 		size *= 1024;
749 		/* fall through */
750 	case 'c':
751 		break;
752 	}
753 	size = (size + pgsize - 1) / pgsize;
754 	return(size);
755 }
756 
757 /*
758  * DO_AUTOLABEL
759  *
760  *	Automatically label the device.  This will wipe any preexisting
761  *	label.
762  */
763 
764 static void
765 do_autolabel(const char *dev __unused, const char *label __unused)
766 {
767 	/* XXX not yet implemented */
768 	fprintf(stderr, "autolabel not yet implemented, sorry\n");
769 	exit(1);
770 }
771 
772