mount.c revision 95289
1331722Seadler/*- 2132332Smarcel * Copyright (c) 1980, 1989, 1993, 1994 3132332Smarcel * The Regents of the University of California. All rights reserved. 4132332Smarcel * 5132332Smarcel * Redistribution and use in source and binary forms, with or without 6132332Smarcel * modification, are permitted provided that the following conditions 7132332Smarcel * are met: 8132332Smarcel * 1. Redistributions of source code must retain the above copyright 9132332Smarcel * notice, this list of conditions and the following disclaimer. 10132332Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11132332Smarcel * notice, this list of conditions and the following disclaimer in the 12132332Smarcel * documentation and/or other materials provided with the distribution. 13132332Smarcel * 3. All advertising materials mentioning features or use of this software 14132332Smarcel * must display the following acknowledgement: 15132332Smarcel * This product includes software developed by the University of 16132332Smarcel * California, Berkeley and its contributors. 17132332Smarcel * 4. Neither the name of the University nor the names of its contributors 18132332Smarcel * may be used to endorse or promote products derived from this software 19132332Smarcel * without specific prior written permission. 20132332Smarcel * 21132332Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22132332Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23132332Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24132332Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25132332Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26132332Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27132332Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28132332Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29132332Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30181059Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31181059Smarcel * SUCH DAMAGE. 32132332Smarcel */ 33132332Smarcel 34132332Smarcel#ifndef lint 35132332Smarcelstatic const char copyright[] = 36132332Smarcel"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 37132332Smarcel The Regents of the University of California. All rights reserved.\n"; 38132332Smarcel#endif /* not lint */ 39132332Smarcel 40132332Smarcel#ifndef lint 41132332Smarcel#if 0 42132332Smarcelstatic char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 43132332Smarcel#endif 44132332Smarcelstatic const char rcsid[] = 45132332Smarcel "$FreeBSD: head/sbin/mount/mount.c 95289 2002-04-22 23:03:03Z mux $"; 46132332Smarcel#endif /* not lint */ 47132332Smarcel 48132332Smarcel#include <sys/param.h> 49132332Smarcel#include <sys/mount.h> 50132332Smarcel#include <sys/stat.h> 51132332Smarcel#include <sys/wait.h> 52132332Smarcel 53132332Smarcel#include <ctype.h> 54132332Smarcel#include <err.h> 55132332Smarcel#include <errno.h> 56132332Smarcel#include <fstab.h> 57132332Smarcel#include <pwd.h> 58132332Smarcel#include <signal.h> 59132332Smarcel#include <stdio.h> 60132332Smarcel#include <stdlib.h> 61132332Smarcel#include <string.h> 62132332Smarcel#include <unistd.h> 63132332Smarcel 64132332Smarcel#include "extern.h" 65132332Smarcel#include "mntopts.h" 66132332Smarcel#include "pathnames.h" 67132332Smarcel 68132332Smarcel/* `meta' options */ 69132332Smarcel#define MOUNT_META_OPTION_FSTAB "fstab" 70132332Smarcel#define MOUNT_META_OPTION_CURRENT "current" 71132332Smarcel 72132332Smarcelint debug, fstab_style, verbose; 73132332Smarcel 74132332Smarcelchar *catopt(char *, const char *); 75277801Sdimstruct statfs *getmntpt(const char *); 76132332Smarcelint hasopt(const char *, const char *); 77132332Smarcelint ismounted(struct fstab *, struct statfs *, int); 78132332Smarcelint isremountable(const char *); 79132332Smarcelvoid mangle(char *, int *, const char **); 80132332Smarcelchar *update_options(char *, char *, int); 81132332Smarcelint mountfs(const char *, const char *, const char *, 82132332Smarcel int, const char *, const char *); 83146818Sdfrvoid remopt(char *, const char *); 84146818Sdfrvoid prmount(struct statfs *); 85146818Sdfrvoid putfsent(const struct statfs *); 86146818Sdfrvoid usage(void); 87146818Sdfrchar *flags2opts(int); 88146818Sdfr 89146818Sdfr/* Map from mount options to printable formats. */ 90146818Sdfrstatic struct opt { 91146818Sdfr int o_opt; 92146818Sdfr const char *o_name; 93146818Sdfr} optnames[] = { 94146818Sdfr { MNT_ASYNC, "asynchronous" }, 95146818Sdfr { MNT_EXPORTED, "NFS exported" }, 96146818Sdfr { MNT_LOCAL, "local" }, 97132332Smarcel { MNT_NOATIME, "noatime" }, 98132332Smarcel { MNT_NODEV, "nodev" }, 99132332Smarcel { MNT_NOEXEC, "noexec" }, 100132332Smarcel { MNT_NOSUID, "nosuid" }, 101132332Smarcel { MNT_NOSYMFOLLOW, "nosymfollow" }, 102132332Smarcel { MNT_QUOTA, "with quotas" }, 103132332Smarcel { MNT_RDONLY, "read-only" }, 104132332Smarcel { MNT_SYNCHRONOUS, "synchronous" }, 105132332Smarcel { MNT_UNION, "union" }, 106132332Smarcel { MNT_NOCLUSTERR, "noclusterr" }, 107132332Smarcel { MNT_NOCLUSTERW, "noclusterw" }, 108132332Smarcel { MNT_SUIDDIR, "suiddir" }, 109132332Smarcel { MNT_SOFTDEP, "soft-updates" }, 110132332Smarcel { 0, NULL } 111132332Smarcel}; 112132332Smarcel 113132332Smarcel/* 114132332Smarcel * List of VFS types that can be remounted without becoming mounted on top 115132332Smarcel * of each other. 116132332Smarcel * XXX Is this list correct? 117132332Smarcel */ 118132332Smarcelstatic const char * 119remountable_fs_names[] = { 120 "ufs", "ffs", "ext2fs", 121 0 122}; 123 124int 125main(argc, argv) 126 int argc; 127 char * const argv[]; 128{ 129 const char *mntfromname, **vfslist, *vfstype; 130 struct fstab *fs; 131 struct statfs *mntbuf; 132 FILE *mountdfp; 133 pid_t pid; 134 int all, ch, i, init_flags, mntsize, rval, have_fstab; 135 char *cp, *ep, *options; 136 137 all = init_flags = 0; 138 options = NULL; 139 vfslist = NULL; 140 vfstype = "ufs"; 141 while ((ch = getopt(argc, argv, "adfo:prwt:uv")) != -1) 142 switch (ch) { 143 case 'a': 144 all = 1; 145 break; 146 case 'd': 147 debug = 1; 148 break; 149 case 'f': 150 init_flags |= MNT_FORCE; 151 break; 152 case 'o': 153 if (*optarg) 154 options = catopt(options, optarg); 155 break; 156 case 'p': 157 fstab_style = 1; 158 verbose = 1; 159 break; 160 case 'r': 161 options = catopt(options, "ro"); 162 break; 163 case 't': 164 if (vfslist != NULL) 165 errx(1, "only one -t option may be specified"); 166 vfslist = makevfslist(optarg); 167 vfstype = optarg; 168 break; 169 case 'u': 170 init_flags |= MNT_UPDATE; 171 break; 172 case 'v': 173 verbose = 1; 174 break; 175 case 'w': 176 options = catopt(options, "noro"); 177 break; 178 case '?': 179 default: 180 usage(); 181 /* NOTREACHED */ 182 } 183 argc -= optind; 184 argv += optind; 185 186#define BADTYPE(type) \ 187 (strcmp(type, FSTAB_RO) && \ 188 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 189 190 rval = 0; 191 switch (argc) { 192 case 0: 193 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 194 err(1, "getmntinfo"); 195 if (all) { 196 while ((fs = getfsent()) != NULL) { 197 if (BADTYPE(fs->fs_type)) 198 continue; 199 if (checkvfsname(fs->fs_vfstype, vfslist)) 200 continue; 201 if (hasopt(fs->fs_mntops, "noauto")) 202 continue; 203 if (!(init_flags & MNT_UPDATE) && 204 ismounted(fs, mntbuf, mntsize)) 205 continue; 206 if (mountfs(fs->fs_vfstype, fs->fs_spec, 207 fs->fs_file, init_flags, options, 208 fs->fs_mntops)) 209 rval = 1; 210 } 211 } else if (fstab_style) { 212 for (i = 0; i < mntsize; i++) { 213 if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 214 continue; 215 putfsent(&mntbuf[i]); 216 } 217 } else { 218 for (i = 0; i < mntsize; i++) { 219 if (checkvfsname(mntbuf[i].f_fstypename, 220 vfslist)) 221 continue; 222 prmount(&mntbuf[i]); 223 } 224 } 225 exit(rval); 226 case 1: 227 if (vfslist != NULL) 228 usage(); 229 230 if (init_flags & MNT_UPDATE) { 231 mntfromname = NULL; 232 have_fstab = 0; 233 if ((mntbuf = getmntpt(*argv)) == NULL) 234 errx(1, "not currently mounted %s", *argv); 235 /* 236 * Only get the mntflags from fstab if both mntpoint 237 * and mntspec are identical. Also handle the special 238 * case where just '/' is mounted and 'spec' is not 239 * identical with the one from fstab ('/dev' is missing 240 * in the spec-string at boot-time). 241 */ 242 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 243 if (strcmp(fs->fs_spec, 244 mntbuf->f_mntfromname) == 0 && 245 strcmp(fs->fs_file, 246 mntbuf->f_mntonname) == 0) { 247 have_fstab = 1; 248 mntfromname = mntbuf->f_mntfromname; 249 } else if (argv[0][0] == '/' && 250 argv[0][1] == '\0') { 251 fs = getfsfile("/"); 252 have_fstab = 1; 253 mntfromname = fs->fs_spec; 254 } 255 } 256 if (have_fstab) { 257 options = update_options(options, fs->fs_mntops, 258 mntbuf->f_flags); 259 } else { 260 mntfromname = mntbuf->f_mntfromname; 261 options = update_options(options, NULL, 262 mntbuf->f_flags); 263 } 264 rval = mountfs(mntbuf->f_fstypename, mntfromname, 265 mntbuf->f_mntonname, init_flags, options, 0); 266 break; 267 } 268 rmslashes(*argv, *argv); 269 if ((fs = getfsfile(*argv)) == NULL && 270 (fs = getfsspec(*argv)) == NULL) 271 errx(1, "%s: unknown special file or file system", 272 *argv); 273 if (BADTYPE(fs->fs_type)) 274 errx(1, "%s has unknown file system type", 275 *argv); 276 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 277 init_flags, options, fs->fs_mntops); 278 break; 279 case 2: 280 /* 281 * If -t flag has not been specified, the path cannot be 282 * found, spec contains either a ':' or a '@', then assume 283 * that an NFS filesystem is being specified ala Sun. 284 * Check if the hostname contains only allowed characters 285 * to reduce false positives. IPv6 addresses containing 286 * ':' will be correctly parsed only if the separator is '@'. 287 * The definition of a valid hostname is taken from RFC 1034. 288 */ 289 if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL) || 290 ((ep = strchr(argv[0], ':')) != NULL)) { 291 cp = argv[0]; 292 while (cp != ep) { 293 if (!isdigit(*cp) && !isalpha(*cp) && 294 *cp != '.' && *cp != '-' && *cp != ':') 295 break; 296 cp++; 297 } 298 if (cp == ep) 299 vfstype = "nfs"; 300 } 301 rval = mountfs(vfstype, 302 argv[0], argv[1], init_flags, options, NULL); 303 break; 304 default: 305 usage(); 306 /* NOTREACHED */ 307 } 308 309 /* 310 * If the mount was successfully, and done by root, tell mountd the 311 * good news. Pid checks are probably unnecessary, but don't hurt. 312 */ 313 if (rval == 0 && getuid() == 0 && 314 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 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 321 exit(rval); 322} 323 324int 325ismounted(fs, mntbuf, mntsize) 326 struct fstab *fs; 327 struct statfs *mntbuf; 328 int mntsize; 329{ 330 int i; 331 332 if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 333 /* the root file system can always be remounted */ 334 return (0); 335 336 for (i = mntsize - 1; i >= 0; --i) 337 if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 && 338 (!isremountable(fs->fs_vfstype) || 339 strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0)) 340 return (1); 341 return (0); 342} 343 344int 345isremountable(vfsname) 346 const char *vfsname; 347{ 348 const char **cp; 349 350 for (cp = remountable_fs_names; *cp; cp++) 351 if (strcmp(*cp, vfsname) == 0) 352 return (1); 353 return (0); 354} 355 356int 357hasopt(mntopts, option) 358 const char *mntopts, *option; 359{ 360 int negative, found; 361 char *opt, *optbuf; 362 363 if (option[0] == 'n' && option[1] == 'o') { 364 negative = 1; 365 option += 2; 366 } else 367 negative = 0; 368 optbuf = strdup(mntopts); 369 found = 0; 370 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 371 if (opt[0] == 'n' && opt[1] == 'o') { 372 if (!strcasecmp(opt + 2, option)) 373 found = negative; 374 } else if (!strcasecmp(opt, option)) 375 found = !negative; 376 } 377 free(optbuf); 378 return (found); 379} 380 381int 382mountfs(vfstype, spec, name, flags, options, mntopts) 383 const char *vfstype, *spec, *name, *options, *mntopts; 384 int flags; 385{ 386 /* List of directories containing mount_xxx subcommands. */ 387 static const char *edirs[] = { 388 _PATH_SBIN, 389 _PATH_USRSBIN, 390 NULL 391 }; 392 const char *argv[100], **edir; 393 struct statfs sf; 394 pid_t pid; 395 int argc, i, status; 396 char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN]; 397 398#if __GNUC__ 399 (void)&optbuf; 400 (void)&name; 401#endif 402 403 /* resolve the mountpoint with realpath(3) */ 404 (void)checkpath(name, mntpath); 405 name = mntpath; 406 407 if (mntopts == NULL) 408 mntopts = ""; 409 if (options == NULL) { 410 if (*mntopts == '\0') { 411 options = "rw"; 412 } else { 413 options = mntopts; 414 mntopts = ""; 415 } 416 } 417 optbuf = catopt(strdup(mntopts), options); 418 419 if (strcmp(name, "/") == 0) 420 flags |= MNT_UPDATE; 421 if (flags & MNT_FORCE) 422 optbuf = catopt(optbuf, "force"); 423 if (flags & MNT_RDONLY) 424 optbuf = catopt(optbuf, "ro"); 425 /* 426 * XXX 427 * The mount_mfs (newfs) command uses -o to select the 428 * optimization mode. We don't pass the default "-o rw" 429 * for that reason. 430 */ 431 if (flags & MNT_UPDATE) 432 optbuf = catopt(optbuf, "update"); 433 434 /* Compatibility glue. */ 435 if (strcmp(vfstype, "msdos") == 0) 436 vfstype = "msdosfs"; 437 438 argc = 0; 439 argv[argc++] = vfstype; 440 mangle(optbuf, &argc, argv); 441 argv[argc++] = spec; 442 argv[argc++] = name; 443 argv[argc] = NULL; 444 445 if (debug) { 446 (void)printf("exec: mount_%s", vfstype); 447 for (i = 1; i < argc; i++) 448 (void)printf(" %s", argv[i]); 449 (void)printf("\n"); 450 return (0); 451 } 452 453 switch (pid = fork()) { 454 case -1: /* Error. */ 455 warn("fork"); 456 free(optbuf); 457 return (1); 458 case 0: /* Child. */ 459 if (strcmp(vfstype, "ufs") == 0) 460 exit(mount_ufs(argc, (char * const *) argv)); 461 462 /* Go find an executable. */ 463 for (edir = edirs; *edir; edir++) { 464 (void)snprintf(execname, 465 sizeof(execname), "%s/mount_%s", *edir, vfstype); 466 execv(execname, (char * const *)argv); 467 } 468 if (errno == ENOENT) { 469 int len = 0; 470 char *cp; 471 for (edir = edirs; *edir; edir++) 472 len += strlen(*edir) + 2; /* ", " */ 473 if ((cp = malloc(len)) == NULL) 474 errx(1, "malloc failed"); 475 cp[0] = '\0'; 476 for (edir = edirs; *edir; edir++) { 477 strcat(cp, *edir); 478 if (edir[1] != NULL) 479 strcat(cp, ", "); 480 } 481 warn("exec mount_%s not found in %s", vfstype, cp); 482 } 483 exit(1); 484 /* NOTREACHED */ 485 default: /* Parent. */ 486 free(optbuf); 487 488 if (waitpid(pid, &status, 0) < 0) { 489 warn("waitpid"); 490 return (1); 491 } 492 493 if (WIFEXITED(status)) { 494 if (WEXITSTATUS(status) != 0) 495 return (WEXITSTATUS(status)); 496 } else if (WIFSIGNALED(status)) { 497 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 498 return (1); 499 } 500 501 if (verbose) { 502 if (statfs(name, &sf) < 0) { 503 warn("statfs %s", name); 504 return (1); 505 } 506 if (fstab_style) 507 putfsent(&sf); 508 else 509 prmount(&sf); 510 } 511 break; 512 } 513 514 return (0); 515} 516 517void 518prmount(sfp) 519 struct statfs *sfp; 520{ 521 int flags; 522 struct opt *o; 523 struct passwd *pw; 524 525 (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, 526 sfp->f_fstypename); 527 528 flags = sfp->f_flags & MNT_VISFLAGMASK; 529 for (o = optnames; flags && o->o_opt; o++) 530 if (flags & o->o_opt) { 531 (void)printf(", %s", o->o_name); 532 flags &= ~o->o_opt; 533 } 534 if (sfp->f_owner) { 535 (void)printf(", mounted by "); 536 if ((pw = getpwuid(sfp->f_owner)) != NULL) 537 (void)printf("%s", pw->pw_name); 538 else 539 (void)printf("%d", sfp->f_owner); 540 } 541 if (verbose) { 542 if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 543 (void)printf(", writes: sync %ld async %ld", 544 sfp->f_syncwrites, sfp->f_asyncwrites); 545 if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0) 546 (void)printf(", reads: sync %ld async %ld", 547 sfp->f_syncreads, sfp->f_asyncreads); 548 } 549 (void)printf(")\n"); 550} 551 552struct statfs * 553getmntpt(name) 554 const char *name; 555{ 556 struct statfs *mntbuf; 557 int i, mntsize; 558 559 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 560 for (i = mntsize - 1; i >= 0; i--) { 561 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 562 strcmp(mntbuf[i].f_mntonname, name) == 0) 563 return (&mntbuf[i]); 564 } 565 return (NULL); 566} 567 568char * 569catopt(s0, s1) 570 char *s0; 571 const char *s1; 572{ 573 size_t i; 574 char *cp; 575 576 if (s1 == NULL || *s1 == '\0') 577 return s0; 578 579 if (s0 && *s0) { 580 i = strlen(s0) + strlen(s1) + 1 + 1; 581 if ((cp = malloc(i)) == NULL) 582 errx(1, "malloc failed"); 583 (void)snprintf(cp, i, "%s,%s", s0, s1); 584 } else 585 cp = strdup(s1); 586 587 if (s0) 588 free(s0); 589 return (cp); 590} 591 592void 593mangle(options, argcp, argv) 594 char *options; 595 int *argcp; 596 const char **argv; 597{ 598 char *p, *s; 599 int argc; 600 601 argc = *argcp; 602 for (s = options; (p = strsep(&s, ",")) != NULL;) 603 if (*p != '\0') { 604 if (*p == '-') { 605 argv[argc++] = p; 606 p = strchr(p, '='); 607 if (p) { 608 *p = '\0'; 609 argv[argc++] = p+1; 610 } 611 } else if (strcmp(p, "rw") != 0) { 612 argv[argc++] = "-o"; 613 argv[argc++] = p; 614 } 615 } 616 617 *argcp = argc; 618} 619 620 621char * 622update_options(opts, fstab, curflags) 623 char *opts; 624 char *fstab; 625 int curflags; 626{ 627 char *o, *p; 628 char *cur; 629 char *expopt, *newopt, *tmpopt; 630 631 if (opts == NULL) 632 return strdup(""); 633 634 /* remove meta options from list */ 635 remopt(fstab, MOUNT_META_OPTION_FSTAB); 636 remopt(fstab, MOUNT_META_OPTION_CURRENT); 637 cur = flags2opts(curflags); 638 639 /* 640 * Expand all meta-options passed to us first. 641 */ 642 expopt = NULL; 643 for (p = opts; (o = strsep(&p, ",")) != NULL;) { 644 if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 645 expopt = catopt(expopt, fstab); 646 else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 647 expopt = catopt(expopt, cur); 648 else 649 expopt = catopt(expopt, o); 650 } 651 free(cur); 652 free(opts); 653 654 /* 655 * Remove previous contradictory arguments. Given option "foo" we 656 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 657 * and "foo" - so we can deal with possible options like "notice". 658 */ 659 newopt = NULL; 660 for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 661 if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 662 errx(1, "malloc failed"); 663 664 strcpy(tmpopt, "no"); 665 strcat(tmpopt, o); 666 remopt(newopt, tmpopt); 667 free(tmpopt); 668 669 if (strncmp("no", o, 2) == 0) 670 remopt(newopt, o+2); 671 672 newopt = catopt(newopt, o); 673 } 674 free(expopt); 675 676 return newopt; 677} 678 679void 680remopt(string, opt) 681 char *string; 682 const char *opt; 683{ 684 char *o, *p, *r; 685 686 if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 687 return; 688 689 r = string; 690 691 for (p = string; (o = strsep(&p, ",")) != NULL;) { 692 if (strcmp(opt, o) != 0) { 693 if (*r == ',' && *o != '\0') 694 r++; 695 while ((*r++ = *o++) != '\0') 696 ; 697 *--r = ','; 698 } 699 } 700 *r = '\0'; 701} 702 703void 704usage() 705{ 706 707 (void)fprintf(stderr, "%s\n%s\n%s\n", 708"usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node", 709" mount [-adfpruvw] [-t ufs | external_type]", 710" mount [-dfpruvw] special | node"); 711 exit(1); 712} 713 714void 715putfsent(ent) 716 const struct statfs *ent; 717{ 718 struct fstab *fst; 719 char *opts; 720 721 opts = flags2opts(ent->f_flags); 722 printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname, 723 ent->f_fstypename, opts); 724 free(opts); 725 726 if ((fst = getfsspec(ent->f_mntfromname))) 727 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 728 else if ((fst = getfsfile(ent->f_mntonname))) 729 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 730 else if (strcmp(ent->f_fstypename, "ufs") == 0) { 731 if (strcmp(ent->f_mntonname, "/") == 0) 732 printf("\t1 1\n"); 733 else 734 printf("\t2 2\n"); 735 } else 736 printf("\t0 0\n"); 737} 738 739 740char * 741flags2opts(flags) 742 int flags; 743{ 744 char *res; 745 746 res = NULL; 747 748 res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); 749 750 if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 751 if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 752 if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 753 if (flags & MNT_NODEV) res = catopt(res, "nodev"); 754 if (flags & MNT_UNION) res = catopt(res, "union"); 755 if (flags & MNT_ASYNC) res = catopt(res, "async"); 756 if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 757 if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 758 if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 759 if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 760 if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 761 762 return res; 763} 764