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.5 2004/03/10 17:54:16 dillon 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
97 int config(struct vndisk *);
98 void getoptions(struct vndisk *, char *);
99 char *rawdevice(char *);
100 void readconfig(int);
101 static void usage(void);
102 static int getsize(const char *arg);
103 static void do_autolabel(const char *dev, const char *label);
104 int what_opt(char *, u_long *);
107 main(int argc, char *argv[])
112 char *autolabel = NULL;
115 configfile = _PATH_VNTAB;
116 while ((i = getopt(argc, argv, "acdef:gr:s:S:TZL:uv")) != -1)
119 /* all -- use config file */
127 flags &= ~VN_UNCONFIG;
138 flags |= (VN_ENABLE|VN_CONFIG);
139 flags &= ~(VN_DISABLE|VN_UNCONFIG);
142 /* alternate config file */
147 /* fiddle global options */
154 for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
155 if (what_opt(s, &resetopt))
156 errx(1, "invalid options '%s'", s);
163 for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
164 if (what_opt(s, &setopt))
165 errx(1, "invalid options '%s'", s);
172 flags |= (VN_DISABLE|VN_UNCONFIG);
173 flags &= ~(VN_ENABLE|VN_CONFIG);
182 size = getsize(optarg);
184 flags &= ~VN_UNCONFIG;
188 flags |= VN_TRUNCATE;
203 if (modfind("vn") < 0)
204 if (kldload("vn") < 0 || modfind("vn") < 0)
205 warnx( "cannot find or load \"vn\" kernel module");
212 vndisks = calloc(sizeof(struct vndisk), 1);
213 if (argc < optind + 1)
215 vndisks[0].dev = argv[optind++];
216 vndisks[0].file = argv[optind++]; /* may be NULL */
217 vndisks[0].flags = flags;
218 vndisks[0].size = size;
219 vndisks[0].autolabel = autolabel;
221 getoptions(&vndisks[0], argv[optind]);
225 for (i = 0; i < nvndisks; i++)
226 rv += config(&vndisks[i]);
231 what_opt(char *str, u_long *p)
233 if (!strcmp(str,"reserve")) { *p |= VN_RESERVE; return 0; }
234 if (!strcmp(str,"labels")) { *p |= VN_LABELS; return 0; }
235 if (!strcmp(str,"follow")) { *p |= VN_FOLLOW; return 0; }
236 if (!strcmp(str,"debug")) { *p |= VN_DEBUG; return 0; }
237 if (!strcmp(str,"io")) { *p |= VN_IO; return 0; }
238 if (!strcmp(str,"all")) { *p |= ~0; return 0; }
239 if (!strcmp(str,"none")) { *p |= 0; return 0; }
244 config(struct vndisk *vnp)
246 char *dev, *file, *oarg;
248 struct vn_ioctl vnio;
253 int pgsize = getpagesize();
258 * Prepend "/dev/" to the specified device name, if necessary.
259 * Operate on vnp->dev because it is used later.
261 if (vnp->dev[0] != '/' && vnp->dev[0] != '.')
262 (void)asprintf(&vnp->dev, "%s%s", _PATH_DEV, vnp->dev);
268 if (flags & VN_IGNORE)
272 * When a regular file has been specified, do any requested setup
273 * of the file. Truncation (also creates the file if necessary),
274 * sizing, and zeroing.
277 if (file && vnp->size != 0 && (flags & VN_CONFIG)) {
281 if (flags & VN_TRUNCATE)
282 fd = open(file, O_RDWR|O_CREAT|O_TRUNC);
284 fd = open(file, O_RDWR);
285 if (fd >= 0 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
286 if (st.st_size < (off_t)vnp->size * pgsize)
287 ftruncate(fd, (off_t)vnp->size * pgsize);
289 st.st_size = (off_t)vnp->size * pgsize;
291 if (flags & VN_ZERO) {
292 char *buf = malloc(ZBUFSIZE);
293 bzero(buf, ZBUFSIZE);
294 while (st.st_size > 0) {
295 int n = (st.st_size > ZBUFSIZE) ?
296 ZBUFSIZE : (int)st.st_size;
297 if (write(fd, buf, n) != n) {
299 printf("Unable to ZERO file %s\n", file);
302 st.st_size -= (off_t)n;
307 printf("Unable to open file %s\n", file);
312 rdev = rawdevice(dev);
313 f = fopen(rdev, "rw");
319 vnio.vn_size = vnp->size; /* non-zero only if swap backed */
324 if (flags & VN_DISABLE) {
325 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
326 rv = unmount(oarg, 0);
330 flags &= ~VN_UNCONFIG;
331 if ((flags & VN_UNCONFIG) == 0)
334 printf("%s: unmounted\n", dev);
338 * Clear (un-configure) the device
340 if (flags & VN_UNCONFIG) {
341 rv = ioctl(fileno(f), VNIOCDETACH, &vnio);
343 if (errno == ENODEV) {
345 printf("%s: not configured\n", dev);
352 printf("%s: cleared\n", dev);
355 * Set specified options
357 if (flags & VN_SET) {
360 rv = ioctl(fileno(f), VNIOCGSET, &l);
362 rv = ioctl(fileno(f), VNIOCUSET, &l);
367 printf("%s: flags now=%08x\n",dev,l);
370 * Reset specified options
372 if (flags & VN_RESET) {
375 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
377 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
380 warn("VNIO[GU]CLEAR");
382 printf("%s: flags now=%08x\n",dev,l);
385 * Configure the device
387 if (flags & VN_CONFIG) {
388 rv = ioctl(fileno(f), VNIOCATTACH, &vnio);
396 "%s: %d bytes on %s\n",
397 dev, vnio.vn_size, file
403 if (vnp->autolabel) {
404 do_autolabel(vnp->dev, vnp->autolabel);
411 if (flags & VN_SET) {
414 rv = ioctl(fileno(f), VNIOCGSET, &l);
416 rv = ioctl(fileno(f), VNIOCUSET, &l);
421 printf("%s: flags now=%08lx\n",dev,l);
426 if (flags & VN_RESET) {
429 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
431 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
434 warn("VNIO[GU]CLEAR");
436 printf("%s: flags now=%08lx\n",dev,l);
440 * Close the device now, as we may want to mount it.
445 * Enable special functions on the device
447 if (flags & VN_ENABLE) {
448 if (flags & VN_SWAP) {
455 printf("%s: swapping enabled\n", dev);
457 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
458 struct ufs_args args;
462 mflags = (flags & VN_MOUNTRO) ? MNT_RDONLY : 0;
463 rv = mount("ufs", oarg, mflags, &args);
469 printf("%s: mounted on %s\n", dev, oarg);
477 #define EOL(c) ((c) == '\0' || (c) == '\n')
478 #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
481 readconfig(int flags)
489 f = fopen(configfile, "r");
491 err(1, "%s", configfile);
492 ix = 0; /* number of elements */
493 ax = 0; /* allocated elements */
494 while (fgets(buf, LINESIZE, f) != NULL) {
498 while (!EOL(*cp) && WHITE(*cp))
503 while (!EOL(*cp) && !WHITE(*cp))
511 vndisks = realloc(vndisks, ax * sizeof(struct vndisk));
512 bzero(&vndisks[ix], (ax - ix) * sizeof(struct vndisk));
514 vndisks[ix].dev = malloc(cp - sp);
515 strcpy(vndisks[ix].dev, sp);
516 while (!EOL(*cp) && WHITE(*cp))
521 while (!EOL(*cp) && !WHITE(*cp))
525 if (*sp == '%' && strtol(sp + 1, NULL, 0) > 0) {
526 vndisks[ix].size = getsize(sp + 1);
528 vndisks[ix].file = malloc(cp - sp);
529 strcpy(vndisks[ix].file, sp);
532 while (!EOL(*cp) && WHITE(*cp))
534 vndisks[ix].flags = flags;
537 while (!EOL(*cp) && !WHITE(*cp))
540 getoptions(&vndisks[ix], sp);
548 getoptions(struct vndisk *vnp, char *fstr)
553 if (strcmp(fstr, "swap") == 0)
555 else if (strncmp(fstr, "mount=", 6) == 0) {
558 } else if (strncmp(fstr, "mountrw=", 8) == 0) {
561 } else if (strncmp(fstr, "mountro=", 8) == 0) {
564 } else if (strcmp(fstr, "ignore") == 0)
568 vnp->oarg = malloc(strlen(oarg) + 1);
569 strcpy(vnp->oarg, oarg);
577 char *rawbuf, *dp, *ep;
582 rawbuf = malloc(len + 2);
584 if (stat(rawbuf, &sb) != 0 || !S_ISCHR(sb.st_mode)) {
585 dp = rindex(rawbuf, '/');
587 for (ep = &rawbuf[len]; ep > dp; --ep)
598 fprintf(stderr, "%s\n%s\n%s\n",
599 "usage: vnconfig [-cdeguv] [-s option] [-r option] [-S value] special_file",
600 " [regular_file] [feature]",
601 " vnconfig -a [-cdeguv] [-s option] [-r option] [-f config_file]");
606 getsize(const char *arg)
609 int pgsize = getpagesize();
610 quad_t size = strtoq(arg, &ptr, 0);
612 switch(tolower(*ptr)) {
615 * GULP! Terrabytes. It's actually possible to create
616 * a 7.9 TB VN device, though newfs can't handle any single
617 * filesystem larger then 1 TB.
634 size = (size + pgsize - 1) / pgsize;
641 * Automatically label the device. This will wipe any preexisting
646 do_autolabel(const char *dev, const char *label)
648 /* XXX not yet implemented */
649 fprintf(stderr, "autolabel not yet implemented, sorry\n");