1 /* $OpenBSD: mount.c,v 1.23 2001/12/16 22:45:37 miod Exp $ */ 2 /* $NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1989, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)mount.c 8.19 (Berkeley) 4/19/94"; 46 #else 47 static char rcsid[] = "$OpenBSD: mount.c,v 1.23 2001/12/16 22:45:37 miod Exp $"; 48 #endif 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/mount.h> 53 #include <sys/socket.h> 54 #include <sys/wait.h> 55 56 #include <nfs/rpcv2.h> 57 #include <nfs/nfsproto.h> 58 #define _KERNEL 59 #include <nfs/nfs.h> 60 #undef _KERNEL 61 62 #include <err.h> 63 #include <errno.h> 64 #include <fstab.h> 65 #include <netdb.h> 66 #include <signal.h> 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <unistd.h> 71 #include <util.h> 72 73 #include "pathnames.h" 74 75 int debug, verbose; 76 char **typelist = NULL; 77 78 int selected __P((const char *)); 79 char *catopt __P((char *, const char *)); 80 struct statfs 81 *getmntpt __P((const char *)); 82 int hasopt __P((const char *, const char *)); 83 void maketypelist __P((char *)); 84 void mangle __P((char *, int *, const char **)); 85 int mountfs __P((const char *, const char *, const char *, 86 int, const char *, const char *, int)); 87 void prmount __P((struct statfs *)); 88 int disklabelcheck __P((struct fstab *)); 89 void usage __P((void)); 90 91 /* Map from mount options to printable formats. */ 92 static struct opt { 93 int o_opt; 94 int o_silent; 95 const char *o_name; 96 } optnames[] = { 97 { MNT_ASYNC, 0, "asynchronous" }, 98 { MNT_DEFEXPORTED, 1, "exported to the world" }, 99 { MNT_EXKERB, 1, "kerberos uid mapping" }, 100 { MNT_EXPORTED, 0, "NFS exported" }, 101 { MNT_EXPORTANON, 1, "anon uid mapping" }, 102 { MNT_EXRDONLY, 1, "exported read-only" }, 103 { MNT_LOCAL, 0, "local" }, 104 { MNT_NOATIME, 0, "noatime" }, 105 { MNT_NOATIME, 0, "noaccesstime" }, 106 { MNT_NODEV, 0, "nodev" }, 107 { MNT_NOEXEC, 0, "noexec" }, 108 { MNT_NOSUID, 0, "nosuid" }, 109 { MNT_QUOTA, 0, "with quotas" }, 110 { MNT_RDONLY, 0, "read-only" }, 111 { MNT_ROOTFS, 1, "root file system" }, 112 { MNT_SYNCHRONOUS, 0, "synchronous" }, 113 { MNT_SOFTDEP, 0, "softdep" }, 114 { MNT_UNION, 0, "union" }, 115 { NULL } 116 }; 117 118 int 119 main(argc, argv) 120 int argc; 121 char * const argv[]; 122 { 123 const char *mntonname, *vfstype; 124 struct fstab *fs; 125 struct statfs *mntbuf; 126 FILE *mountdfp; 127 pid_t pid; 128 int all, ch, forceall, i, init_flags, mntsize, rval; 129 char *options; 130 131 all = forceall = init_flags = 0; 132 options = NULL; 133 vfstype = "ffs"; 134 while ((ch = getopt(argc, argv, "Aadfo:rwt:uv")) != -1) 135 switch (ch) { 136 case 'A': 137 all = forceall = 1; 138 break; 139 case 'a': 140 all = 1; 141 break; 142 case 'd': 143 debug = 1; 144 break; 145 case 'f': 146 init_flags |= MNT_FORCE; 147 break; 148 case 'o': 149 if (*optarg) 150 options = catopt(options, optarg); 151 break; 152 case 'r': 153 init_flags |= MNT_RDONLY; 154 break; 155 case 't': 156 if (typelist != NULL) 157 errx(1, "only one -t option may be specified."); 158 maketypelist(optarg); 159 vfstype = optarg; 160 break; 161 case 'u': 162 init_flags |= MNT_UPDATE; 163 break; 164 case 'v': 165 verbose = 1; 166 break; 167 case 'w': 168 init_flags &= ~MNT_RDONLY; 169 break; 170 case '?': 171 default: 172 usage(); 173 /* NOTREACHED */ 174 } 175 argc -= optind; 176 argv += optind; 177 178 #define BADTYPE(type) \ 179 (strcmp(type, FSTAB_RO) && \ 180 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 181 182 rval = 0; 183 switch (argc) { 184 case 0: 185 if (all) 186 while ((fs = getfsent()) != NULL) { 187 if (BADTYPE(fs->fs_type)) 188 continue; 189 if (!selected(fs->fs_vfstype)) 190 continue; 191 if (hasopt(fs->fs_mntops, "noauto")) 192 continue; 193 if (disklabelcheck(fs)) 194 continue; 195 if (mountfs(fs->fs_vfstype, fs->fs_spec, 196 fs->fs_file, init_flags, options, 197 fs->fs_mntops, !forceall)) 198 rval = 1; 199 } 200 else { 201 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 202 err(1, "getmntinfo"); 203 for (i = 0; i < mntsize; i++) { 204 if (!selected(mntbuf[i].f_fstypename)) 205 continue; 206 prmount(&mntbuf[i]); 207 } 208 } 209 exit(rval); 210 case 1: 211 if (typelist != NULL) 212 usage(); 213 214 if (init_flags & MNT_UPDATE) { 215 if ((mntbuf = getmntpt(*argv)) == NULL) 216 errx(1, 217 "unknown special file or file system %s.", 218 *argv); 219 if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL) 220 errx(1, "can't find fstab entry for %s.", 221 *argv); 222 /* If it's an update, ignore the fstab file options. */ 223 fs->fs_mntops = NULL; 224 mntonname = mntbuf->f_mntonname; 225 } else { 226 if ((fs = getfsfile(*argv)) == NULL && 227 (fs = getfsspec(*argv)) == NULL) 228 errx(1, 229 "%s: unknown special file or file system.", 230 *argv); 231 if (BADTYPE(fs->fs_type)) 232 errx(1, "%s has unknown file system type.", 233 *argv); 234 mntonname = fs->fs_file; 235 } 236 rval = mountfs(fs->fs_vfstype, fs->fs_spec, 237 mntonname, init_flags, options, fs->fs_mntops, 0); 238 break; 239 case 2: 240 /* 241 * If -t flag has not been specified, and spec contains either 242 * a ':' or a '@' then assume that an NFS filesystem is being 243 * specified ala Sun. If not, check the disklabel for a 244 * known filesystem type. 245 */ 246 if (typelist == NULL) { 247 if (strpbrk(argv[0], ":@") != NULL) 248 vfstype = "nfs"; 249 else { 250 char *labelfs = readlabelfs(argv[0], 0); 251 if (labelfs != NULL) 252 vfstype = labelfs; 253 } 254 } 255 256 rval = mountfs(vfstype, 257 argv[0], argv[1], init_flags, options, NULL, 0); 258 break; 259 default: 260 usage(); 261 /* NOTREACHED */ 262 } 263 264 /* 265 * If the mount was successfully, and done by root, tell mountd the 266 * good news. Pid checks are probably unnecessary, but don't hurt. 267 */ 268 if (rval == 0 && getuid() == 0 && 269 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 270 if (fscanf(mountdfp, "%d", &pid) == 1 && 271 pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 272 err(1, "signal mountd"); 273 (void)fclose(mountdfp); 274 } 275 276 exit(rval); 277 } 278 279 int 280 hasopt(mntopts, option) 281 const char *mntopts, *option; 282 { 283 int negative, found; 284 char *opt, *optbuf; 285 286 if (option[0] == 'n' && option[1] == 'o') { 287 negative = 1; 288 option += 2; 289 } else 290 negative = 0; 291 optbuf = strdup(mntopts); 292 found = 0; 293 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 294 if (opt[0] == 'n' && opt[1] == 'o') { 295 if (!strcasecmp(opt + 2, option)) 296 found = negative; 297 } else if (!strcasecmp(opt, option)) 298 found = !negative; 299 } 300 free(optbuf); 301 return (found); 302 } 303 304 int 305 mountfs(vfstype, spec, name, flags, options, mntopts, skipmounted) 306 const char *vfstype, *spec, *name, *options, *mntopts; 307 int flags, skipmounted; 308 { 309 /* List of directories containing mount_xxx subcommands. */ 310 static const char *edirs[] = { 311 _PATH_SBIN, 312 _PATH_USRSBIN, 313 NULL 314 }; 315 const char *argv[100], **edir; 316 struct statfs sf; 317 pid_t pid; 318 int argc, i, status; 319 char *optbuf, execname[MAXPATHLEN], mntpath[MAXPATHLEN]; 320 char mountname[MAXPATHLEN]; 321 322 if (realpath(name, mntpath) == NULL) { 323 warn("realpath %s", name); 324 return (1); 325 } 326 327 name = mntpath; 328 329 if (mntopts == NULL) 330 mntopts = ""; 331 if (options == NULL) { 332 if (*mntopts == '\0') 333 options = "rw"; 334 else { 335 options = mntopts; 336 mntopts = ""; 337 } 338 } 339 optbuf = catopt(strdup(mntopts), options); 340 341 if (strcmp(name, "/") == 0) 342 flags |= MNT_UPDATE; 343 else if (skipmounted) { 344 if (statfs(name, &sf) < 0) { 345 warn("statfs %s", name); 346 return (1); 347 } 348 /* XXX can't check f_mntfromname, thanks to mfs, union, etc. */ 349 if (strncmp(name, sf.f_mntonname, MNAMELEN) == 0 && 350 strncmp(vfstype, sf.f_fstypename, MFSNAMELEN) == 0) { 351 if (verbose) 352 (void)printf("%s on %s type %.*s: %s\n", 353 sf.f_mntfromname, sf.f_mntonname, 354 MFSNAMELEN, sf.f_fstypename, 355 "already mounted"); 356 return (0); 357 } 358 } 359 if (flags & MNT_FORCE) 360 optbuf = catopt(optbuf, "force"); 361 if (flags & MNT_RDONLY) 362 optbuf = catopt(optbuf, "ro"); 363 /* 364 * XXX 365 * The mount_mfs (newfs) command uses -o to select the 366 * optimisation mode. We don't pass the default "-o rw" 367 * for that reason. 368 */ 369 if (flags & MNT_UPDATE) 370 optbuf = catopt(optbuf, "update"); 371 372 (void)snprintf(mountname, 373 sizeof(mountname), "mount_%s", vfstype); 374 375 argc = 0; 376 argv[argc++] = mountname; 377 mangle(optbuf, &argc, argv); 378 argv[argc++] = spec; 379 argv[argc++] = name; 380 argv[argc] = NULL; 381 382 if (debug) { 383 (void)printf("exec: mount_%s", vfstype); 384 for (i = 1; i < argc; i++) 385 (void)printf(" %s", argv[i]); 386 (void)printf("\n"); 387 return (0); 388 } 389 390 switch ((pid = fork())) { 391 case -1: /* Error. */ 392 warn("fork"); 393 free(optbuf); 394 return (1); 395 case 0: /* Child. */ 396 /* Go find an executable. */ 397 edir = edirs; 398 do { 399 (void)snprintf(execname, 400 sizeof(execname), "%s/mount_%s", *edir, vfstype); 401 execv(execname, (char * const *)argv); 402 if (errno != ENOENT) 403 warn("exec %s for %s", execname, name); 404 } while (*++edir != NULL); 405 406 if (errno == ENOENT) 407 warn("no mount helper program found for %s", vfstype); 408 exit(1); 409 /* NOTREACHED */ 410 default: /* Parent. */ 411 free(optbuf); 412 413 if (waitpid(pid, &status, 0) < 0) { 414 warn("waitpid"); 415 return (1); 416 } 417 418 if (WIFEXITED(status)) { 419 if (WEXITSTATUS(status) != 0) 420 return (WEXITSTATUS(status)); 421 } else if (WIFSIGNALED(status)) { 422 warnx("%s: %s", name, strsignal(WTERMSIG(status))); 423 return (1); 424 } 425 426 if (verbose) { 427 if (statfs(name, &sf) < 0) { 428 warn("statfs %s", name); 429 return (1); 430 } 431 prmount(&sf); 432 } 433 break; 434 } 435 436 return (0); 437 } 438 439 void 440 prmount(sf) 441 struct statfs *sf; 442 { 443 int flags; 444 struct opt *o; 445 int f = 0; 446 447 (void)printf("%s on %s type %.*s", sf->f_mntfromname, sf->f_mntonname, 448 MFSNAMELEN, sf->f_fstypename); 449 450 flags = sf->f_flags & MNT_VISFLAGMASK; 451 if (verbose && !(flags & MNT_RDONLY)) 452 (void)printf("%s%s", !f++ ? " (" : ", ", "rw"); 453 for (o = optnames; flags && o->o_opt; o++) 454 if (flags & o->o_opt) { 455 if (!o->o_silent) 456 (void)printf("%s%s", !f++ ? " (" : ", ", 457 o->o_name); 458 flags &= ~o->o_opt; 459 } 460 if (flags) 461 (void)printf("%sunknown flag%s %#x", !f++ ? " (" : ", ", 462 flags & (flags - 1) ? "s" : "", flags); 463 464 /* 465 * Filesystem-specific options 466 * We only print the "interesting" values unless in verboser 467 * mode in order to keep the signal/noise ratio high. 468 */ 469 if (strcmp(sf->f_fstypename, MOUNT_NFS) == 0) { 470 struct protoent *pr; 471 struct nfs_args *nfs_args = &sf->mount_info.nfs_args; 472 473 (void)printf("%s%s", !f++ ? " (" : ", ", 474 (nfs_args->flags & NFSMNT_NFSV3) ? "v3" : "v2"); 475 if (nfs_args->proto && (pr = getprotobynumber(nfs_args->proto))) 476 (void)printf("%s%s", !f++ ? " (" : ", ", pr->p_name); 477 else 478 (void)printf("%s%s", !f++ ? " (" : ", ", 479 (nfs_args->sotype == SOCK_DGRAM) ? "udp" : "tcp"); 480 if (nfs_args->flags & NFSMNT_SOFT) 481 (void)printf("%s%s", !f++ ? " (" : ", ", "soft"); 482 else if (verbose) 483 (void)printf("%s%s", !f++ ? " (" : ", ", "hard"); 484 if (nfs_args->flags & NFSMNT_INT) 485 (void)printf("%s%s", !f++ ? " (" : ", ", "intr"); 486 if (nfs_args->flags & NFSMNT_NOCONN) 487 (void)printf("%s%s", !f++ ? " (" : ", ", "noconn"); 488 if (verbose || nfs_args->wsize != NFS_WSIZE) 489 (void)printf("%s%s=%d", !f++ ? " (" : ", ", 490 "wsize", nfs_args->wsize); 491 if (verbose || nfs_args->rsize != NFS_RSIZE) 492 (void)printf("%s%s=%d", !f++ ? " (" : ", ", 493 "rsize", nfs_args->rsize); 494 if (verbose || nfs_args->readdirsize != NFS_READDIRSIZE) 495 (void)printf("%s%s=%d", !f++ ? " (" : ", ", 496 "rdirsize", nfs_args->readdirsize); 497 if (verbose || nfs_args->timeo != 10) /* XXX */ 498 (void)printf("%s%s=%d", !f++ ? " (" : ", ", 499 "timeo", nfs_args->timeo); 500 if (verbose || nfs_args->retrans != NFS_RETRANS) 501 (void)printf("%s%s=%d", !f++ ? " (" : ", ", 502 "retrans", nfs_args->retrans); 503 if (verbose || nfs_args->maxgrouplist != NFS_MAXGRPS) 504 (void)printf("%s%s=%d", !f++ ? " (" : ", ", 505 "maxgrouplist", nfs_args->maxgrouplist); 506 if (verbose || nfs_args->readahead != NFS_DEFRAHEAD) 507 (void)printf("%s%s=%d", !f++ ? " (" : ", ", 508 "readahead", nfs_args->readahead); 509 } else if (strcmp(sf->f_fstypename, MOUNT_MFS) == 0) { 510 int headerlen; 511 long blocksize; 512 char *header; 513 514 header = getbsize(&headerlen, &blocksize); 515 (void)printf("%s%s=%lu %s", !f++ ? " (" : ", ", 516 "size", sf->mount_info.mfs_args.size / blocksize, header); 517 } else if (strcmp(sf->f_fstypename, MOUNT_ADOSFS) == 0) { 518 struct adosfs_args *adosfs_args = &sf->mount_info.adosfs_args; 519 520 if (verbose || adosfs_args->uid || adosfs_args->gid) 521 (void)printf("%s%s=%u, %s=%u", !f++ ? " (" : ", ", 522 "uid", adosfs_args->uid, "gid", adosfs_args->gid); 523 if (verbose || adosfs_args->mask != 0755) 524 (void)printf("%s%s=0%o", !f++ ? " (" : ", ", 525 "mask", adosfs_args->mask); 526 } else if (strcmp(sf->f_fstypename, MOUNT_MSDOS) == 0) { 527 struct msdosfs_args *msdosfs_args = &sf->mount_info.msdosfs_args; 528 529 if (verbose || msdosfs_args->uid || msdosfs_args->gid) 530 (void)printf("%s%s=%u, %s=%u", !f++ ? " (" : ", ", 531 "uid", msdosfs_args->uid, "gid", msdosfs_args->gid); 532 if (verbose || msdosfs_args->mask != 0755) 533 (void)printf("%s%s=0%o", !f++ ? " (" : ", ", 534 "mask", msdosfs_args->mask); 535 if (msdosfs_args->flags & MSDOSFSMNT_SHORTNAME) 536 (void)printf("%s%s", !f++ ? " (" : ", ", "short"); 537 if (msdosfs_args->flags & MSDOSFSMNT_LONGNAME) 538 (void)printf("%s%s", !f++ ? " (" : ", ", "long"); 539 if (msdosfs_args->flags & MSDOSFSMNT_NOWIN95) 540 (void)printf("%s%s", !f++ ? " (" : ", ", "nowin95"); 541 if (msdosfs_args->flags & MSDOSFSMNT_GEMDOSFS) 542 (void)printf("%s%s", !f++ ? " (" : ", ", "gem"); 543 } else if (strcmp(sf->f_fstypename, MOUNT_CD9660) == 0) { 544 struct iso_args *iso_args = &sf->mount_info.iso_args; 545 546 if (iso_args->flags & ISOFSMNT_NORRIP) 547 (void)printf("%s%s", !f++ ? " (" : ", ", "norrip"); 548 if (iso_args->flags & ISOFSMNT_GENS) 549 (void)printf("%s%s", !f++ ? " (" : ", ", "gens"); 550 if (iso_args->flags & ISOFSMNT_EXTATT) 551 (void)printf("%s%s", !f++ ? " (" : ", ", "extatt"); 552 } 553 (void)printf(f ? ")\n" : "\n"); 554 } 555 556 struct statfs * 557 getmntpt(name) 558 const char *name; 559 { 560 struct statfs *mntbuf; 561 int i, mntsize; 562 563 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 564 for (i = 0; i < mntsize; i++) 565 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 566 strcmp(mntbuf[i].f_mntonname, name) == 0) 567 return (&mntbuf[i]); 568 return (NULL); 569 } 570 571 static enum { IN_LIST, NOT_IN_LIST } which; 572 573 int 574 selected(type) 575 const char *type; 576 { 577 char **av; 578 579 /* If no type specified, it's always selected. */ 580 if (typelist == NULL) 581 return (1); 582 for (av = typelist; *av != NULL; ++av) 583 if (!strncmp(type, *av, MFSNAMELEN)) 584 return (which == IN_LIST ? 1 : 0); 585 return (which == IN_LIST ? 0 : 1); 586 } 587 588 void 589 maketypelist(fslist) 590 char *fslist; 591 { 592 int i; 593 char *nextcp, **av; 594 595 if ((fslist == NULL) || (fslist[0] == '\0')) 596 errx(1, "empty type list"); 597 598 /* 599 * XXX 600 * Note: the syntax is "noxxx,yyy" for no xxx's and 601 * no yyy's, not the more intuitive "noyyy,noyyy". 602 */ 603 if (fslist[0] == 'n' && fslist[1] == 'o') { 604 fslist += 2; 605 which = NOT_IN_LIST; 606 } else 607 which = IN_LIST; 608 609 /* Count the number of types. */ 610 for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) 611 ++nextcp; 612 613 /* Build an array of that many types. */ 614 if ((av = typelist = malloc((i + 1) * sizeof(char *))) == NULL) 615 err(1, NULL); 616 av[0] = fslist; 617 for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) { 618 *nextcp = '\0'; 619 av[i] = ++nextcp; 620 } 621 /* Terminate the array. */ 622 av[i] = NULL; 623 } 624 625 char * 626 catopt(s0, s1) 627 char *s0; 628 const char *s1; 629 { 630 size_t i; 631 char *cp; 632 633 if (s0 && *s0) { 634 i = strlen(s0) + strlen(s1) + 1 + 1; 635 if ((cp = malloc(i)) == NULL) 636 err(1, NULL); 637 (void)snprintf(cp, i, "%s,%s", s0, s1); 638 } else 639 cp = strdup(s1); 640 641 if (s0) 642 free(s0); 643 return (cp); 644 } 645 646 void 647 mangle(options, argcp, argv) 648 char *options; 649 int *argcp; 650 const char **argv; 651 { 652 char *p, *s; 653 int argc; 654 655 argc = *argcp; 656 for (s = options; (p = strsep(&s, ",")) != NULL;) 657 if (*p != '\0') { 658 if (*p == '-') { 659 argv[argc++] = p; 660 p = strchr(p, '='); 661 if (p) { 662 *p = '\0'; 663 argv[argc++] = p+1; 664 } 665 } else if (strcmp(p, "rw") != 0) { 666 argv[argc++] = "-o"; 667 argv[argc++] = p; 668 } 669 } 670 671 *argcp = argc; 672 } 673 674 void 675 usage() 676 { 677 678 (void)fprintf(stderr, 679 "usage: mount %s %s\n mount %s\n mount %s\n", 680 "[-dfruvw] [-o options] [-t ffs | external_type]", 681 "special node", 682 "[-adfruvw] [-t ffs | external_type]", 683 "[-dfruvw] special | node"); 684 exit(1); 685 } 686 687 int 688 disklabelcheck(fs) 689 struct fstab *fs; 690 { 691 char *labelfs; 692 693 if (strcmp(fs->fs_vfstype, "nfs") != 0 || 694 strpbrk(fs->fs_spec, ":@") == NULL) { 695 labelfs = readlabelfs(fs->fs_spec, 0); 696 if (labelfs == NULL || 697 strcmp(labelfs, fs->fs_vfstype) == 0) 698 return (0); 699 if (strcmp(fs->fs_vfstype, "ufs") == 0 && 700 strcmp(labelfs, "ffs") == 0) { 701 warnx("%s: fstab uses outdated type 'ufs' -- fix please", 702 fs->fs_spec); 703 return (0); 704 } 705 warnx("%s: fstab type %s != disklabel type %s", 706 fs->fs_spec, fs->fs_vfstype, labelfs); 707 return (1); 708 } 709 return (0); 710 } 711 712