Correct a bug in the -S truncation mode where the mode was not being passed
[dragonfly/vkernel-mp.git] / usr.sbin / vnconfig / vnconfig.c
blob38e25ad35bb2e60f1cb5b4c1774540dedd605583
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.12 2007/06/19 19:28:18 dillon 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 u_long setopt = 0;
94 u_long resetopt = 0;
95 char *configfile;
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 int64_t 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[])
109 int i, rv;
110 int flags = 0;
111 int64_t size = 0;
112 char *autolabel = NULL;
113 char *s;
115 configfile = _PATH_VNTAB;
116 while ((i = getopt(argc, argv, "acdef:gr:s:S:TZL:uv")) != -1)
117 switch (i) {
119 /* all -- use config file */
120 case 'a':
121 all++;
122 break;
124 /* configure */
125 case 'c':
126 flags |= VN_CONFIG;
127 flags &= ~VN_UNCONFIG;
128 break;
130 /* disable */
131 case 'd':
132 flags |= VN_DISABLE;
133 flags &= ~VN_ENABLE;
134 break;
136 /* enable */
137 case 'e':
138 flags |= (VN_ENABLE|VN_CONFIG);
139 flags &= ~(VN_DISABLE|VN_UNCONFIG);
140 break;
142 /* alternate config file */
143 case 'f':
144 configfile = optarg;
145 break;
147 /* fiddle global options */
148 case 'g':
149 global = 1 - global;
150 break;
152 /* reset options */
153 case 'r':
154 for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
155 if (what_opt(s, &resetopt))
156 errx(1, "invalid options '%s'", s);
158 flags |= VN_RESET;
159 break;
161 /* set options */
162 case 's':
163 for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) {
164 if (what_opt(s, &setopt))
165 errx(1, "invalid options '%s'", s);
167 flags |= VN_SET;
168 break;
170 /* unconfigure */
171 case 'u':
172 flags |= (VN_DISABLE|VN_UNCONFIG);
173 flags &= ~(VN_ENABLE|VN_CONFIG);
174 break;
176 /* verbose */
177 case 'v':
178 verbose++;
179 break;
181 case 'S':
182 size = getsize(optarg);
183 flags |= VN_CONFIG;
184 flags &= ~VN_UNCONFIG;
185 break;
187 case 'T':
188 flags |= VN_TRUNCATE;
189 break;
191 case 'Z':
192 flags |= VN_ZERO;
193 break;
195 case 'L':
196 autolabel = optarg;
197 break;
199 default:
200 usage();
203 if (modfind("vn") < 0)
204 if (kldload("vn") < 0 || modfind("vn") < 0)
205 warnx( "cannot find or load \"vn\" kernel module");
207 if (flags == 0)
208 flags = VN_CONFIG;
209 if (all) {
210 readconfig(flags);
211 } else {
212 vndisks = calloc(sizeof(struct vndisk), 1);
213 if (argc < optind + 1)
214 usage();
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;
220 if (optind < argc)
221 getoptions(&vndisks[0], argv[optind]);
222 nvndisks = 1;
224 rv = 0;
225 for (i = 0; i < nvndisks; i++)
226 rv += config(&vndisks[i]);
227 exit(rv);
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; }
240 return 1;
244 config(struct vndisk *vnp)
246 char *dev, *file, *rdev, *oarg;
247 FILE *f;
248 struct vn_ioctl vnio;
249 int flags, pgsize, rv, status;
250 u_long l;
252 pgsize = getpagesize();
254 status = rv = 0;
257 * Prepend "/dev/" to the specified device name, if necessary.
258 * Operate on vnp->dev because it is used later.
260 if (vnp->dev[0] != '/' && vnp->dev[0] != '.')
261 asprintf(&vnp->dev, "%s%s", _PATH_DEV, vnp->dev);
262 dev = vnp->dev;
263 file = vnp->file;
264 flags = vnp->flags;
265 oarg = vnp->oarg;
267 if (flags & VN_IGNORE)
268 return(0);
271 * When a regular file has been specified, do any requested setup
272 * of the file. Truncation (also creates the file if necessary),
273 * sizing, and zeroing.
276 if (file && vnp->size != 0 && (flags & VN_CONFIG)) {
277 int fd;
278 struct stat st;
280 if (flags & VN_TRUNCATE)
281 fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600);
282 else
283 fd = open(file, O_RDWR);
284 if (fd >= 0 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
285 if (st.st_size < vnp->size * pgsize)
286 ftruncate(fd, vnp->size * pgsize);
287 if (vnp->size != 0)
288 st.st_size = vnp->size * pgsize;
290 if (flags & VN_ZERO) {
291 char *buf = malloc(ZBUFSIZE);
292 bzero(buf, ZBUFSIZE);
293 while (st.st_size > 0) {
294 int n = (st.st_size > ZBUFSIZE) ?
295 ZBUFSIZE : (int)st.st_size;
296 if (write(fd, buf, n) != n) {
297 ftruncate(fd, 0);
298 printf("Unable to ZERO file %s\n", file);
299 return(0);
301 st.st_size -= (off_t)n;
304 close(fd);
305 } else {
306 printf("Unable to open file %s\n", file);
307 return(0);
311 rdev = rawdevice(dev);
312 f = fopen(rdev, "rw");
313 if (f == NULL) {
314 warn("%s", dev);
315 return(1);
317 vnio.vn_file = file;
318 vnio.vn_size = vnp->size; /* non-zero only if swap backed */
321 * Disable the device
323 if (flags & VN_DISABLE) {
324 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
325 rv = unmount(oarg, 0);
326 if (rv) {
327 status--;
328 if (errno == EBUSY)
329 flags &= ~VN_UNCONFIG;
330 if ((flags & VN_UNCONFIG) == 0)
331 warn("umount");
332 } else if (verbose)
333 printf("%s: unmounted\n", dev);
337 * Clear (un-configure) the device
339 if (flags & VN_UNCONFIG) {
340 rv = ioctl(fileno(f), VNIOCDETACH, &vnio);
341 if (rv) {
342 if (errno == ENODEV) {
343 if (verbose)
344 printf("%s: not configured\n", dev);
345 rv = 0;
346 } else {
347 status--;
348 warn("VNIOCDETACH");
350 } else if (verbose)
351 printf("%s: cleared\n", dev);
354 * Set specified options
356 if (flags & VN_SET) {
357 l = setopt;
358 if (global)
359 rv = ioctl(fileno(f), VNIOCGSET, &l);
360 else
361 rv = ioctl(fileno(f), VNIOCUSET, &l);
362 if (rv) {
363 status--;
364 warn("VNIO[GU]SET");
365 } else if (verbose)
366 printf("%s: flags now=%08x\n",dev,l);
369 * Reset specified options
371 if (flags & VN_RESET) {
372 l = resetopt;
373 if (global)
374 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
375 else
376 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
377 if (rv) {
378 status--;
379 warn("VNIO[GU]CLEAR");
380 } else if (verbose)
381 printf("%s: flags now=%08x\n",dev,l);
384 * Configure the device
386 if (flags & VN_CONFIG) {
387 rv = ioctl(fileno(f), VNIOCATTACH, &vnio);
388 if (rv) {
389 status--;
390 warn("VNIOCATTACH");
391 flags &= ~VN_ENABLE;
392 } else {
393 if (verbose) {
394 printf("%s: %s, ", dev, file);
395 if (vnp->size != 0) {
396 printf("%lld bytes mapped\n", vnio.vn_size);
397 } else {
398 printf("complete file mapped\n");
402 * autolabel
404 if (vnp->autolabel) {
405 do_autolabel(vnp->dev, vnp->autolabel);
410 * Set an option
412 if (flags & VN_SET) {
413 l = setopt;
414 if (global)
415 rv = ioctl(fileno(f), VNIOCGSET, &l);
416 else
417 rv = ioctl(fileno(f), VNIOCUSET, &l);
418 if (rv) {
419 status--;
420 warn("VNIO[GU]SET");
421 } else if (verbose)
422 printf("%s: flags now=%08lx\n",dev,l);
425 * Reset an option
427 if (flags & VN_RESET) {
428 l = resetopt;
429 if (global)
430 rv = ioctl(fileno(f), VNIOCGCLEAR, &l);
431 else
432 rv = ioctl(fileno(f), VNIOCUCLEAR, &l);
433 if (rv) {
434 status--;
435 warn("VNIO[GU]CLEAR");
436 } else if (verbose)
437 printf("%s: flags now=%08lx\n",dev,l);
441 * Close the device now, as we may want to mount it.
443 fclose(f);
446 * Enable special functions on the device
448 if (flags & VN_ENABLE) {
449 if (flags & VN_SWAP) {
450 rv = swapon(dev);
451 if (rv) {
452 status--;
453 warn("swapon");
455 else if (verbose)
456 printf("%s: swapping enabled\n", dev);
458 if (flags & (VN_MOUNTRO|VN_MOUNTRW)) {
459 struct ufs_args args;
460 int mflags;
462 args.fspec = dev;
463 mflags = (flags & VN_MOUNTRO) ? MNT_RDONLY : 0;
464 rv = mount("ufs", oarg, mflags, &args);
465 if (rv) {
466 status--;
467 warn("mount");
469 else if (verbose)
470 printf("%s: mounted on %s\n", dev, oarg);
473 /* done: */
474 fflush(stdout);
475 return(status < 0);
478 #define EOL(c) ((c) == '\0' || (c) == '\n')
479 #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
481 void
482 readconfig(int flags)
484 char buf[LINESIZE];
485 FILE *f;
486 char *cp, *sp;
487 int ix;
488 int ax;
490 f = fopen(configfile, "r");
491 if (f == NULL)
492 err(1, "%s", configfile);
493 ix = 0; /* number of elements */
494 ax = 0; /* allocated elements */
495 while (fgets(buf, LINESIZE, f) != NULL) {
496 cp = buf;
497 if (*cp == '#')
498 continue;
499 while (!EOL(*cp) && WHITE(*cp))
500 cp++;
501 if (EOL(*cp))
502 continue;
503 sp = cp;
504 while (!EOL(*cp) && !WHITE(*cp))
505 cp++;
506 if (EOL(*cp))
507 continue;
508 *cp++ = '\0';
510 if (ix == ax) {
511 ax = ax + 16;
512 vndisks = realloc(vndisks, ax * sizeof(struct vndisk));
513 bzero(&vndisks[ix], (ax - ix) * sizeof(struct vndisk));
515 vndisks[ix].dev = malloc(cp - sp);
516 strcpy(vndisks[ix].dev, sp);
517 while (!EOL(*cp) && WHITE(*cp))
518 cp++;
519 if (EOL(*cp))
520 continue;
521 sp = cp;
522 while (!EOL(*cp) && !WHITE(*cp))
523 cp++;
524 *cp++ = '\0';
526 if (*sp == '%' && strtol(sp + 1, NULL, 0) > 0) {
527 vndisks[ix].size = getsize(sp + 1);
528 } else {
529 vndisks[ix].file = malloc(cp - sp);
530 strcpy(vndisks[ix].file, sp);
533 while (!EOL(*cp) && WHITE(*cp))
534 cp++;
535 vndisks[ix].flags = flags;
536 if (!EOL(*cp)) {
537 sp = cp;
538 while (!EOL(*cp) && !WHITE(*cp))
539 cp++;
540 *cp++ = '\0';
541 getoptions(&vndisks[ix], sp);
543 nvndisks++;
544 ix++;
548 void
549 getoptions(struct vndisk *vnp, char *fstr)
551 int flags = 0;
552 char *oarg = NULL;
554 if (strcmp(fstr, "swap") == 0)
555 flags |= VN_SWAP;
556 else if (strncmp(fstr, "mount=", 6) == 0) {
557 flags |= VN_MOUNTRW;
558 oarg = &fstr[6];
559 } else if (strncmp(fstr, "mountrw=", 8) == 0) {
560 flags |= VN_MOUNTRW;
561 oarg = &fstr[8];
562 } else if (strncmp(fstr, "mountro=", 8) == 0) {
563 flags |= VN_MOUNTRO;
564 oarg = &fstr[8];
565 } else if (strcmp(fstr, "ignore") == 0)
566 flags |= VN_IGNORE;
567 vnp->flags |= flags;
568 if (oarg) {
569 vnp->oarg = malloc(strlen(oarg) + 1);
570 strcpy(vnp->oarg, oarg);
571 } else
572 vnp->oarg = NULL;
575 char *
576 rawdevice(char *dev)
578 char *rawbuf, *dp, *ep;
579 struct stat sb;
580 int len;
582 len = strlen(dev);
583 rawbuf = malloc(len + 2);
584 strcpy(rawbuf, dev);
585 if (stat(rawbuf, &sb) != 0 || !S_ISCHR(sb.st_mode)) {
586 dp = strrchr(rawbuf, '/');
587 if (dp) {
588 for (ep = &rawbuf[len]; ep > dp; --ep)
589 *(ep+1) = *ep;
590 *++ep = 'r';
593 return (rawbuf);
596 static void
597 usage(void)
599 fprintf(stderr, "%s\n%s\n%s\n",
600 "usage: vnconfig [-cdeguv] [-s option] [-r option] [-S value] special_file",
601 " [regular_file] [feature]",
602 " vnconfig -a [-cdeguv] [-s option] [-r option] [-f config_file]");
603 exit(1);
606 static int64_t
607 getsize(const char *arg)
609 char *ptr;
610 int pgsize = getpagesize();
611 int64_t size = strtoq(arg, &ptr, 0);
613 switch(tolower(*ptr)) {
614 case 't':
616 * GULP! Terrabytes. It's actually possible to create
617 * a 7.9 TB VN device, though newfs can't handle any single
618 * filesystem larger then 1 TB.
620 size *= 1024;
621 /* fall through */
622 case 'g':
623 size *= 1024;
624 /* fall through */
625 default:
626 case 'm':
627 size *= 1024;
628 /* fall through */
629 case 'k':
630 size *= 1024;
631 /* fall through */
632 case 'c':
633 break;
635 size = (size + pgsize - 1) / pgsize;
636 return(size);
640 * DO_AUTOLABEL
642 * Automatically label the device. This will wipe any preexisting
643 * label.
646 static void
647 do_autolabel(const char *dev, const char *label)
649 /* XXX not yet implemented */
650 fprintf(stderr, "autolabel not yet implemented, sorry\n");
651 exit(1);