Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * Copyright (c) 1993 University of Utah. | |
3 | * Copyright (c) 1990, 1993 | |
4 | * The Regents of the University of California. All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
7 | * the Systems Programming Group of the University of Utah Computer | |
8 | * Science Department. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
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. | |
25 | * | |
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 | |
36 | * SUCH DAMAGE. | |
37 | * | |
38 | * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$ | |
1de703da MD |
39 | * |
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 $ | |
daa51328 | 42 | * $DragonFly: src/usr.sbin/vnconfig/vnconfig.c,v 1.15 2008/07/27 22:36:01 thomas Exp $ |
984263bc MD |
43 | */ |
44 | ||
984263bc MD |
45 | #include <ctype.h> |
46 | #include <err.h> | |
47 | #include <errno.h> | |
48 | #include <paths.h> | |
49 | #include <stdio.h> | |
50 | #include <stdlib.h> | |
51 | #include <fcntl.h> | |
52 | #include <string.h> | |
53 | #include <unistd.h> | |
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> | |
59 | #include <sys/stat.h> | |
60 | #include <sys/vnioctl.h> | |
38a690d7 | 61 | #include <vfs/ufs/ufsmount.h> |
984263bc MD |
62 | |
63 | #define LINESIZE 1024 | |
64 | #define ZBUFSIZE 32768 | |
65 | ||
66 | struct vndisk { | |
67 | char *dev; | |
68 | char *file; | |
69 | char *autolabel; | |
70 | int flags; | |
57fec106 | 71 | int64_t size; |
984263bc MD |
72 | char *oarg; |
73 | } *vndisks; | |
74 | ||
75 | #define VN_CONFIG 0x01 | |
76 | #define VN_UNCONFIG 0x02 | |
77 | #define VN_ENABLE 0x04 | |
78 | #define VN_DISABLE 0x08 | |
79 | #define VN_SWAP 0x10 | |
80 | #define VN_MOUNTRO 0x20 | |
81 | #define VN_MOUNTRW 0x40 | |
82 | #define VN_IGNORE 0x80 | |
83 | #define VN_SET 0x100 | |
84 | #define VN_RESET 0x200 | |
85 | #define VN_TRUNCATE 0x400 | |
86 | #define VN_ZERO 0x800 | |
87 | ||
88 | int nvndisks; | |
89 | ||
90 | int all = 0; | |
91 | int verbose = 0; | |
92 | int global = 0; | |
30c1fde0 | 93 | int listopt = 0; |
984263bc MD |
94 | u_long setopt = 0; |
95 | u_long resetopt = 0; | |
96 | char *configfile; | |
97 | ||
2d8a3be7 | 98 | int config(struct vndisk *); |
acc9b5f2 | 99 | void getoptions(struct vndisk *, const char *); |
30c1fde0 | 100 | int getinfo(const char *vname); |
acc9b5f2 | 101 | char *rawdevice(const char *); |
2d8a3be7 EN |
102 | void readconfig(int); |
103 | static void usage(void); | |
57fec106 | 104 | static int64_t getsize(const char *arg); |
984263bc | 105 | static void do_autolabel(const char *dev, const char *label); |
acc9b5f2 | 106 | int what_opt(const char *, u_long *); |
984263bc MD |
107 | |
108 | int | |
cf287f0a | 109 | main(int argc, char *argv[]) |
984263bc | 110 | { |
cf287f0a | 111 | int i, rv; |
984263bc | 112 | int flags = 0; |
57fec106 | 113 | int64_t size = 0; |
984263bc MD |
114 | char *autolabel = NULL; |
115 | char *s; | |
116 | ||
117 | configfile = _PATH_VNTAB; | |
30c1fde0 | 118 | while ((i = getopt(argc, argv, "acdef:glr:s:S:TZL:uv")) != -1) |
984263bc MD |
119 | switch (i) { |
120 | ||
121 | /* all -- use config file */ | |
122 | case 'a': | |
123 | all++; | |
124 | break; | |
125 | ||
126 | /* configure */ | |
127 | case 'c': | |
128 | flags |= VN_CONFIG; | |
129 | flags &= ~VN_UNCONFIG; | |
130 | break; | |
131 | ||
132 | /* disable */ | |
133 | case 'd': | |
134 | flags |= VN_DISABLE; | |
135 | flags &= ~VN_ENABLE; | |
136 | break; | |
137 | ||
138 | /* enable */ | |
139 | case 'e': | |
140 | flags |= (VN_ENABLE|VN_CONFIG); | |
141 | flags &= ~(VN_DISABLE|VN_UNCONFIG); | |
142 | break; | |
143 | ||
144 | /* alternate config file */ | |
145 | case 'f': | |
146 | configfile = optarg; | |
147 | break; | |
148 | ||
149 | /* fiddle global options */ | |
150 | case 'g': | |
151 | global = 1 - global; | |
152 | break; | |
153 | ||
154 | /* reset options */ | |
155 | case 'r': | |
156 | for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) { | |
157 | if (what_opt(s, &resetopt)) | |
158 | errx(1, "invalid options '%s'", s); | |
159 | } | |
160 | flags |= VN_RESET; | |
161 | break; | |
162 | ||
30c1fde0 CT |
163 | case 'l': |
164 | listopt = 1; | |
165 | break; | |
166 | ||
984263bc MD |
167 | /* set options */ |
168 | case 's': | |
169 | for (s = strtok(optarg, ","); s; s = strtok(NULL, ",")) { | |
170 | if (what_opt(s, &setopt)) | |
171 | errx(1, "invalid options '%s'", s); | |
172 | } | |
173 | flags |= VN_SET; | |
174 | break; | |
175 | ||
176 | /* unconfigure */ | |
177 | case 'u': | |
178 | flags |= (VN_DISABLE|VN_UNCONFIG); | |
179 | flags &= ~(VN_ENABLE|VN_CONFIG); | |
180 | break; | |
181 | ||
182 | /* verbose */ | |
183 | case 'v': | |
184 | verbose++; | |
185 | break; | |
186 | ||
187 | case 'S': | |
188 | size = getsize(optarg); | |
189 | flags |= VN_CONFIG; | |
190 | flags &= ~VN_UNCONFIG; | |
191 | break; | |
192 | ||
193 | case 'T': | |
194 | flags |= VN_TRUNCATE; | |
195 | break; | |
196 | ||
197 | case 'Z': | |
198 | flags |= VN_ZERO; | |
199 | break; | |
200 | ||
201 | case 'L': | |
202 | autolabel = optarg; | |
203 | break; | |
204 | ||
205 | default: | |
206 | usage(); | |
207 | } | |
208 | ||
209 | if (modfind("vn") < 0) | |
210 | if (kldload("vn") < 0 || modfind("vn") < 0) | |
211 | warnx( "cannot find or load \"vn\" kernel module"); | |
212 | ||
30c1fde0 CT |
213 | if (listopt) { |
214 | if(argc > optind) | |
215 | while(argc > optind) | |
216 | rv += getinfo( argv[optind++]); | |
217 | else { | |
218 | rv = getinfo( NULL ); | |
219 | } | |
220 | exit(rv); | |
221 | } | |
222 | ||
984263bc MD |
223 | if (flags == 0) |
224 | flags = VN_CONFIG; | |
225 | if (all) { | |
226 | readconfig(flags); | |
227 | } else { | |
228 | vndisks = calloc(sizeof(struct vndisk), 1); | |
229 | if (argc < optind + 1) | |
230 | usage(); | |
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; | |
236 | if (optind < argc) | |
237 | getoptions(&vndisks[0], argv[optind]); | |
238 | nvndisks = 1; | |
239 | } | |
240 | rv = 0; | |
241 | for (i = 0; i < nvndisks; i++) | |
242 | rv += config(&vndisks[i]); | |
243 | exit(rv); | |
244 | } | |
245 | ||
246 | int | |
acc9b5f2 | 247 | what_opt(const char *str, u_long *p) |
984263bc MD |
248 | { |
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; } | |
256 | return 1; | |
257 | } | |
258 | ||
30c1fde0 CT |
259 | /* |
260 | * | |
261 | * GETINFO | |
262 | * | |
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. | |
266 | * | |
267 | * Todo: correctly use vm_secsize for swap-backed vn's .. | |
268 | */ | |
269 | ||
270 | int | |
271 | getinfo( const char *vname ) | |
272 | { | |
273 | int i, vd, printlim = 0; | |
274 | char vnpath[PATH_MAX], *tmp; | |
275 | ||
276 | struct vn_user vnu; | |
277 | struct stat sb; | |
278 | ||
279 | if (vname == NULL) { | |
280 | i = 0; | |
281 | printlim = 1024; | |
282 | } | |
283 | else { | |
284 | tmp = (char *) vname; | |
201b3f37 | 285 | while (*tmp != 0) { |
30c1fde0 CT |
286 | if(isdigit(*tmp)){ |
287 | i = atoi(tmp); | |
288 | printlim = i + 1; | |
289 | break; | |
290 | } | |
291 | tmp++; | |
292 | } | |
293 | if (tmp == NULL) { | |
294 | printf("unknown vn device: %s", vname); | |
295 | return 1; | |
296 | } | |
297 | } | |
298 | ||
299 | snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", i); | |
300 | ||
acc9b5f2 | 301 | vd = open(vnpath, O_RDONLY); |
30c1fde0 CT |
302 | if (vd < 0) { |
303 | err(1, "open: %s", vnpath); | |
304 | return 1; | |
305 | } | |
306 | ||
307 | for (i; i<printlim; i++) { | |
308 | ||
309 | bzero((void *) &vnpath, sizeof(vnpath)); | |
310 | bzero((void *) &sb, sizeof(struct stat)); | |
311 | bzero((void *) &vnu, sizeof(struct vn_user)); | |
312 | ||
313 | vnu.vnu_unit = i; | |
314 | ||
315 | snprintf(vnpath, sizeof(vnpath), "/dev/vn%d", vnu.vnu_unit); | |
316 | ||
acc9b5f2 | 317 | if(stat(vnpath, &sb) < 0) { |
30c1fde0 | 318 | break; |
acc9b5f2 | 319 | } |
30c1fde0 CT |
320 | else { |
321 | if (ioctl(vd, VNIOCGET, &vnu) == -1) { | |
322 | if (errno != ENXIO) { | |
2ddea4d5 SK |
323 | if (*vnu.vnu_file == '\0') { |
324 | fprintf(stdout, | |
325 | "vn%d: ioctl: can't access regular file\n", | |
326 | vnu.vnu_unit); | |
327 | continue; | |
328 | } | |
329 | else { | |
330 | err(1, "ioctl: %s", vname); | |
331 | close(vd); | |
332 | return 1; | |
333 | } | |
30c1fde0 CT |
334 | } |
335 | } | |
336 | ||
337 | fprintf(stdout, "vn%d: ", vnu.vnu_unit); | |
338 | ||
339 | if (vnu.vnu_file[0] == 0) | |
340 | fprintf(stdout, "not in use\n"); | |
341 | else if ((strcmp(vnu.vnu_file, _VN_USER_SWAP)) == 0) | |
342 | fprintf(stdout, | |
343 | "consuming %d VM pages\n", | |
344 | vnu.vnu_size); | |
345 | else | |
346 | fprintf(stdout, | |
0656dd4c | 347 | "covering %s on %s, inode %ju\n", |
30c1fde0 CT |
348 | vnu.vnu_file, |
349 | devname(vnu.vnu_dev, S_IFBLK), | |
0656dd4c | 350 | (uintmax_t)vnu.vnu_ino); |
30c1fde0 CT |
351 | } |
352 | } | |
353 | close(vd); | |
354 | return 0; | |
355 | } | |
356 | ||
984263bc | 357 | int |
cf287f0a | 358 | config(struct vndisk *vnp) |
984263bc | 359 | { |
66950a15 | 360 | char *dev, *file, *rdev, *oarg; |
984263bc | 361 | FILE *f; |
66950a15 HP |
362 | struct vn_ioctl vnio; |
363 | int flags, pgsize, rv, status; | |
984263bc | 364 | u_long l; |
66950a15 HP |
365 | |
366 | pgsize = getpagesize(); | |
984263bc MD |
367 | |
368 | status = rv = 0; | |
369 | ||
370 | /* | |
371 | * Prepend "/dev/" to the specified device name, if necessary. | |
372 | * Operate on vnp->dev because it is used later. | |
373 | */ | |
374 | if (vnp->dev[0] != '/' && vnp->dev[0] != '.') | |
71126e33 | 375 | asprintf(&vnp->dev, "%s%s", _PATH_DEV, vnp->dev); |
984263bc MD |
376 | dev = vnp->dev; |
377 | file = vnp->file; | |
378 | flags = vnp->flags; | |
379 | oarg = vnp->oarg; | |
380 | ||
381 | if (flags & VN_IGNORE) | |
382 | return(0); | |
383 | ||
384 | /* | |
385 | * When a regular file has been specified, do any requested setup | |
386 | * of the file. Truncation (also creates the file if necessary), | |
387 | * sizing, and zeroing. | |
388 | */ | |
389 | ||
390 | if (file && vnp->size != 0 && (flags & VN_CONFIG)) { | |
391 | int fd; | |
392 | struct stat st; | |
393 | ||
394 | if (flags & VN_TRUNCATE) | |
c7daadb1 | 395 | fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600); |
984263bc MD |
396 | else |
397 | fd = open(file, O_RDWR); | |
398 | if (fd >= 0 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { | |
57fec106 MD |
399 | if (st.st_size < vnp->size * pgsize) |
400 | ftruncate(fd, vnp->size * pgsize); | |
984263bc | 401 | if (vnp->size != 0) |
57fec106 | 402 | st.st_size = vnp->size * pgsize; |
984263bc MD |
403 | |
404 | if (flags & VN_ZERO) { | |
405 | char *buf = malloc(ZBUFSIZE); | |
406 | bzero(buf, ZBUFSIZE); | |
407 | while (st.st_size > 0) { | |
408 | int n = (st.st_size > ZBUFSIZE) ? | |
409 | ZBUFSIZE : (int)st.st_size; | |
410 | if (write(fd, buf, n) != n) { | |
411 | ftruncate(fd, 0); | |
412 | printf("Unable to ZERO file %s\n", file); | |
413 | return(0); | |
414 | } | |
415 | st.st_size -= (off_t)n; | |
416 | } | |
417 | } | |
418 | close(fd); | |
419 | } else { | |
420 | printf("Unable to open file %s\n", file); | |
421 | return(0); | |
422 | } | |
ba2933c8 SW |
423 | } else if (file == NULL && vnp->size == 0 && (flags & VN_CONFIG)) { |
424 | warnx("specify regular filename or swap size"); | |
425 | return (0); | |
984263bc MD |
426 | } |
427 | ||
428 | rdev = rawdevice(dev); | |
429 | f = fopen(rdev, "rw"); | |
430 | if (f == NULL) { | |
431 | warn("%s", dev); | |
432 | return(1); | |
433 | } | |
434 | vnio.vn_file = file; | |
435 | vnio.vn_size = vnp->size; /* non-zero only if swap backed */ | |
436 | ||
437 | /* | |
438 | * Disable the device | |
439 | */ | |
440 | if (flags & VN_DISABLE) { | |
441 | if (flags & (VN_MOUNTRO|VN_MOUNTRW)) { | |
442 | rv = unmount(oarg, 0); | |
443 | if (rv) { | |
444 | status--; | |
445 | if (errno == EBUSY) | |
446 | flags &= ~VN_UNCONFIG; | |
447 | if ((flags & VN_UNCONFIG) == 0) | |
448 | warn("umount"); | |
449 | } else if (verbose) | |
450 | printf("%s: unmounted\n", dev); | |
451 | } | |
452 | } | |
453 | /* | |
454 | * Clear (un-configure) the device | |
455 | */ | |
456 | if (flags & VN_UNCONFIG) { | |
457 | rv = ioctl(fileno(f), VNIOCDETACH, &vnio); | |
458 | if (rv) { | |
459 | if (errno == ENODEV) { | |
460 | if (verbose) | |
461 | printf("%s: not configured\n", dev); | |
462 | rv = 0; | |
463 | } else { | |
464 | status--; | |
465 | warn("VNIOCDETACH"); | |
466 | } | |
467 | } else if (verbose) | |
468 | printf("%s: cleared\n", dev); | |
469 | } | |
470 | /* | |
471 | * Set specified options | |
472 | */ | |
473 | if (flags & VN_SET) { | |
474 | l = setopt; | |
475 | if (global) | |
476 | rv = ioctl(fileno(f), VNIOCGSET, &l); | |
477 | else | |
478 | rv = ioctl(fileno(f), VNIOCUSET, &l); | |
479 | if (rv) { | |
480 | status--; | |
481 | warn("VNIO[GU]SET"); | |
482 | } else if (verbose) | |
483 | printf("%s: flags now=%08x\n",dev,l); | |
484 | } | |
485 | /* | |
486 | * Reset specified options | |
487 | */ | |
488 | if (flags & VN_RESET) { | |
489 | l = resetopt; | |
490 | if (global) | |
491 | rv = ioctl(fileno(f), VNIOCGCLEAR, &l); | |
492 | else | |
493 | rv = ioctl(fileno(f), VNIOCUCLEAR, &l); | |
494 | if (rv) { | |
495 | status--; | |
496 | warn("VNIO[GU]CLEAR"); | |
497 | } else if (verbose) | |
498 | printf("%s: flags now=%08x\n",dev,l); | |
499 | } | |
500 | /* | |
501 | * Configure the device | |
502 | */ | |
503 | if (flags & VN_CONFIG) { | |
504 | rv = ioctl(fileno(f), VNIOCATTACH, &vnio); | |
505 | if (rv) { | |
506 | status--; | |
507 | warn("VNIOCATTACH"); | |
508 | flags &= ~VN_ENABLE; | |
509 | } else { | |
510 | if (verbose) { | |
b3f9ca10 HP |
511 | printf("%s: %s, ", dev, file); |
512 | if (vnp->size != 0) { | |
57fec106 | 513 | printf("%lld bytes mapped\n", vnio.vn_size); |
b3f9ca10 HP |
514 | } else { |
515 | printf("complete file mapped\n"); | |
516 | } | |
984263bc MD |
517 | } |
518 | /* | |
519 | * autolabel | |
520 | */ | |
521 | if (vnp->autolabel) { | |
522 | do_autolabel(vnp->dev, vnp->autolabel); | |
523 | } | |
524 | } | |
525 | } | |
526 | /* | |
527 | * Set an option | |
528 | */ | |
529 | if (flags & VN_SET) { | |
530 | l = setopt; | |
531 | if (global) | |
532 | rv = ioctl(fileno(f), VNIOCGSET, &l); | |
533 | else | |
534 | rv = ioctl(fileno(f), VNIOCUSET, &l); | |
535 | if (rv) { | |
536 | status--; | |
537 | warn("VNIO[GU]SET"); | |
538 | } else if (verbose) | |
539 | printf("%s: flags now=%08lx\n",dev,l); | |
540 | } | |
541 | /* | |
542 | * Reset an option | |
543 | */ | |
544 | if (flags & VN_RESET) { | |
545 | l = resetopt; | |
546 | if (global) | |
547 | rv = ioctl(fileno(f), VNIOCGCLEAR, &l); | |
548 | else | |
549 | rv = ioctl(fileno(f), VNIOCUCLEAR, &l); | |
550 | if (rv) { | |
551 | status--; | |
552 | warn("VNIO[GU]CLEAR"); | |
553 | } else if (verbose) | |
554 | printf("%s: flags now=%08lx\n",dev,l); | |
555 | } | |
556 | ||
557 | /* | |
558 | * Close the device now, as we may want to mount it. | |
559 | */ | |
560 | fclose(f); | |
561 | ||
562 | /* | |
563 | * Enable special functions on the device | |
564 | */ | |
565 | if (flags & VN_ENABLE) { | |
566 | if (flags & VN_SWAP) { | |
567 | rv = swapon(dev); | |
568 | if (rv) { | |
569 | status--; | |
570 | warn("swapon"); | |
571 | } | |
572 | else if (verbose) | |
573 | printf("%s: swapping enabled\n", dev); | |
574 | } | |
575 | if (flags & (VN_MOUNTRO|VN_MOUNTRW)) { | |
576 | struct ufs_args args; | |
577 | int mflags; | |
578 | ||
579 | args.fspec = dev; | |
580 | mflags = (flags & VN_MOUNTRO) ? MNT_RDONLY : 0; | |
581 | rv = mount("ufs", oarg, mflags, &args); | |
582 | if (rv) { | |
583 | status--; | |
584 | warn("mount"); | |
585 | } | |
586 | else if (verbose) | |
587 | printf("%s: mounted on %s\n", dev, oarg); | |
588 | } | |
589 | } | |
590 | /* done: */ | |
591 | fflush(stdout); | |
592 | return(status < 0); | |
593 | } | |
594 | ||
595 | #define EOL(c) ((c) == '\0' || (c) == '\n') | |
596 | #define WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') | |
597 | ||
598 | void | |
cf287f0a | 599 | readconfig(int flags) |
984263bc MD |
600 | { |
601 | char buf[LINESIZE]; | |
602 | FILE *f; | |
cf287f0a MD |
603 | char *cp, *sp; |
604 | int ix; | |
984263bc MD |
605 | int ax; |
606 | ||
607 | f = fopen(configfile, "r"); | |
608 | if (f == NULL) | |
609 | err(1, "%s", configfile); | |
610 | ix = 0; /* number of elements */ | |
611 | ax = 0; /* allocated elements */ | |
612 | while (fgets(buf, LINESIZE, f) != NULL) { | |
613 | cp = buf; | |
614 | if (*cp == '#') | |
615 | continue; | |
616 | while (!EOL(*cp) && WHITE(*cp)) | |
617 | cp++; | |
618 | if (EOL(*cp)) | |
619 | continue; | |
620 | sp = cp; | |
621 | while (!EOL(*cp) && !WHITE(*cp)) | |
622 | cp++; | |
623 | if (EOL(*cp)) | |
624 | continue; | |
625 | *cp++ = '\0'; | |
626 | ||
627 | if (ix == ax) { | |
628 | ax = ax + 16; | |
629 | vndisks = realloc(vndisks, ax * sizeof(struct vndisk)); | |
630 | bzero(&vndisks[ix], (ax - ix) * sizeof(struct vndisk)); | |
631 | } | |
632 | vndisks[ix].dev = malloc(cp - sp); | |
633 | strcpy(vndisks[ix].dev, sp); | |
634 | while (!EOL(*cp) && WHITE(*cp)) | |
635 | cp++; | |
636 | if (EOL(*cp)) | |
637 | continue; | |
638 | sp = cp; | |
639 | while (!EOL(*cp) && !WHITE(*cp)) | |
640 | cp++; | |
641 | *cp++ = '\0'; | |
642 | ||
643 | if (*sp == '%' && strtol(sp + 1, NULL, 0) > 0) { | |
644 | vndisks[ix].size = getsize(sp + 1); | |
645 | } else { | |
646 | vndisks[ix].file = malloc(cp - sp); | |
647 | strcpy(vndisks[ix].file, sp); | |
648 | } | |
649 | ||
650 | while (!EOL(*cp) && WHITE(*cp)) | |
651 | cp++; | |
652 | vndisks[ix].flags = flags; | |
653 | if (!EOL(*cp)) { | |
654 | sp = cp; | |
655 | while (!EOL(*cp) && !WHITE(*cp)) | |
656 | cp++; | |
657 | *cp++ = '\0'; | |
658 | getoptions(&vndisks[ix], sp); | |
659 | } | |
660 | nvndisks++; | |
661 | ix++; | |
662 | } | |
663 | } | |
664 | ||
665 | void | |
acc9b5f2 | 666 | getoptions(struct vndisk *vnp, const char *fstr) |
984263bc MD |
667 | { |
668 | int flags = 0; | |
acc9b5f2 | 669 | const char *oarg = NULL; |
984263bc MD |
670 | |
671 | if (strcmp(fstr, "swap") == 0) | |
672 | flags |= VN_SWAP; | |
673 | else if (strncmp(fstr, "mount=", 6) == 0) { | |
674 | flags |= VN_MOUNTRW; | |
675 | oarg = &fstr[6]; | |
676 | } else if (strncmp(fstr, "mountrw=", 8) == 0) { | |
677 | flags |= VN_MOUNTRW; | |
678 | oarg = &fstr[8]; | |
679 | } else if (strncmp(fstr, "mountro=", 8) == 0) { | |
680 | flags |= VN_MOUNTRO; | |
681 | oarg = &fstr[8]; | |
682 | } else if (strcmp(fstr, "ignore") == 0) | |
683 | flags |= VN_IGNORE; | |
684 | vnp->flags |= flags; | |
685 | if (oarg) { | |
686 | vnp->oarg = malloc(strlen(oarg) + 1); | |
687 | strcpy(vnp->oarg, oarg); | |
688 | } else | |
689 | vnp->oarg = NULL; | |
690 | } | |
691 | ||
692 | char * | |
acc9b5f2 | 693 | rawdevice(const char *dev) |
984263bc | 694 | { |
cf287f0a | 695 | char *rawbuf, *dp, *ep; |
984263bc MD |
696 | struct stat sb; |
697 | int len; | |
698 | ||
699 | len = strlen(dev); | |
700 | rawbuf = malloc(len + 2); | |
701 | strcpy(rawbuf, dev); | |
702 | if (stat(rawbuf, &sb) != 0 || !S_ISCHR(sb.st_mode)) { | |
17b61719 | 703 | dp = strrchr(rawbuf, '/'); |
984263bc MD |
704 | if (dp) { |
705 | for (ep = &rawbuf[len]; ep > dp; --ep) | |
706 | *(ep+1) = *ep; | |
707 | *++ep = 'r'; | |
708 | } | |
709 | } | |
710 | return (rawbuf); | |
711 | } | |
712 | ||
713 | static void | |
44d05a04 | 714 | usage(void) |
984263bc | 715 | { |
daa51328 TN |
716 | fprintf(stderr, "%s\n%s\n%s\n%s\n", |
717 | "usage: vnconfig [-cdeguvTZ] [-s options] [-r options]", | |
718 | " [-S value] special_file [regular_file] [feature]", | |
719 | " vnconfig -a [-cdeguv] [-s options] [-r options] [-f config_file]", | |
720 | " vnconfig -l [special_file ...]"); | |
984263bc MD |
721 | exit(1); |
722 | } | |
723 | ||
57fec106 | 724 | static int64_t |
984263bc MD |
725 | getsize(const char *arg) |
726 | { | |
727 | char *ptr; | |
728 | int pgsize = getpagesize(); | |
57fec106 | 729 | int64_t size = strtoq(arg, &ptr, 0); |
984263bc MD |
730 | |
731 | switch(tolower(*ptr)) { | |
732 | case 't': | |
733 | /* | |
acc9b5f2 | 734 | * GULP! Terabytes. It's actually possible to create |
984263bc MD |
735 | * a 7.9 TB VN device, though newfs can't handle any single |
736 | * filesystem larger then 1 TB. | |
737 | */ | |
738 | size *= 1024; | |
739 | /* fall through */ | |
740 | case 'g': | |
741 | size *= 1024; | |
742 | /* fall through */ | |
743 | default: | |
744 | case 'm': | |
745 | size *= 1024; | |
746 | /* fall through */ | |
747 | case 'k': | |
748 | size *= 1024; | |
749 | /* fall through */ | |
750 | case 'c': | |
751 | break; | |
752 | } | |
753 | size = (size + pgsize - 1) / pgsize; | |
57fec106 | 754 | return(size); |
984263bc MD |
755 | } |
756 | ||
757 | /* | |
758 | * DO_AUTOLABEL | |
759 | * | |
760 | * Automatically label the device. This will wipe any preexisting | |
761 | * label. | |
762 | */ | |
763 | ||
764 | static void | |
765 | do_autolabel(const char *dev, const char *label) | |
766 | { | |
767 | /* XXX not yet implemented */ | |
768 | fprintf(stderr, "autolabel not yet implemented, sorry\n"); | |
769 | exit(1); | |
770 | } | |
771 |