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
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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 $
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>
60 #include <sys/vnioctl.h>
61 #include <vfs/ufs/ufsmount.h>
64 #define ZBUFSIZE 32768
75 #define VN_CONFIG 0x01
76 #define VN_UNCONFIG 0x02
77 #define VN_ENABLE 0x04
78 #define VN_DISABLE 0x08
80 #define VN_MOUNTRO 0x20
81 #define VN_MOUNTRW 0x40
82 #define VN_IGNORE 0x80
84 #define VN_RESET 0x200
85 #define VN_TRUNCATE 0x400
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[])
114 char *autolabel = NULL;
117 configfile = _PATH_VNTAB;
118 while ((i = getopt(argc, argv, "acdef:glr:s:S:TZL:uv")) != -1)
121 /* all -- use config file */
129 flags &= ~VN_UNCONFIG;
140 flags |= (VN_ENABLE|VN_CONFIG);
141 flags &= ~(VN_DISABLE|VN_UNCONFIG);
144 /* alternate config file */
149 /* fiddle global options */
156 for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
157 if (what_opt(s, &resetopt))
158 errx(1, "invalid options '%s'", s);
169 for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
170 if (what_opt(s, &setopt))
171 errx(1, "invalid options '%s'", s);
178 flags |= (VN_DISABLE|VN_UNCONFIG);
179 flags &= ~(VN_ENABLE|VN_CONFIG);
188 size = getsize(optarg);
190 flags &= ~VN_UNCONFIG;
194 flags |= VN_TRUNCATE;
209 if (modfind("vn") < 0)
210 if (kldload("vn") < 0 || modfind("vn") < 0)
211 warnx( "cannot find or load \"vn\" kernel module");
217 rv += getinfo( argv[optind++]);
219 rv = getinfo( NULL );
229 vndisks = calloc(sizeof(struct vndisk), 1);
230 if (argc < optind + 1)
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;
238 getoptions(&vndisks[0], argv[optind]);
242 for (i = 0; i < nvndisks; i++)
243 rv += config(&vndisks[i]);
248 what_opt(const char *str, u_long *p)
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; }
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];
294 errx(1, "unknown vn device: %s", vname);
297 snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", i);
299 vd = open(vnpath, O_RDONLY);
301 err(1, "open: %s", vnpath);
305 for (; i<printlim; i++) {
307 bzero((void *) &vnpath, sizeof(vnpath));
308 bzero((void *) &sb, sizeof(struct stat));
309 bzero((void *) &vnu, sizeof(struct vn_user));
313 snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", vnu.vnu_unit);
315 if(stat(vnpath, &sb) < 0) {
319 if (ioctl(vd, VNIOCGET, &vnu) == -1) {
320 if (errno != ENXIO) {
321 if (*vnu.vnu_file == '\0') {
323 "vn%d: ioctl: can't access regular file\n",
328 err(1, "ioctl: %s", vname);
335 fprintf(stdout, "vn%d: ", vnu.vnu_unit);
337 if (vnu.vnu_file[0] == 0)
338 fprintf(stdout, "not in use\n");
339 else if ((strcmp(vnu.vnu_file, _VN_USER_SWAP)) == 0)
341 "consuming %lld VM pages\n",
345 "covering %s on %s, inode %ju\n",
347 devname(vnu.vnu_dev, S_IFBLK),
348 (uintmax_t)vnu.vnu_ino);
356 config(struct vndisk *vnp)
358 char *dev, *file, *rdev, *oarg;
360 struct vn_ioctl vnio;
361 int flags, pgsize, rv, status;
364 pgsize = getpagesize();
369 * Prepend "/dev/" to the specified device name, if necessary.
370 * Operate on vnp->dev because it is used later.
372 if (vnp->dev[0] != '/' && vnp->dev[0] != '.')
373 asprintf(&vnp->dev, "%s%s", _PATH_DEV, vnp->dev);
379 if (flags & VN_IGNORE)
383 * When a regular file has been specified, do any requested setup
384 * of the file. Truncation (also creates the file if necessary),
385 * sizing, and zeroing.
388 if (file && vnp->size != 0 && (flags & VN_CONFIG)) {
392 if (flags & VN_TRUNCATE)
393 fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600);
395 fd = open(file, O_RDWR);
396 if (fd >= 0 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
397 if (st.st_size < vnp->size * pgsize)
398 ftruncate(fd, vnp->size * pgsize);
400 st.st_size = vnp->size * pgsize;
402 if (flags & VN_ZERO) {
403 char *buf = malloc(ZBUFSIZE);
404 bzero(buf, ZBUFSIZE);
405 while (st.st_size > 0) {
406 int n = (st.st_size > ZBUFSIZE) ?
407 ZBUFSIZE : (int)st.st_size;
408 if (write(fd, buf, n) != n) {
410 printf("Unable to ZERO file %s\n", file);
413 st.st_size -= (off_t)n;
418 printf("Unable to open file %s\n", file);
421 } else if (file == NULL && vnp->size == 0 && (flags & VN_CONFIG)) {
422 warnx("specify regular filename or swap size");
426 rdev = rawdevice(dev);
427 f = fopen(rdev, "rw");
433 vnio.vn_size = vnp->size; /* non-zero only if swap backed */
438 if (flags & VN_DISABLE) {
439 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
440 rv = unmount(oarg, 0);
444 flags &= ~VN_UNCONFIG;
445 if ((flags & VN_UNCONFIG) == 0)
448 printf("%s: unmounted\n", dev);
452 * Clear (un-configure) the device
454 if (flags & VN_UNCONFIG) {
455 rv = ioctl(fileno(f), VNIOCDETACH, &vnio);
457 if (errno == ENODEV) {
459 printf("%s: not configured\n", dev);
466 printf("%s: cleared\n", dev);
469 * Set specified options
471 if (flags & VN_SET) {
474 rv = ioctl(fileno(f), VNIOCGSET, &l);
476 rv = ioctl(fileno(f), VNIOCUSET, &l);
481 printf("%s: flags now=%08lx\n",dev,l);
484 * Reset specified options
486 if (flags & VN_RESET) {
489 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
491 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
494 warn("VNIO[GU]CLEAR");
496 printf("%s: flags now=%08lx\n",dev,l);
499 * Configure the device
501 if (flags & VN_CONFIG) {
502 rv = ioctl(fileno(f), VNIOCATTACH, &vnio);
509 printf("%s: %s, ", dev, file);
510 if (vnp->size != 0) {
511 printf("%lld bytes mapped\n", vnio.vn_size);
513 printf("complete file mapped\n");
519 if (vnp->autolabel) {
520 do_autolabel(vnp->dev, vnp->autolabel);
527 if (flags & VN_SET) {
530 rv = ioctl(fileno(f), VNIOCGSET, &l);
532 rv = ioctl(fileno(f), VNIOCUSET, &l);
537 printf("%s: flags now=%08lx\n",dev,l);
542 if (flags & VN_RESET) {
545 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
547 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
550 warn("VNIO[GU]CLEAR");
552 printf("%s: flags now=%08lx\n",dev,l);
556 * Close the device now, as we may want to mount it.
561 * Enable special functions on the device
563 if (flags & VN_ENABLE) {
564 if (flags & VN_SWAP) {
571 printf("%s: swapping enabled\n", dev);
573 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
574 struct ufs_args args;
578 mflags = (flags & VN_MOUNTRO) ? MNT_RDONLY : 0;
579 rv = mount("ufs", oarg, mflags, &args);
585 printf("%s: mounted on %s\n", dev, oarg);
593 #define EOL(c) ((c) == '\0' || (c) == '\n')
594 #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
597 readconfig(int flags)
605 f = fopen(configfile, "r");
607 err(1, "%s", configfile);
608 ix = 0; /* number of elements */
609 ax = 0; /* allocated elements */
610 while (fgets(buf, LINESIZE, f) != NULL) {
614 while (!EOL(*cp) && WHITE(*cp))
619 while (!EOL(*cp) && !WHITE(*cp))
627 vndisks = realloc(vndisks, ax * sizeof(struct vndisk));
628 bzero(&vndisks[ix], (ax - ix) * sizeof(struct vndisk));
630 vndisks[ix].dev = malloc(cp - sp);
631 strcpy(vndisks[ix].dev, sp);
632 while (!EOL(*cp) && WHITE(*cp))
637 while (!EOL(*cp) && !WHITE(*cp))
641 if (*sp == '%' && strtol(sp + 1, NULL, 0) > 0) {
642 vndisks[ix].size = getsize(sp + 1);
644 vndisks[ix].file = malloc(cp - sp);
645 strcpy(vndisks[ix].file, sp);
648 while (!EOL(*cp) && WHITE(*cp))
650 vndisks[ix].flags = flags;
653 while (!EOL(*cp) && !WHITE(*cp))
656 getoptions(&vndisks[ix], sp);
664 getoptions(struct vndisk *vnp, const char *fstr)
667 const char *oarg = NULL;
669 if (strcmp(fstr, "swap") == 0)
671 else if (strncmp(fstr, "mount=", 6) == 0) {
674 } else if (strncmp(fstr, "mountrw=", 8) == 0) {
677 } else if (strncmp(fstr, "mountro=", 8) == 0) {
680 } else if (strcmp(fstr, "ignore") == 0)
684 vnp->oarg = malloc(strlen(oarg) + 1);
685 strcpy(vnp->oarg, oarg);
691 rawdevice(const char *dev)
693 char *rawbuf, *dp, *ep;
698 rawbuf = malloc(len + 2);
700 if (stat(rawbuf, &sb) != 0 || !S_ISCHR(sb.st_mode)) {
701 dp = strrchr(rawbuf, '/');
703 for (ep = &rawbuf[len]; ep > dp; --ep)
714 fprintf(stderr, "%s\n%s\n%s\n%s\n",
715 "usage: vnconfig [-cdeguvTZ] [-s options] [-r options]",
716 " [-S value] special_file [regular_file] [feature]",
717 " vnconfig -a [-cdeguv] [-s options] [-r options] [-f config_file]",
718 " vnconfig -l [special_file ...]");
723 getsize(const char *arg)
726 int pgsize = getpagesize();
727 int64_t size = strtoq(arg, &ptr, 0);
729 switch(tolower(*ptr)) {
732 * GULP! Terabytes. It's actually possible to create
733 * a 7.9 TB VN device, though newfs can't handle any single
734 * filesystem larger then 1 TB.
751 size = (size + pgsize - 1) / pgsize;
758 * Automatically label the device. This will wipe any preexisting
763 do_autolabel(const char *dev __unused, const char *label __unused)
765 /* XXX not yet implemented */
766 fprintf(stderr, "autolabel not yet implemented, sorry\n");