1 /* $NetBSD: mount.c,v 1.89 2009/05/04 11:41:48 yamt Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1989, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993, 1994\ 35 The Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 41 #else 42 __RCSID("$NetBSD: mount.c,v 1.89 2009/05/04 11:41:48 yamt Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/mount.h> 48 #include <sys/wait.h> 49 50 #include <err.h> 51 #include <errno.h> 52 #include <fstab.h> 53 #include <pwd.h> 54 #include <signal.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 60 #define MOUNTNAMES 61 #include <fcntl.h> 62 #include <sys/disk.h> 63 #include <sys/disklabel.h> 64 #include <sys/ioctl.h> 65 66 #include "pathnames.h" 67 #include "mountprog.h" 68 69 static int debug, verbose; 70 71 static void catopt(char **, const char *); 72 static const char * 73 getfslab(const char *str); 74 static struct statvfs * 75 getmntpt(const char *); 76 static int getmntargs(struct statvfs *, char *, size_t); 77 static int hasopt(const char *, const char *); 78 static void mangle(char *, int *, const char ** volatile *, int *); 79 static int mountfs(const char *, const char *, const char *, 80 int, const char *, const char *, int, char *, size_t); 81 static void prmount(struct statvfs *); 82 static void usage(void); 83 84 85 /* Map from mount otions to printable formats. */ 86 static const struct opt { 87 int o_opt; 88 int o_silent; 89 const char *o_name; 90 } optnames[] = { 91 __MNT_FLAGS 92 }; 93 94 static char ffs_fstype[] = "ffs"; 95 96 int 97 main(int argc, char *argv[]) 98 { 99 const char *mntfromname, *mntonname, **vfslist, *vfstype; 100 struct fstab *fs; 101 struct statvfs *mntbuf; 102 #if 0 103 FILE *mountdfp; 104 #endif 105 int all, ch, forceall, i, init_flags, mntsize, rval; 106 char *options; 107 const char *mountopts, *fstypename; 108 char canonical_path_buf[MAXPATHLEN]; 109 char *canonical_path; 110 111 /* started as "mount" */ 112 all = forceall = init_flags = 0; 113 options = NULL; 114 vfslist = NULL; 115 vfstype = ffs_fstype; 116 while ((ch = getopt(argc, argv, "Aadfo:rwt:uv")) != -1) 117 switch (ch) { 118 case 'A': 119 all = forceall = 1; 120 break; 121 case 'a': 122 all = 1; 123 break; 124 case 'd': 125 debug = 1; 126 break; 127 case 'f': 128 init_flags |= MNT_FORCE; 129 break; 130 case 'o': 131 if (*optarg) 132 catopt(&options, optarg); 133 break; 134 case 'r': 135 init_flags |= MNT_RDONLY; 136 break; 137 case 't': 138 if (vfslist != NULL) 139 errx(1, 140 "only one -t option may be specified."); 141 vfslist = makevfslist(optarg); 142 vfstype = optarg; 143 break; 144 case 'u': 145 init_flags |= MNT_UPDATE; 146 break; 147 case 'v': 148 verbose++; 149 break; 150 case 'w': 151 init_flags &= ~MNT_RDONLY; 152 break; 153 case '?': 154 default: 155 usage(); 156 /* NOTREACHED */ 157 } 158 argc -= optind; 159 argv += optind; 160 161 #define BADTYPE(type) \ 162 (strcmp(type, FSTAB_RO) && \ 163 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 164 165 rval = 0; 166 switch (argc) { 167 case 0: 168 if (all) 169 while ((fs = getfsent()) != NULL) { 170 if (BADTYPE(fs->fs_type)) 171 continue; 172 if (checkvfsname(fs->fs_vfstype, vfslist)) 173 continue; 174 if (hasopt(fs->fs_mntops, "noauto")) 175 continue; 176 if (strcmp(fs->fs_spec, "from_mount") == 0) { 177 if ((mntbuf = getmntpt(fs->fs_file)) == NULL) 178 errx(1, 179 "unknown file system %s.", 180 fs->fs_file); 181 mntfromname = mntbuf->f_mntfromname; 182 } else 183 mntfromname = fs->fs_spec; 184 if (mountfs(fs->fs_vfstype, mntfromname, 185 fs->fs_file, init_flags, options, 186 fs->fs_mntops, !forceall, NULL, 0)) 187 rval = 1; 188 } 189 else { 190 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 191 err(1, "getmntinfo"); 192 for (i = 0; i < mntsize; i++) { 193 if (checkvfsname(mntbuf[i].f_fstypename, 194 vfslist)) 195 continue; 196 prmount(&mntbuf[i]); 197 } 198 } 199 exit(rval); 200 /* NOTREACHED */ 201 case 1: 202 if (vfslist != NULL) { 203 usage(); 204 /* NOTREACHED */ 205 } 206 207 /* 208 * Create a canonical version of the device or mount path 209 * passed to us. It's ok for this to fail. It's also ok 210 * for the result to be exactly the same as the original. 211 */ 212 canonical_path = realpath(*argv, canonical_path_buf); 213 214 if (init_flags & MNT_UPDATE) { 215 /* 216 * Try looking up the canonical path first, 217 * then try exactly what the user entered. 218 */ 219 if ((canonical_path == NULL || 220 (mntbuf = getmntpt(canonical_path)) == NULL) && 221 (mntbuf = getmntpt(*argv)) == NULL 222 ) 223 { 224 errx(1, 225 "unknown special file or file system %s.", 226 *argv); 227 } 228 mntfromname = mntbuf->f_mntfromname; 229 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 230 if (strcmp(fs->fs_spec, "from_mount") != 0) 231 mntfromname = fs->fs_spec; 232 /* ignore the fstab file options. */ 233 fs->fs_mntops = NULL; 234 } 235 mntonname = mntbuf->f_mntonname; 236 fstypename = mntbuf->f_fstypename; 237 mountopts = NULL; 238 } else { 239 /* 240 * Try looking up the canonical path first, 241 * then try exactly what the user entered. 242 */ 243 if (canonical_path == NULL || 244 ((fs = getfsfile(canonical_path)) == NULL && 245 (fs = getfsspec(canonical_path)) == NULL)) 246 { 247 if ((fs = getfsfile(*argv)) == NULL && 248 (fs = getfsspec(*argv)) == NULL) 249 { 250 errx(1, 251 "%s: unknown special file or file system.", 252 *argv); 253 } 254 } 255 if (BADTYPE(fs->fs_type)) 256 errx(1, "%s has unknown file system type.", 257 *argv); 258 if (strcmp(fs->fs_spec, "from_mount") == 0) { 259 if ((canonical_path == NULL || 260 (mntbuf = getmntpt(canonical_path)) == NULL) && 261 (mntbuf = getmntpt(*argv)) == NULL 262 ) 263 { 264 errx(1, 265 "unknown special file or file system %s.", 266 *argv); 267 } 268 mntfromname = mntbuf->f_mntfromname; 269 } else 270 mntfromname = fs->fs_spec; 271 mntonname = fs->fs_file; 272 fstypename = fs->fs_vfstype; 273 mountopts = fs->fs_mntops; 274 } 275 rval = mountfs(fstypename, mntfromname, 276 mntonname, init_flags, options, mountopts, 0, NULL, 0); 277 break; 278 case 2: 279 /* 280 * If -t flag has not been specified, and spec contains either 281 * a ':' or a '@' then assume that an NFS filesystem is being 282 * specified ala Sun. 283 */ 284 if (vfslist == NULL) { 285 if (strpbrk(argv[0], ":@") != NULL) { 286 fprintf(stderr, "WARNING: autoselecting nfs " 287 "based on : or @ in the device name is " 288 "deprecated!\n" 289 "WARNING: This behaviour will be removed " 290 "in a future release\n"); 291 vfstype = "nfs"; 292 } else { 293 vfstype = getfslab(argv[0]); 294 if (vfstype == NULL) 295 vfstype = ffs_fstype; 296 } 297 } 298 rval = mountfs(vfstype, 299 argv[0], argv[1], init_flags, options, NULL, 0, NULL, 0); 300 break; 301 default: 302 usage(); 303 /* NOTREACHED */ 304 } 305 306 #if 0 /* disabled because it interferes the service. */ 307 /* 308 * If the mount was successfully, and done by root, tell mountd the 309 * good news. Pid checks are probably unnecessary, but don't hurt. 310 */ 311 if (rval == 0 && getuid() == 0 && 312 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 313 int pid; 314 315 if (fscanf(mountdfp, "%d", &pid) == 1 && 316 pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 317 err(1, "signal mountd"); 318 (void)fclose(mountdfp); 319 } 320 #endif 321 322 exit(rval); 323 /* NOTREACHED */ 324 } 325 326 int 327 hasopt(const char *mntopts, const char *option) 328 { 329 int negative, found; 330 char *opt, *optbuf; 331 332 if (option[0] == 'n' && option[1] == 'o') { 333 negative = 1; 334 option += 2; 335 } else 336 negative = 0; 337 optbuf = strdup(mntopts); 338 found = 0; 339 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 340 if (opt[0] == 'n' && opt[1] == 'o') { 341 if (!strcasecmp(opt + 2, option)) 342 found = negative; 343 } else if (!strcasecmp(opt, option)) 344 found = !negative; 345 } 346 free(optbuf); 347 return (found); 348 } 349 350 static int 351 mountfs(const char *vfstype, const char *spec, const char *name, 352 int flags, const char *options, const char *mntopts, 353 int skipmounted, char *buf, size_t buflen) 354 { 355 /* List of directories containing mount_xxx subcommands. */ 356 static const char *edirs[] = { 357 #ifdef RESCUEDIR 358 RESCUEDIR, 359 #endif 360 _PATH_SBIN, 361 _PATH_USRSBIN, 362 NULL 363 }; 364 const char ** volatile argv, **edir; 365 struct statvfs *sfp, sf; 366 pid_t pid; 367 int pfd[2]; 368 int argc, numfs, i, status, maxargc; 369 char *optbuf, execname[MAXPATHLEN + 1], execbase[MAXPATHLEN], 370 mntpath[MAXPATHLEN]; 371 volatile int getargs; 372 373 if (realpath(name, mntpath) == NULL) { 374 warn("realpath %s", name); 375 return (1); 376 } 377 378 name = mntpath; 379 380 optbuf = NULL; 381 if (mntopts) 382 catopt(&optbuf, mntopts); 383 384 if (options) { 385 catopt(&optbuf, options); 386 getargs = strstr(options, "getargs") != NULL; 387 } else 388 getargs = 0; 389 390 if (!mntopts && !options) 391 catopt(&optbuf, "rw"); 392 393 if (getargs == 0 && strcmp(name, "/") == 0) 394 flags |= MNT_UPDATE; 395 else if (skipmounted) { 396 if ((numfs = getmntinfo(&sfp, MNT_WAIT)) == 0) { 397 warn("getmntinfo"); 398 return (1); 399 } 400 for(i = 0; i < numfs; i++) { 401 /* 402 * XXX can't check f_mntfromname, 403 * thanks to mfs, union, etc. 404 */ 405 if (strncmp(name, sfp[i].f_mntonname, MNAMELEN) == 0 && 406 strncmp(vfstype, sfp[i].f_fstypename, 407 sizeof(sfp[i].f_fstypename)) == 0) { 408 if (verbose) 409 (void)printf("%s on %s type %.*s: " 410 "%s\n", 411 sfp[i].f_mntfromname, 412 sfp[i].f_mntonname, 413 (int)sizeof(sfp[i].f_fstypename), 414 sfp[i].f_fstypename, 415 "already mounted"); 416 return (0); 417 } 418 } 419 } 420 if (flags & MNT_FORCE) 421 catopt(&optbuf, "force"); 422 if (flags & MNT_RDONLY) 423 catopt(&optbuf, "ro"); 424 425 if (flags & MNT_UPDATE) { 426 catopt(&optbuf, "update"); 427 /* Figure out the fstype only if we defaulted to ffs */ 428 if (vfstype == ffs_fstype && statvfs(name, &sf) != -1) 429 vfstype = sf.f_fstypename; 430 } 431 432 maxargc = 64; 433 argv = malloc(sizeof(char *) * maxargc); 434 if (argv == NULL) 435 err(1, "malloc"); 436 437 if (hasopt(optbuf, "rump")) 438 (void)snprintf(execbase, sizeof(execbase), "rump_%s", vfstype); 439 else 440 (void)snprintf(execbase, sizeof(execbase), "mount_%s", vfstype); 441 argc = 0; 442 argv[argc++] = execbase; 443 if (optbuf) 444 mangle(optbuf, &argc, &argv, &maxargc); 445 argv[argc++] = spec; 446 argv[argc++] = name; 447 argv[argc] = NULL; 448 449 if ((verbose && buf == NULL) || debug) { 450 (void)printf("exec:"); 451 for (i = 0; i < argc; i++) 452 (void)printf(" %s", argv[i]); 453 (void)printf("\n"); 454 } 455 456 if (buf) { 457 if (pipe(pfd) == -1) 458 warn("Cannot create pipe"); 459 } 460 461 switch (pid = vfork()) { 462 case -1: /* Error. */ 463 warn("vfork"); 464 if (optbuf) 465 free(optbuf); 466 free(argv); 467 return (1); 468 469 case 0: /* Child. */ 470 if (debug) 471 _exit(0); 472 473 if (buf) { 474 (void)close(pfd[0]); 475 (void)close(STDOUT_FILENO); 476 if (dup2(pfd[1], STDOUT_FILENO) == -1) 477 warn("Cannot open fd to mount program"); 478 } 479 480 /* Go find an executable. */ 481 edir = edirs; 482 do { 483 (void)snprintf(execname, 484 sizeof(execname), "%s/%s", *edir, execbase); 485 (void)execv(execname, __UNCONST(argv)); 486 if (errno != ENOENT) 487 warn("exec %s for %s", execname, name); 488 } while (*++edir != NULL); 489 490 if (errno == ENOENT) 491 warnx("%s not found for %s", execbase, name); 492 _exit(1); 493 /* NOTREACHED */ 494 495 default: /* Parent. */ 496 if (optbuf) 497 free(optbuf); 498 free(argv); 499 500 if (buf || getargs) { 501 char tbuf[1024], *ptr; 502 int nread; 503 504 if (buf == NULL) { 505 ptr = tbuf; 506 buflen = sizeof(tbuf) - 1; 507 } else { 508 ptr = buf; 509 buflen--; 510 } 511 (void)close(pfd[1]); 512 (void)signal(SIGPIPE, SIG_IGN); 513 while ((nread = read(pfd[0], ptr, buflen)) > 0) { 514 buflen -= nread; 515 ptr += nread; 516 } 517 *ptr = '\0'; 518 if (buflen == 0) { 519 while (read(pfd[0], &nread, sizeof(nread)) > 0) 520 continue; 521 } 522 if (buf == NULL) 523 (void)fprintf(stdout, "%s", tbuf); 524 } 525 526 if (waitpid(pid, &status, 0) < 0) { 527 warn("waitpid"); 528 return (1); 529 } 530 531 if (WIFEXITED(status)) { 532 if (WEXITSTATUS(status) != 0) 533 return (WEXITSTATUS(status)); 534 } else if (WIFSIGNALED(status)) { 535 warnx("%s: %s", name, strsignal(WTERMSIG(status))); 536 return (1); 537 } 538 539 if (buf == NULL) { 540 if (verbose) { 541 if (statvfs(name, &sf) < 0) { 542 warn("statvfs %s", name); 543 return (1); 544 } 545 prmount(&sf); 546 } 547 } 548 break; 549 } 550 551 return (0); 552 } 553 554 static void 555 prmount(struct statvfs *sfp) 556 { 557 int flags; 558 const struct opt *o; 559 struct passwd *pw; 560 int f; 561 562 (void)printf("%s on %s type %.*s", sfp->f_mntfromname, 563 sfp->f_mntonname, (int)sizeof(sfp->f_fstypename), 564 sfp->f_fstypename); 565 566 flags = sfp->f_flag & MNT_VISFLAGMASK; 567 for (f = 0, o = optnames; flags && o < 568 &optnames[sizeof(optnames)/sizeof(optnames[0])]; o++) 569 if (flags & o->o_opt) { 570 if (!o->o_silent || verbose) 571 (void)printf("%s%s", !f++ ? " (" : ", ", 572 o->o_name); 573 flags &= ~o->o_opt; 574 } 575 if (flags) 576 (void)printf("%sunknown flag%s %#x", !f++ ? " (" : ", ", 577 flags & (flags - 1) ? "s" : "", flags); 578 if (sfp->f_owner) { 579 (void)printf("%smounted by ", !f++ ? " (" : ", "); 580 if ((pw = getpwuid(sfp->f_owner)) != NULL) 581 (void)printf("%s", pw->pw_name); 582 else 583 (void)printf("%d", sfp->f_owner); 584 } 585 if (verbose) 586 (void)printf("%sfsid: 0x%x/0x%x", 587 !f++ ? " (" /* ) */: ", ", 588 sfp->f_fsidx.__fsid_val[0], sfp->f_fsidx.__fsid_val[1]); 589 590 if (verbose) { 591 (void)printf("%s", !f++ ? " (" : ", "); 592 (void)printf("reads: sync %" PRIu64 " async %" PRIu64 "", 593 sfp->f_syncreads, sfp->f_asyncreads); 594 (void)printf(", writes: sync %" PRIu64 " async %" PRIu64 "", 595 sfp->f_syncwrites, sfp->f_asyncwrites); 596 if (verbose > 1) { 597 char buf[2048]; 598 599 if (getmntargs(sfp, buf, sizeof(buf))) 600 printf(", [%s: %s]", sfp->f_fstypename, buf); 601 } 602 printf(")\n"); 603 } else 604 (void)printf("%s", f ? ")\n" : "\n"); 605 } 606 607 static int 608 getmntargs(struct statvfs *sfs, char *buf, size_t buflen) 609 { 610 611 if (mountfs(sfs->f_fstypename, sfs->f_mntfromname, sfs->f_mntonname, 0, 612 "getargs", NULL, 0, buf, buflen)) 613 return (0); 614 else { 615 if (*buf == '\0') 616 return (0); 617 if ((buf = strchr(buf, '\n')) != NULL) 618 *buf = '\0'; 619 return (1); 620 } 621 } 622 623 static struct statvfs * 624 getmntpt(const char *name) 625 { 626 struct statvfs *mntbuf; 627 int i, mntsize; 628 629 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 630 for (i = 0; i < mntsize; i++) 631 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 632 strcmp(mntbuf[i].f_mntonname, name) == 0) 633 return (&mntbuf[i]); 634 return (NULL); 635 } 636 637 static void 638 catopt(char **sp, const char *o) 639 { 640 char *s, *n; 641 642 s = *sp; 643 if (s) { 644 if (asprintf(&n, "%s,%s", s, o) < 0) 645 err(1, "asprintf"); 646 free(s); 647 s = n; 648 } else 649 s = strdup(o); 650 *sp = s; 651 } 652 653 static void 654 mangle(char *options, int *argcp, const char ** volatile *argvp, int *maxargcp) 655 { 656 char *p, *s; 657 int argc, maxargc; 658 const char **argv, **nargv; 659 660 argc = *argcp; 661 argv = *argvp; 662 maxargc = *maxargcp; 663 664 for (s = options; (p = strsep(&s, ",")) != NULL;) { 665 /* Always leave space for one more argument and the NULL. */ 666 if (argc >= maxargc - 4) { 667 nargv = realloc(argv, (maxargc << 1) * sizeof(char *)); 668 if (!nargv) 669 err(1, "realloc"); 670 argv = nargv; 671 maxargc <<= 1; 672 } 673 if (*p != '\0') { 674 if (*p == '-') { 675 argv[argc++] = p; 676 p = strchr(p, '='); 677 if (p) { 678 *p = '\0'; 679 argv[argc++] = p+1; 680 } 681 } else if (strcmp(p, "rw") != 0) { 682 argv[argc++] = "-o"; 683 argv[argc++] = p; 684 } 685 } 686 } 687 688 *argcp = argc; 689 *argvp = argv; 690 *maxargcp = maxargc; 691 } 692 693 /* Deduce the filesystem type from the disk label. */ 694 static const char * 695 getfslab(const char *str) 696 { 697 static struct dkwedge_info dkw; 698 struct disklabel dl; 699 int fd; 700 int part; 701 const char *vfstype; 702 u_char fstype; 703 char buf[MAXPATHLEN + 1]; 704 char *sp, *ep; 705 706 if ((fd = open(str, O_RDONLY)) == -1) { 707 /* 708 * Iff we get EBUSY try the raw device. Since mount always uses 709 * the block device we know we are never passed a raw device. 710 */ 711 if (errno != EBUSY) 712 err(1, "cannot open `%s'", str); 713 strlcpy(buf, str, MAXPATHLEN); 714 if ((sp = strrchr(buf, '/')) != NULL) 715 ++sp; 716 else 717 sp = buf; 718 for (ep = sp + strlen(sp) + 1; ep > sp; ep--) 719 *ep = *(ep - 1); 720 *sp = 'r'; 721 722 /* Silently fail here - mount call can display error */ 723 if ((fd = open(buf, O_RDONLY)) == -1) 724 return (NULL); 725 } 726 727 /* Check to see if this is a wedge. */ 728 if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) { 729 /* Yup, this is easy. */ 730 (void) close(fd); 731 return (dkw.dkw_ptype); 732 } 733 734 if (ioctl(fd, DIOCGDINFO, &dl) == -1) { 735 (void) close(fd); 736 return (NULL); 737 } 738 739 (void) close(fd); 740 741 part = str[strlen(str) - 1] - 'a'; 742 743 if (part < 0 || part >= dl.d_npartitions) 744 return (NULL); 745 746 /* Return NULL for unknown types - caller can fall back to ffs */ 747 if ((fstype = dl.d_partitions[part].p_fstype) >= FSMAXMOUNTNAMES) 748 vfstype = NULL; 749 else 750 vfstype = mountnames[fstype]; 751 752 return (vfstype); 753 } 754 755 static void 756 usage(void) 757 { 758 759 (void)fprintf(stderr, 760 "usage: mount %s\n mount %s\n mount %s\n", 761 "[-Aadfruvw] [-t type]", 762 "[-dfruvw] special | node", 763 "[-dfruvw] [-o options] [-t type] special node"); 764 exit(1); 765 /* NOTREACHED */ 766 } 767