mount.c revision 128073
1/*- 2 * Copyright (c) 1980, 1989, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#ifndef lint 31static const char copyright[] = 32"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 33 The Regents of the University of California. All rights reserved.\n"; 34#endif /* not lint */ 35 36#ifndef lint 37#if 0 38static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 39#endif 40static const char rcsid[] = 41 "$FreeBSD: head/sbin/mount/mount.c 128073 2004-04-09 19:58:40Z markm $"; 42#endif /* not lint */ 43 44#include <sys/param.h> 45#include <sys/mount.h> 46#include <sys/stat.h> 47#include <sys/wait.h> 48 49#include <ufs/ufs/ufsmount.h> 50#include <ufs/ufs/dinode.h> 51#include <ufs/ffs/fs.h> 52 53#include <ctype.h> 54#include <err.h> 55#include <errno.h> 56#include <fstab.h> 57#include <paths.h> 58#include <pwd.h> 59#include <signal.h> 60#include <stdint.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <string.h> 64#include <unistd.h> 65#include <libufs.h> 66 67#include "extern.h" 68#include "mntopts.h" 69#include "pathnames.h" 70 71/* `meta' options */ 72#define MOUNT_META_OPTION_FSTAB "fstab" 73#define MOUNT_META_OPTION_CURRENT "current" 74 75int debug, fstab_style, verbose; 76 77char *catopt(char *, const char *); 78struct statfs *getmntpt(const char *); 79int hasopt(const char *, const char *); 80int ismounted(struct fstab *, struct statfs *, int); 81int isremountable(const char *); 82void mangle(char *, int *, const char **); 83char *update_options(char *, char *, int); 84int mountfs(const char *, const char *, const char *, 85 int, const char *, const char *); 86void remopt(char *, const char *); 87void prmount(struct statfs *); 88void putfsent(const struct statfs *); 89void usage(void); 90char *flags2opts(int); 91 92/* Map from mount options to printable formats. */ 93static struct opt { 94 int o_opt; 95 const char *o_name; 96} optnames[] = { 97 { MNT_ASYNC, "asynchronous" }, 98 { MNT_EXPORTED, "NFS exported" }, 99 { MNT_LOCAL, "local" }, 100 { MNT_NOATIME, "noatime" }, 101 { MNT_NODEV, "nodev" }, 102 { MNT_NOEXEC, "noexec" }, 103 { MNT_NOSUID, "nosuid" }, 104 { MNT_NOSYMFOLLOW, "nosymfollow" }, 105 { MNT_QUOTA, "with quotas" }, 106 { MNT_RDONLY, "read-only" }, 107 { MNT_SYNCHRONOUS, "synchronous" }, 108 { MNT_UNION, "union" }, 109 { MNT_NOCLUSTERR, "noclusterr" }, 110 { MNT_NOCLUSTERW, "noclusterw" }, 111 { MNT_SUIDDIR, "suiddir" }, 112 { MNT_SOFTDEP, "soft-updates" }, 113 { MNT_MULTILABEL, "multilabel" }, 114 { MNT_ACLS, "acls" }, 115 { 0, NULL } 116}; 117 118/* 119 * List of VFS types that can be remounted without becoming mounted on top 120 * of each other. 121 * XXX Is this list correct? 122 */ 123static const char * 124remountable_fs_names[] = { 125 "ufs", "ffs", "ext2fs", 126 0 127}; 128 129int 130main(argc, argv) 131 int argc; 132 char * const argv[]; 133{ 134 const char *mntfromname, **vfslist, *vfstype; 135 struct fstab *fs; 136 struct statfs *mntbuf; 137 FILE *mountdfp; 138 pid_t pid; 139 int all, ch, i, init_flags, mntsize, rval, have_fstab; 140 char *cp, *ep, *options; 141 142 all = init_flags = 0; 143 options = NULL; 144 vfslist = NULL; 145 vfstype = "ufs"; 146 while ((ch = getopt(argc, argv, "adF:fo:prwt:uv")) != -1) 147 switch (ch) { 148 case 'a': 149 all = 1; 150 break; 151 case 'd': 152 debug = 1; 153 break; 154 case 'F': 155 setfstab(optarg); 156 break; 157 case 'f': 158 init_flags |= MNT_FORCE; 159 break; 160 case 'o': 161 if (*optarg) 162 options = catopt(options, optarg); 163 break; 164 case 'p': 165 fstab_style = 1; 166 verbose = 1; 167 break; 168 case 'r': 169 options = catopt(options, "ro"); 170 break; 171 case 't': 172 if (vfslist != NULL) 173 errx(1, "only one -t option may be specified"); 174 vfslist = makevfslist(optarg); 175 vfstype = optarg; 176 break; 177 case 'u': 178 init_flags |= MNT_UPDATE; 179 break; 180 case 'v': 181 verbose = 1; 182 break; 183 case 'w': 184 options = catopt(options, "noro"); 185 break; 186 case '?': 187 default: 188 usage(); 189 /* NOTREACHED */ 190 } 191 argc -= optind; 192 argv += optind; 193 194#define BADTYPE(type) \ 195 (strcmp(type, FSTAB_RO) && \ 196 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 197 198 rval = 0; 199 switch (argc) { 200 case 0: 201 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 202 err(1, "getmntinfo"); 203 if (all) { 204 while ((fs = getfsent()) != NULL) { 205 if (BADTYPE(fs->fs_type)) 206 continue; 207 if (checkvfsname(fs->fs_vfstype, vfslist)) 208 continue; 209 if (hasopt(fs->fs_mntops, "noauto")) 210 continue; 211 if (!(init_flags & MNT_UPDATE) && 212 ismounted(fs, mntbuf, mntsize)) 213 continue; 214 options = update_options(options, fs->fs_mntops, 215 mntbuf->f_flags); 216 if (mountfs(fs->fs_vfstype, fs->fs_spec, 217 fs->fs_file, init_flags, options, 218 fs->fs_mntops)) 219 rval = 1; 220 } 221 } else if (fstab_style) { 222 for (i = 0; i < mntsize; i++) { 223 if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 224 continue; 225 putfsent(&mntbuf[i]); 226 } 227 } else { 228 for (i = 0; i < mntsize; i++) { 229 if (checkvfsname(mntbuf[i].f_fstypename, 230 vfslist)) 231 continue; 232 prmount(&mntbuf[i]); 233 } 234 } 235 exit(rval); 236 case 1: 237 if (vfslist != NULL) 238 usage(); 239 240 rmslashes(*argv, *argv); 241 if (init_flags & MNT_UPDATE) { 242 mntfromname = NULL; 243 have_fstab = 0; 244 if ((mntbuf = getmntpt(*argv)) == NULL) 245 errx(1, "not currently mounted %s", *argv); 246 /* 247 * Only get the mntflags from fstab if both mntpoint 248 * and mntspec are identical. Also handle the special 249 * case where just '/' is mounted and 'spec' is not 250 * identical with the one from fstab ('/dev' is missing 251 * in the spec-string at boot-time). 252 */ 253 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 254 if (strcmp(fs->fs_spec, 255 mntbuf->f_mntfromname) == 0 && 256 strcmp(fs->fs_file, 257 mntbuf->f_mntonname) == 0) { 258 have_fstab = 1; 259 mntfromname = mntbuf->f_mntfromname; 260 } else if (argv[0][0] == '/' && 261 argv[0][1] == '\0') { 262 fs = getfsfile("/"); 263 have_fstab = 1; 264 mntfromname = fs->fs_spec; 265 } 266 } 267 if (have_fstab) { 268 options = update_options(options, fs->fs_mntops, 269 mntbuf->f_flags); 270 } else { 271 mntfromname = mntbuf->f_mntfromname; 272 options = update_options(options, NULL, 273 mntbuf->f_flags); 274 } 275 rval = mountfs(mntbuf->f_fstypename, mntfromname, 276 mntbuf->f_mntonname, init_flags, options, 0); 277 break; 278 } 279 if ((fs = getfsfile(*argv)) == NULL && 280 (fs = getfsspec(*argv)) == NULL) 281 errx(1, "%s: unknown special file or file system", 282 *argv); 283 if (BADTYPE(fs->fs_type)) 284 errx(1, "%s has unknown file system type", 285 *argv); 286 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 287 init_flags, options, fs->fs_mntops); 288 break; 289 case 2: 290 /* 291 * If -t flag has not been specified, the path cannot be 292 * found, spec contains either a ':' or a '@', then assume 293 * that an NFS file system is being specified ala Sun. 294 * Check if the hostname contains only allowed characters 295 * to reduce false positives. IPv6 addresses containing 296 * ':' will be correctly parsed only if the separator is '@'. 297 * The definition of a valid hostname is taken from RFC 1034. 298 */ 299 if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL || 300 (ep = strchr(argv[0], ':')) != NULL)) { 301 if (*ep == '@') { 302 cp = ep + 1; 303 ep = cp + strlen(cp); 304 } else 305 cp = argv[0]; 306 while (cp != ep) { 307 if (!isdigit(*cp) && !isalpha(*cp) && 308 *cp != '.' && *cp != '-' && *cp != ':') 309 break; 310 cp++; 311 } 312 if (cp == ep) 313 vfstype = "nfs"; 314 } 315 rval = mountfs(vfstype, 316 argv[0], argv[1], init_flags, options, NULL); 317 break; 318 default: 319 usage(); 320 /* NOTREACHED */ 321 } 322 323 /* 324 * If the mount was successfully, and done by root, tell mountd the 325 * good news. Pid checks are probably unnecessary, but don't hurt. 326 */ 327 if (rval == 0 && getuid() == 0 && 328 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 329 if (fscanf(mountdfp, "%d", &pid) == 1 && 330 pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 331 err(1, "signal mountd"); 332 (void)fclose(mountdfp); 333 } 334 335 exit(rval); 336} 337 338int 339ismounted(fs, mntbuf, mntsize) 340 struct fstab *fs; 341 struct statfs *mntbuf; 342 int mntsize; 343{ 344 int i; 345 346 if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 347 /* the root file system can always be remounted */ 348 return (0); 349 350 for (i = mntsize - 1; i >= 0; --i) 351 if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 && 352 (!isremountable(fs->fs_vfstype) || 353 strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0)) 354 return (1); 355 return (0); 356} 357 358int 359isremountable(vfsname) 360 const char *vfsname; 361{ 362 const char **cp; 363 364 for (cp = remountable_fs_names; *cp; cp++) 365 if (strcmp(*cp, vfsname) == 0) 366 return (1); 367 return (0); 368} 369 370int 371hasopt(mntopts, option) 372 const char *mntopts, *option; 373{ 374 int negative, found; 375 char *opt, *optbuf; 376 377 if (option[0] == 'n' && option[1] == 'o') { 378 negative = 1; 379 option += 2; 380 } else 381 negative = 0; 382 optbuf = strdup(mntopts); 383 found = 0; 384 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 385 if (opt[0] == 'n' && opt[1] == 'o') { 386 if (!strcasecmp(opt + 2, option)) 387 found = negative; 388 } else if (!strcasecmp(opt, option)) 389 found = !negative; 390 } 391 free(optbuf); 392 return (found); 393} 394 395int 396mountfs(vfstype, spec, name, flags, options, mntopts) 397 const char *vfstype, *spec, *name, *options, *mntopts; 398 int flags; 399{ 400 const char *argv[100]; 401 struct statfs sf; 402 pid_t pid; 403 int argc, i, status; 404 char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX]; 405 406#if __GNUC__ 407 (void)&optbuf; 408 (void)&name; 409#endif 410 411 /* resolve the mountpoint with realpath(3) */ 412 (void)checkpath(name, mntpath); 413 name = mntpath; 414 415 if (mntopts == NULL) 416 mntopts = ""; 417 if (options == NULL) { 418 if (*mntopts == '\0') { 419 options = "rw"; 420 } else { 421 options = mntopts; 422 mntopts = ""; 423 } 424 } 425 optbuf = catopt(strdup(mntopts), options); 426 427 if (strcmp(name, "/") == 0) 428 flags |= MNT_UPDATE; 429 if (flags & MNT_FORCE) 430 optbuf = catopt(optbuf, "force"); 431 if (flags & MNT_RDONLY) 432 optbuf = catopt(optbuf, "ro"); 433 /* 434 * XXX 435 * The mount_mfs (newfs) command uses -o to select the 436 * optimization mode. We don't pass the default "-o rw" 437 * for that reason. 438 */ 439 if (flags & MNT_UPDATE) 440 optbuf = catopt(optbuf, "update"); 441 442 /* Compatibility glue. */ 443 if (strcmp(vfstype, "msdos") == 0) 444 vfstype = "msdosfs"; 445 446 argc = 0; 447 argv[argc++] = vfstype; 448 mangle(optbuf, &argc, argv); 449 argv[argc++] = spec; 450 argv[argc++] = name; 451 argv[argc] = NULL; 452 453 if (debug) { 454 (void)printf("exec: mount_%s", vfstype); 455 for (i = 1; i < argc; i++) 456 (void)printf(" %s", argv[i]); 457 (void)printf("\n"); 458 return (0); 459 } 460 461 switch (pid = fork()) { 462 case -1: /* Error. */ 463 warn("fork"); 464 free(optbuf); 465 return (1); 466 case 0: /* Child. */ 467 if (strcmp(vfstype, "ufs") == 0) 468 exit(mount_ufs(argc, (char * const *) argv)); 469 470 /* Go find an executable. */ 471 (void)snprintf(execname, sizeof(execname), "mount_%s", vfstype); 472 execvP(execname, _PATH_SYSPATH, (char * const *)argv); 473 if (errno == ENOENT) { 474 warn("exec mount_%s not found in %s", vfstype, 475 _PATH_SYSPATH); 476 } 477 exit(1); 478 /* NOTREACHED */ 479 default: /* Parent. */ 480 free(optbuf); 481 482 if (waitpid(pid, &status, 0) < 0) { 483 warn("waitpid"); 484 return (1); 485 } 486 487 if (WIFEXITED(status)) { 488 if (WEXITSTATUS(status) != 0) 489 return (WEXITSTATUS(status)); 490 } else if (WIFSIGNALED(status)) { 491 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 492 return (1); 493 } 494 495 if (verbose) { 496 if (statfs(name, &sf) < 0) { 497 warn("statfs %s", name); 498 return (1); 499 } 500 if (fstab_style) 501 putfsent(&sf); 502 else 503 prmount(&sf); 504 } 505 break; 506 } 507 508 return (0); 509} 510 511void 512prmount(sfp) 513 struct statfs *sfp; 514{ 515 int flags, i; 516 struct opt *o; 517 struct passwd *pw; 518 struct uufsd disk; 519 520 (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, 521 sfp->f_fstypename); 522 523 if (strncmp(sfp->f_fstypename, "ufs", 3) == 0) { 524 ufs_disk_fillout(&disk, sfp->f_mntonname); 525 printf("%s", (disk.d_ufs == 2) ? "2" : ""); 526 } 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 /* 535 * Inform when file system is mounted by an unprivileged user 536 * or privileged non-root user. 537 */ 538 if ((flags & MNT_USER) != 0 || sfp->f_owner != 0) { 539 (void)printf(", mounted by "); 540 if ((pw = getpwuid(sfp->f_owner)) != NULL) 541 (void)printf("%s", pw->pw_name); 542 else 543 (void)printf("%d", sfp->f_owner); 544 } 545 if (verbose) { 546 if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 547 (void)printf(", writes: sync %ju async %ju", 548 (uintmax_t)sfp->f_syncwrites, 549 (uintmax_t)sfp->f_asyncwrites); 550 if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0) 551 (void)printf(", reads: sync %ju async %ju", 552 (uintmax_t)sfp->f_syncreads, 553 (uintmax_t)sfp->f_asyncreads); 554 if (sfp->f_fsid.val[0] != 0 || sfp->f_fsid.val[1] != 0) { 555 printf(", fsid "); 556 for (i = 0; i < sizeof(sfp->f_fsid); i++) 557 printf("%02x", ((u_char *)&sfp->f_fsid)[i]); 558 } 559 } 560 (void)printf(")\n"); 561} 562 563struct statfs * 564getmntpt(name) 565 const char *name; 566{ 567 struct statfs *mntbuf; 568 int i, mntsize; 569 570 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 571 for (i = mntsize - 1; i >= 0; i--) { 572 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 573 strcmp(mntbuf[i].f_mntonname, name) == 0) 574 return (&mntbuf[i]); 575 } 576 return (NULL); 577} 578 579char * 580catopt(s0, s1) 581 char *s0; 582 const char *s1; 583{ 584 size_t i; 585 char *cp; 586 587 if (s1 == NULL || *s1 == '\0') 588 return s0; 589 590 if (s0 && *s0) { 591 i = strlen(s0) + strlen(s1) + 1 + 1; 592 if ((cp = malloc(i)) == NULL) 593 errx(1, "malloc failed"); 594 (void)snprintf(cp, i, "%s,%s", s0, s1); 595 } else 596 cp = strdup(s1); 597 598 if (s0) 599 free(s0); 600 return (cp); 601} 602 603void 604mangle(options, argcp, argv) 605 char *options; 606 int *argcp; 607 const char **argv; 608{ 609 char *p, *s; 610 int argc; 611 612 argc = *argcp; 613 for (s = options; (p = strsep(&s, ",")) != NULL;) 614 if (*p != '\0') { 615 if (*p == '-') { 616 argv[argc++] = p; 617 p = strchr(p, '='); 618 if (p != NULL) { 619 *p = '\0'; 620 argv[argc++] = p+1; 621 } 622 } else if (strcmp(p, "rw") != 0) { 623 argv[argc++] = "-o"; 624 argv[argc++] = p; 625 } 626 } 627 628 *argcp = argc; 629} 630 631 632char * 633update_options(opts, fstab, curflags) 634 char *opts; 635 char *fstab; 636 int curflags; 637{ 638 char *o, *p; 639 char *cur; 640 char *expopt, *newopt, *tmpopt; 641 642 if (opts == NULL) 643 return strdup(""); 644 645 /* remove meta options from list */ 646 remopt(fstab, MOUNT_META_OPTION_FSTAB); 647 remopt(fstab, MOUNT_META_OPTION_CURRENT); 648 cur = flags2opts(curflags); 649 650 /* 651 * Expand all meta-options passed to us first. 652 */ 653 expopt = NULL; 654 for (p = opts; (o = strsep(&p, ",")) != NULL;) { 655 if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 656 expopt = catopt(expopt, fstab); 657 else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 658 expopt = catopt(expopt, cur); 659 else 660 expopt = catopt(expopt, o); 661 } 662 free(cur); 663 free(opts); 664 665 /* 666 * Remove previous contradictory arguments. Given option "foo" we 667 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 668 * and "foo" - so we can deal with possible options like "notice". 669 */ 670 newopt = NULL; 671 for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 672 if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 673 errx(1, "malloc failed"); 674 675 strcpy(tmpopt, "no"); 676 strcat(tmpopt, o); 677 remopt(newopt, tmpopt); 678 free(tmpopt); 679 680 if (strncmp("no", o, 2) == 0) 681 remopt(newopt, o+2); 682 683 newopt = catopt(newopt, o); 684 } 685 free(expopt); 686 687 return newopt; 688} 689 690void 691remopt(string, opt) 692 char *string; 693 const char *opt; 694{ 695 char *o, *p, *r; 696 697 if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 698 return; 699 700 r = string; 701 702 for (p = string; (o = strsep(&p, ",")) != NULL;) { 703 if (strcmp(opt, o) != 0) { 704 if (*r == ',' && *o != '\0') 705 r++; 706 while ((*r++ = *o++) != '\0') 707 ; 708 *--r = ','; 709 } 710 } 711 *r = '\0'; 712} 713 714void 715usage() 716{ 717 718 (void)fprintf(stderr, "%s\n%s\n%s\n", 719"usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node", 720" mount [-adfpruvw] [ -F fstab] [-o options] [-t ufs | external_type]", 721" mount [-dfpruvw] special | node"); 722 exit(1); 723} 724 725void 726putfsent(ent) 727 const struct statfs *ent; 728{ 729 struct fstab *fst; 730 char *opts; 731 732 opts = flags2opts(ent->f_flags); 733 printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname, 734 ent->f_fstypename, opts); 735 free(opts); 736 737 if ((fst = getfsspec(ent->f_mntfromname))) 738 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 739 else if ((fst = getfsfile(ent->f_mntonname))) 740 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 741 else if (strcmp(ent->f_fstypename, "ufs") == 0) { 742 if (strcmp(ent->f_mntonname, "/") == 0) 743 printf("\t1 1\n"); 744 else 745 printf("\t2 2\n"); 746 } else 747 printf("\t0 0\n"); 748} 749 750 751char * 752flags2opts(flags) 753 int flags; 754{ 755 char *res; 756 757 res = NULL; 758 759 res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); 760 761 if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 762 if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 763 if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 764 if (flags & MNT_NODEV) res = catopt(res, "nodev"); 765 if (flags & MNT_UNION) res = catopt(res, "union"); 766 if (flags & MNT_ASYNC) res = catopt(res, "async"); 767 if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 768 if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 769 if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 770 if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 771 if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 772 if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel"); 773 if (flags & MNT_ACLS) res = catopt(res, "acls"); 774 775 return res; 776} 777