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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$
36 * @(#)vnconfig.c 8.1 (Berkeley) 12/15/93
37 * $FreeBSD: src/usr.sbin/vnconfig/vnconfig.c,v 1.13.2.7 2003/06/02 09:10:27 maxim Exp $
38 * $DragonFly: src/usr.sbin/vnconfig/vnconfig.c,v 1.15 2008/07/27 22:36:01 thomas Exp $
50 #include <sys/param.h>
51 #include <sys/ioctl.h>
52 #include <sys/linker.h>
53 #include <sys/mount.h>
54 #include <sys/module.h>
56 #include <sys/vnioctl.h>
57 #include <vfs/ufs/ufsmount.h>
60 #define ZBUFSIZE 32768
71 #define VN_CONFIG 0x01
72 #define VN_UNCONFIG 0x02
73 #define VN_ENABLE 0x04
74 #define VN_DISABLE 0x08
76 #define VN_MOUNTRO 0x20
77 #define VN_MOUNTRW 0x40
78 #define VN_IGNORE 0x80
80 #define VN_RESET 0x200
81 #define VN_TRUNCATE 0x400
92 const char *configfile
;
94 int config(struct vndisk
*);
95 void getoptions(struct vndisk
*, const char *);
96 int getinfo(const char *vname
);
97 char *rawdevice(const char *);
99 static void usage(void);
100 static int64_t getsize(const char *arg
);
101 static void do_autolabel(const char *dev
, const char *label
);
102 int what_opt(const char *, u_long
*);
105 main(int argc
, char *argv
[])
110 char *autolabel
= NULL
;
113 configfile
= _PATH_VNTAB
;
114 while ((i
= getopt(argc
, argv
, "acdef:glr:s:S:TZL:uv")) != -1)
117 /* all -- use config file */
125 flags
&= ~VN_UNCONFIG
;
136 flags
|= (VN_ENABLE
|VN_CONFIG
);
137 flags
&= ~(VN_DISABLE
|VN_UNCONFIG
);
140 /* alternate config file */
145 /* fiddle global options */
152 for (s
= strtok(optarg
, ","); s
; s
= strtok(NULL
, ",")) {
153 if (what_opt(s
, &resetopt
))
154 errx(1, "invalid options '%s'", s
);
165 for (s
= strtok(optarg
, ","); s
; s
= strtok(NULL
, ",")) {
166 if (what_opt(s
, &setopt
))
167 errx(1, "invalid options '%s'", s
);
174 flags
|= (VN_DISABLE
|VN_UNCONFIG
);
175 flags
&= ~(VN_ENABLE
|VN_CONFIG
);
184 size
= getsize(optarg
);
186 flags
&= ~VN_UNCONFIG
;
190 flags
|= VN_TRUNCATE
;
205 if (modfind("vn") < 0)
206 if (kldload("vn") < 0 || modfind("vn") < 0)
207 warnx( "cannot find or load \"vn\" kernel module");
213 rv
+= getinfo( argv
[optind
++]);
215 rv
= getinfo( NULL
);
225 vndisks
= calloc(sizeof(struct vndisk
), 1);
226 if (argc
< optind
+ 1)
228 vndisks
[0].dev
= argv
[optind
++];
229 vndisks
[0].file
= argv
[optind
++]; /* may be NULL */
230 vndisks
[0].flags
= flags
;
231 vndisks
[0].size
= size
;
232 vndisks
[0].autolabel
= autolabel
;
234 getoptions(&vndisks
[0], argv
[optind
]);
238 for (i
= 0; i
< nvndisks
; i
++)
239 rv
+= config(&vndisks
[i
]);
244 what_opt(const char *str
, u_long
*p
)
246 if (!strcmp(str
,"reserve")) { *p
|= VN_RESERVE
; return 0; }
247 if (!strcmp(str
,"labels")) { return 0; } /* deprecated */
248 if (!strcmp(str
,"follow")) { *p
|= VN_FOLLOW
; return 0; }
249 if (!strcmp(str
,"debug")) { *p
|= VN_DEBUG
; return 0; }
250 if (!strcmp(str
,"io")) { *p
|= VN_IO
; return 0; }
251 if (!strcmp(str
,"all")) { *p
|= ~0; return 0; }
252 if (!strcmp(str
,"none")) { *p
|= 0; return 0; }
260 * Print vnode disk information to stdout for the device at
261 * path 'vname', or all existing 'vn' devices if none is given.
262 * Any 'vn' devices must exist under /dev in order to be queried.
264 * Todo: correctly use vm_secsize for swap-backed vn's ..
268 getinfo( const char *vname
)
270 int i
= 0, vd
, printlim
= 0;
271 char vnpath
[PATH_MAX
];
290 errx(1, "unknown vn device: %s", vname
);
293 snprintf(vnpath
, sizeof(vnpath
), "/dev/vn%d", i
);
295 vd
= open(vnpath
, O_RDONLY
);
297 err(1, "open: %s", vnpath
);
299 for (; i
<printlim
; i
++) {
301 bzero(&vnpath
, sizeof(vnpath
));
302 bzero(&sb
, sizeof(struct stat
));
303 bzero(&vnu
, sizeof(struct vn_user
));
307 snprintf(vnpath
, sizeof(vnpath
), "/dev/vn%d", vnu
.vnu_unit
);
309 if(stat(vnpath
, &sb
) < 0) {
313 if (ioctl(vd
, VNIOCGET
, &vnu
) == -1) {
314 warn("vn%d: ioctl", i
);
318 fprintf(stdout
, "vn%d: ", vnu
.vnu_unit
);
320 if (vnu
.vnu_file
[0] == 0)
321 fprintf(stdout
, "not in use\n");
322 else if ((strcmp(vnu
.vnu_file
, _VN_USER_SWAP
)) == 0)
324 "consuming %jd VM pages\n",
325 (intmax_t)vnu
.vnu_size
);
328 "covering %s on %s, inode %ju\n",
330 devname(vnu
.vnu_dev
, S_IFBLK
),
331 (uintmax_t)vnu
.vnu_ino
);
339 config(struct vndisk
*vnp
)
341 char *dev
, *file
, *rdev
, *oarg
;
343 struct vn_ioctl vnio
;
344 int flags
, pgsize
, rv
, status
;
347 pgsize
= getpagesize();
352 * Prepend "/dev/" to the specified device name, if necessary.
353 * Operate on vnp->dev because it is used later.
355 if (vnp
->dev
[0] != '/' && vnp
->dev
[0] != '.')
356 asprintf(&vnp
->dev
, "%s%s", _PATH_DEV
, vnp
->dev
);
362 if (flags
& VN_IGNORE
)
366 * When a regular file has been specified, do any requested setup
367 * of the file. Truncation (also creates the file if necessary),
368 * sizing, and zeroing.
371 if (file
&& vnp
->size
!= 0 && (flags
& VN_CONFIG
)) {
375 if (flags
& VN_TRUNCATE
)
376 fd
= open(file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600);
378 fd
= open(file
, O_RDWR
);
379 if (fd
>= 0 && fstat(fd
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
380 if (st
.st_size
< vnp
->size
* pgsize
)
381 ftruncate(fd
, vnp
->size
* pgsize
);
383 st
.st_size
= vnp
->size
* pgsize
;
385 if (flags
& VN_ZERO
) {
386 char *buf
= malloc(ZBUFSIZE
);
387 bzero(buf
, ZBUFSIZE
);
388 while (st
.st_size
> 0) {
389 int n
= (st
.st_size
> ZBUFSIZE
) ?
390 ZBUFSIZE
: (int)st
.st_size
;
391 if (write(fd
, buf
, n
) != n
) {
393 printf("Unable to ZERO file %s\n", file
);
396 st
.st_size
-= (off_t
)n
;
401 printf("Unable to open file %s\n", file
);
404 } else if (file
== NULL
&& vnp
->size
== 0 && (flags
& VN_CONFIG
)) {
405 warnx("specify regular filename or swap size");
409 rdev
= rawdevice(dev
);
410 f
= fopen(rdev
, "rw");
415 if (!strcmp(rdev
, "/dev/vn")) {
416 printf("%s\n", fdevname(fileno(f
)));
417 rv
= asprintf(&dev
, "%s%s", _PATH_DEV
, fdevname(fileno(f
)));
419 dev
= fdevname(fileno(f
));
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=%08lx\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=%08lx\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("%jd bytes mapped\n", (intmax_t)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
, const char *fstr
)
657 const char *oarg
= NULL
;
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
);
681 rawdevice(const char *dev
)
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%s\n",
705 "usage: vnconfig [-cdeguvTZ] [-s options] [-r options]",
706 " [-S value] special_file [regular_file] [feature]",
707 " vnconfig -a [-cdeguv] [-s options] [-r options] [-f config_file]",
708 " vnconfig -l [special_file ...]");
713 getsize(const char *arg
)
716 int pgsize
= getpagesize();
717 int64_t size
= strtoq(arg
, &ptr
, 0);
719 switch(tolower(*ptr
)) {
722 * GULP! Terabytes. It's actually possible to create
723 * a 7.9 TB VN device, though newfs can't handle any single
724 * filesystem larger then 1 TB.
741 size
= (size
+ pgsize
- 1) / pgsize
;
748 * Automatically label the device. This will wipe any preexisting
753 do_autolabel(const char *dev __unused
, const char *label __unused
)
755 /* XXX not yet implemented */
756 fprintf(stderr
, "autolabel not yet implemented, sorry\n");