mount.c revision 46619
128671Ssteve/*- 21558Srgrimes * Copyright (c) 1980, 1989, 1993, 1994 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3528671Sstevestatic const char copyright[] = 361558Srgrimes"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 371558Srgrimes The Regents of the University of California. All rights reserved.\n"; 381558Srgrimes#endif /* not lint */ 391558Srgrimes 401558Srgrimes#ifndef lint 4128671Ssteve#if 0 4223678Speterstatic char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 4337425Scharnier#endif 4428671Sstevestatic const char rcsid[] = 4546619Sjkoshy "$Id: mount.c,v 1.29 1999/03/16 22:26:51 bde Exp $"; 461558Srgrimes#endif /* not lint */ 471558Srgrimes 481558Srgrimes#include <sys/param.h> 491558Srgrimes#include <sys/mount.h> 5023805Sbde#include <sys/stat.h> 511558Srgrimes#include <sys/wait.h> 521558Srgrimes 531558Srgrimes#include <err.h> 541558Srgrimes#include <errno.h> 551558Srgrimes#include <fstab.h> 5623678Speter#include <pwd.h> 571558Srgrimes#include <signal.h> 581558Srgrimes#include <stdio.h> 591558Srgrimes#include <stdlib.h> 601558Srgrimes#include <string.h> 611558Srgrimes#include <unistd.h> 621558Srgrimes 6328671Ssteve#include "extern.h" 641558Srgrimes#include "pathnames.h" 651558Srgrimes 6646619Sjkoshy/* `meta' options */ 6746619Sjkoshy#define MOUNT_META_OPTION_FSTAB "fstab" 6846619Sjkoshy#define MOUNT_META_OPTION_CURRENT "current" 6946619Sjkoshy 7023805Sbdeint debug, fstab_style, verbose; 711558Srgrimes 721558Srgrimeschar *catopt __P((char *, const char *)); 731558Srgrimesstruct statfs 741558Srgrimes *getmntpt __P((const char *)); 7523678Speterint hasopt __P((const char *, const char *)); 7628671Ssteveint ismounted __P((struct fstab *, struct statfs *, int)); 7728671Ssteveint isremountable __P((const char *)); 781558Srgrimesvoid mangle __P((char *, int *, const char **)); 7946619Sjkoshychar *update_options __P((char *, char *, int)); 801558Srgrimesint mountfs __P((const char *, const char *, const char *, 811558Srgrimes int, const char *, const char *)); 8246619Sjkoshyvoid remopt __P((char *, const char *)); 8323678Spetervoid prmount __P((struct statfs *)); 8423805Sbdevoid putfsent __P((const struct statfs *)); 851558Srgrimesvoid usage __P((void)); 8646619Sjkoshychar *flags2opts __P((int)); 871558Srgrimes 8837425Scharnier/* Map from mount options to printable formats. */ 891558Srgrimesstatic struct opt { 901558Srgrimes int o_opt; 911558Srgrimes const char *o_name; 921558Srgrimes} optnames[] = { 931558Srgrimes { MNT_ASYNC, "asynchronous" }, 941558Srgrimes { MNT_EXPORTED, "NFS exported" }, 951558Srgrimes { MNT_LOCAL, "local" }, 9618007Sdg { MNT_NOATIME, "noatime" }, 971558Srgrimes { MNT_NODEV, "nodev" }, 981558Srgrimes { MNT_NOEXEC, "noexec" }, 991558Srgrimes { MNT_NOSUID, "nosuid" }, 10035105Swosch { MNT_NOSYMFOLLOW, "nosymfollow" }, 1011558Srgrimes { MNT_QUOTA, "with quotas" }, 1021558Srgrimes { MNT_RDONLY, "read-only" }, 1031558Srgrimes { MNT_SYNCHRONOUS, "synchronous" }, 1041558Srgrimes { MNT_UNION, "union" }, 10529890Skato { MNT_NOCLUSTERR, "noclusterr" }, 10629890Skato { MNT_NOCLUSTERW, "noclusterw" }, 10731144Sjulian { MNT_SUIDDIR, "suiddir" }, 10834266Sjulian { MNT_SOFTDEP, "soft-updates" }, 10946619Sjkoshy { 0, NULL } 1101558Srgrimes}; 1111558Srgrimes 11228671Ssteve/* 11328671Ssteve * List of VFS types that can be remounted without becoming mounted on top 11428671Ssteve * of each other. 11528671Ssteve * XXX Is this list correct? 11628671Ssteve */ 11728671Sstevestatic const char * 11828671Ssteveremountable_fs_names[] = { 11928671Ssteve "ufs", "ffs", "lfs", "ext2fs", 12028671Ssteve 0 12128671Ssteve}; 12228671Ssteve 1231558Srgrimesint 1241558Srgrimesmain(argc, argv) 1251558Srgrimes int argc; 1261558Srgrimes char * const argv[]; 1271558Srgrimes{ 12823678Speter const char *mntfromname, **vfslist, *vfstype; 1291558Srgrimes struct fstab *fs; 1301558Srgrimes struct statfs *mntbuf; 1311558Srgrimes FILE *mountdfp; 1321558Srgrimes pid_t pid; 1331558Srgrimes int all, ch, i, init_flags, mntsize, rval; 1341558Srgrimes char *options; 1351558Srgrimes 1361558Srgrimes all = init_flags = 0; 1371558Srgrimes options = NULL; 1381558Srgrimes vfslist = NULL; 1391558Srgrimes vfstype = "ufs"; 14023805Sbde while ((ch = getopt(argc, argv, "adfo:prwt:uv")) != -1) 1411558Srgrimes switch (ch) { 1421558Srgrimes case 'a': 1431558Srgrimes all = 1; 1441558Srgrimes break; 1451558Srgrimes case 'd': 1461558Srgrimes debug = 1; 1471558Srgrimes break; 1481558Srgrimes case 'f': 1491558Srgrimes init_flags |= MNT_FORCE; 1501558Srgrimes break; 1511558Srgrimes case 'o': 1521558Srgrimes if (*optarg) 1531558Srgrimes options = catopt(options, optarg); 1541558Srgrimes break; 15523805Sbde case 'p': 15623805Sbde fstab_style = 1; 15723805Sbde verbose = 1; 15823805Sbde break; 1591558Srgrimes case 'r': 1601558Srgrimes init_flags |= MNT_RDONLY; 1611558Srgrimes break; 1621558Srgrimes case 't': 1631558Srgrimes if (vfslist != NULL) 16437425Scharnier errx(1, "only one -t option may be specified"); 1651558Srgrimes vfslist = makevfslist(optarg); 1661558Srgrimes vfstype = optarg; 1671558Srgrimes break; 1681558Srgrimes case 'u': 1691558Srgrimes init_flags |= MNT_UPDATE; 1701558Srgrimes break; 1711558Srgrimes case 'v': 1721558Srgrimes verbose = 1; 1731558Srgrimes break; 1741558Srgrimes case 'w': 1751558Srgrimes init_flags &= ~MNT_RDONLY; 1761558Srgrimes break; 1771558Srgrimes case '?': 1781558Srgrimes default: 1791558Srgrimes usage(); 1801558Srgrimes /* NOTREACHED */ 1811558Srgrimes } 1821558Srgrimes argc -= optind; 1831558Srgrimes argv += optind; 1841558Srgrimes 1851558Srgrimes#define BADTYPE(type) \ 1861558Srgrimes (strcmp(type, FSTAB_RO) && \ 1871558Srgrimes strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 1881558Srgrimes 1891558Srgrimes rval = 0; 1901558Srgrimes switch (argc) { 1911558Srgrimes case 0: 19228671Ssteve if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 19328671Ssteve err(1, "getmntinfo"); 19428671Ssteve if (all) { 1951558Srgrimes while ((fs = getfsent()) != NULL) { 1961558Srgrimes if (BADTYPE(fs->fs_type)) 1971558Srgrimes continue; 19823678Speter if (checkvfsname(fs->fs_vfstype, vfslist)) 1991558Srgrimes continue; 20023678Speter if (hasopt(fs->fs_mntops, "noauto")) 20110288Sdg continue; 20244811Sbde if (!(init_flags & MNT_UPDATE) && 20344811Sbde ismounted(fs, mntbuf, mntsize)) 20428671Ssteve continue; 2051558Srgrimes if (mountfs(fs->fs_vfstype, fs->fs_spec, 20623805Sbde fs->fs_file, init_flags, options, 20723805Sbde fs->fs_mntops)) 20823805Sbde rval = 1; 2091558Srgrimes } 21028671Ssteve } else if (fstab_style) { 21117243Sjkh for (i = 0; i < mntsize; i++) { 21223678Speter if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 21317243Sjkh continue; 21423805Sbde putfsent(&mntbuf[i]); 21517243Sjkh } 21623805Sbde } else { 2171558Srgrimes for (i = 0; i < mntsize; i++) { 21823805Sbde if (checkvfsname(mntbuf[i].f_fstypename, 21923805Sbde vfslist)) 2201558Srgrimes continue; 22123678Speter prmount(&mntbuf[i]); 2221558Srgrimes } 2231558Srgrimes } 2241558Srgrimes exit(rval); 2251558Srgrimes case 1: 2261558Srgrimes if (vfslist != NULL) 2271558Srgrimes usage(); 2281558Srgrimes 2291558Srgrimes if (init_flags & MNT_UPDATE) { 2301558Srgrimes if ((mntbuf = getmntpt(*argv)) == NULL) 2311558Srgrimes errx(1, 23237425Scharnier "unknown special file or file system %s", 2331558Srgrimes *argv); 23446619Sjkoshy if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 23523678Speter mntfromname = fs->fs_spec; 23646619Sjkoshy options = update_options(options, fs->fs_mntops, 23746619Sjkoshy mntbuf->f_flags); 23846619Sjkoshy } else { 23923678Speter mntfromname = mntbuf->f_mntfromname; 24046619Sjkoshy options = update_options(options, NULL, 24146619Sjkoshy mntbuf->f_flags); 24246619Sjkoshy } 24323678Speter rval = mountfs(mntbuf->f_fstypename, mntfromname, 24423678Speter mntbuf->f_mntonname, init_flags, options, 0); 24523678Speter break; 2461558Srgrimes } 24723678Speter if ((fs = getfsfile(*argv)) == NULL && 24823678Speter (fs = getfsspec(*argv)) == NULL) 24937425Scharnier errx(1, "%s: unknown special file or file system", 25023678Speter *argv); 25123678Speter if (BADTYPE(fs->fs_type)) 25237425Scharnier errx(1, "%s has unknown file system type", 25323678Speter *argv); 25423678Speter rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 25523678Speter init_flags, options, fs->fs_mntops); 2561558Srgrimes break; 2571558Srgrimes case 2: 2581558Srgrimes /* 2591558Srgrimes * If -t flag has not been specified, and spec contains either 2601558Srgrimes * a ':' or a '@' then assume that an NFS filesystem is being 2611558Srgrimes * specified ala Sun. 2621558Srgrimes */ 2631558Srgrimes if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL) 2641558Srgrimes vfstype = "nfs"; 2651558Srgrimes rval = mountfs(vfstype, 2661558Srgrimes argv[0], argv[1], init_flags, options, NULL); 2671558Srgrimes break; 2681558Srgrimes default: 2691558Srgrimes usage(); 2701558Srgrimes /* NOTREACHED */ 2711558Srgrimes } 2721558Srgrimes 2731558Srgrimes /* 2741558Srgrimes * If the mount was successfully, and done by root, tell mountd the 2751558Srgrimes * good news. Pid checks are probably unnecessary, but don't hurt. 2761558Srgrimes */ 2771558Srgrimes if (rval == 0 && getuid() == 0 && 2781558Srgrimes (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 27928671Ssteve if (fscanf(mountdfp, "%d", &pid) == 1 && 2801558Srgrimes pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 2811558Srgrimes err(1, "signal mountd"); 2821558Srgrimes (void)fclose(mountdfp); 2831558Srgrimes } 2841558Srgrimes 2851558Srgrimes exit(rval); 2861558Srgrimes} 2871558Srgrimes 2881558Srgrimesint 28928671Ssteveismounted(fs, mntbuf, mntsize) 29028671Ssteve struct fstab *fs; 29128671Ssteve struct statfs *mntbuf; 29228671Ssteve int mntsize; 29328671Ssteve{ 29428671Ssteve int i; 29528671Ssteve 29628671Ssteve if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 29728671Ssteve /* the root file system can always be remounted */ 29828671Ssteve return (0); 29928671Ssteve 30028671Ssteve for (i = mntsize - 1; i >= 0; --i) 30128671Ssteve if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 && 30228671Ssteve (!isremountable(fs->fs_vfstype) || 30328671Ssteve strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0)) 30428671Ssteve return (1); 30528671Ssteve return (0); 30628671Ssteve} 30728671Ssteve 30828671Ssteveint 30928671Ssteveisremountable(vfsname) 31028671Ssteve const char *vfsname; 31128671Ssteve{ 31228671Ssteve const char **cp; 31328671Ssteve 31428671Ssteve for (cp = remountable_fs_names; *cp; cp++) 31528671Ssteve if (strcmp(*cp, vfsname) == 0) 31628671Ssteve return (1); 31728671Ssteve return (0); 31828671Ssteve} 31928671Ssteve 32028671Ssteveint 32123678Speterhasopt(mntopts, option) 32223678Speter const char *mntopts, *option; 32323678Speter{ 32423678Speter int negative, found; 32523678Speter char *opt, *optbuf; 32623678Speter 32723678Speter if (option[0] == 'n' && option[1] == 'o') { 32823678Speter negative = 1; 32923678Speter option += 2; 33023678Speter } else 33123678Speter negative = 0; 33223678Speter optbuf = strdup(mntopts); 33323678Speter found = 0; 33423678Speter for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 33523678Speter if (opt[0] == 'n' && opt[1] == 'o') { 33623678Speter if (!strcasecmp(opt + 2, option)) 33723678Speter found = negative; 33823678Speter } else if (!strcasecmp(opt, option)) 33923678Speter found = !negative; 34023678Speter } 34123678Speter free(optbuf); 34223678Speter return (found); 34323678Speter} 34423678Speter 34523678Speterint 3461558Srgrimesmountfs(vfstype, spec, name, flags, options, mntopts) 3471558Srgrimes const char *vfstype, *spec, *name, *options, *mntopts; 3481558Srgrimes int flags; 3491558Srgrimes{ 3501558Srgrimes /* List of directories containing mount_xxx subcommands. */ 3511558Srgrimes static const char *edirs[] = { 3521558Srgrimes _PATH_SBIN, 3531558Srgrimes _PATH_USRSBIN, 3541558Srgrimes NULL 3551558Srgrimes }; 3561558Srgrimes const char *argv[100], **edir; 35723805Sbde struct stat sb; 3581558Srgrimes struct statfs sf; 3591558Srgrimes pid_t pid; 3601558Srgrimes int argc, i, status; 3611558Srgrimes char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN]; 3621558Srgrimes 36328671Ssteve#if __GNUC__ 36428671Ssteve (void)&optbuf; 36528671Ssteve (void)&name; 36628671Ssteve#endif 36728671Ssteve 3686491Sbde if (realpath(name, mntpath) != NULL && stat(mntpath, &sb) == 0) { 3696444Sdg if (!S_ISDIR(sb.st_mode)) { 37037425Scharnier warnx("%s: not a directory", mntpath); 3716441Sdg return (1); 3726441Sdg } 3736441Sdg } else { 3741558Srgrimes warn("%s", mntpath); 3751558Srgrimes return (1); 3761558Srgrimes } 3776441Sdg 3781558Srgrimes name = mntpath; 3791558Srgrimes 38023678Speter if (mntopts == NULL) 38123678Speter mntopts = ""; 3821558Srgrimes if (options == NULL) { 38323678Speter if (*mntopts == '\0') { 3841558Srgrimes options = "rw"; 38523678Speter } else { 3861558Srgrimes options = mntopts; 38723678Speter mntopts = ""; 38823678Speter } 3891558Srgrimes } 3901558Srgrimes optbuf = catopt(strdup(mntopts), options); 3911558Srgrimes 3921558Srgrimes if (strcmp(name, "/") == 0) 3931558Srgrimes flags |= MNT_UPDATE; 3941558Srgrimes if (flags & MNT_FORCE) 3951558Srgrimes optbuf = catopt(optbuf, "force"); 3961558Srgrimes if (flags & MNT_RDONLY) 3971558Srgrimes optbuf = catopt(optbuf, "ro"); 3981558Srgrimes /* 3991558Srgrimes * XXX 4001558Srgrimes * The mount_mfs (newfs) command uses -o to select the 40137425Scharnier * optimization mode. We don't pass the default "-o rw" 4021558Srgrimes * for that reason. 4031558Srgrimes */ 4041558Srgrimes if (flags & MNT_UPDATE) 4051558Srgrimes optbuf = catopt(optbuf, "update"); 4061558Srgrimes 4071558Srgrimes argc = 0; 4081558Srgrimes argv[argc++] = vfstype; 4091558Srgrimes mangle(optbuf, &argc, argv); 4101558Srgrimes argv[argc++] = spec; 4111558Srgrimes argv[argc++] = name; 4121558Srgrimes argv[argc] = NULL; 4131558Srgrimes 4141558Srgrimes if (debug) { 4151558Srgrimes (void)printf("exec: mount_%s", vfstype); 4161558Srgrimes for (i = 1; i < argc; i++) 4171558Srgrimes (void)printf(" %s", argv[i]); 4181558Srgrimes (void)printf("\n"); 4191558Srgrimes return (0); 4201558Srgrimes } 4211558Srgrimes 42225120Sache switch (pid = fork()) { 4231558Srgrimes case -1: /* Error. */ 42425120Sache warn("fork"); 4251558Srgrimes free(optbuf); 4261558Srgrimes return (1); 4271558Srgrimes case 0: /* Child. */ 4281558Srgrimes if (strcmp(vfstype, "ufs") == 0) 4291558Srgrimes exit(mount_ufs(argc, (char * const *) argv)); 4301558Srgrimes 4311558Srgrimes /* Go find an executable. */ 43214626Sasami for (edir = edirs; *edir; edir++) { 4331558Srgrimes (void)snprintf(execname, 4341558Srgrimes sizeof(execname), "%s/mount_%s", *edir, vfstype); 4351558Srgrimes execv(execname, (char * const *)argv); 43614626Sasami } 43714626Sasami if (errno == ENOENT) { 43814626Sasami int len = 0; 43914626Sasami char *cp; 44014626Sasami for (edir = edirs; *edir; edir++) 44114626Sasami len += strlen(*edir) + 2; /* ", " */ 44237425Scharnier if ((cp = malloc(len)) == NULL) 44337425Scharnier errx(1, "malloc failed"); 44414626Sasami cp[0] = '\0'; 44514626Sasami for (edir = edirs; *edir; edir++) { 44614626Sasami strcat(cp, *edir); 44714626Sasami if (edir[1] != NULL) 44814626Sasami strcat(cp, ", "); 44914626Sasami } 45014626Sasami warn("exec mount_%s not found in %s", vfstype, cp); 45114626Sasami } 4521558Srgrimes exit(1); 4531558Srgrimes /* NOTREACHED */ 4541558Srgrimes default: /* Parent. */ 4551558Srgrimes free(optbuf); 4561558Srgrimes 4571558Srgrimes if (waitpid(pid, &status, 0) < 0) { 4581558Srgrimes warn("waitpid"); 4591558Srgrimes return (1); 4601558Srgrimes } 4611558Srgrimes 4621558Srgrimes if (WIFEXITED(status)) { 4631558Srgrimes if (WEXITSTATUS(status) != 0) 4641558Srgrimes return (WEXITSTATUS(status)); 4651558Srgrimes } else if (WIFSIGNALED(status)) { 4661558Srgrimes warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 4671558Srgrimes return (1); 4681558Srgrimes } 4691558Srgrimes 4701558Srgrimes if (verbose) { 4711558Srgrimes if (statfs(name, &sf) < 0) { 47223678Speter warn("statfs %s", name); 4731558Srgrimes return (1); 4741558Srgrimes } 47517243Sjkh if (fstab_style) 47623805Sbde putfsent(&sf); 47717243Sjkh else 47823678Speter prmount(&sf); 4791558Srgrimes } 4801558Srgrimes break; 4811558Srgrimes } 4821558Srgrimes 4831558Srgrimes return (0); 4841558Srgrimes} 4851558Srgrimes 4861558Srgrimesvoid 48723678Speterprmount(sfp) 48823678Speter struct statfs *sfp; 48923678Speter{ 4901558Srgrimes int flags; 4911558Srgrimes struct opt *o; 49223678Speter struct passwd *pw; 4931558Srgrimes int f; 4941558Srgrimes 49523678Speter (void)printf("%s on %s", sfp->f_mntfromname, sfp->f_mntonname); 4961558Srgrimes 49723678Speter flags = sfp->f_flags & MNT_VISFLAGMASK; 4981558Srgrimes for (f = 0, o = optnames; flags && o->o_opt; o++) 4991558Srgrimes if (flags & o->o_opt) { 5001558Srgrimes (void)printf("%s%s", !f++ ? " (" : ", ", o->o_name); 5011558Srgrimes flags &= ~o->o_opt; 5021558Srgrimes } 50323678Speter if (sfp->f_owner) { 50423678Speter (void)printf("%smounted by ", !f++ ? " (" : ", "); 50523678Speter if ((pw = getpwuid(sfp->f_owner)) != NULL) 50623678Speter (void)printf("%s", pw->pw_name); 50723678Speter else 50823678Speter (void)printf("%d", sfp->f_owner); 50923678Speter } 51036772Sbde if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 51136772Sbde (void)printf("%swrites: sync %ld async %ld", 51234910Speter !f++ ? " (" : ", ", sfp->f_syncwrites, sfp->f_asyncwrites); 51334910Speter (void)printf("%s\n", f ? ")" : ""); 5141558Srgrimes} 5151558Srgrimes 5161558Srgrimesstruct statfs * 5171558Srgrimesgetmntpt(name) 5181558Srgrimes const char *name; 5191558Srgrimes{ 5201558Srgrimes struct statfs *mntbuf; 5211558Srgrimes int i, mntsize; 5221558Srgrimes 5231558Srgrimes mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 5241558Srgrimes for (i = 0; i < mntsize; i++) 5251558Srgrimes if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 5261558Srgrimes strcmp(mntbuf[i].f_mntonname, name) == 0) 5271558Srgrimes return (&mntbuf[i]); 5281558Srgrimes return (NULL); 5291558Srgrimes} 5301558Srgrimes 5311558Srgrimeschar * 5321558Srgrimescatopt(s0, s1) 5331558Srgrimes char *s0; 5341558Srgrimes const char *s1; 5351558Srgrimes{ 5361558Srgrimes size_t i; 5371558Srgrimes char *cp; 5381558Srgrimes 53946619Sjkoshy if (s1 == NULL || *s1 == '\0') 54046619Sjkoshy return s0; 54146619Sjkoshy 5421558Srgrimes if (s0 && *s0) { 5431558Srgrimes i = strlen(s0) + strlen(s1) + 1 + 1; 5441558Srgrimes if ((cp = malloc(i)) == NULL) 54537425Scharnier errx(1, "malloc failed"); 5461558Srgrimes (void)snprintf(cp, i, "%s,%s", s0, s1); 5471558Srgrimes } else 5481558Srgrimes cp = strdup(s1); 5491558Srgrimes 5501558Srgrimes if (s0) 5511558Srgrimes free(s0); 5521558Srgrimes return (cp); 5531558Srgrimes} 5541558Srgrimes 5551558Srgrimesvoid 5561558Srgrimesmangle(options, argcp, argv) 5571558Srgrimes char *options; 5581558Srgrimes int *argcp; 5591558Srgrimes const char **argv; 5601558Srgrimes{ 5611558Srgrimes char *p, *s; 5621558Srgrimes int argc; 5631558Srgrimes 5641558Srgrimes argc = *argcp; 5651558Srgrimes for (s = options; (p = strsep(&s, ",")) != NULL;) 56646619Sjkoshy if (*p != '\0') { 5671558Srgrimes if (*p == '-') { 5681558Srgrimes argv[argc++] = p; 5691558Srgrimes p = strchr(p, '='); 5701558Srgrimes if (p) { 5711558Srgrimes *p = '\0'; 5721558Srgrimes argv[argc++] = p+1; 5731558Srgrimes } 5741558Srgrimes } else if (strcmp(p, "rw") != 0) { 5751558Srgrimes argv[argc++] = "-o"; 5761558Srgrimes argv[argc++] = p; 5771558Srgrimes } 57846619Sjkoshy } 5791558Srgrimes 5801558Srgrimes *argcp = argc; 5811558Srgrimes} 5821558Srgrimes 58346619Sjkoshy 58446619Sjkoshychar * 58546619Sjkoshyupdate_options(opts, fstab, curflags) 58646619Sjkoshy char *opts; 58746619Sjkoshy char *fstab; 58846619Sjkoshy int curflags; 58946619Sjkoshy{ 59046619Sjkoshy char *o, *p; 59146619Sjkoshy char *cur; 59246619Sjkoshy char *expopt, *newopt, *tmpopt; 59346619Sjkoshy 59446619Sjkoshy if (opts == NULL) 59546619Sjkoshy return strdup(""); 59646619Sjkoshy 59746619Sjkoshy fstab = strdup(fstab); 59846619Sjkoshy 59946619Sjkoshy /* remove meta options from list */ 60046619Sjkoshy remopt(fstab, MOUNT_META_OPTION_FSTAB); 60146619Sjkoshy remopt(fstab, MOUNT_META_OPTION_CURRENT); 60246619Sjkoshy cur = flags2opts(curflags); 60346619Sjkoshy 60446619Sjkoshy /* 60546619Sjkoshy * Expand all meta-options passed to us first. 60646619Sjkoshy */ 60746619Sjkoshy expopt = NULL; 60846619Sjkoshy for (p = opts; (o = strsep(&p, ",")) != NULL;) { 60946619Sjkoshy if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 61046619Sjkoshy expopt = catopt(expopt, fstab); 61146619Sjkoshy else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 61246619Sjkoshy expopt = catopt(expopt, cur); 61346619Sjkoshy else 61446619Sjkoshy expopt = catopt(expopt, o); 61546619Sjkoshy } 61646619Sjkoshy free(fstab); 61746619Sjkoshy free(cur); 61846619Sjkoshy free(opts); 61946619Sjkoshy 62046619Sjkoshy /* 62146619Sjkoshy * Remove previous contradictory arguments. Given option "foo" we 62246619Sjkoshy * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 62346619Sjkoshy * and "foo" - so we can deal with possible options like "notice". 62446619Sjkoshy */ 62546619Sjkoshy newopt = NULL; 62646619Sjkoshy for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 62746619Sjkoshy if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 62846619Sjkoshy errx(1, "malloc failed"); 62946619Sjkoshy 63046619Sjkoshy strcpy(tmpopt, "no"); 63146619Sjkoshy strcat(tmpopt, o); 63246619Sjkoshy remopt(newopt, tmpopt); 63346619Sjkoshy free(tmpopt); 63446619Sjkoshy 63546619Sjkoshy if (strncmp("no", o, 2) == 0) 63646619Sjkoshy remopt(newopt, o+2); 63746619Sjkoshy 63846619Sjkoshy newopt = catopt(newopt, o); 63946619Sjkoshy } 64046619Sjkoshy free(expopt); 64146619Sjkoshy 64246619Sjkoshy return newopt; 64346619Sjkoshy} 64446619Sjkoshy 6451558Srgrimesvoid 64646619Sjkoshyremopt(string, opt) 64746619Sjkoshy char *string; 64846619Sjkoshy const char *opt; 64946619Sjkoshy{ 65046619Sjkoshy char *o, *p, *r; 65146619Sjkoshy 65246619Sjkoshy if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 65346619Sjkoshy return; 65446619Sjkoshy 65546619Sjkoshy r = string; 65646619Sjkoshy 65746619Sjkoshy for (p = string; (o = strsep(&p, ",")) != NULL;) { 65846619Sjkoshy if (strcmp(opt, o) != 0) { 65946619Sjkoshy if (*r == ',' && *o != '\0') 66046619Sjkoshy r++; 66146619Sjkoshy while ((*r++ = *o++) != '\0') 66246619Sjkoshy ; 66346619Sjkoshy *--r = ','; 66446619Sjkoshy } 66546619Sjkoshy } 66646619Sjkoshy *r = '\0'; 66746619Sjkoshy} 66846619Sjkoshy 66946619Sjkoshyvoid 6701558Srgrimesusage() 6711558Srgrimes{ 6721558Srgrimes 67337425Scharnier (void)fprintf(stderr, "%s\n%s\n%s\n", 67437425Scharnier"usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node", 67537425Scharnier" mount [-adfpruvw] [-t ufs | external_type]", 67637425Scharnier" mount [-dfpruvw] special | node"); 6771558Srgrimes exit(1); 6781558Srgrimes} 67917243Sjkh 68017243Sjkhvoid 68123805Sbdeputfsent(ent) 68223805Sbde const struct statfs *ent; 68317243Sjkh{ 68423805Sbde struct fstab *fst; 68546619Sjkoshy char *opts; 68646619Sjkoshy 68746619Sjkoshy opts = flags2opts(ent->f_flags); 68823805Sbde printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname, 68946619Sjkoshy ent->f_fstypename, opts); 69046619Sjkoshy free(opts); 69117243Sjkh 69228671Ssteve if ((fst = getfsspec(ent->f_mntfromname))) 69323805Sbde printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 69428671Ssteve else if ((fst = getfsfile(ent->f_mntonname))) 69523805Sbde printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 69633304Sbde else if (strcmp(ent->f_fstypename, "ufs") == 0) 69723805Sbde printf("\t1 1\n"); 69823805Sbde else 69923805Sbde printf("\t0 0\n"); 70017243Sjkh} 70146619Sjkoshy 70246619Sjkoshy 70346619Sjkoshychar * 70446619Sjkoshyflags2opts(flags) 70546619Sjkoshy int flags; 70646619Sjkoshy{ 70746619Sjkoshy char *res; 70846619Sjkoshy 70946619Sjkoshy res = NULL; 71046619Sjkoshy 71146619Sjkoshy res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); 71246619Sjkoshy 71346619Sjkoshy if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 71446619Sjkoshy if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 71546619Sjkoshy if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 71646619Sjkoshy if (flags & MNT_NODEV) res = catopt(res, "nodev"); 71746619Sjkoshy if (flags & MNT_UNION) res = catopt(res, "union"); 71846619Sjkoshy if (flags & MNT_ASYNC) res = catopt(res, "async"); 71946619Sjkoshy if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 72046619Sjkoshy if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 72146619Sjkoshy if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 72246619Sjkoshy if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 72346619Sjkoshy if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 72446619Sjkoshy 72546619Sjkoshy return res; 72646619Sjkoshy} 727