1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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 #ifndef lint 33 static const char copyright[] = 34 "@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #if 0 37 static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include <sys/param.h> 45 #define _WANT_MNTOPTNAMES 46 #include <sys/mount.h> 47 #include <sys/stat.h> 48 #include <sys/wait.h> 49 50 #include <ctype.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <fstab.h> 54 #include <paths.h> 55 #include <pwd.h> 56 #include <signal.h> 57 #include <stdint.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 #include <libutil.h> 63 64 #include "extern.h" 65 #include "mntopts.h" 66 #include "pathnames.h" 67 68 /* `meta' options */ 69 #define MOUNT_META_OPTION_FSTAB "fstab" 70 #define MOUNT_META_OPTION_CURRENT "current" 71 72 static int debug, fstab_style, verbose; 73 74 struct cpa { 75 char **a; 76 ssize_t sz; 77 int c; 78 }; 79 80 char *catopt(char *, const char *); 81 struct statfs *getmntpt(const char *); 82 int hasopt(const char *, const char *); 83 int ismounted(struct fstab *, struct statfs *, int); 84 int isremountable(const char *); 85 void mangle(char *, struct cpa *); 86 char *update_options(char *, char *, int); 87 int mountfs(const char *, const char *, const char *, 88 int, const char *, const char *); 89 void remopt(char *, const char *); 90 void prmount(struct statfs *); 91 void putfsent(struct statfs *); 92 void usage(void); 93 char *flags2opts(int); 94 95 /* Map from mount options to printable formats. */ 96 static struct mntoptnames optnames[] = { 97 MNTOPT_NAMES 98 }; 99 100 /* 101 * List of VFS types that can be remounted without becoming mounted on top 102 * of each other. 103 * XXX Is this list correct? 104 */ 105 static const char * 106 remountable_fs_names[] = { 107 "ufs", "ffs", "ext2fs", 108 0 109 }; 110 111 static const char userquotaeq[] = "userquota="; 112 static const char groupquotaeq[] = "groupquota="; 113 114 static char *mountprog = NULL; 115 116 static int 117 use_mountprog(const char *vfstype) 118 { 119 /* XXX: We need to get away from implementing external mount 120 * programs for every filesystem, and move towards having 121 * each filesystem properly implement the nmount() system call. 122 */ 123 unsigned int i; 124 const char *fs[] = { 125 "cd9660", "mfs", "msdosfs", "nfs", 126 "nullfs", "smbfs", "udf", "unionfs", 127 NULL 128 }; 129 130 if (mountprog != NULL) 131 return (1); 132 133 for (i = 0; fs[i] != NULL; ++i) { 134 if (strcmp(vfstype, fs[i]) == 0) 135 return (1); 136 } 137 138 return (0); 139 } 140 141 static int 142 exec_mountprog(const char *name, const char *execname, char *const argv[]) 143 { 144 pid_t pid; 145 int status; 146 147 switch (pid = fork()) { 148 case -1: /* Error. */ 149 warn("fork"); 150 exit (1); 151 case 0: /* Child. */ 152 /* Go find an executable. */ 153 execvP(execname, _PATH_SYSPATH, argv); 154 if (errno == ENOENT) { 155 warn("exec %s not found", execname); 156 if (execname[0] != '/') { 157 warnx("in path: %s", _PATH_SYSPATH); 158 } 159 } 160 exit(1); 161 default: /* Parent. */ 162 if (waitpid(pid, &status, 0) < 0) { 163 warn("waitpid"); 164 return (1); 165 } 166 167 if (WIFEXITED(status)) { 168 if (WEXITSTATUS(status) != 0) 169 return (WEXITSTATUS(status)); 170 } else if (WIFSIGNALED(status)) { 171 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 172 return (1); 173 } 174 break; 175 } 176 177 return (0); 178 } 179 180 static int 181 specified_ro(const char *arg) 182 { 183 char *optbuf, *opt; 184 int ret = 0; 185 186 optbuf = strdup(arg); 187 if (optbuf == NULL) 188 err(1, NULL); 189 190 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 191 if (strcmp(opt, "ro") == 0) { 192 ret = 1; 193 break; 194 } 195 } 196 free(optbuf); 197 return (ret); 198 } 199 200 static void 201 restart_mountd(void) 202 { 203 struct pidfh *pfh; 204 pid_t mountdpid; 205 206 mountdpid = 0; 207 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &mountdpid); 208 if (pfh != NULL) { 209 /* Mountd is not running. */ 210 pidfile_remove(pfh); 211 return; 212 } 213 if (errno != EEXIST) { 214 /* Cannot open pidfile for some reason. */ 215 return; 216 } 217 218 /* 219 * Refuse to send broadcast or group signals, this has 220 * happened due to the bugs in pidfile(3). 221 */ 222 if (mountdpid <= 0) { 223 warnx("mountd pid %d, refusing to send SIGHUP", mountdpid); 224 return; 225 } 226 227 /* We have mountd(8) PID in mountdpid varible, let's signal it. */ 228 if (kill(mountdpid, SIGHUP) == -1) 229 err(1, "signal mountd"); 230 } 231 232 int 233 main(int argc, char *argv[]) 234 { 235 const char *mntfromname, **vfslist, *vfstype; 236 struct fstab *fs; 237 struct statfs *mntbuf; 238 int all, ch, i, init_flags, late, failok, mntsize, rval, have_fstab, ro; 239 int onlylate; 240 char *cp, *ep, *options; 241 242 all = init_flags = late = onlylate = 0; 243 ro = 0; 244 options = NULL; 245 vfslist = NULL; 246 vfstype = "ufs"; 247 while ((ch = getopt(argc, argv, "adF:fLlno:prt:uvw")) != -1) 248 switch (ch) { 249 case 'a': 250 all = 1; 251 break; 252 case 'd': 253 debug = 1; 254 break; 255 case 'F': 256 setfstab(optarg); 257 break; 258 case 'f': 259 init_flags |= MNT_FORCE; 260 break; 261 case 'L': 262 onlylate = 1; 263 late = 1; 264 break; 265 case 'l': 266 late = 1; 267 break; 268 case 'n': 269 /* For compatibility with the Linux version of mount. */ 270 break; 271 case 'o': 272 if (*optarg) { 273 options = catopt(options, optarg); 274 if (specified_ro(optarg)) 275 ro = 1; 276 } 277 break; 278 case 'p': 279 fstab_style = 1; 280 verbose = 1; 281 break; 282 case 'r': 283 options = catopt(options, "ro"); 284 ro = 1; 285 break; 286 case 't': 287 if (vfslist != NULL) 288 errx(1, "only one -t option may be specified"); 289 vfslist = makevfslist(optarg); 290 vfstype = optarg; 291 break; 292 case 'u': 293 init_flags |= MNT_UPDATE; 294 break; 295 case 'v': 296 verbose = 1; 297 break; 298 case 'w': 299 options = catopt(options, "noro"); 300 break; 301 case '?': 302 default: 303 usage(); 304 /* NOTREACHED */ 305 } 306 argc -= optind; 307 argv += optind; 308 309 #define BADTYPE(type) \ 310 (strcmp(type, FSTAB_RO) && \ 311 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 312 313 if ((init_flags & MNT_UPDATE) && (ro == 0)) 314 options = catopt(options, "noro"); 315 316 rval = 0; 317 switch (argc) { 318 case 0: 319 if ((mntsize = getmntinfo(&mntbuf, 320 verbose ? MNT_WAIT : MNT_NOWAIT)) == 0) 321 err(1, "getmntinfo"); 322 if (all) { 323 while ((fs = getfsent()) != NULL) { 324 if (BADTYPE(fs->fs_type)) 325 continue; 326 if (checkvfsname(fs->fs_vfstype, vfslist)) 327 continue; 328 if (hasopt(fs->fs_mntops, "noauto")) 329 continue; 330 if (!hasopt(fs->fs_mntops, "late") && onlylate) 331 continue; 332 if (hasopt(fs->fs_mntops, "late") && !late) 333 continue; 334 if (hasopt(fs->fs_mntops, "failok")) 335 failok = 1; 336 else 337 failok = 0; 338 if (!(init_flags & MNT_UPDATE) && 339 !hasopt(fs->fs_mntops, "update") && 340 ismounted(fs, mntbuf, mntsize)) 341 continue; 342 options = update_options(options, fs->fs_mntops, 343 mntbuf->f_flags); 344 if (mountfs(fs->fs_vfstype, fs->fs_spec, 345 fs->fs_file, init_flags, options, 346 fs->fs_mntops) && !failok) 347 rval = 1; 348 } 349 } else if (fstab_style) { 350 for (i = 0; i < mntsize; i++) { 351 if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 352 continue; 353 putfsent(&mntbuf[i]); 354 } 355 } else { 356 for (i = 0; i < mntsize; i++) { 357 if (checkvfsname(mntbuf[i].f_fstypename, 358 vfslist)) 359 continue; 360 if (!verbose && 361 (mntbuf[i].f_flags & MNT_IGNORE) != 0) 362 continue; 363 prmount(&mntbuf[i]); 364 } 365 } 366 exit(rval); 367 case 1: 368 if (vfslist != NULL) 369 usage(); 370 371 rmslashes(*argv, *argv); 372 if (init_flags & MNT_UPDATE) { 373 mntfromname = NULL; 374 have_fstab = 0; 375 if ((mntbuf = getmntpt(*argv)) == NULL) 376 errx(1, "not currently mounted %s", *argv); 377 /* 378 * Only get the mntflags from fstab if both mntpoint 379 * and mntspec are identical. Also handle the special 380 * case where just '/' is mounted and 'spec' is not 381 * identical with the one from fstab ('/dev' is missing 382 * in the spec-string at boot-time). 383 */ 384 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 385 if (strcmp(fs->fs_spec, 386 mntbuf->f_mntfromname) == 0 && 387 strcmp(fs->fs_file, 388 mntbuf->f_mntonname) == 0) { 389 have_fstab = 1; 390 mntfromname = mntbuf->f_mntfromname; 391 } else if (argv[0][0] == '/' && 392 argv[0][1] == '\0' && 393 strcmp(fs->fs_vfstype, 394 mntbuf->f_fstypename) == 0) { 395 fs = getfsfile("/"); 396 have_fstab = 1; 397 mntfromname = fs->fs_spec; 398 } 399 } 400 if (have_fstab) { 401 options = update_options(options, fs->fs_mntops, 402 mntbuf->f_flags); 403 } else { 404 mntfromname = mntbuf->f_mntfromname; 405 options = update_options(options, NULL, 406 mntbuf->f_flags); 407 } 408 rval = mountfs(mntbuf->f_fstypename, mntfromname, 409 mntbuf->f_mntonname, init_flags, options, 0); 410 break; 411 } 412 if ((fs = getfsfile(*argv)) == NULL && 413 (fs = getfsspec(*argv)) == NULL) 414 errx(1, "%s: unknown special file or file system", 415 *argv); 416 if (BADTYPE(fs->fs_type)) 417 errx(1, "%s has unknown file system type", 418 *argv); 419 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 420 init_flags, options, fs->fs_mntops); 421 break; 422 case 2: 423 /* 424 * If -t flag has not been specified, the path cannot be 425 * found, spec contains either a ':' or a '@', then assume 426 * that an NFS file system is being specified ala Sun. 427 * Check if the hostname contains only allowed characters 428 * to reduce false positives. IPv6 addresses containing 429 * ':' will be correctly parsed only if the separator is '@'. 430 * The definition of a valid hostname is taken from RFC 1034. 431 */ 432 if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL || 433 (ep = strchr(argv[0], ':')) != NULL)) { 434 if (*ep == '@') { 435 cp = ep + 1; 436 ep = cp + strlen(cp); 437 } else 438 cp = argv[0]; 439 while (cp != ep) { 440 if (!isdigit(*cp) && !isalpha(*cp) && 441 *cp != '.' && *cp != '-' && *cp != ':') 442 break; 443 cp++; 444 } 445 if (cp == ep) 446 vfstype = "nfs"; 447 } 448 rval = mountfs(vfstype, 449 argv[0], argv[1], init_flags, options, NULL); 450 break; 451 default: 452 usage(); 453 /* NOTREACHED */ 454 } 455 456 /* 457 * If the mount was successfully, and done by root, tell mountd the 458 * good news. 459 */ 460 if (rval == 0 && getuid() == 0) 461 restart_mountd(); 462 463 exit(rval); 464 } 465 466 int 467 ismounted(struct fstab *fs, struct statfs *mntbuf, int mntsize) 468 { 469 char realfsfile[PATH_MAX]; 470 int i; 471 472 if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 473 /* the root file system can always be remounted */ 474 return (0); 475 476 /* The user may have specified a symlink in fstab, resolve the path */ 477 if (realpath(fs->fs_file, realfsfile) == NULL) { 478 /* Cannot resolve the path, use original one */ 479 strlcpy(realfsfile, fs->fs_file, sizeof(realfsfile)); 480 } 481 482 /* 483 * Consider the filesystem to be mounted if: 484 * It has the same mountpoint as a mounted filesytem, and 485 * It has the same type as that same mounted filesystem, and 486 * It has the same device name as that same mounted filesystem, OR 487 * It is a nonremountable filesystem 488 */ 489 for (i = mntsize - 1; i >= 0; --i) 490 if (strcmp(realfsfile, mntbuf[i].f_mntonname) == 0 && 491 strcmp(fs->fs_vfstype, mntbuf[i].f_fstypename) == 0 && 492 (!isremountable(fs->fs_vfstype) || 493 (strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0))) 494 return (1); 495 return (0); 496 } 497 498 int 499 isremountable(const char *vfsname) 500 { 501 const char **cp; 502 503 for (cp = remountable_fs_names; *cp; cp++) 504 if (strcmp(*cp, vfsname) == 0) 505 return (1); 506 return (0); 507 } 508 509 int 510 hasopt(const char *mntopts, const char *option) 511 { 512 int negative, found; 513 char *opt, *optbuf; 514 515 if (option[0] == 'n' && option[1] == 'o') { 516 negative = 1; 517 option += 2; 518 } else 519 negative = 0; 520 optbuf = strdup(mntopts); 521 found = 0; 522 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 523 if (opt[0] == 'n' && opt[1] == 'o') { 524 if (!strcasecmp(opt + 2, option)) 525 found = negative; 526 } else if (!strcasecmp(opt, option)) 527 found = !negative; 528 } 529 free(optbuf); 530 return (found); 531 } 532 533 static void 534 append_arg(struct cpa *sa, char *arg) 535 { 536 if (sa->c + 1 == sa->sz) { 537 sa->sz = sa->sz == 0 ? 8 : sa->sz * 2; 538 sa->a = realloc(sa->a, sizeof(*sa->a) * sa->sz); 539 if (sa->a == NULL) 540 errx(1, "realloc failed"); 541 } 542 sa->a[++sa->c] = arg; 543 } 544 545 int 546 mountfs(const char *vfstype, const char *spec, const char *name, int flags, 547 const char *options, const char *mntopts) 548 { 549 struct statfs sf; 550 int i, ret; 551 char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX]; 552 static struct cpa mnt_argv; 553 554 /* resolve the mountpoint with realpath(3) */ 555 if (checkpath(name, mntpath) != 0) { 556 warn("%s", mntpath); 557 return (1); 558 } 559 name = mntpath; 560 561 if (mntopts == NULL) 562 mntopts = ""; 563 optbuf = catopt(strdup(mntopts), options); 564 565 if (strcmp(name, "/") == 0) 566 flags |= MNT_UPDATE; 567 if (flags & MNT_FORCE) 568 optbuf = catopt(optbuf, "force"); 569 if (flags & MNT_RDONLY) 570 optbuf = catopt(optbuf, "ro"); 571 /* 572 * XXX 573 * The mount_mfs (newfs) command uses -o to select the 574 * optimization mode. We don't pass the default "-o rw" 575 * for that reason. 576 */ 577 if (flags & MNT_UPDATE) 578 optbuf = catopt(optbuf, "update"); 579 580 /* Compatibility glue. */ 581 if (strcmp(vfstype, "msdos") == 0) 582 vfstype = "msdosfs"; 583 584 /* Construct the name of the appropriate mount command */ 585 (void)snprintf(execname, sizeof(execname), "mount_%s", vfstype); 586 587 mnt_argv.c = -1; 588 append_arg(&mnt_argv, execname); 589 mangle(optbuf, &mnt_argv); 590 if (mountprog != NULL) 591 strlcpy(execname, mountprog, sizeof(execname)); 592 593 append_arg(&mnt_argv, strdup(spec)); 594 append_arg(&mnt_argv, strdup(name)); 595 append_arg(&mnt_argv, NULL); 596 597 if (debug) { 598 if (use_mountprog(vfstype)) 599 printf("exec: %s", execname); 600 else 601 printf("mount -t %s", vfstype); 602 for (i = 1; i < mnt_argv.c; i++) 603 (void)printf(" %s", mnt_argv.a[i]); 604 (void)printf("\n"); 605 free(optbuf); 606 free(mountprog); 607 mountprog = NULL; 608 return (0); 609 } 610 611 if (use_mountprog(vfstype)) { 612 ret = exec_mountprog(name, execname, mnt_argv.a); 613 } else { 614 ret = mount_fs(vfstype, mnt_argv.c, mnt_argv.a); 615 } 616 617 free(optbuf); 618 free(mountprog); 619 mountprog = NULL; 620 621 if (verbose) { 622 if (statfs(name, &sf) < 0) { 623 warn("statfs %s", name); 624 return (1); 625 } 626 if (fstab_style) 627 putfsent(&sf); 628 else 629 prmount(&sf); 630 } 631 632 return (ret); 633 } 634 635 void 636 prmount(struct statfs *sfp) 637 { 638 uint64_t flags; 639 unsigned int i; 640 struct mntoptnames *o; 641 struct passwd *pw; 642 643 (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, 644 sfp->f_fstypename); 645 646 flags = sfp->f_flags & MNT_VISFLAGMASK; 647 for (o = optnames; flags != 0 && o->o_opt != 0; o++) 648 if (flags & o->o_opt) { 649 (void)printf(", %s", o->o_name); 650 flags &= ~o->o_opt; 651 } 652 /* 653 * Inform when file system is mounted by an unprivileged user 654 * or privileged non-root user. 655 */ 656 if ((flags & MNT_USER) != 0 || sfp->f_owner != 0) { 657 (void)printf(", mounted by "); 658 if ((pw = getpwuid(sfp->f_owner)) != NULL) 659 (void)printf("%s", pw->pw_name); 660 else 661 (void)printf("%d", sfp->f_owner); 662 } 663 if (verbose) { 664 if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 665 (void)printf(", writes: sync %ju async %ju", 666 (uintmax_t)sfp->f_syncwrites, 667 (uintmax_t)sfp->f_asyncwrites); 668 if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0) 669 (void)printf(", reads: sync %ju async %ju", 670 (uintmax_t)sfp->f_syncreads, 671 (uintmax_t)sfp->f_asyncreads); 672 if (sfp->f_fsid.val[0] != 0 || sfp->f_fsid.val[1] != 0) { 673 (void)printf(", fsid "); 674 for (i = 0; i < sizeof(sfp->f_fsid); i++) 675 (void)printf("%02x", ((u_char *)&sfp->f_fsid)[i]); 676 } 677 } 678 (void)printf(")\n"); 679 } 680 681 struct statfs * 682 getmntpt(const char *name) 683 { 684 struct statfs *mntbuf; 685 int i, mntsize; 686 687 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 688 for (i = mntsize - 1; i >= 0; i--) { 689 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 690 strcmp(mntbuf[i].f_mntonname, name) == 0) 691 return (&mntbuf[i]); 692 } 693 return (NULL); 694 } 695 696 char * 697 catopt(char *s0, const char *s1) 698 { 699 char *cp; 700 701 if (s1 == NULL || *s1 == '\0') 702 return (s0); 703 704 if (s0 && *s0) { 705 if (asprintf(&cp, "%s,%s", s0, s1) == -1) 706 errx(1, "asprintf failed"); 707 } else 708 cp = strdup(s1); 709 710 if (s0) 711 free(s0); 712 return (cp); 713 } 714 715 void 716 mangle(char *options, struct cpa *a) 717 { 718 char *p, *s, *val; 719 720 for (s = options; (p = strsep(&s, ",")) != NULL;) 721 if (*p != '\0') { 722 if (strcmp(p, "noauto") == 0) { 723 /* 724 * Do not pass noauto option to nmount(). 725 * or external mount program. noauto is 726 * only used to prevent mounting a filesystem 727 * when 'mount -a' is specified, and is 728 * not a real mount option. 729 */ 730 continue; 731 } else if (strcmp(p, "late") == 0) { 732 /* 733 * "late" is used to prevent certain file 734 * systems from being mounted before late 735 * in the boot cycle; for instance, 736 * loopback NFS mounts can't be mounted 737 * before mountd starts. 738 */ 739 continue; 740 } else if (strcmp(p, "failok") == 0) { 741 /* 742 * "failok" is used to prevent certain file 743 * systems from being causing the system to 744 * drop into single user mode in the boot 745 * cycle, and is not a real mount option. 746 */ 747 continue; 748 } else if (strncmp(p, "mountprog", 9) == 0) { 749 /* 750 * "mountprog" is used to force the use of 751 * userland mount programs. 752 */ 753 val = strchr(p, '='); 754 if (val != NULL) { 755 ++val; 756 if (*val != '\0') 757 mountprog = strdup(val); 758 } 759 760 if (mountprog == NULL) { 761 errx(1, "Need value for -o mountprog"); 762 } 763 continue; 764 } else if (strcmp(p, "userquota") == 0) { 765 continue; 766 } else if (strncmp(p, userquotaeq, 767 sizeof(userquotaeq) - 1) == 0) { 768 continue; 769 } else if (strcmp(p, "groupquota") == 0) { 770 continue; 771 } else if (strncmp(p, groupquotaeq, 772 sizeof(groupquotaeq) - 1) == 0) { 773 continue; 774 } else if (*p == '-') { 775 append_arg(a, p); 776 p = strchr(p, '='); 777 if (p != NULL) { 778 *p = '\0'; 779 append_arg(a, p + 1); 780 } 781 } else { 782 append_arg(a, strdup("-o")); 783 append_arg(a, p); 784 } 785 } 786 } 787 788 789 char * 790 update_options(char *opts, char *fstab, int curflags) 791 { 792 char *o, *p; 793 char *cur; 794 char *expopt, *newopt, *tmpopt; 795 796 if (opts == NULL) 797 return (strdup("")); 798 799 /* remove meta options from list */ 800 remopt(fstab, MOUNT_META_OPTION_FSTAB); 801 remopt(fstab, MOUNT_META_OPTION_CURRENT); 802 cur = flags2opts(curflags); 803 804 /* 805 * Expand all meta-options passed to us first. 806 */ 807 expopt = NULL; 808 for (p = opts; (o = strsep(&p, ",")) != NULL;) { 809 if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 810 expopt = catopt(expopt, fstab); 811 else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 812 expopt = catopt(expopt, cur); 813 else 814 expopt = catopt(expopt, o); 815 } 816 free(cur); 817 free(opts); 818 819 /* 820 * Remove previous contradictory arguments. Given option "foo" we 821 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 822 * and "foo" - so we can deal with possible options like "notice". 823 */ 824 newopt = NULL; 825 for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 826 if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 827 errx(1, "malloc failed"); 828 829 strcpy(tmpopt, "no"); 830 strcat(tmpopt, o); 831 remopt(newopt, tmpopt); 832 free(tmpopt); 833 834 if (strncmp("no", o, 2) == 0) 835 remopt(newopt, o+2); 836 837 newopt = catopt(newopt, o); 838 } 839 free(expopt); 840 841 return (newopt); 842 } 843 844 void 845 remopt(char *string, const char *opt) 846 { 847 char *o, *p, *r; 848 849 if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 850 return; 851 852 r = string; 853 854 for (p = string; (o = strsep(&p, ",")) != NULL;) { 855 if (strcmp(opt, o) != 0) { 856 if (*r == ',' && *o != '\0') 857 r++; 858 while ((*r++ = *o++) != '\0') 859 ; 860 *--r = ','; 861 } 862 } 863 *r = '\0'; 864 } 865 866 void 867 usage(void) 868 { 869 870 (void)fprintf(stderr, "%s\n%s\n%s\n", 871 "usage: mount [-adflpruvw] [-F fstab] [-o options] [-t ufs | external_type]", 872 " mount [-dfpruvw] special | node", 873 " mount [-dfpruvw] [-o options] [-t ufs | external_type] special node"); 874 exit(1); 875 } 876 877 void 878 putfsent(struct statfs *ent) 879 { 880 struct fstab *fst; 881 char *opts, *rw; 882 int l; 883 884 opts = NULL; 885 /* flags2opts() doesn't return the "rw" option. */ 886 if ((ent->f_flags & MNT_RDONLY) != 0) 887 rw = NULL; 888 else 889 rw = catopt(NULL, "rw"); 890 891 opts = flags2opts(ent->f_flags); 892 opts = catopt(rw, opts); 893 894 if (strncmp(ent->f_mntfromname, "<below>", 7) == 0 || 895 strncmp(ent->f_mntfromname, "<above>", 7) == 0) { 896 strlcpy(ent->f_mntfromname, 897 (strnstr(ent->f_mntfromname, ":", 8) +1), 898 sizeof(ent->f_mntfromname)); 899 } 900 901 l = strlen(ent->f_mntfromname); 902 printf("%s%s%s%s", ent->f_mntfromname, 903 l < 8 ? "\t" : "", 904 l < 16 ? "\t" : "", 905 l < 24 ? "\t" : " "); 906 l = strlen(ent->f_mntonname); 907 printf("%s%s%s%s", ent->f_mntonname, 908 l < 8 ? "\t" : "", 909 l < 16 ? "\t" : "", 910 l < 24 ? "\t" : " "); 911 printf("%s\t", ent->f_fstypename); 912 l = strlen(opts); 913 printf("%s%s", opts, 914 l < 8 ? "\t" : " "); 915 free(opts); 916 917 if ((fst = getfsspec(ent->f_mntfromname))) 918 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 919 else if ((fst = getfsfile(ent->f_mntonname))) 920 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 921 else if (strcmp(ent->f_fstypename, "ufs") == 0) { 922 if (strcmp(ent->f_mntonname, "/") == 0) 923 printf("\t1 1\n"); 924 else 925 printf("\t2 2\n"); 926 } else 927 printf("\t0 0\n"); 928 } 929 930 931 char * 932 flags2opts(int flags) 933 { 934 char *res; 935 936 res = NULL; 937 938 if (flags & MNT_RDONLY) res = catopt(res, "ro"); 939 if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 940 if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 941 if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 942 if (flags & MNT_UNION) res = catopt(res, "union"); 943 if (flags & MNT_ASYNC) res = catopt(res, "async"); 944 if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 945 if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 946 if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 947 if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 948 if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 949 if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel"); 950 if (flags & MNT_ACLS) res = catopt(res, "acls"); 951 if (flags & MNT_NFS4ACLS) res = catopt(res, "nfsv4acls"); 952 if (flags & MNT_UNTRUSTED) res = catopt(res, "untrusted"); 953 if (flags & MNT_NOCOVER) res = catopt(res, "nocover"); 954 if (flags & MNT_EMPTYDIR) res = catopt(res, "emptydir"); 955 956 return (res); 957 } 958