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.13 2008/01/30 11:46:33 cat 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
98 int config(struct vndisk
*);
99 void getoptions(struct vndisk
*, char *);
100 int getinfo(const char *vname
);
101 char *rawdevice(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(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");
216 rv
+= getinfo( argv
[optind
++]);
218 rv
= getinfo( NULL
);
228 vndisks
= calloc(sizeof(struct vndisk
), 1);
229 if (argc
< optind
+ 1)
231 vndisks
[0].dev
= argv
[optind
++];
232 vndisks
[0].file
= argv
[optind
++]; /* may be NULL */
233 vndisks
[0].flags
= flags
;
234 vndisks
[0].size
= size
;
235 vndisks
[0].autolabel
= autolabel
;
237 getoptions(&vndisks
[0], argv
[optind
]);
241 for (i
= 0; i
< nvndisks
; i
++)
242 rv
+= config(&vndisks
[i
]);
247 what_opt(char *str
, u_long
*p
)
249 if (!strcmp(str
,"reserve")) { *p
|= VN_RESERVE
; return 0; }
250 if (!strcmp(str
,"labels")) { *p
|= VN_LABELS
; return 0; }
251 if (!strcmp(str
,"follow")) { *p
|= VN_FOLLOW
; return 0; }
252 if (!strcmp(str
,"debug")) { *p
|= VN_DEBUG
; return 0; }
253 if (!strcmp(str
,"io")) { *p
|= VN_IO
; return 0; }
254 if (!strcmp(str
,"all")) { *p
|= ~0; return 0; }
255 if (!strcmp(str
,"none")) { *p
|= 0; return 0; }
263 * Print vnode disk information to stdout for the device at
264 * path 'vname', or all existing 'vn' devices if none is given.
265 * Any 'vn' devices must exist under /dev in order to be queried.
267 * Todo: correctly use vm_secsize for swap-backed vn's ..
271 getinfo( const char *vname
)
273 int i
, vd
, printlim
= 0;
274 char vnpath
[PATH_MAX
], *tmp
;
284 tmp
= (char *) vname
;
285 while (*tmp
!= NULL
) {
294 printf("unknown vn device: %s", vname
);
299 snprintf(vnpath
, sizeof(vnpath
), "/dev/vn%d", i
);
301 vd
= open((char *)vnpath
, O_RDONLY
);
303 err(1, "open: %s", vnpath
);
307 for (i
; i
<printlim
; i
++) {
309 bzero((void *) &vnpath
, sizeof(vnpath
));
310 bzero((void *) &sb
, sizeof(struct stat
));
311 bzero((void *) &vnu
, sizeof(struct vn_user
));
315 snprintf(vnpath
, sizeof(vnpath
), "/dev/vn%d", vnu
.vnu_unit
);
317 if(stat(vnpath
, &sb
) < 0)
320 if (ioctl(vd
, VNIOCGET
, &vnu
) == -1) {
321 if (errno
!= ENXIO
) {
322 err(1, "ioctl: %s", vname
);
328 fprintf(stdout
, "vn%d: ", vnu
.vnu_unit
);
330 if (vnu
.vnu_file
[0] == 0)
331 fprintf(stdout
, "not in use\n");
332 else if ((strcmp(vnu
.vnu_file
, _VN_USER_SWAP
)) == 0)
334 "consuming %d VM pages\n",
338 "covering %s on %s, inode %d\n",
340 devname(vnu
.vnu_dev
, S_IFBLK
),
349 config(struct vndisk
*vnp
)
351 char *dev
, *file
, *rdev
, *oarg
;
353 struct vn_ioctl vnio
;
354 int flags
, pgsize
, rv
, status
;
357 pgsize
= getpagesize();
362 * Prepend "/dev/" to the specified device name, if necessary.
363 * Operate on vnp->dev because it is used later.
365 if (vnp
->dev
[0] != '/' && vnp
->dev
[0] != '.')
366 asprintf(&vnp
->dev
, "%s%s", _PATH_DEV
, vnp
->dev
);
372 if (flags
& VN_IGNORE
)
376 * When a regular file has been specified, do any requested setup
377 * of the file. Truncation (also creates the file if necessary),
378 * sizing, and zeroing.
381 if (file
&& vnp
->size
!= 0 && (flags
& VN_CONFIG
)) {
385 if (flags
& VN_TRUNCATE
)
386 fd
= open(file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600);
388 fd
= open(file
, O_RDWR
);
389 if (fd
>= 0 && fstat(fd
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
390 if (st
.st_size
< vnp
->size
* pgsize
)
391 ftruncate(fd
, vnp
->size
* pgsize
);
393 st
.st_size
= vnp
->size
* pgsize
;
395 if (flags
& VN_ZERO
) {
396 char *buf
= malloc(ZBUFSIZE
);
397 bzero(buf
, ZBUFSIZE
);
398 while (st
.st_size
> 0) {
399 int n
= (st
.st_size
> ZBUFSIZE
) ?
400 ZBUFSIZE
: (int)st
.st_size
;
401 if (write(fd
, buf
, n
) != n
) {
403 printf("Unable to ZERO file %s\n", file
);
406 st
.st_size
-= (off_t
)n
;
411 printf("Unable to open file %s\n", file
);
416 rdev
= rawdevice(dev
);
417 f
= fopen(rdev
, "rw");
423 vnio
.vn_size
= vnp
->size
; /* non-zero only if swap backed */
428 if (flags
& VN_DISABLE
) {
429 if (flags
& (VN_MOUNTRO
|VN_MOUNTRW
)) {
430 rv
= unmount(oarg
, 0);
434 flags
&= ~VN_UNCONFIG
;
435 if ((flags
& VN_UNCONFIG
) == 0)
438 printf("%s: unmounted\n", dev
);
442 * Clear (un-configure) the device
444 if (flags
& VN_UNCONFIG
) {
445 rv
= ioctl(fileno(f
), VNIOCDETACH
, &vnio
);
447 if (errno
== ENODEV
) {
449 printf("%s: not configured\n", dev
);
456 printf("%s: cleared\n", dev
);
459 * Set specified options
461 if (flags
& VN_SET
) {
464 rv
= ioctl(fileno(f
), VNIOCGSET
, &l
);
466 rv
= ioctl(fileno(f
), VNIOCUSET
, &l
);
471 printf("%s: flags now=%08x\n",dev
,l
);
474 * Reset specified options
476 if (flags
& VN_RESET
) {
479 rv
= ioctl(fileno(f
), VNIOCGCLEAR
, &l
);
481 rv
= ioctl(fileno(f
), VNIOCUCLEAR
, &l
);
484 warn("VNIO[GU]CLEAR");
486 printf("%s: flags now=%08x\n",dev
,l
);
489 * Configure the device
491 if (flags
& VN_CONFIG
) {
492 rv
= ioctl(fileno(f
), VNIOCATTACH
, &vnio
);
499 printf("%s: %s, ", dev
, file
);
500 if (vnp
->size
!= 0) {
501 printf("%lld bytes mapped\n", vnio
.vn_size
);
503 printf("complete file mapped\n");
509 if (vnp
->autolabel
) {
510 do_autolabel(vnp
->dev
, vnp
->autolabel
);
517 if (flags
& VN_SET
) {
520 rv
= ioctl(fileno(f
), VNIOCGSET
, &l
);
522 rv
= ioctl(fileno(f
), VNIOCUSET
, &l
);
527 printf("%s: flags now=%08lx\n",dev
,l
);
532 if (flags
& VN_RESET
) {
535 rv
= ioctl(fileno(f
), VNIOCGCLEAR
, &l
);
537 rv
= ioctl(fileno(f
), VNIOCUCLEAR
, &l
);
540 warn("VNIO[GU]CLEAR");
542 printf("%s: flags now=%08lx\n",dev
,l
);
546 * Close the device now, as we may want to mount it.
551 * Enable special functions on the device
553 if (flags
& VN_ENABLE
) {
554 if (flags
& VN_SWAP
) {
561 printf("%s: swapping enabled\n", dev
);
563 if (flags
& (VN_MOUNTRO
|VN_MOUNTRW
)) {
564 struct ufs_args args
;
568 mflags
= (flags
& VN_MOUNTRO
) ? MNT_RDONLY
: 0;
569 rv
= mount("ufs", oarg
, mflags
, &args
);
575 printf("%s: mounted on %s\n", dev
, oarg
);
583 #define EOL(c) ((c) == '\0' || (c) == '\n')
584 #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
587 readconfig(int flags
)
595 f
= fopen(configfile
, "r");
597 err(1, "%s", configfile
);
598 ix
= 0; /* number of elements */
599 ax
= 0; /* allocated elements */
600 while (fgets(buf
, LINESIZE
, f
) != NULL
) {
604 while (!EOL(*cp
) && WHITE(*cp
))
609 while (!EOL(*cp
) && !WHITE(*cp
))
617 vndisks
= realloc(vndisks
, ax
* sizeof(struct vndisk
));
618 bzero(&vndisks
[ix
], (ax
- ix
) * sizeof(struct vndisk
));
620 vndisks
[ix
].dev
= malloc(cp
- sp
);
621 strcpy(vndisks
[ix
].dev
, sp
);
622 while (!EOL(*cp
) && WHITE(*cp
))
627 while (!EOL(*cp
) && !WHITE(*cp
))
631 if (*sp
== '%' && strtol(sp
+ 1, NULL
, 0) > 0) {
632 vndisks
[ix
].size
= getsize(sp
+ 1);
634 vndisks
[ix
].file
= malloc(cp
- sp
);
635 strcpy(vndisks
[ix
].file
, sp
);
638 while (!EOL(*cp
) && WHITE(*cp
))
640 vndisks
[ix
].flags
= flags
;
643 while (!EOL(*cp
) && !WHITE(*cp
))
646 getoptions(&vndisks
[ix
], sp
);
654 getoptions(struct vndisk
*vnp
, char *fstr
)
659 if (strcmp(fstr
, "swap") == 0)
661 else if (strncmp(fstr
, "mount=", 6) == 0) {
664 } else if (strncmp(fstr
, "mountrw=", 8) == 0) {
667 } else if (strncmp(fstr
, "mountro=", 8) == 0) {
670 } else if (strcmp(fstr
, "ignore") == 0)
674 vnp
->oarg
= malloc(strlen(oarg
) + 1);
675 strcpy(vnp
->oarg
, oarg
);
683 char *rawbuf
, *dp
, *ep
;
688 rawbuf
= malloc(len
+ 2);
690 if (stat(rawbuf
, &sb
) != 0 || !S_ISCHR(sb
.st_mode
)) {
691 dp
= strrchr(rawbuf
, '/');
693 for (ep
= &rawbuf
[len
]; ep
> dp
; --ep
)
704 fprintf(stderr
, "%s\n%s\n%s\n",
705 "usage: vnconfig [-cdeguv] [-s option] [-r option] [-S value] special_file",
706 " [regular_file] [feature]",
707 " vnconfig -a [-cdeguv] [-s option] [-r option] [-f config_file]");
712 getsize(const char *arg
)
715 int pgsize
= getpagesize();
716 int64_t size
= strtoq(arg
, &ptr
, 0);
718 switch(tolower(*ptr
)) {
721 * GULP! Terrabytes. It's actually possible to create
722 * a 7.9 TB VN device, though newfs can't handle any single
723 * filesystem larger then 1 TB.
740 size
= (size
+ pgsize
- 1) / pgsize
;
747 * Automatically label the device. This will wipe any preexisting
752 do_autolabel(const char *dev
, const char *label
)
754 /* XXX not yet implemented */
755 fprintf(stderr
, "autolabel not yet implemented, sorry\n");