kernel: Fix buildkernel without INVARIANTS.
[dragonfly.git] / usr.sbin / vnconfig / vnconfig.c
blobbea54450b2020bb3aa0e6d6b571bc3a6ee937f19
1 /*
2 * Copyright (c) 1993 University of Utah.
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
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.
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.
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.
38 * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
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 $
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>
63 #define LINESIZE 1024
64 #define ZBUFSIZE 32768
66 struct vndisk {
67 char *dev;
68 char *file;
69 char *autolabel;
70 int flags;
71 int64_t size;
72 char *oarg;
73 } *vndisks;
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
88 int nvndisks;
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;
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 *);
109 main(int argc, char *argv[])
111 int i, rv;
112 int flags = 0;
113 int64_t size = 0;
114 char *autolabel = NULL;
115 char *s;
117 configfile = _PATH_VNTAB;
118 while ((i = getopt(argc, argv, "acdef:glr:s:S:TZL:uv")) != -1)
119 switch (i) {
121 /* all -- use config file */
122 case 'a':
123 all++;
124 break;
126 /* configure */
127 case 'c':
128 flags |= VN_CONFIG;
129 flags &= ~VN_UNCONFIG;
130 break;
132 /* disable */
133 case 'd':
134 flags |= VN_DISABLE;
135 flags &= ~VN_ENABLE;
136 break;
138 /* enable */
139 case 'e':
140 flags |= (VN_ENABLE|VN_CONFIG);
141 flags &= ~(VN_DISABLE|VN_UNCONFIG);
142 break;
144 /* alternate config file */
145 case 'f':
146 configfile = optarg;
147 break;
149 /* fiddle global options */
150 case 'g':
151 global = 1 - global;
152 break;
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);
160 flags |= VN_RESET;
161 break;
163 case 'l':
164 listopt = 1;
165 break;
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);
173 flags |= VN_SET;
174 break;
176 /* unconfigure */
177 case 'u':
178 flags |= (VN_DISABLE|VN_UNCONFIG);
179 flags &= ~(VN_ENABLE|VN_CONFIG);
180 break;
182 /* verbose */
183 case 'v':
184 verbose++;
185 break;
187 case 'S':
188 size = getsize(optarg);
189 flags |= VN_CONFIG;
190 flags &= ~VN_UNCONFIG;
191 break;
193 case 'T':
194 flags |= VN_TRUNCATE;
195 break;
197 case 'Z':
198 flags |= VN_ZERO;
199 break;
201 case 'L':
202 autolabel = optarg;
203 break;
205 default:
206 usage();
209 if (modfind("vn") < 0)
210 if (kldload("vn") < 0 || modfind("vn") < 0)
211 warnx( "cannot find or load \"vn\" kernel module");
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 );
221 exit(rv);
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;
241 rv = 0;
242 for (i = 0; i < nvndisks; i++)
243 rv += config(&vndisks[i]);
244 exit(rv);
248 what_opt(const char *str, u_long *p)
250 if (!strcmp(str,"reserve")) { *p |= VN_RESERVE; return 0; }
251 if (!strcmp(str,"labels")) { return 0; } /* deprecated */
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;
262 * GETINFO
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.
268 * Todo: correctly use vm_secsize for swap-backed vn's ..
272 getinfo( const char *vname )
274 int i = 0, vd, printlim = 0;
275 char vnpath[PATH_MAX];
276 const char *tmp;
278 struct vn_user vnu;
279 struct stat sb;
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;
291 tmp++;
293 if (*tmp == '\0')
294 errx(1, "unknown vn device: %s", vname);
297 snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", i);
299 vd = open(vnpath, O_RDONLY);
300 if (vd < 0)
301 err(1, "open: %s", vnpath);
303 for (; i<printlim; i++) {
305 bzero(&vnpath, sizeof(vnpath));
306 bzero(&sb, sizeof(struct stat));
307 bzero(&vnu, sizeof(struct vn_user));
309 vnu.vnu_unit = i;
311 snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", vnu.vnu_unit);
313 if(stat(vnpath, &sb) < 0) {
314 break;
316 else {
317 if (ioctl(vd, VNIOCGET, &vnu) == -1) {
318 warn("vn%d: ioctl", i);
319 continue;
322 fprintf(stdout, "vn%d: ", vnu.vnu_unit);
324 if (vnu.vnu_file[0] == 0)
325 fprintf(stdout, "not in use\n");
326 else if ((strcmp(vnu.vnu_file, _VN_USER_SWAP)) == 0)
327 fprintf(stdout,
328 "consuming %jd VM pages\n",
329 (intmax_t)vnu.vnu_size);
330 else
331 fprintf(stdout,
332 "covering %s on %s, inode %ju\n",
333 vnu.vnu_file,
334 devname(vnu.vnu_dev, S_IFBLK),
335 (uintmax_t)vnu.vnu_ino);
338 close(vd);
339 return 0;
343 config(struct vndisk *vnp)
345 char *dev, *file, *rdev, *oarg;
346 FILE *f;
347 struct vn_ioctl vnio;
348 int flags, pgsize, rv, status;
349 u_long l;
351 pgsize = getpagesize();
353 status = rv = 0;
356 * Prepend "/dev/" to the specified device name, if necessary.
357 * Operate on vnp->dev because it is used later.
359 if (vnp->dev[0] != '/' && vnp->dev[0] != '.')
360 asprintf(&vnp->dev, "%s%s", _PATH_DEV, vnp->dev);
361 dev = vnp->dev;
362 file = vnp->file;
363 flags = vnp->flags;
364 oarg = vnp->oarg;
366 if (flags & VN_IGNORE)
367 return(0);
370 * When a regular file has been specified, do any requested setup
371 * of the file. Truncation (also creates the file if necessary),
372 * sizing, and zeroing.
375 if (file && vnp->size != 0 && (flags & VN_CONFIG)) {
376 int fd;
377 struct stat st;
379 if (flags & VN_TRUNCATE)
380 fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600);
381 else
382 fd = open(file, O_RDWR);
383 if (fd >= 0 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
384 if (st.st_size < vnp->size * pgsize)
385 ftruncate(fd, vnp->size * pgsize);
386 if (vnp->size != 0)
387 st.st_size = vnp->size * pgsize;
389 if (flags & VN_ZERO) {
390 char *buf = malloc(ZBUFSIZE);
391 bzero(buf, ZBUFSIZE);
392 while (st.st_size > 0) {
393 int n = (st.st_size > ZBUFSIZE) ?
394 ZBUFSIZE : (int)st.st_size;
395 if (write(fd, buf, n) != n) {
396 ftruncate(fd, 0);
397 printf("Unable to ZERO file %s\n", file);
398 return(0);
400 st.st_size -= (off_t)n;
403 close(fd);
404 } else {
405 printf("Unable to open file %s\n", file);
406 return(0);
408 } else if (file == NULL && vnp->size == 0 && (flags & VN_CONFIG)) {
409 warnx("specify regular filename or swap size");
410 return (0);
413 rdev = rawdevice(dev);
414 f = fopen(rdev, "rw");
415 if (f == NULL) {
416 warn("%s", dev);
417 return(1);
419 if (!strcmp(rdev, "/dev/vn")) {
420 printf("Using: %s\n", fdevname(fileno(f)));
421 rv = asprintf(&dev, "%s%s", _PATH_DEV, fdevname(fileno(f)));
422 if (rv < 0)
423 dev = fdevname(fileno(f));
426 vnio.vn_file = file;
427 vnio.vn_size = vnp->size; /* non-zero only if swap backed */
430 * Disable the device
432 if (flags & VN_DISABLE) {
433 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
434 rv = unmount(oarg, 0);
435 if (rv) {
436 status--;
437 if (errno == EBUSY)
438 flags &= ~VN_UNCONFIG;
439 if ((flags & VN_UNCONFIG) == 0)
440 warn("umount");
441 } else if (verbose)
442 printf("%s: unmounted\n", dev);
446 * Clear (un-configure) the device
448 if (flags & VN_UNCONFIG) {
449 rv = ioctl(fileno(f), VNIOCDETACH, &vnio);
450 if (rv) {
451 if (errno == ENODEV) {
452 if (verbose)
453 printf("%s: not configured\n", dev);
454 rv = 0;
455 } else {
456 status--;
457 warn("VNIOCDETACH");
459 } else if (verbose)
460 printf("%s: cleared\n", dev);
463 * Set specified options
465 if (flags & VN_SET) {
466 l = setopt;
467 if (global)
468 rv = ioctl(fileno(f), VNIOCGSET, &l);
469 else
470 rv = ioctl(fileno(f), VNIOCUSET, &l);
471 if (rv) {
472 status--;
473 warn("VNIO[GU]SET");
474 } else if (verbose)
475 printf("%s: flags now=%08lx\n",dev,l);
478 * Reset specified options
480 if (flags & VN_RESET) {
481 l = resetopt;
482 if (global)
483 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
484 else
485 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
486 if (rv) {
487 status--;
488 warn("VNIO[GU]CLEAR");
489 } else if (verbose)
490 printf("%s: flags now=%08lx\n",dev,l);
493 * Configure the device
495 if (flags & VN_CONFIG) {
496 rv = ioctl(fileno(f), VNIOCATTACH, &vnio);
497 if (rv) {
498 status--;
499 warn("VNIOCATTACH");
500 flags &= ~VN_ENABLE;
501 } else {
502 if (verbose) {
503 printf("%s: %s, ", dev, file);
504 if (vnp->size != 0) {
505 printf("%jd bytes mapped\n", (intmax_t)vnio.vn_size);
506 } else {
507 printf("complete file mapped\n");
511 * autolabel
513 if (vnp->autolabel) {
514 do_autolabel(vnp->dev, vnp->autolabel);
519 * Set an option
521 if (flags & VN_SET) {
522 l = setopt;
523 if (global)
524 rv = ioctl(fileno(f), VNIOCGSET, &l);
525 else
526 rv = ioctl(fileno(f), VNIOCUSET, &l);
527 if (rv) {
528 status--;
529 warn("VNIO[GU]SET");
530 } else if (verbose)
531 printf("%s: flags now=%08lx\n",dev,l);
534 * Reset an option
536 if (flags & VN_RESET) {
537 l = resetopt;
538 if (global)
539 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
540 else
541 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
542 if (rv) {
543 status--;
544 warn("VNIO[GU]CLEAR");
545 } else if (verbose)
546 printf("%s: flags now=%08lx\n",dev,l);
550 * Close the device now, as we may want to mount it.
552 fclose(f);
555 * Enable special functions on the device
557 if (flags & VN_ENABLE) {
558 if (flags & VN_SWAP) {
559 rv = swapon(dev);
560 if (rv) {
561 status--;
562 warn("swapon");
564 else if (verbose)
565 printf("%s: swapping enabled\n", dev);
567 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
568 struct ufs_args args;
569 int mflags;
571 args.fspec = dev;
572 mflags = (flags & VN_MOUNTRO) ? MNT_RDONLY : 0;
573 rv = mount("ufs", oarg, mflags, &args);
574 if (rv) {
575 status--;
576 warn("mount");
578 else if (verbose)
579 printf("%s: mounted on %s\n", dev, oarg);
582 /* done: */
583 fflush(stdout);
584 return(status < 0);
587 #define EOL(c) ((c) == '\0' || (c) == '\n')
588 #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
590 void
591 readconfig(int flags)
593 char buf[LINESIZE];
594 FILE *f;
595 char *cp, *sp;
596 int ix;
597 int ax;
599 f = fopen(configfile, "r");
600 if (f == NULL)
601 err(1, "%s", configfile);
602 ix = 0; /* number of elements */
603 ax = 0; /* allocated elements */
604 while (fgets(buf, LINESIZE, f) != NULL) {
605 cp = buf;
606 if (*cp == '#')
607 continue;
608 while (!EOL(*cp) && WHITE(*cp))
609 cp++;
610 if (EOL(*cp))
611 continue;
612 sp = cp;
613 while (!EOL(*cp) && !WHITE(*cp))
614 cp++;
615 if (EOL(*cp))
616 continue;
617 *cp++ = '\0';
619 if (ix == ax) {
620 ax = ax + 16;
621 vndisks = realloc(vndisks, ax * sizeof(struct vndisk));
622 bzero(&vndisks[ix], (ax - ix) * sizeof(struct vndisk));
624 vndisks[ix].dev = malloc(cp - sp);
625 strcpy(vndisks[ix].dev, sp);
626 while (!EOL(*cp) && WHITE(*cp))
627 cp++;
628 if (EOL(*cp))
629 continue;
630 sp = cp;
631 while (!EOL(*cp) && !WHITE(*cp))
632 cp++;
633 *cp++ = '\0';
635 if (*sp == '%' && strtol(sp + 1, NULL, 0) > 0) {
636 vndisks[ix].size = getsize(sp + 1);
637 } else {
638 vndisks[ix].file = malloc(cp - sp);
639 strcpy(vndisks[ix].file, sp);
642 while (!EOL(*cp) && WHITE(*cp))
643 cp++;
644 vndisks[ix].flags = flags;
645 if (!EOL(*cp)) {
646 sp = cp;
647 while (!EOL(*cp) && !WHITE(*cp))
648 cp++;
649 *cp++ = '\0';
650 getoptions(&vndisks[ix], sp);
652 nvndisks++;
653 ix++;
657 void
658 getoptions(struct vndisk *vnp, const char *fstr)
660 int flags = 0;
661 const char *oarg = NULL;
663 if (strcmp(fstr, "swap") == 0)
664 flags |= VN_SWAP;
665 else if (strncmp(fstr, "mount=", 6) == 0) {
666 flags |= VN_MOUNTRW;
667 oarg = &fstr[6];
668 } else if (strncmp(fstr, "mountrw=", 8) == 0) {
669 flags |= VN_MOUNTRW;
670 oarg = &fstr[8];
671 } else if (strncmp(fstr, "mountro=", 8) == 0) {
672 flags |= VN_MOUNTRO;
673 oarg = &fstr[8];
674 } else if (strcmp(fstr, "ignore") == 0)
675 flags |= VN_IGNORE;
676 vnp->flags |= flags;
677 if (oarg) {
678 vnp->oarg = malloc(strlen(oarg) + 1);
679 strcpy(vnp->oarg, oarg);
680 } else
681 vnp->oarg = NULL;
684 char *
685 rawdevice(const char *dev)
687 char *rawbuf, *dp, *ep;
688 struct stat sb;
689 int len;
691 len = strlen(dev);
692 rawbuf = malloc(len + 2);
693 strcpy(rawbuf, dev);
694 if (stat(rawbuf, &sb) != 0 || !S_ISCHR(sb.st_mode)) {
695 dp = strrchr(rawbuf, '/');
696 if (dp) {
697 for (ep = &rawbuf[len]; ep > dp; --ep)
698 *(ep+1) = *ep;
699 *++ep = 'r';
702 return (rawbuf);
705 static void
706 usage(void)
708 fprintf(stderr, "%s\n%s\n%s\n%s\n",
709 "usage: vnconfig [-cdeguvTZ] [-s options] [-r options]",
710 " [-S value] special_file [regular_file] [feature]",
711 " vnconfig -a [-cdeguv] [-s options] [-r options] [-f config_file]",
712 " vnconfig -l [special_file ...]");
713 exit(1);
716 static int64_t
717 getsize(const char *arg)
719 char *ptr;
720 int pgsize = getpagesize();
721 int64_t size = strtoq(arg, &ptr, 0);
723 switch(tolower(*ptr)) {
724 case 't':
726 * GULP! Terabytes. It's actually possible to create
727 * a 7.9 TB VN device, though newfs can't handle any single
728 * filesystem larger then 1 TB.
730 size *= 1024;
731 /* fall through */
732 case 'g':
733 size *= 1024;
734 /* fall through */
735 default:
736 case 'm':
737 size *= 1024;
738 /* fall through */
739 case 'k':
740 size *= 1024;
741 /* fall through */
742 case 'c':
743 break;
745 size = (size + pgsize - 1) / pgsize;
746 return(size);
750 * DO_AUTOLABEL
752 * Automatically label the device. This will wipe any preexisting
753 * label.
756 static void
757 do_autolabel(const char *dev __unused, const char *label __unused)
759 /* XXX not yet implemented */
760 fprintf(stderr, "autolabel not yet implemented, sorry\n");
761 exit(1);