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 "
397 st
.st_size
-= (off_t
)n
;
402 printf("Unable to open file %s\n", file
);
405 } else if (file
== NULL
&& vnp
->size
== 0 && (flags
& VN_CONFIG
)) {
406 warnx("specify regular filename or swap size");
410 rdev
= rawdevice(dev
);
411 f
= fopen(rdev
, "rw");
416 if (!strcmp(rdev
, "/dev/vn")) {
417 printf("%s\n", fdevname(fileno(f
)));
418 rv
= asprintf(&dev
, "%s%s", _PATH_DEV
, fdevname(fileno(f
)));
420 dev
= fdevname(fileno(f
));
424 vnio
.vn_size
= vnp
->size
; /* non-zero only if swap backed */
429 if (flags
& VN_DISABLE
) {
430 if (flags
& (VN_MOUNTRO
|VN_MOUNTRW
)) {
431 rv
= unmount(oarg
, 0);
435 flags
&= ~VN_UNCONFIG
;
436 if ((flags
& VN_UNCONFIG
) == 0)
439 printf("%s: unmounted\n", dev
);
443 * Clear (un-configure) the device
445 if (flags
& VN_UNCONFIG
) {
446 rv
= ioctl(fileno(f
), VNIOCDETACH
, &vnio
);
448 if (errno
== ENODEV
) {
450 printf("%s: not configured\n", dev
);
457 printf("%s: cleared\n", dev
);
460 * Set specified options
462 if (flags
& VN_SET
) {
465 rv
= ioctl(fileno(f
), VNIOCGSET
, &l
);
467 rv
= ioctl(fileno(f
), VNIOCUSET
, &l
);
472 printf("%s: flags now=%08lx\n",dev
,l
);
475 * Reset specified options
477 if (flags
& VN_RESET
) {
480 rv
= ioctl(fileno(f
), VNIOCGCLEAR
, &l
);
482 rv
= ioctl(fileno(f
), VNIOCUCLEAR
, &l
);
485 warn("VNIO[GU]CLEAR");
487 printf("%s: flags now=%08lx\n",dev
,l
);
490 * Configure the device
492 if (flags
& VN_CONFIG
) {
493 rv
= ioctl(fileno(f
), VNIOCATTACH
, &vnio
);
500 printf("%s: %s, ", dev
, file
);
501 if (vnp
->size
!= 0) {
502 printf("%jd bytes mapped\n",
503 (intmax_t)vnio
.vn_size
);
505 printf("complete file mapped\n");
511 if (vnp
->autolabel
) {
512 do_autolabel(vnp
->dev
, vnp
->autolabel
);
519 if (flags
& VN_SET
) {
522 rv
= ioctl(fileno(f
), VNIOCGSET
, &l
);
524 rv
= ioctl(fileno(f
), VNIOCUSET
, &l
);
529 printf("%s: flags now=%08lx\n",dev
,l
);
534 if (flags
& VN_RESET
) {
537 rv
= ioctl(fileno(f
), VNIOCGCLEAR
, &l
);
539 rv
= ioctl(fileno(f
), VNIOCUCLEAR
, &l
);
542 warn("VNIO[GU]CLEAR");
544 printf("%s: flags now=%08lx\n",dev
,l
);
548 * Close the device now, as we may want to mount it.
553 * Enable special functions on the device
555 if (flags
& VN_ENABLE
) {
556 if (flags
& VN_SWAP
) {
563 printf("%s: swapping enabled\n", dev
);
565 if (flags
& (VN_MOUNTRO
|VN_MOUNTRW
)) {
566 struct ufs_args args
;
570 mflags
= (flags
& VN_MOUNTRO
) ? MNT_RDONLY
: 0;
571 rv
= mount("ufs", oarg
, mflags
, &args
);
577 printf("%s: mounted on %s\n", dev
, oarg
);
585 #define EOL(c) ((c) == '\0' || (c) == '\n')
586 #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
589 readconfig(int flags
)
597 f
= fopen(configfile
, "r");
599 err(1, "%s", configfile
);
600 ix
= 0; /* number of elements */
601 ax
= 0; /* allocated elements */
602 while (fgets(buf
, LINESIZE
, f
) != NULL
) {
606 while (!EOL(*cp
) && WHITE(*cp
))
611 while (!EOL(*cp
) && !WHITE(*cp
))
619 vndisks
= realloc(vndisks
, ax
* sizeof(struct vndisk
));
620 bzero(&vndisks
[ix
], (ax
- ix
) * sizeof(struct vndisk
));
622 vndisks
[ix
].dev
= malloc(cp
- sp
);
623 strcpy(vndisks
[ix
].dev
, sp
);
624 while (!EOL(*cp
) && WHITE(*cp
))
629 while (!EOL(*cp
) && !WHITE(*cp
))
633 if (*sp
== '%' && strtol(sp
+ 1, NULL
, 0) > 0) {
634 vndisks
[ix
].size
= getsize(sp
+ 1);
636 vndisks
[ix
].file
= malloc(cp
- sp
);
637 strcpy(vndisks
[ix
].file
, sp
);
640 while (!EOL(*cp
) && WHITE(*cp
))
642 vndisks
[ix
].flags
= flags
;
645 while (!EOL(*cp
) && !WHITE(*cp
))
648 getoptions(&vndisks
[ix
], sp
);
656 getoptions(struct vndisk
*vnp
, const char *fstr
)
659 const char *oarg
= NULL
;
661 if (strcmp(fstr
, "swap") == 0)
663 else if (strncmp(fstr
, "mount=", 6) == 0) {
666 } else if (strncmp(fstr
, "mountrw=", 8) == 0) {
669 } else if (strncmp(fstr
, "mountro=", 8) == 0) {
672 } else if (strcmp(fstr
, "ignore") == 0)
676 vnp
->oarg
= malloc(strlen(oarg
) + 1);
677 strcpy(vnp
->oarg
, oarg
);
683 rawdevice(const char *dev
)
685 char *rawbuf
, *dp
, *ep
;
690 rawbuf
= malloc(len
+ 2);
692 if (stat(rawbuf
, &sb
) != 0 || !S_ISCHR(sb
.st_mode
)) {
693 dp
= strrchr(rawbuf
, '/');
695 for (ep
= &rawbuf
[len
]; ep
> dp
; --ep
)
706 fprintf(stderr
, "%s\n%s\n%s\n%s\n",
707 "usage: vnconfig [-cdeguvTZ] [-s options] [-r options]",
708 " [-S value] special_file [regular_file] [feature]",
709 " vnconfig -a [-cdeguv] [-s options] [-r options] [-f config_file]",
710 " vnconfig -l [special_file ...]");
715 getsize(const char *arg
)
718 int pgsize
= getpagesize();
719 int64_t size
= strtoq(arg
, &ptr
, 0);
721 switch(tolower(*ptr
)) {
724 * GULP! Terabytes. It's actually possible to create
725 * a 7.9 TB VN device, though newfs can't handle any single
726 * filesystem larger then 1 TB.
743 size
= (size
+ pgsize
- 1) / pgsize
;
750 * Automatically label the device. This will wipe any preexisting
755 do_autolabel(const char *dev __unused
, const char *label __unused
)
757 /* XXX not yet implemented */
758 fprintf(stderr
, "autolabel not yet implemented, sorry\n");