mount.c revision 77577
1214501Srpaulo/*- 2214501Srpaulo * Copyright (c) 1980, 1989, 1993, 1994 3337817Scy * The Regents of the University of California. All rights reserved. 4214501Srpaulo * 5252726Srpaulo * Redistribution and use in source and binary forms, with or without 6252726Srpaulo * modification, are permitted provided that the following conditions 7214501Srpaulo * are met: 8214501Srpaulo * 1. Redistributions of source code must retain the above copyright 9214501Srpaulo * notice, this list of conditions and the following disclaimer. 10214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11214501Srpaulo * notice, this list of conditions and the following disclaimer in the 12214501Srpaulo * documentation and/or other materials provided with the distribution. 13214501Srpaulo * 3. All advertising materials mentioning features or use of this software 14214501Srpaulo * must display the following acknowledgement: 15214501Srpaulo * This product includes software developed by the University of 16214501Srpaulo * California, Berkeley and its contributors. 17214501Srpaulo * 4. Neither the name of the University nor the names of its contributors 18214501Srpaulo * may be used to endorse or promote products derived from this software 19214501Srpaulo * without specific prior written permission. 20214501Srpaulo * 21214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22252726Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25252726Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31214501Srpaulo * SUCH DAMAGE. 32214501Srpaulo */ 33214501Srpaulo 34214501Srpaulo#ifndef lint 35214501Srpaulostatic const char copyright[] = 36214501Srpaulo"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 37214501Srpaulo The Regents of the University of California. All rights reserved.\n"; 38252726Srpaulo#endif /* not lint */ 39252726Srpaulo 40252726Srpaulo#ifndef lint 41252726Srpaulo#if 0 42214501Srpaulostatic char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 43281806Srpaulo#endif 44214501Srpaulostatic const char rcsid[] = 45214501Srpaulo "$FreeBSD: head/sbin/mount/mount.c 77577 2001-06-01 10:57:26Z ru $"; 46252726Srpaulo#endif /* not lint */ 47252726Srpaulo 48252726Srpaulo#include <sys/param.h> 49281806Srpaulo#include <sys/mount.h> 50252726Srpaulo#include <sys/stat.h> 51252726Srpaulo#include <sys/wait.h> 52252726Srpaulo 53252726Srpaulo#include <err.h> 54252726Srpaulo#include <errno.h> 55252726Srpaulo#include <fstab.h> 56252726Srpaulo#include <pwd.h> 57252726Srpaulo#include <signal.h> 58252726Srpaulo#include <stdio.h> 59252726Srpaulo#include <stdlib.h> 60252726Srpaulo#include <string.h> 61252726Srpaulo#include <unistd.h> 62281806Srpaulo 63281806Srpaulo#include "extern.h" 64281806Srpaulo#include "mntopts.h" 65281806Srpaulo#include "pathnames.h" 66281806Srpaulo 67281806Srpaulo/* `meta' options */ 68281806Srpaulo#define MOUNT_META_OPTION_FSTAB "fstab" 69281806Srpaulo#define MOUNT_META_OPTION_CURRENT "current" 70252726Srpaulo 71252726Srpauloint debug, fstab_style, verbose; 72252726Srpaulo 73252726Srpaulochar *catopt __P((char *, const char *)); 74252726Srpaulostruct statfs 75252726Srpaulo *getmntpt __P((const char *)); 76252726Srpauloint hasopt __P((const char *, const char *)); 77252726Srpauloint ismounted __P((struct fstab *, struct statfs *, int)); 78252726Srpauloint isremountable __P((const char *)); 79252726Srpaulovoid mangle __P((char *, int *, const char **)); 80252726Srpaulochar *update_options __P((char *, char *, int)); 81252726Srpauloint mountfs __P((const char *, const char *, const char *, 82252726Srpaulo int, const char *, const char *)); 83252726Srpaulovoid remopt __P((char *, const char *)); 84252726Srpaulovoid prmount __P((struct statfs *)); 85252726Srpaulovoid putfsent __P((const struct statfs *)); 86281806Srpaulovoid usage __P((void)); 87252726Srpaulochar *flags2opts __P((int)); 88252726Srpaulo 89252726Srpaulo/* Map from mount options to printable formats. */ 90252726Srpaulostatic struct opt { 91252726Srpaulo int o_opt; 92252726Srpaulo const char *o_name; 93252726Srpaulo} optnames[] = { 94252726Srpaulo { MNT_ASYNC, "asynchronous" }, 95281806Srpaulo { MNT_EXPORTED, "NFS exported" }, 96281806Srpaulo { MNT_LOCAL, "local" }, 97214501Srpaulo { MNT_NOATIME, "noatime" }, 98214501Srpaulo { MNT_NODEV, "nodev" }, 99214501Srpaulo { MNT_NOEXEC, "noexec" }, 100214501Srpaulo { MNT_NOSUID, "nosuid" }, 101214501Srpaulo { MNT_NOSYMFOLLOW, "nosymfollow" }, 102214501Srpaulo { MNT_QUOTA, "with quotas" }, 103281806Srpaulo { MNT_RDONLY, "read-only" }, 104281806Srpaulo { MNT_SYNCHRONOUS, "synchronous" }, 105281806Srpaulo { MNT_UNION, "union" }, 106281806Srpaulo { MNT_NOCLUSTERR, "noclusterr" }, 107281806Srpaulo { MNT_NOCLUSTERW, "noclusterw" }, 108281806Srpaulo { MNT_SUIDDIR, "suiddir" }, 109281806Srpaulo { MNT_SOFTDEP, "soft-updates" }, 110281806Srpaulo { 0, NULL } 111281806Srpaulo}; 112281806Srpaulo 113214501Srpaulo/* 114214501Srpaulo * List of VFS types that can be remounted without becoming mounted on top 115214501Srpaulo * of each other. 116214501Srpaulo * XXX Is this list correct? 117214501Srpaulo */ 118214501Srpaulostatic const char * 119214501Srpauloremountable_fs_names[] = { 120214501Srpaulo "ufs", "ffs", "ext2fs", 121214501Srpaulo 0 122214501Srpaulo}; 123214501Srpaulo 124214501Srpauloint 125214501Srpaulomain(argc, argv) 126281806Srpaulo int argc; 127214501Srpaulo char * const argv[]; 128214501Srpaulo{ 129281806Srpaulo const char *mntfromname, **vfslist, *vfstype; 130281806Srpaulo struct fstab *fs; 131281806Srpaulo struct statfs *mntbuf; 132281806Srpaulo FILE *mountdfp; 133281806Srpaulo pid_t pid; 134214501Srpaulo int all, ch, i, init_flags, mntsize, rval, have_fstab; 135214501Srpaulo char *options; 136214501Srpaulo 137214501Srpaulo all = init_flags = 0; 138214501Srpaulo options = NULL; 139214501Srpaulo vfslist = NULL; 140214501Srpaulo vfstype = "ufs"; 141214501Srpaulo while ((ch = getopt(argc, argv, "adfo:prwt:uv")) != -1) 142214501Srpaulo switch (ch) { 143214501Srpaulo case 'a': 144214501Srpaulo all = 1; 145214501Srpaulo break; 146214501Srpaulo case 'd': 147214501Srpaulo debug = 1; 148214501Srpaulo break; 149214501Srpaulo case 'f': 150214501Srpaulo init_flags |= MNT_FORCE; 151214501Srpaulo break; 152214501Srpaulo case 'o': 153214501Srpaulo if (*optarg) 154214501Srpaulo options = catopt(options, optarg); 155214501Srpaulo break; 156214501Srpaulo case 'p': 157214501Srpaulo fstab_style = 1; 158214501Srpaulo verbose = 1; 159214501Srpaulo break; 160214501Srpaulo case 'r': 161214501Srpaulo options = catopt(options, "ro"); 162214501Srpaulo break; 163214501Srpaulo case 't': 164214501Srpaulo if (vfslist != NULL) 165252726Srpaulo errx(1, "only one -t option may be specified"); 166252726Srpaulo vfslist = makevfslist(optarg); 167252726Srpaulo vfstype = optarg; 168214501Srpaulo break; 169214501Srpaulo case 'u': 170214501Srpaulo init_flags |= MNT_UPDATE; 171214501Srpaulo break; 172214501Srpaulo case 'v': 173214501Srpaulo verbose = 1; 174214501Srpaulo break; 175214501Srpaulo case 'w': 176214501Srpaulo options = catopt(options, "noro"); 177214501Srpaulo break; 178214501Srpaulo case '?': 179214501Srpaulo default: 180214501Srpaulo usage(); 181214501Srpaulo /* NOTREACHED */ 182214501Srpaulo } 183214501Srpaulo argc -= optind; 184214501Srpaulo argv += optind; 185214501Srpaulo 186214501Srpaulo#define BADTYPE(type) \ 187214501Srpaulo (strcmp(type, FSTAB_RO) && \ 188281806Srpaulo strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 189214501Srpaulo 190214501Srpaulo rval = 0; 191214501Srpaulo switch (argc) { 192214501Srpaulo case 0: 193214501Srpaulo if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 194214501Srpaulo err(1, "getmntinfo"); 195214501Srpaulo if (all) { 196214501Srpaulo while ((fs = getfsent()) != NULL) { 197214501Srpaulo if (BADTYPE(fs->fs_type)) 198214501Srpaulo continue; 199214501Srpaulo if (checkvfsname(fs->fs_vfstype, vfslist)) 200214501Srpaulo continue; 201214501Srpaulo if (hasopt(fs->fs_mntops, "noauto")) 202214501Srpaulo continue; 203214501Srpaulo if (!(init_flags & MNT_UPDATE) && 204214501Srpaulo ismounted(fs, mntbuf, mntsize)) 205214501Srpaulo continue; 206214501Srpaulo if (mountfs(fs->fs_vfstype, fs->fs_spec, 207214501Srpaulo fs->fs_file, init_flags, options, 208214501Srpaulo fs->fs_mntops)) 209214501Srpaulo rval = 1; 210252726Srpaulo } 211252726Srpaulo } else if (fstab_style) { 212252726Srpaulo for (i = 0; i < mntsize; i++) { 213252726Srpaulo if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 214252726Srpaulo continue; 215252726Srpaulo putfsent(&mntbuf[i]); 216252726Srpaulo } 217252726Srpaulo } else { 218252726Srpaulo for (i = 0; i < mntsize; i++) { 219252726Srpaulo if (checkvfsname(mntbuf[i].f_fstypename, 220252726Srpaulo vfslist)) 221252726Srpaulo continue; 222252726Srpaulo prmount(&mntbuf[i]); 223252726Srpaulo } 224252726Srpaulo } 225252726Srpaulo exit(rval); 226252726Srpaulo case 1: 227214501Srpaulo if (vfslist != NULL) 228252726Srpaulo usage(); 229252726Srpaulo 230214501Srpaulo if (init_flags & MNT_UPDATE) { 231214501Srpaulo mntfromname = NULL; 232214501Srpaulo have_fstab = 0; 233252726Srpaulo if ((mntbuf = getmntpt(*argv)) == NULL) 234214501Srpaulo errx(1, "not currently mounted %s", *argv); 235214501Srpaulo /* 236214501Srpaulo * Only get the mntflags from fstab if both mntpoint 237214501Srpaulo * and mntspec are identical. Also handle the special 238214501Srpaulo * case where just '/' is mounted and 'spec' is not 239214501Srpaulo * identical with the one from fstab ('/dev' is missing 240214501Srpaulo * in the spec-string at boot-time). 241252726Srpaulo */ 242252726Srpaulo if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 243252726Srpaulo if (strcmp(fs->fs_spec, 244252726Srpaulo mntbuf->f_mntfromname) == 0 && 245252726Srpaulo strcmp(fs->fs_file, 246214501Srpaulo mntbuf->f_mntonname) == 0) { 247214501Srpaulo have_fstab = 1; 248214501Srpaulo mntfromname = mntbuf->f_mntfromname; 249214501Srpaulo } else if (argv[0][0] == '/' && 250214501Srpaulo argv[0][1] == '\0') { 251214501Srpaulo fs = getfsfile("/"); 252214501Srpaulo have_fstab = 1; 253214501Srpaulo mntfromname = fs->fs_spec; 254214501Srpaulo } 255214501Srpaulo } 256214501Srpaulo if (have_fstab) { 257214501Srpaulo options = update_options(options, fs->fs_mntops, 258214501Srpaulo mntbuf->f_flags); 259214501Srpaulo } else { 260214501Srpaulo mntfromname = mntbuf->f_mntfromname; 261214501Srpaulo options = update_options(options, NULL, 262214501Srpaulo mntbuf->f_flags); 263214501Srpaulo } 264214501Srpaulo rval = mountfs(mntbuf->f_fstypename, mntfromname, 265214501Srpaulo mntbuf->f_mntonname, init_flags, options, 0); 266214501Srpaulo break; 267214501Srpaulo } 268214501Srpaulo rmslashes(*argv, *argv); 269214501Srpaulo if ((fs = getfsfile(*argv)) == NULL && 270214501Srpaulo (fs = getfsspec(*argv)) == NULL) 271214501Srpaulo errx(1, "%s: unknown special file or file system", 272214501Srpaulo *argv); 273214501Srpaulo if (BADTYPE(fs->fs_type)) 274214501Srpaulo errx(1, "%s has unknown file system type", 275214501Srpaulo *argv); 276214501Srpaulo rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 277252726Srpaulo init_flags, options, fs->fs_mntops); 278252726Srpaulo break; 279214501Srpaulo case 2: 280214501Srpaulo /* 281214501Srpaulo * If -t flag has not been specified, the path cannot be 282214501Srpaulo * found, spec contains either a ':' or a '@', and the 283214501Srpaulo * spec is not a file with those characters, then assume 284214501Srpaulo * that an NFS filesystem is being specified ala Sun. 285281806Srpaulo */ 286281806Srpaulo if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL && 287281806Srpaulo access(argv[0], 0) == -1) 288281806Srpaulo vfstype = "nfs"; 289281806Srpaulo rval = mountfs(vfstype, 290281806Srpaulo argv[0], argv[1], init_flags, options, NULL); 291281806Srpaulo break; 292281806Srpaulo default: 293281806Srpaulo usage(); 294281806Srpaulo /* NOTREACHED */ 295281806Srpaulo } 296281806Srpaulo 297281806Srpaulo /* 298281806Srpaulo * If the mount was successfully, and done by root, tell mountd the 299252726Srpaulo * good news. Pid checks are probably unnecessary, but don't hurt. 300252726Srpaulo */ 301214501Srpaulo if (rval == 0 && getuid() == 0 && 302252726Srpaulo (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 303252726Srpaulo if (fscanf(mountdfp, "%d", &pid) == 1 && 304252726Srpaulo pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 305252726Srpaulo err(1, "signal mountd"); 306252726Srpaulo (void)fclose(mountdfp); 307252726Srpaulo } 308252726Srpaulo 309252726Srpaulo exit(rval); 310252726Srpaulo} 311252726Srpaulo 312252726Srpauloint 313281806Srpauloismounted(fs, mntbuf, mntsize) 314281806Srpaulo struct fstab *fs; 315281806Srpaulo struct statfs *mntbuf; 316281806Srpaulo int mntsize; 317281806Srpaulo{ 318281806Srpaulo int i; 319281806Srpaulo 320281806Srpaulo if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 321289549Srpaulo /* the root file system can always be remounted */ 322281806Srpaulo return (0); 323281806Srpaulo 324281806Srpaulo for (i = mntsize - 1; i >= 0; --i) 325281806Srpaulo if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 && 326281806Srpaulo (!isremountable(fs->fs_vfstype) || 327281806Srpaulo strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0)) 328281806Srpaulo return (1); 329281806Srpaulo return (0); 330281806Srpaulo} 331281806Srpaulo 332281806Srpauloint 333281806Srpauloisremountable(vfsname) 334281806Srpaulo const char *vfsname; 335281806Srpaulo{ 336281806Srpaulo const char **cp; 337281806Srpaulo 338281806Srpaulo for (cp = remountable_fs_names; *cp; cp++) 339281806Srpaulo if (strcmp(*cp, vfsname) == 0) 340281806Srpaulo return (1); 341281806Srpaulo return (0); 342281806Srpaulo} 343281806Srpaulo 344289549Srpauloint 345289549Srpaulohasopt(mntopts, option) 346289549Srpaulo const char *mntopts, *option; 347289549Srpaulo{ 348289549Srpaulo int negative, found; 349289549Srpaulo char *opt, *optbuf; 350281806Srpaulo 351281806Srpaulo if (option[0] == 'n' && option[1] == 'o') { 352281806Srpaulo negative = 1; 353281806Srpaulo option += 2; 354281806Srpaulo } else 355281806Srpaulo negative = 0; 356281806Srpaulo optbuf = strdup(mntopts); 357346981Scy found = 0; 358346981Scy for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 359346981Scy if (opt[0] == 'n' && opt[1] == 'o') { 360346981Scy if (!strcasecmp(opt + 2, option)) 361346981Scy found = negative; 362346981Scy } else if (!strcasecmp(opt, option)) 363346981Scy found = !negative; 364346981Scy } 365346981Scy free(optbuf); 366346981Scy return (found); 367346981Scy} 368346981Scy 369281806Srpauloint 370281806Srpaulomountfs(vfstype, spec, name, flags, options, mntopts) 371281806Srpaulo const char *vfstype, *spec, *name, *options, *mntopts; 372281806Srpaulo int flags; 373281806Srpaulo{ 374281806Srpaulo /* List of directories containing mount_xxx subcommands. */ 375281806Srpaulo static const char *edirs[] = { 376281806Srpaulo _PATH_SBIN, 377281806Srpaulo _PATH_USRSBIN, 378281806Srpaulo NULL 379281806Srpaulo }; 380281806Srpaulo const char *argv[100], **edir; 381281806Srpaulo struct statfs sf; 382281806Srpaulo pid_t pid; 383281806Srpaulo int argc, i, status; 384281806Srpaulo char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN]; 385281806Srpaulo 386281806Srpaulo#if __GNUC__ 387281806Srpaulo (void)&optbuf; 388281806Srpaulo (void)&name; 389281806Srpaulo#endif 390281806Srpaulo 391281806Srpaulo /* resolve the mountpoint with realpath(3) */ 392281806Srpaulo (void)checkpath(name, mntpath); 393281806Srpaulo name = mntpath; 394281806Srpaulo 395281806Srpaulo if (mntopts == NULL) 396281806Srpaulo mntopts = ""; 397281806Srpaulo if (options == NULL) { 398281806Srpaulo if (*mntopts == '\0') { 399281806Srpaulo options = "rw"; 400281806Srpaulo } else { 401281806Srpaulo options = mntopts; 402281806Srpaulo mntopts = ""; 403281806Srpaulo } 404281806Srpaulo } 405281806Srpaulo optbuf = catopt(strdup(mntopts), options); 406281806Srpaulo 407252726Srpaulo if (strcmp(name, "/") == 0) 408252726Srpaulo flags |= MNT_UPDATE; 409252726Srpaulo if (flags & MNT_FORCE) 410214501Srpaulo optbuf = catopt(optbuf, "force"); 411214501Srpaulo if (flags & MNT_RDONLY) 412214501Srpaulo optbuf = catopt(optbuf, "ro"); 413214501Srpaulo /* 414214501Srpaulo * XXX 415214501Srpaulo * The mount_mfs (newfs) command uses -o to select the 416346981Scy * optimization mode. We don't pass the default "-o rw" 417214501Srpaulo * for that reason. 418252726Srpaulo */ 419252726Srpaulo if (flags & MNT_UPDATE) 420252726Srpaulo optbuf = catopt(optbuf, "update"); 421214501Srpaulo 422214501Srpaulo /* Compatibility glue. */ 423214501Srpaulo if (strcmp(vfstype, "msdos") == 0) 424214501Srpaulo vfstype = "msdosfs"; 425214501Srpaulo 426214501Srpaulo argc = 0; 427214501Srpaulo argv[argc++] = vfstype; 428214501Srpaulo mangle(optbuf, &argc, argv); 429214501Srpaulo argv[argc++] = spec; 430214501Srpaulo argv[argc++] = name; 431214501Srpaulo argv[argc] = NULL; 432214501Srpaulo 433214501Srpaulo if (debug) { 434214501Srpaulo (void)printf("exec: mount_%s", vfstype); 435214501Srpaulo for (i = 1; i < argc; i++) 436214501Srpaulo (void)printf(" %s", argv[i]); 437252726Srpaulo (void)printf("\n"); 438252726Srpaulo return (0); 439252726Srpaulo } 440252726Srpaulo 441252726Srpaulo switch (pid = fork()) { 442252726Srpaulo case -1: /* Error. */ 443252726Srpaulo warn("fork"); 444252726Srpaulo free(optbuf); 445252726Srpaulo return (1); 446214501Srpaulo case 0: /* Child. */ 447214501Srpaulo if (strcmp(vfstype, "ufs") == 0) 448214501Srpaulo exit(mount_ufs(argc, (char * const *) argv)); 449214501Srpaulo 450214501Srpaulo /* Go find an executable. */ 451214501Srpaulo for (edir = edirs; *edir; edir++) { 452214501Srpaulo (void)snprintf(execname, 453214501Srpaulo sizeof(execname), "%s/mount_%s", *edir, vfstype); 454214501Srpaulo execv(execname, (char * const *)argv); 455337817Scy } 456337817Scy if (errno == ENOENT) { 457214501Srpaulo int len = 0; 458281806Srpaulo char *cp; 459281806Srpaulo for (edir = edirs; *edir; edir++) 460214501Srpaulo len += strlen(*edir) + 2; /* ", " */ 461214501Srpaulo if ((cp = malloc(len)) == NULL) 462214501Srpaulo errx(1, "malloc failed"); 463214501Srpaulo cp[0] = '\0'; 464289549Srpaulo for (edir = edirs; *edir; edir++) { 465289549Srpaulo strcat(cp, *edir); 466289549Srpaulo if (edir[1] != NULL) 467289549Srpaulo strcat(cp, ", "); 468289549Srpaulo } 469214501Srpaulo warn("exec mount_%s not found in %s", vfstype, cp); 470214501Srpaulo } 471214501Srpaulo exit(1); 472214501Srpaulo /* NOTREACHED */ 473214501Srpaulo default: /* Parent. */ 474214501Srpaulo free(optbuf); 475214501Srpaulo 476214501Srpaulo if (waitpid(pid, &status, 0) < 0) { 477214501Srpaulo warn("waitpid"); 478214501Srpaulo return (1); 479214501Srpaulo } 480214501Srpaulo 481214501Srpaulo if (WIFEXITED(status)) { 482214501Srpaulo if (WEXITSTATUS(status) != 0) 483252726Srpaulo return (WEXITSTATUS(status)); 484281806Srpaulo } else if (WIFSIGNALED(status)) { 485214501Srpaulo warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 486214501Srpaulo return (1); 487214501Srpaulo } 488214501Srpaulo 489214501Srpaulo if (verbose) { 490214501Srpaulo if (statfs(name, &sf) < 0) { 491214501Srpaulo warn("statfs %s", name); 492214501Srpaulo return (1); 493214501Srpaulo } 494214501Srpaulo if (fstab_style) 495214501Srpaulo putfsent(&sf); 496214501Srpaulo else 497214501Srpaulo prmount(&sf); 498214501Srpaulo } 499214501Srpaulo break; 500214501Srpaulo } 501214501Srpaulo 502214501Srpaulo return (0); 503214501Srpaulo} 504214501Srpaulo 505214501Srpaulovoid 506214501Srpauloprmount(sfp) 507214501Srpaulo struct statfs *sfp; 508214501Srpaulo{ 509214501Srpaulo int flags; 510214501Srpaulo struct opt *o; 511214501Srpaulo struct passwd *pw; 512252726Srpaulo 513252726Srpaulo (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, 514252726Srpaulo sfp->f_fstypename); 515252726Srpaulo 516252726Srpaulo flags = sfp->f_flags & MNT_VISFLAGMASK; 517252726Srpaulo for (o = optnames; flags && o->o_opt; o++) 518252726Srpaulo if (flags & o->o_opt) { 519252726Srpaulo (void)printf(", %s", o->o_name); 520252726Srpaulo flags &= ~o->o_opt; 521252726Srpaulo } 522252726Srpaulo if (sfp->f_owner) { 523214501Srpaulo (void)printf(", mounted by "); 524214501Srpaulo if ((pw = getpwuid(sfp->f_owner)) != NULL) 525214501Srpaulo (void)printf("%s", pw->pw_name); 526214501Srpaulo else 527214501Srpaulo (void)printf("%d", sfp->f_owner); 528214501Srpaulo } 529214501Srpaulo if (verbose) { 530214501Srpaulo if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 531214501Srpaulo (void)printf(", writes: sync %ld async %ld", 532214501Srpaulo sfp->f_syncwrites, sfp->f_asyncwrites); 533214501Srpaulo if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0) 534214501Srpaulo (void)printf(", reads: sync %ld async %ld", 535214501Srpaulo sfp->f_syncreads, sfp->f_asyncreads); 536346981Scy } 537346981Scy (void)printf(")\n"); 538346981Scy} 539346981Scy 540214501Srpaulostruct statfs * 541214501Srpaulogetmntpt(name) 542214501Srpaulo const char *name; 543214501Srpaulo{ 544214501Srpaulo struct statfs *mntbuf; 545214501Srpaulo int i, mntsize; 546214501Srpaulo 547214501Srpaulo mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 548346981Scy for (i = mntsize - 1; i >= 0; i--) { 549214501Srpaulo if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 550346981Scy strcmp(mntbuf[i].f_mntonname, name) == 0) 551346981Scy return (&mntbuf[i]); 552346981Scy } 553346981Scy return (NULL); 554346981Scy} 555346981Scy 556346981Scychar * 557346981Scycatopt(s0, s1) 558346981Scy char *s0; 559346981Scy const char *s1; 560214501Srpaulo{ 561214501Srpaulo size_t i; 562346981Scy char *cp; 563346981Scy 564346981Scy if (s1 == NULL || *s1 == '\0') 565346981Scy return s0; 566346981Scy 567346981Scy if (s0 && *s0) { 568346981Scy i = strlen(s0) + strlen(s1) + 1 + 1; 569346981Scy if ((cp = malloc(i)) == NULL) 570346981Scy errx(1, "malloc failed"); 571346981Scy (void)snprintf(cp, i, "%s,%s", s0, s1); 572214501Srpaulo } else 573214501Srpaulo cp = strdup(s1); 574214501Srpaulo 575289549Srpaulo if (s0) 576289549Srpaulo free(s0); 577289549Srpaulo return (cp); 578289549Srpaulo} 579289549Srpaulo 580214501Srpaulovoid 581214501Srpaulomangle(options, argcp, argv) 582214501Srpaulo char *options; 583214501Srpaulo int *argcp; 584214501Srpaulo const char **argv; 585214501Srpaulo{ 586214501Srpaulo char *p, *s; 587214501Srpaulo int argc; 588214501Srpaulo 589214501Srpaulo argc = *argcp; 590214501Srpaulo for (s = options; (p = strsep(&s, ",")) != NULL;) 591214501Srpaulo if (*p != '\0') { 592214501Srpaulo if (*p == '-') { 593214501Srpaulo argv[argc++] = p; 594214501Srpaulo p = strchr(p, '='); 595214501Srpaulo if (p) { 596214501Srpaulo *p = '\0'; 597214501Srpaulo argv[argc++] = p+1; 598214501Srpaulo } 599214501Srpaulo } else if (strcmp(p, "rw") != 0) { 600214501Srpaulo argv[argc++] = "-o"; 601214501Srpaulo argv[argc++] = p; 602214501Srpaulo } 603214501Srpaulo } 604214501Srpaulo 605281806Srpaulo *argcp = argc; 606281806Srpaulo} 607281806Srpaulo 608281806Srpaulo 609281806Srpaulochar * 610214501Srpauloupdate_options(opts, fstab, curflags) 611214501Srpaulo char *opts; 612214501Srpaulo char *fstab; 613214501Srpaulo int curflags; 614214501Srpaulo{ 615214501Srpaulo char *o, *p; 616214501Srpaulo char *cur; 617214501Srpaulo char *expopt, *newopt, *tmpopt; 618214501Srpaulo 619214501Srpaulo if (opts == NULL) 620252726Srpaulo return strdup(""); 621214501Srpaulo 622252726Srpaulo /* remove meta options from list */ 623252726Srpaulo remopt(fstab, MOUNT_META_OPTION_FSTAB); 624214501Srpaulo remopt(fstab, MOUNT_META_OPTION_CURRENT); 625346981Scy cur = flags2opts(curflags); 626214501Srpaulo 627214501Srpaulo /* 628214501Srpaulo * Expand all meta-options passed to us first. 629214501Srpaulo */ 630214501Srpaulo expopt = NULL; 631214501Srpaulo for (p = opts; (o = strsep(&p, ",")) != NULL;) { 632214501Srpaulo if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 633214501Srpaulo expopt = catopt(expopt, fstab); 634214501Srpaulo else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 635214501Srpaulo expopt = catopt(expopt, cur); 636214501Srpaulo else 637214501Srpaulo expopt = catopt(expopt, o); 638214501Srpaulo } 639214501Srpaulo free(cur); 640214501Srpaulo free(opts); 641214501Srpaulo 642214501Srpaulo /* 643214501Srpaulo * Remove previous contradictory arguments. Given option "foo" we 644214501Srpaulo * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 645214501Srpaulo * and "foo" - so we can deal with possible options like "notice". 646214501Srpaulo */ 647214501Srpaulo newopt = NULL; 648214501Srpaulo for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 649214501Srpaulo if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 650214501Srpaulo errx(1, "malloc failed"); 651214501Srpaulo 652214501Srpaulo strcpy(tmpopt, "no"); 653214501Srpaulo strcat(tmpopt, o); 654214501Srpaulo remopt(newopt, tmpopt); 655214501Srpaulo free(tmpopt); 656214501Srpaulo 657214501Srpaulo if (strncmp("no", o, 2) == 0) 658214501Srpaulo remopt(newopt, o+2); 659214501Srpaulo 660214501Srpaulo newopt = catopt(newopt, o); 661252726Srpaulo } 662252726Srpaulo free(expopt); 663252726Srpaulo 664252726Srpaulo return newopt; 665252726Srpaulo} 666252726Srpaulo 667252726Srpaulovoid 668214501Srpauloremopt(string, opt) 669214501Srpaulo char *string; 670214501Srpaulo const char *opt; 671214501Srpaulo{ 672214501Srpaulo char *o, *p, *r; 673214501Srpaulo 674252726Srpaulo if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 675252726Srpaulo return; 676214501Srpaulo 677214501Srpaulo r = string; 678214501Srpaulo 679214501Srpaulo for (p = string; (o = strsep(&p, ",")) != NULL;) { 680214501Srpaulo if (strcmp(opt, o) != 0) { 681214501Srpaulo if (*r == ',' && *o != '\0') 682214501Srpaulo r++; 683214501Srpaulo while ((*r++ = *o++) != '\0') 684252726Srpaulo ; 685214501Srpaulo *--r = ','; 686252726Srpaulo } 687214501Srpaulo } 688252726Srpaulo *r = '\0'; 689252726Srpaulo} 690252726Srpaulo 691214501Srpaulovoid 692214501Srpaulousage() 693214501Srpaulo{ 694214501Srpaulo 695214501Srpaulo (void)fprintf(stderr, "%s\n%s\n%s\n", 696214501Srpaulo"usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node", 697252726Srpaulo" mount [-adfpruvw] [-t ufs | external_type]", 698252726Srpaulo" mount [-dfpruvw] special | node"); 699252726Srpaulo exit(1); 700252726Srpaulo} 701214501Srpaulo 702252726Srpaulovoid 703214501Srpauloputfsent(ent) 704214501Srpaulo const struct statfs *ent; 705214501Srpaulo{ 706214501Srpaulo struct fstab *fst; 707214501Srpaulo char *opts; 708214501Srpaulo 709252726Srpaulo opts = flags2opts(ent->f_flags); 710252726Srpaulo printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname, 711252726Srpaulo ent->f_fstypename, opts); 712252726Srpaulo free(opts); 713252726Srpaulo 714252726Srpaulo if ((fst = getfsspec(ent->f_mntfromname))) 715252726Srpaulo printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 716252726Srpaulo else if ((fst = getfsfile(ent->f_mntonname))) 717252726Srpaulo printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 718214501Srpaulo else if (strcmp(ent->f_fstypename, "ufs") == 0) { 719214501Srpaulo if (strcmp(ent->f_mntonname, "/") == 0) 720214501Srpaulo printf("\t1 1\n"); 721214501Srpaulo else 722214501Srpaulo printf("\t2 2\n"); 723214501Srpaulo } else 724214501Srpaulo printf("\t0 0\n"); 725214501Srpaulo} 726214501Srpaulo 727214501Srpaulo 728214501Srpaulochar * 729214501Srpauloflags2opts(flags) 730214501Srpaulo int flags; 731214501Srpaulo{ 732252726Srpaulo char *res; 733214501Srpaulo 734214501Srpaulo res = NULL; 735214501Srpaulo 736252726Srpaulo res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); 737252726Srpaulo 738252726Srpaulo if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 739281806Srpaulo if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 740281806Srpaulo if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 741281806Srpaulo if (flags & MNT_NODEV) res = catopt(res, "nodev"); 742281806Srpaulo if (flags & MNT_UNION) res = catopt(res, "union"); 743281806Srpaulo if (flags & MNT_ASYNC) res = catopt(res, "async"); 744281806Srpaulo if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 745252726Srpaulo if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 746252726Srpaulo if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 747252726Srpaulo if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 748252726Srpaulo if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 749252726Srpaulo 750252726Srpaulo return res; 751252726Srpaulo} 752252726Srpaulo