1 /* $NetBSD: vnconfig.c,v 1.42 2014/05/23 20:50:16 dholland 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 #if !defined(__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 <minix/paths.h> 80 #include <sys/wait.h> 81 #endif /* !defined(__minix) */ 82 83 #include <dev/vndvar.h> 84 85 #include <disktab.h> 86 #include <err.h> 87 #include <dirent.h> 88 #include <errno.h> 89 #include <fcntl.h> 90 #include <stddef.h> 91 #include <stdio.h> 92 #include <stdlib.h> 93 #include <string.h> 94 #include <unistd.h> 95 #include <util.h> 96 #include <paths.h> 97 98 #define VND_CONFIG 1 99 #define VND_UNCONFIG 2 100 #define VND_GET 3 101 102 static int verbose = 0; 103 static int readonly = 0; 104 static int force = 0; 105 static int compressed = 0; 106 static char *tabname; 107 #if defined(__minix) 108 static int service = 1; 109 #endif /* defined(__minix) */ 110 111 #if !defined(__minix) 112 static void show(int, int); 113 #else 114 static void show(const char *, int); 115 #endif /* !defined(__minix) */ 116 static int config(char *, char *, char *, int); 117 static int getgeom(struct vndgeom *, char *); 118 __dead static void usage(void); 119 120 #if defined(__minix) 121 /* 122 * Start a driver instance for the given vnd name. The return value indicates 123 * whether the instance has been started successfully. 124 */ 125 static int 126 start_service(char *dev) 127 { 128 char *p, *endp, cmd[PATH_MAX]; 129 int n, status; 130 131 p = strrchr(dev, '/'); 132 if (p == NULL) p = dev; 133 else p++; 134 135 /* 136 * There are two alternatives to get the instance number for the 137 * driver: either we scan the given device name, or we obtain its major 138 * number. We choose to scan the name, because major numbers are more 139 * likely to change in the future. 140 */ 141 if (strncmp(p, "vnd", 3) != 0) 142 return 0; 143 n = strtoul(p + 3, &endp, 10); 144 if (endp[0]) 145 return 0; 146 147 if (verbose) 148 printf("%s: starting driver\n", dev); 149 150 snprintf(cmd, sizeof(cmd), 151 "%s up %s/vnd -label vnd%u -args instance=%u -dev %s", 152 _PATH_SERVICE, _PATH_DRIVERS, n, n, dev); 153 154 status = system(cmd); 155 156 if (!WIFEXITED(status)) 157 return 0; 158 return !WEXITSTATUS(status); 159 } 160 161 /* 162 * Stop the driver instance responsible for the given file descriptor. 163 * The file descriptor is closed upon return. 164 */ 165 static void 166 stop_service(int fd, char *dev) 167 { 168 char cmd[PATH_MAX]; 169 struct vnd_user vnu; 170 int openct, stop = 0; 171 172 /* Only shut down the driver if the device is opened once, by us. */ 173 if (ioctl(fd, DIOCOPENCT, &openct) == 0 && openct == 1) { 174 /* We let the driver tell us what instance number it has. */ 175 if (ioctl(fd, VNDIOCGET, &vnu) == 0) 176 stop = 1; 177 } 178 179 /* Close the file descriptor before shutting down the driver! */ 180 (void) close(fd); 181 182 if (stop) { 183 if (verbose) 184 printf("%s: stopping driver\n", dev); 185 186 snprintf(cmd, sizeof(cmd), "%s down vnd%u", _PATH_SERVICE, 187 vnu.vnu_unit); 188 189 system(cmd); 190 } 191 } 192 #endif /* defined(__minix) */ 193 194 int 195 main(int argc, char *argv[]) 196 { 197 int ch, rv, action = VND_CONFIG; 198 199 #if !defined(__minix) 200 while ((ch = getopt(argc, argv, "Fcf:lrt:uvz")) != -1) { 201 #else 202 /* MINIX3: added -S; no support for -f, -t, -z at this time. */ 203 while ((ch = getopt(argc, argv, "SFclruv")) != -1) { 204 #endif /* !defined(__minix) */ 205 switch (ch) { 206 #if defined(__minix) 207 case 'S': 208 service = 0; 209 break; 210 #endif /* defined(__minix) */ 211 case 'F': 212 force = 1; 213 break; 214 case 'c': 215 action = VND_CONFIG; 216 break; 217 case 'f': 218 #if !defined(__minix) 219 if (setdisktab(optarg) == -1) 220 usage(); 221 #endif /* !defined(__minix) */ 222 break; 223 case 'l': 224 action = VND_GET; 225 break; 226 case 'r': 227 readonly = 1; 228 break; 229 case 't': 230 tabname = optarg; 231 break; 232 case 'u': 233 action = VND_UNCONFIG; 234 break; 235 case 'v': 236 verbose = 1; 237 break; 238 case 'z': 239 compressed = 1; 240 readonly = 1; 241 break; 242 default: 243 case '?': 244 usage(); 245 /* NOTREACHED */ 246 } 247 } 248 argc -= optind; 249 argv += optind; 250 251 if (action == VND_CONFIG) { 252 if ((argc < 2 || argc > 3) || 253 (argc == 3 && tabname != NULL)) 254 usage(); 255 rv = config(argv[0], argv[1], (argc == 3) ? argv[2] : NULL, 256 action); 257 } else if (action == VND_UNCONFIG) { 258 if (argc != 1 || tabname != NULL) 259 usage(); 260 rv = config(argv[0], NULL, NULL, action); 261 } else { /* VND_GET */ 262 #if !defined(__minix) 263 int n, v; 264 const char *vn; 265 char path[64]; 266 #else 267 int n; 268 #endif /* !defined(__minix) */ 269 270 if (argc != 0 && argc != 1) 271 usage(); 272 273 #if !defined(__minix) 274 vn = argc ? argv[0] : "vnd0"; 275 276 v = opendisk(vn, O_RDONLY, path, sizeof(path), 0); 277 if (v == -1) 278 err(1, "open: %s", vn); 279 #endif /* !defined(__minix) */ 280 281 if (argc) 282 #if !defined(__minix) 283 show(v, -1); 284 #else 285 show(argv[0], -1); 286 #endif /* !defined(__minix) */ 287 else { 288 DIR *dirp; 289 struct dirent *dp; 290 #if !defined(__minix) 291 __BITMAP_TYPE(, uint32_t, 65536) bm; 292 293 __BITMAP_ZERO(&bm); 294 #else 295 char *endp; 296 #endif /* !defined(__minix) */ 297 298 if ((dirp = opendir(_PATH_DEV)) == NULL) 299 err(1, "opendir: %s", _PATH_DEV); 300 301 while ((dp = readdir(dirp)) != NULL) { 302 #if !defined(__minix) 303 if (strncmp(dp->d_name, "rvnd", 4) != 0) 304 continue; 305 n = atoi(dp->d_name + 4); 306 if (__BITMAP_ISSET(n, &bm)) 307 continue; 308 __BITMAP_SET(n, &bm); 309 show(v, n); 310 #else 311 if (strncmp(dp->d_name, "vnd", 3) != 0) 312 continue; 313 n = strtoul(dp->d_name + 3, &endp, 10); 314 if (endp[0]) 315 continue; 316 show(dp->d_name, n); 317 #endif /* !defined(__minix) */ 318 } 319 320 closedir(dirp); 321 } 322 #if !defined(__minix) 323 close(v); 324 #endif /* !defined(__minix) */ 325 rv = 0; 326 } 327 return rv; 328 } 329 330 static void 331 #if !defined(__minix) 332 show(int v, int n) 333 #else 334 show(const char *vn, int n) 335 #endif /* !defined(__minix) */ 336 { 337 struct vnd_user vnu; 338 char *dev; 339 struct statvfs *mnt; 340 int i, nmount; 341 #if defined(__minix) 342 int v; 343 char path[PATH_MAX]; 344 345 v = opendisk(vn, O_RDONLY, path, sizeof(path), 0); 346 if (v == -1) { 347 if (n == -1) 348 err(1, "open: %s", vn); 349 else 350 printf("vnd%d: not in use\n", n); 351 return; 352 } 353 #endif /* defined(__minix) */ 354 355 vnu.vnu_unit = n; 356 if (ioctl(v, VNDIOCGET, &vnu) == -1) 357 err(1, "VNDIOCGET"); 358 359 #if defined(__minix) 360 close(v); 361 #endif /* defined(__minix) */ 362 363 if (vnu.vnu_ino == 0) { 364 printf("vnd%d: not in use\n", vnu.vnu_unit); 365 return; 366 } 367 368 printf("vnd%d: ", vnu.vnu_unit); 369 370 dev = devname(vnu.vnu_dev, S_IFBLK); 371 if (dev != NULL) 372 nmount = getmntinfo(&mnt, MNT_NOWAIT); 373 else { 374 mnt = NULL; 375 nmount = 0; 376 } 377 378 if (mnt != NULL) { 379 for (i = 0; i < nmount; i++) { 380 if (strncmp(mnt[i].f_mntfromname, "/dev/", 5) == 0 && 381 strcmp(mnt[i].f_mntfromname + 5, dev) == 0) 382 break; 383 } 384 if (i < nmount) 385 printf("%s (%s) ", mnt[i].f_mntonname, 386 mnt[i].f_mntfromname); 387 else 388 printf("%s ", dev); 389 } 390 else if (dev != NULL) 391 printf("%s ", dev); 392 else 393 printf("dev %llu,%llu ", 394 (unsigned long long)major(vnu.vnu_dev), 395 (unsigned long long)minor(vnu.vnu_dev)); 396 397 printf("inode %llu\n", (unsigned long long)vnu.vnu_ino); 398 } 399 400 static int 401 config(char *dev, char *file, char *geom, int action) 402 { 403 struct vnd_ioctl vndio; 404 #if !defined(__minix) 405 struct disklabel *lp; 406 #else 407 int stop = 0; 408 #endif /* !defined(__minix) */ 409 char rdev[MAXPATHLEN + 1]; 410 int fd, rv; 411 412 #if defined(__minix) 413 /* 414 * MINIX does not have the concept of raw devices. As such, the access 415 * checks that apply to opening block devices, automatically apply here 416 * as well. Therefore, we must open the device as read-only, or we 417 * would be unable to un-configure a device that was configured as 418 * read-only: opening such a device as read-write would fail. 419 */ 420 fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0); 421 422 if (fd < 0 && errno == ENXIO && action == VND_CONFIG && service) { 423 stop = start_service(rdev); 424 425 fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0); 426 } 427 #else 428 fd = opendisk(dev, O_RDWR, rdev, sizeof(rdev), 0); 429 #endif /* defined(__minix) */ 430 if (fd < 0) { 431 warn("%s: opendisk", rdev); 432 return (1); 433 } 434 435 memset(&vndio, 0, sizeof(vndio)); 436 #ifdef __GNUC__ 437 rv = 0; /* XXX */ 438 #endif 439 440 #if !defined(__minix) 441 vndio.vnd_file = file; 442 #endif /* !defined(__minix) */ 443 if (geom != NULL) { 444 rv = getgeom(&vndio.vnd_geom, geom); 445 #if defined(__minix) 446 if (rv && stop) 447 stop_service(fd, rdev); 448 #endif /* defined(__minix) */ 449 if (rv != 0) 450 errx(1, "invalid geometry: %s", geom); 451 vndio.vnd_flags = VNDIOF_HASGEOM; 452 #if !defined(__minix) 453 } else if (tabname != NULL) { 454 lp = getdiskbyname(tabname); 455 if (lp == NULL) 456 errx(1, "unknown disk type: %s", tabname); 457 vndio.vnd_geom.vng_secsize = lp->d_secsize; 458 vndio.vnd_geom.vng_nsectors = lp->d_nsectors; 459 vndio.vnd_geom.vng_ntracks = lp->d_ntracks; 460 vndio.vnd_geom.vng_ncylinders = lp->d_ncylinders; 461 vndio.vnd_flags = VNDIOF_HASGEOM; 462 #endif /* !defined(__minix) */ 463 } 464 465 if (readonly) 466 vndio.vnd_flags |= VNDIOF_READONLY; 467 468 #if !defined(__minix) 469 if (compressed) 470 vndio.vnd_flags |= VNF_COMP; 471 #endif /* !defined(__minix) */ 472 473 /* 474 * Clear (un-configure) the device 475 */ 476 if (action == VND_UNCONFIG) { 477 if (force) 478 vndio.vnd_flags |= VNDIOF_FORCE; 479 rv = ioctl(fd, VNDIOCCLR, &vndio); 480 #ifdef VNDIOOCCLR 481 if (rv && errno == ENOTTY) 482 rv = ioctl(fd, VNDIOOCCLR, &vndio); 483 #endif 484 if (rv) 485 warn("%s: VNDIOCCLR", rdev); 486 else if (verbose) 487 printf("%s: cleared\n", rdev); 488 #if defined(__minix) 489 if (!rv && service) 490 stop = 2; 491 #endif /* defined(__minix) */ 492 } 493 /* 494 * Configure the device 495 */ 496 if (action == VND_CONFIG) { 497 int ffd; 498 499 ffd = open(file, readonly ? O_RDONLY : O_RDWR); 500 if (ffd < 0) { 501 warn("%s", file); 502 rv = -1; 503 } else { 504 #if !defined(__minix) 505 (void) close(ffd); 506 #else 507 vndio.vnd_fildes = ffd; 508 #endif /* !defined(__minix) */ 509 510 rv = ioctl(fd, VNDIOCSET, &vndio); 511 #ifdef VNDIOOCSET 512 if (rv && errno == ENOTTY) { 513 rv = ioctl(fd, VNDIOOCSET, &vndio); 514 vndio.vnd_size = vndio.vnd_osize; 515 } 516 #endif 517 #if defined(__minix) 518 (void) close(ffd); 519 #endif /* defined(__minix) */ 520 if (rv) 521 warn("%s: VNDIOCSET", rdev); 522 else if (verbose) { 523 printf("%s: %" PRIu64 " bytes on %s", rdev, 524 vndio.vnd_size, file); 525 if (vndio.vnd_flags & VNDIOF_HASGEOM) 526 printf(" using geometry %d/%d/%d/%d", 527 vndio.vnd_geom.vng_secsize, 528 vndio.vnd_geom.vng_nsectors, 529 vndio.vnd_geom.vng_ntracks, 530 vndio.vnd_geom.vng_ncylinders); 531 printf("\n"); 532 } 533 } 534 #if defined(__minix) 535 if ((ffd < 0 || rv) && service) 536 stop++; 537 #endif /* defined(__minix) */ 538 } 539 540 #if defined(__minix) 541 if (stop >= 2) 542 stop_service(fd, rdev); 543 else 544 #endif /* defined(__minix) */ 545 (void) close(fd); 546 fflush(stdout); 547 return (rv < 0); 548 } 549 550 static int 551 getgeom(struct vndgeom *vng, char *cp) 552 { 553 char *secsize, *nsectors, *ntracks, *ncylinders; 554 555 #define GETARG(arg) \ 556 do { \ 557 if (cp == NULL || *cp == '\0') \ 558 return (1); \ 559 arg = strsep(&cp, "/"); \ 560 if (arg == NULL) \ 561 return (1); \ 562 } while (0) 563 564 GETARG(secsize); 565 GETARG(nsectors); 566 GETARG(ntracks); 567 GETARG(ncylinders); 568 569 #undef GETARG 570 571 /* Too many? */ 572 if (cp != NULL) 573 return (1); 574 575 #define CVTARG(str, num) \ 576 do { \ 577 num = strtol(str, &cp, 10); \ 578 if (*cp != '\0') \ 579 return (1); \ 580 } while (0) 581 582 CVTARG(secsize, vng->vng_secsize); 583 CVTARG(nsectors, vng->vng_nsectors); 584 CVTARG(ntracks, vng->vng_ntracks); 585 CVTARG(ncylinders, vng->vng_ncylinders); 586 587 #undef CVTARG 588 589 return (0); 590 } 591 592 static void 593 usage(void) 594 { 595 596 (void)fprintf(stderr, "%s%s", 597 #if !defined(__minix) 598 "usage: vnconfig [-crvz] [-f disktab] [-t typename] vnode_disk" 599 " regular-file [geomspec]\n", 600 " vnconfig -u [-Fv] vnode_disk\n" 601 #else 602 "usage: vnconfig [-Scrv] vnode_disk regular-file [geomspec]\n", 603 " vnconfig -u [-SFv] vnode_disk\n" 604 #endif /* !defined(__minix) */ 605 " vnconfig -l [vnode_disk]\n"); 606 exit(1); 607 } 608