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.12 2007/06/19 19:28:18 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 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
[])
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
, *rdev
, *oarg
;
248 struct vn_ioctl vnio
;
249 int flags
, pgsize
, rv
, status
;
252 pgsize
= getpagesize();
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
);
267 if (flags
& VN_IGNORE
)
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
)) {
280 if (flags
& VN_TRUNCATE
)
281 fd
= open(file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600);
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
);
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
) {
298 printf("Unable to ZERO file %s\n", file
);
301 st
.st_size
-= (off_t
)n
;
306 printf("Unable to open file %s\n", file
);
311 rdev
= rawdevice(dev
);
312 f
= fopen(rdev
, "rw");
318 vnio
.vn_size
= vnp
->size
; /* non-zero only if swap backed */
323 if (flags
& VN_DISABLE
) {
324 if (flags
& (VN_MOUNTRO
|VN_MOUNTRW
)) {
325 rv
= unmount(oarg
, 0);
329 flags
&= ~VN_UNCONFIG
;
330 if ((flags
& VN_UNCONFIG
) == 0)
333 printf("%s: unmounted\n", dev
);
337 * Clear (un-configure) the device
339 if (flags
& VN_UNCONFIG
) {
340 rv
= ioctl(fileno(f
), VNIOCDETACH
, &vnio
);
342 if (errno
== ENODEV
) {
344 printf("%s: not configured\n", dev
);
351 printf("%s: cleared\n", dev
);
354 * Set specified options
356 if (flags
& VN_SET
) {
359 rv
= ioctl(fileno(f
), VNIOCGSET
, &l
);
361 rv
= ioctl(fileno(f
), VNIOCUSET
, &l
);
366 printf("%s: flags now=%08x\n",dev
,l
);
369 * Reset specified options
371 if (flags
& VN_RESET
) {
374 rv
= ioctl(fileno(f
), VNIOCGCLEAR
, &l
);
376 rv
= ioctl(fileno(f
), VNIOCUCLEAR
, &l
);
379 warn("VNIO[GU]CLEAR");
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
);
394 printf("%s: %s, ", dev
, file
);
395 if (vnp
->size
!= 0) {
396 printf("%lld bytes mapped\n", vnio
.vn_size
);
398 printf("complete file mapped\n");
404 if (vnp
->autolabel
) {
405 do_autolabel(vnp
->dev
, vnp
->autolabel
);
412 if (flags
& VN_SET
) {
415 rv
= ioctl(fileno(f
), VNIOCGSET
, &l
);
417 rv
= ioctl(fileno(f
), VNIOCUSET
, &l
);
422 printf("%s: flags now=%08lx\n",dev
,l
);
427 if (flags
& VN_RESET
) {
430 rv
= ioctl(fileno(f
), VNIOCGCLEAR
, &l
);
432 rv
= ioctl(fileno(f
), VNIOCUCLEAR
, &l
);
435 warn("VNIO[GU]CLEAR");
437 printf("%s: flags now=%08lx\n",dev
,l
);
441 * Close the device now, as we may want to mount it.
446 * Enable special functions on the device
448 if (flags
& VN_ENABLE
) {
449 if (flags
& VN_SWAP
) {
456 printf("%s: swapping enabled\n", dev
);
458 if (flags
& (VN_MOUNTRO
|VN_MOUNTRW
)) {
459 struct ufs_args args
;
463 mflags
= (flags
& VN_MOUNTRO
) ? MNT_RDONLY
: 0;
464 rv
= mount("ufs", oarg
, mflags
, &args
);
470 printf("%s: mounted on %s\n", dev
, oarg
);
478 #define EOL(c) ((c) == '\0' || (c) == '\n')
479 #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
482 readconfig(int flags
)
490 f
= fopen(configfile
, "r");
492 err(1, "%s", configfile
);
493 ix
= 0; /* number of elements */
494 ax
= 0; /* allocated elements */
495 while (fgets(buf
, LINESIZE
, f
) != NULL
) {
499 while (!EOL(*cp
) && WHITE(*cp
))
504 while (!EOL(*cp
) && !WHITE(*cp
))
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
))
522 while (!EOL(*cp
) && !WHITE(*cp
))
526 if (*sp
== '%' && strtol(sp
+ 1, NULL
, 0) > 0) {
527 vndisks
[ix
].size
= getsize(sp
+ 1);
529 vndisks
[ix
].file
= malloc(cp
- sp
);
530 strcpy(vndisks
[ix
].file
, sp
);
533 while (!EOL(*cp
) && WHITE(*cp
))
535 vndisks
[ix
].flags
= flags
;
538 while (!EOL(*cp
) && !WHITE(*cp
))
541 getoptions(&vndisks
[ix
], sp
);
549 getoptions(struct vndisk
*vnp
, char *fstr
)
554 if (strcmp(fstr
, "swap") == 0)
556 else if (strncmp(fstr
, "mount=", 6) == 0) {
559 } else if (strncmp(fstr
, "mountrw=", 8) == 0) {
562 } else if (strncmp(fstr
, "mountro=", 8) == 0) {
565 } else if (strcmp(fstr
, "ignore") == 0)
569 vnp
->oarg
= malloc(strlen(oarg
) + 1);
570 strcpy(vnp
->oarg
, oarg
);
578 char *rawbuf
, *dp
, *ep
;
583 rawbuf
= malloc(len
+ 2);
585 if (stat(rawbuf
, &sb
) != 0 || !S_ISCHR(sb
.st_mode
)) {
586 dp
= strrchr(rawbuf
, '/');
588 for (ep
= &rawbuf
[len
]; ep
> dp
; --ep
)
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]");
607 getsize(const char *arg
)
610 int pgsize
= getpagesize();
611 int64_t size
= strtoq(arg
, &ptr
, 0);
613 switch(tolower(*ptr
)) {
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.
635 size
= (size
+ pgsize
- 1) / pgsize
;
642 * Automatically label the device. This will wipe any preexisting
647 do_autolabel(const char *dev
, const char *label
)
649 /* XXX not yet implemented */
650 fprintf(stderr
, "autolabel not yet implemented, sorry\n");