1 /* $NetBSD: vnconfig.c,v 1.41 2013/06/09 13:25:40 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1993 University of Utah. 34 * Copyright (c) 1990, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * the Systems Programming Group of the University of Utah Computer 39 * Science Department. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$ 66 * 67 * @(#)vnconfig.c 8.1 (Berkeley) 12/15/93 68 */ 69 70 #include <sys/param.h> 71 #include <sys/ioctl.h> 72 #include <sys/mount.h> 73 #ifndef __minix 74 #include <sys/buf.h> 75 #include <sys/disklabel.h> 76 #include <sys/disk.h> 77 #include <sys/bitops.h> 78 #else 79 #include <sys/wait.h> 80 #endif 81 82 #include <dev/vndvar.h> 83 84 #include <disktab.h> 85 #include <err.h> 86 #include <dirent.h> 87 #include <errno.h> 88 #include <fcntl.h> 89 #include <stddef.h> 90 #include <stdio.h> 91 #include <stdlib.h> 92 #include <string.h> 93 #include <unistd.h> 94 #include <util.h> 95 #include <paths.h> 96 97 #define VND_CONFIG 1 98 #define VND_UNCONFIG 2 99 #define VND_GET 3 100 101 static int verbose = 0; 102 static int readonly = 0; 103 static int force = 0; 104 static int compressed = 0; 105 static char *tabname; 106 #ifdef __minix 107 static int service = 1; 108 #endif 109 110 #ifndef __minix 111 static void show(int, int); 112 #else 113 static void show(const char *, int); 114 #endif 115 static int config(char *, char *, char *, int); 116 static int getgeom(struct vndgeom *, char *); 117 __dead static void usage(void); 118 119 #ifdef __minix 120 /* 121 * Start a driver instance for the given vnd name. The return value indicates 122 * whether the instance has been started successfully. 123 */ 124 static int 125 start_service(char *dev) 126 { 127 char *p, *endp, cmd[PATH_MAX]; 128 int n, status; 129 130 p = strrchr(dev, '/'); 131 if (p == NULL) p = dev; 132 else p++; 133 134 /* 135 * There are two alternatives to get the instance number for the 136 * driver: either we scan the given device name, or we obtain its major 137 * number. We choose to scan the name, because major numbers are more 138 * likely to change in the future. 139 */ 140 if (strncmp(p, "vnd", 3) != 0) 141 return 0; 142 n = strtoul(p + 3, &endp, 10); 143 if (endp[0]) 144 return 0; 145 146 if (verbose) 147 printf("%s: starting driver\n", dev); 148 149 snprintf(cmd, sizeof(cmd), 150 "%s up %s/vnd -label vnd%u -args instance=%u -dev %s", 151 _PATH_SERVICE, _PATH_DRIVERS, n, n, dev); 152 153 status = system(cmd); 154 155 if (!WIFEXITED(status)) 156 return 0; 157 return !WEXITSTATUS(status); 158 } 159 160 /* 161 * Stop the driver instance responsible for the given file descriptor. 162 * The file descriptor is closed upon return. 163 */ 164 static void 165 stop_service(int fd, char *dev) 166 { 167 char cmd[PATH_MAX]; 168 struct vnd_user vnu; 169 int openct, stop = 0; 170 171 /* Only shut down the driver if the device is opened once, by us. */ 172 if (ioctl(fd, DIOCOPENCT, &openct) == 0 && openct == 1) { 173 /* We let the driver tell us what instance number it has. */ 174 if (ioctl(fd, VNDIOCGET, &vnu) == 0) 175 stop = 1; 176 } 177 178 /* Close the file descriptor before shutting down the driver! */ 179 (void) close(fd); 180 181 if (stop) { 182 if (verbose) 183 printf("%s: stopping driver\n", dev); 184 185 snprintf(cmd, sizeof(cmd), "%s down vnd%u", _PATH_SERVICE, 186 vnu.vnu_unit); 187 188 system(cmd); 189 } 190 } 191 #endif 192 193 int 194 main(int argc, char *argv[]) 195 { 196 int ch, rv, action = VND_CONFIG; 197 198 #ifndef __minix 199 while ((ch = getopt(argc, argv, "Fcf:lrt:uvz")) != -1) { 200 #else 201 /* MINIX3: added -S; no support for -f, -t, -z at this time. */ 202 while ((ch = getopt(argc, argv, "SFclruv")) != -1) { 203 #endif 204 switch (ch) { 205 #ifdef __minix 206 case 'S': 207 service = 0; 208 break; 209 #endif 210 case 'F': 211 force = 1; 212 break; 213 case 'c': 214 action = VND_CONFIG; 215 break; 216 case 'f': 217 #ifndef __minix 218 if (setdisktab(optarg) == -1) 219 usage(); 220 #endif 221 break; 222 case 'l': 223 action = VND_GET; 224 break; 225 case 'r': 226 readonly = 1; 227 break; 228 case 't': 229 tabname = optarg; 230 break; 231 case 'u': 232 action = VND_UNCONFIG; 233 break; 234 case 'v': 235 verbose = 1; 236 break; 237 case 'z': 238 compressed = 1; 239 readonly = 1; 240 break; 241 default: 242 case '?': 243 usage(); 244 /* NOTREACHED */ 245 } 246 } 247 argc -= optind; 248 argv += optind; 249 250 if (action == VND_CONFIG) { 251 if ((argc < 2 || argc > 3) || 252 (argc == 3 && tabname != NULL)) 253 usage(); 254 rv = config(argv[0], argv[1], (argc == 3) ? argv[2] : NULL, 255 action); 256 } else if (action == VND_UNCONFIG) { 257 if (argc != 1 || tabname != NULL) 258 usage(); 259 rv = config(argv[0], NULL, NULL, action); 260 } else { /* VND_GET */ 261 #ifndef __minix 262 int n, v; 263 const char *vn; 264 char path[64]; 265 #else 266 int n; 267 #endif 268 269 if (argc != 0 && argc != 1) 270 usage(); 271 272 #ifndef __minix 273 vn = argc ? argv[0] : "vnd0"; 274 275 v = opendisk(vn, O_RDONLY, path, sizeof(path), 0); 276 if (v == -1) 277 err(1, "open: %s", vn); 278 #endif 279 280 if (argc) 281 #ifndef __minix 282 show(v, -1); 283 #else 284 show(argv[0], -1); 285 #endif 286 else { 287 DIR *dirp; 288 struct dirent *dp; 289 #ifndef __minix 290 __BITMAP_TYPE(, uint32_t, 65536) bm; 291 292 __BITMAP_ZERO(&bm); 293 #else 294 char *endp; 295 #endif 296 297 if ((dirp = opendir(_PATH_DEV)) == NULL) 298 err(1, "opendir: %s", _PATH_DEV); 299 300 while ((dp = readdir(dirp)) != NULL) { 301 #ifndef __minix 302 if (strncmp(dp->d_name, "rvnd", 4) != 0) 303 continue; 304 n = atoi(dp->d_name + 4); 305 if (__BITMAP_ISSET(n, &bm)) 306 continue; 307 __BITMAP_SET(n, &bm); 308 show(v, n); 309 #else 310 if (strncmp(dp->d_name, "vnd", 3) != 0) 311 continue; 312 n = strtoul(dp->d_name + 3, &endp, 10); 313 if (endp[0]) 314 continue; 315 show(dp->d_name, n); 316 #endif 317 } 318 319 closedir(dirp); 320 } 321 #ifndef __minix 322 close(v); 323 #endif 324 rv = 0; 325 } 326 return rv; 327 } 328 329 static void 330 #ifndef __minix 331 show(int v, int n) 332 #else 333 show(const char *vn, int n) 334 #endif 335 { 336 struct vnd_user vnu; 337 char *dev; 338 struct statvfs *mnt; 339 int i, nmount; 340 #ifdef __minix 341 int v; 342 char path[PATH_MAX]; 343 344 v = opendisk(vn, O_RDONLY, path, sizeof(path), 0); 345 if (v == -1) { 346 if (n == -1) 347 err(1, "open: %s", vn); 348 else 349 printf("vnd%d: not in use\n", n); 350 return; 351 } 352 #endif 353 354 vnu.vnu_unit = n; 355 if (ioctl(v, VNDIOCGET, &vnu) == -1) 356 err(1, "VNDIOCGET"); 357 358 #ifdef __minix 359 close(v); 360 #endif 361 362 if (vnu.vnu_ino == 0) { 363 printf("vnd%d: not in use\n", vnu.vnu_unit); 364 return; 365 } 366 367 printf("vnd%d: ", vnu.vnu_unit); 368 369 dev = devname(vnu.vnu_dev, S_IFBLK); 370 if (dev != NULL) 371 nmount = getmntinfo(&mnt, MNT_NOWAIT); 372 else { 373 mnt = NULL; 374 nmount = 0; 375 } 376 377 if (mnt != NULL) { 378 for (i = 0; i < nmount; i++) { 379 if (strncmp(mnt[i].f_mntfromname, "/dev/", 5) == 0 && 380 strcmp(mnt[i].f_mntfromname + 5, dev) == 0) 381 break; 382 } 383 if (i < nmount) 384 printf("%s (%s) ", mnt[i].f_mntonname, 385 mnt[i].f_mntfromname); 386 else 387 printf("%s ", dev); 388 } 389 else if (dev != NULL) 390 printf("%s ", dev); 391 else 392 printf("dev %llu,%llu ", 393 (unsigned long long)major(vnu.vnu_dev), 394 (unsigned long long)minor(vnu.vnu_dev)); 395 396 printf("inode %llu\n", (unsigned long long)vnu.vnu_ino); 397 } 398 399 static int 400 config(char *dev, char *file, char *geom, int action) 401 { 402 struct vnd_ioctl vndio; 403 #ifndef __minix 404 struct disklabel *lp; 405 #else 406 int stop = 0; 407 #endif 408 char rdev[MAXPATHLEN + 1]; 409 int fd, rv; 410 411 #ifdef __minix 412 /* 413 * MINIX does not have the concept of raw devices. As such, the access 414 * checks that apply to opening block devices, automatically apply here 415 * as well. Therefore, we must open the device as read-only, or we 416 * would be unable to un-configure a device that was configured as 417 * read-only: opening such a device as read-write would fail. 418 */ 419 fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0); 420 421 if (fd < 0 && errno == ENXIO && action == VND_CONFIG && service) { 422 stop = start_service(rdev); 423 424 fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0); 425 } 426 #else 427 fd = opendisk(dev, O_RDWR, rdev, sizeof(rdev), 0); 428 #endif 429 if (fd < 0) { 430 warn("%s: opendisk", rdev); 431 return (1); 432 } 433 434 memset(&vndio, 0, sizeof(vndio)); 435 #ifdef __GNUC__ 436 rv = 0; /* XXX */ 437 #endif 438 439 #ifndef __minix 440 vndio.vnd_file = file; 441 #endif 442 if (geom != NULL) { 443 rv = getgeom(&vndio.vnd_geom, geom); 444 #ifdef __minix 445 if (rv && stop) 446 stop_service(fd, rdev); 447 #endif 448 if (rv != 0) 449 errx(1, "invalid geometry: %s", geom); 450 vndio.vnd_flags = VNDIOF_HASGEOM; 451 #ifndef __minix 452 } else if (tabname != NULL) { 453 lp = getdiskbyname(tabname); 454 if (lp == NULL) 455 errx(1, "unknown disk type: %s", tabname); 456 vndio.vnd_geom.vng_secsize = lp->d_secsize; 457 vndio.vnd_geom.vng_nsectors = lp->d_nsectors; 458 vndio.vnd_geom.vng_ntracks = lp->d_ntracks; 459 vndio.vnd_geom.vng_ncylinders = lp->d_ncylinders; 460 vndio.vnd_flags = VNDIOF_HASGEOM; 461 #endif 462 } 463 464 if (readonly) 465 vndio.vnd_flags |= VNDIOF_READONLY; 466 467 #ifndef __minix 468 if (compressed) 469 vndio.vnd_flags |= VNF_COMP; 470 #endif 471 472 /* 473 * Clear (un-configure) the device 474 */ 475 if (action == VND_UNCONFIG) { 476 if (force) 477 vndio.vnd_flags |= VNDIOF_FORCE; 478 rv = ioctl(fd, VNDIOCCLR, &vndio); 479 #ifdef VNDIOOCCLR 480 if (rv && errno == ENOTTY) 481 rv = ioctl(fd, VNDIOOCCLR, &vndio); 482 #endif 483 if (rv) 484 warn("%s: VNDIOCCLR", rdev); 485 else if (verbose) 486 printf("%s: cleared\n", rdev); 487 #ifdef __minix 488 if (!rv && service) 489 stop = 2; 490 #endif 491 } 492 /* 493 * Configure the device 494 */ 495 if (action == VND_CONFIG) { 496 int ffd; 497 498 ffd = open(file, readonly ? O_RDONLY : O_RDWR); 499 if (ffd < 0) 500 warn("%s", file); 501 else { 502 #ifndef __minix 503 (void) close(ffd); 504 #else 505 vndio.vnd_fildes = ffd; 506 #endif 507 508 rv = ioctl(fd, VNDIOCSET, &vndio); 509 #ifdef VNDIOOCSET 510 if (rv && errno == ENOTTY) { 511 rv = ioctl(fd, VNDIOOCSET, &vndio); 512 vndio.vnd_size = vndio.vnd_osize; 513 } 514 #endif 515 #ifdef __minix 516 (void) close(ffd); 517 #endif 518 if (rv) 519 warn("%s: VNDIOCSET", rdev); 520 else if (verbose) { 521 printf("%s: %" PRIu64 " bytes on %s", rdev, 522 vndio.vnd_size, file); 523 if (vndio.vnd_flags & VNDIOF_HASGEOM) 524 printf(" using geometry %d/%d/%d/%d", 525 vndio.vnd_geom.vng_secsize, 526 vndio.vnd_geom.vng_nsectors, 527 vndio.vnd_geom.vng_ntracks, 528 vndio.vnd_geom.vng_ncylinders); 529 printf("\n"); 530 } 531 } 532 #ifdef __minix 533 if ((ffd < 0 || rv) && service) 534 stop++; 535 #endif 536 } 537 538 #ifdef __minix 539 if (stop >= 2) 540 stop_service(fd, rdev); 541 else 542 #endif 543 (void) close(fd); 544 fflush(stdout); 545 return (rv < 0); 546 } 547 548 static int 549 getgeom(struct vndgeom *vng, char *cp) 550 { 551 char *secsize, *nsectors, *ntracks, *ncylinders; 552 553 #define GETARG(arg) \ 554 do { \ 555 if (cp == NULL || *cp == '\0') \ 556 return (1); \ 557 arg = strsep(&cp, "/"); \ 558 if (arg == NULL) \ 559 return (1); \ 560 } while (0) 561 562 GETARG(secsize); 563 GETARG(nsectors); 564 GETARG(ntracks); 565 GETARG(ncylinders); 566 567 #undef GETARG 568 569 /* Too many? */ 570 if (cp != NULL) 571 return (1); 572 573 #define CVTARG(str, num) \ 574 do { \ 575 num = strtol(str, &cp, 10); \ 576 if (*cp != '\0') \ 577 return (1); \ 578 } while (0) 579 580 CVTARG(secsize, vng->vng_secsize); 581 CVTARG(nsectors, vng->vng_nsectors); 582 CVTARG(ntracks, vng->vng_ntracks); 583 CVTARG(ncylinders, vng->vng_ncylinders); 584 585 #undef CVTARG 586 587 return (0); 588 } 589 590 static void 591 usage(void) 592 { 593 594 (void)fprintf(stderr, "%s%s", 595 #ifndef __minix 596 "usage: vnconfig [-crvz] [-f disktab] [-t typename] vnode_disk" 597 " regular-file [geomspec]\n", 598 " vnconfig -u [-Fv] vnode_disk\n" 599 #else 600 "usage: vnconfig [-Scrv] vnode_disk regular-file [geomspec]\n", 601 " vnconfig -u [-SFv] vnode_disk\n" 602 #endif 603 " vnconfig -l [vnode_disk]\n"); 604 exit(1); 605 } 606