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.15 2008/07/27 22:36:01 thomas 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
96 const char *configfile
;
98 int config(struct vndisk
*);
99 void getoptions(struct vndisk
*, const char *);
100 int getinfo(const char *vname
);
101 char *rawdevice(const 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(const 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");
217 rv
+= getinfo( argv
[optind
++]);
219 rv
= getinfo( NULL
);
229 vndisks
= calloc(sizeof(struct vndisk
), 1);
230 if (argc
< optind
+ 1)
232 vndisks
[0].dev
= argv
[optind
++];
233 vndisks
[0].file
= argv
[optind
++]; /* may be NULL */
234 vndisks
[0].flags
= flags
;
235 vndisks
[0].size
= size
;
236 vndisks
[0].autolabel
= autolabel
;
238 getoptions(&vndisks
[0], argv
[optind
]);
242 for (i
= 0; i
< nvndisks
; i
++)
243 rv
+= config(&vndisks
[i
]);
248 what_opt(const char *str
, u_long
*p
)
250 if (!strcmp(str
,"reserve")) { *p
|= VN_RESERVE
; return 0; }
251 if (!strcmp(str
,"labels")) { return 0; } /* deprecated */
252 if (!strcmp(str
,"follow")) { *p
|= VN_FOLLOW
; return 0; }
253 if (!strcmp(str
,"debug")) { *p
|= VN_DEBUG
; return 0; }
254 if (!strcmp(str
,"io")) { *p
|= VN_IO
; return 0; }
255 if (!strcmp(str
,"all")) { *p
|= ~0; return 0; }
256 if (!strcmp(str
,"none")) { *p
|= 0; return 0; }
264 * Print vnode disk information to stdout for the device at
265 * path 'vname', or all existing 'vn' devices if none is given.
266 * Any 'vn' devices must exist under /dev in order to be queried.
268 * Todo: correctly use vm_secsize for swap-backed vn's ..
272 getinfo( const char *vname
)
274 int i
= 0, vd
, printlim
= 0;
275 char vnpath
[PATH_MAX
];
294 errx(1, "unknown vn device: %s", vname
);
297 snprintf(vnpath
, sizeof(vnpath
), "/dev/vn%d", i
);
299 vd
= open(vnpath
, O_RDONLY
);
301 err(1, "open: %s", vnpath
);
303 for (; i
<printlim
; i
++) {
305 bzero(&vnpath
, sizeof(vnpath
));
306 bzero(&sb
, sizeof(struct stat
));
307 bzero(&vnu
, sizeof(struct vn_user
));
311 snprintf(vnpath
, sizeof(vnpath
), "/dev/vn%d", vnu
.vnu_unit
);
313 if(stat(vnpath
, &sb
) < 0) {
317 if (ioctl(vd
, VNIOCGET
, &vnu
) == -1) {
318 warn("vn%d: ioctl", i
);
322 fprintf(stdout
, "vn%d: ", vnu
.vnu_unit
);
324 if (vnu
.vnu_file
[0] == 0)
325 fprintf(stdout
, "not in use\n");
326 else if ((strcmp(vnu
.vnu_file
, _VN_USER_SWAP
)) == 0)
328 "consuming %jd VM pages\n",
329 (intmax_t)vnu
.vnu_size
);
332 "covering %s on %s, inode %ju\n",
334 devname(vnu
.vnu_dev
, S_IFBLK
),
335 (uintmax_t)vnu
.vnu_ino
);
343 config(struct vndisk
*vnp
)
345 char *dev
, *file
, *rdev
, *oarg
;
347 struct vn_ioctl vnio
;
348 int flags
, pgsize
, rv
, status
;
351 pgsize
= getpagesize();
356 * Prepend "/dev/" to the specified device name, if necessary.
357 * Operate on vnp->dev because it is used later.
359 if (vnp
->dev
[0] != '/' && vnp
->dev
[0] != '.')
360 asprintf(&vnp
->dev
, "%s%s", _PATH_DEV
, vnp
->dev
);
366 if (flags
& VN_IGNORE
)
370 * When a regular file has been specified, do any requested setup
371 * of the file. Truncation (also creates the file if necessary),
372 * sizing, and zeroing.
375 if (file
&& vnp
->size
!= 0 && (flags
& VN_CONFIG
)) {
379 if (flags
& VN_TRUNCATE
)
380 fd
= open(file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600);
382 fd
= open(file
, O_RDWR
);
383 if (fd
>= 0 && fstat(fd
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
384 if (st
.st_size
< vnp
->size
* pgsize
)
385 ftruncate(fd
, vnp
->size
* pgsize
);
387 st
.st_size
= vnp
->size
* pgsize
;
389 if (flags
& VN_ZERO
) {
390 char *buf
= malloc(ZBUFSIZE
);
391 bzero(buf
, ZBUFSIZE
);
392 while (st
.st_size
> 0) {
393 int n
= (st
.st_size
> ZBUFSIZE
) ?
394 ZBUFSIZE
: (int)st
.st_size
;
395 if (write(fd
, buf
, n
) != n
) {
397 printf("Unable to ZERO file %s\n", file
);
400 st
.st_size
-= (off_t
)n
;
405 printf("Unable to open file %s\n", file
);
408 } else if (file
== NULL
&& vnp
->size
== 0 && (flags
& VN_CONFIG
)) {
409 warnx("specify regular filename or swap size");
413 rdev
= rawdevice(dev
);
414 f
= fopen(rdev
, "rw");
419 if (!strcmp(rdev
, "/dev/vn"))
420 printf("Using: %s\n", 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");