Home | History | Annotate | Line # | Download | only in mount
      1  1.108       kre /*	$NetBSD: mount.c,v 1.108 2025/07/01 17:55:05 kre Exp $	*/
      2   1.16       cgd 
      3    1.1       cgd /*
      4   1.12   mycroft  * Copyright (c) 1980, 1989, 1993, 1994
      5   1.12   mycroft  *	The Regents of the University of California.  All rights reserved.
      6    1.1       cgd  *
      7    1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8    1.1       cgd  * modification, are permitted provided that the following conditions
      9    1.1       cgd  * are met:
     10    1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11    1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12    1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13    1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14    1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15   1.66       agc  * 3. Neither the name of the University nor the names of its contributors
     16    1.1       cgd  *    may be used to endorse or promote products derived from this software
     17    1.1       cgd  *    without specific prior written permission.
     18    1.1       cgd  *
     19    1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20    1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21    1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22    1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23    1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24    1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25    1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26    1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27    1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28    1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29    1.1       cgd  * SUCH DAMAGE.
     30    1.1       cgd  */
     31    1.1       cgd 
     32   1.29  christos #include <sys/cdefs.h>
     33    1.1       cgd #ifndef lint
     34   1.85     lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993, 1994\
     35   1.85     lukem  The Regents of the University of California.  All rights reserved.");
     36    1.1       cgd #endif /* not lint */
     37    1.1       cgd 
     38    1.1       cgd #ifndef lint
     39   1.16       cgd #if 0
     40   1.32     lukem static char sccsid[] = "@(#)mount.c	8.25 (Berkeley) 5/8/95";
     41   1.16       cgd #else
     42  1.108       kre __RCSID("$NetBSD: mount.c,v 1.108 2025/07/01 17:55:05 kre Exp $");
     43   1.16       cgd #endif
     44    1.1       cgd #endif /* not lint */
     45    1.1       cgd 
     46    1.1       cgd #include <sys/param.h>
     47   1.12   mycroft #include <sys/mount.h>
     48    1.1       cgd #include <sys/wait.h>
     49   1.12   mycroft 
     50   1.90     pooka #include <fs/puffs/puffs_msgif.h>
     51   1.90     pooka 
     52   1.12   mycroft #include <err.h>
     53   1.12   mycroft #include <errno.h>
     54    1.1       cgd #include <fstab.h>
     55   1.32     lukem #include <pwd.h>
     56   1.12   mycroft #include <signal.h>
     57    1.1       cgd #include <stdio.h>
     58    1.1       cgd #include <stdlib.h>
     59   1.12   mycroft #include <string.h>
     60   1.12   mycroft #include <unistd.h>
     61   1.94  christos #include <util.h>
     62   1.12   mycroft 
     63   1.48       abs #define MOUNTNAMES
     64   1.48       abs #include <fcntl.h>
     65   1.73   thorpej #include <sys/disk.h>
     66   1.48       abs #include <sys/disklabel.h>
     67   1.48       abs #include <sys/ioctl.h>
     68   1.48       abs 
     69    1.1       cgd #include "pathnames.h"
     70   1.86     pooka #include "mountprog.h"
     71    1.1       cgd 
     72  1.108       kre static int	debug, verbose, noise;
     73    1.1       cgd 
     74   1.76   xtraeme static void	catopt(char **, const char *);
     75   1.53     enami static const char *
     76   1.76   xtraeme 		getfslab(const char *str);
     77   1.69  christos static struct statvfs *
     78   1.76   xtraeme 		getmntpt(const char *);
     79   1.76   xtraeme static int 	getmntargs(struct statvfs *, char *, size_t);
     80   1.76   xtraeme static int	hasopt(const char *, const char *);
     81   1.82  christos static void	mangle(char *, int *, const char ** volatile *, int *);
     82   1.76   xtraeme static int	mountfs(const char *, const char *, const char *,
     83   1.76   xtraeme 		    int, const char *, const char *, int, char *, size_t);
     84   1.76   xtraeme static void	prmount(struct statvfs *);
     85   1.93     joerg __dead static void	usage(void);
     86   1.53     enami 
     87   1.12   mycroft 
     88   1.99       ast /* Map from mount options to printable formats. */
     89   1.52  jdolecek static const struct opt {
     90   1.12   mycroft 	int o_opt;
     91   1.24       cgd 	int o_silent;
     92   1.12   mycroft 	const char *o_name;
     93   1.12   mycroft } optnames[] = {
     94   1.58  christos 	__MNT_FLAGS
     95    1.1       cgd };
     96    1.1       cgd 
     97  1.103   mlelstv #define FLG_UPDATE	1
     98  1.103   mlelstv #define FLG_RDONLY	2
     99  1.103   mlelstv #define FLG_RDWRITE	4
    100  1.103   mlelstv #define FLG_FORCE	8
    101  1.103   mlelstv 
    102   1.94  christos static const char ffs_fstype[] = "ffs";
    103   1.30  christos 
    104   1.12   mycroft int
    105   1.76   xtraeme main(int argc, char *argv[])
    106    1.1       cgd {
    107   1.32     lukem 	const char *mntfromname, *mntonname, **vfslist, *vfstype;
    108   1.12   mycroft 	struct fstab *fs;
    109   1.69  christos 	struct statvfs *mntbuf;
    110   1.89      yamt #if 0
    111   1.12   mycroft 	FILE *mountdfp;
    112   1.89      yamt #endif
    113   1.22       cgd 	int all, ch, forceall, i, init_flags, mntsize, rval;
    114   1.12   mycroft 	char *options;
    115   1.43   mycroft 	const char *mountopts, *fstypename;
    116   1.94  christos 	char canonical_path_buf[MAXPATHLEN], buf[MAXPATHLEN];
    117   1.75        he 	char *canonical_path;
    118   1.52  jdolecek 
    119   1.52  jdolecek 	/* started as "mount" */
    120   1.22       cgd 	all = forceall = init_flags = 0;
    121   1.12   mycroft 	options = NULL;
    122   1.32     lukem 	vfslist = NULL;
    123   1.40       cgd 	vfstype = ffs_fstype;
    124   1.31     lukem 	while ((ch = getopt(argc, argv, "Aadfo:rwt:uv")) != -1)
    125   1.12   mycroft 		switch (ch) {
    126   1.22       cgd 		case 'A':
    127   1.22       cgd 			all = forceall = 1;
    128   1.22       cgd 			break;
    129    1.1       cgd 		case 'a':
    130    1.1       cgd 			all = 1;
    131    1.1       cgd 			break;
    132   1.12   mycroft 		case 'd':
    133   1.12   mycroft 			debug = 1;
    134   1.12   mycroft 			break;
    135    1.1       cgd 		case 'f':
    136  1.103   mlelstv 			init_flags |= FLG_FORCE;
    137   1.12   mycroft 			break;
    138   1.12   mycroft 		case 'o':
    139   1.12   mycroft 			if (*optarg)
    140   1.35   mycroft 				catopt(&options, optarg);
    141    1.1       cgd 			break;
    142    1.1       cgd 		case 'r':
    143  1.103   mlelstv 			init_flags |= FLG_RDONLY;
    144   1.12   mycroft 			break;
    145   1.12   mycroft 		case 't':
    146   1.32     lukem 			if (vfslist != NULL)
    147   1.94  christos 				errx(EXIT_FAILURE,
    148   1.94  christos 				    "Only one -t option may be specified.");
    149   1.32     lukem 			vfslist = makevfslist(optarg);
    150   1.12   mycroft 			vfstype = optarg;
    151    1.1       cgd 			break;
    152    1.1       cgd 		case 'u':
    153  1.103   mlelstv 			init_flags |= FLG_UPDATE;
    154    1.1       cgd 			break;
    155    1.1       cgd 		case 'v':
    156   1.61  christos 			verbose++;
    157    1.1       cgd 			break;
    158    1.1       cgd 		case 'w':
    159  1.103   mlelstv 			init_flags |= FLG_RDWRITE;
    160    1.1       cgd 			break;
    161    1.1       cgd 		case '?':
    162    1.1       cgd 		default:
    163    1.1       cgd 			usage();
    164    1.1       cgd 			/* NOTREACHED */
    165    1.1       cgd 		}
    166    1.1       cgd 	argc -= optind;
    167    1.1       cgd 	argv += optind;
    168    1.1       cgd 
    169   1.12   mycroft #define	BADTYPE(type)							\
    170   1.12   mycroft 	(strcmp(type, FSTAB_RO) &&					\
    171   1.12   mycroft 	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
    172   1.12   mycroft 
    173  1.108       kre 	noise = 0;
    174  1.108       kre 	if (argc > 0 && verbose) {
    175  1.108       kre 		noise = 1;
    176  1.108       kre 		verbose--;
    177  1.108       kre 	}
    178  1.108       kre 
    179   1.12   mycroft 	rval = 0;
    180   1.12   mycroft 	switch (argc) {
    181   1.12   mycroft 	case 0:
    182  1.105    simonb 		if (all) {
    183   1.12   mycroft 			while ((fs = getfsent()) != NULL) {
    184   1.12   mycroft 				if (BADTYPE(fs->fs_type))
    185   1.12   mycroft 					continue;
    186   1.32     lukem 				if (checkvfsname(fs->fs_vfstype, vfslist))
    187   1.12   mycroft 					continue;
    188   1.12   mycroft 				if (hasopt(fs->fs_mntops, "noauto"))
    189   1.12   mycroft 					continue;
    190   1.68       cgd 				if (strcmp(fs->fs_spec, "from_mount") == 0) {
    191   1.94  christos 					if ((mntbuf = getmntpt(fs->fs_file))
    192   1.94  christos 					    == NULL)
    193   1.94  christos 						errx(EXIT_FAILURE,
    194   1.94  christos 						    "Unknown file system %s",
    195   1.68       cgd 						    fs->fs_file);
    196   1.68       cgd 					mntfromname = mntbuf->f_mntfromname;
    197   1.68       cgd 				} else
    198   1.68       cgd 					mntfromname = fs->fs_spec;
    199   1.95  christos 				mntfromname = getfsspecname(buf, sizeof(buf),
    200   1.95  christos 				    mntfromname);
    201   1.95  christos 				if (mntfromname == NULL)
    202   1.97  christos 					err(EXIT_FAILURE, "%s", buf);
    203   1.68       cgd 				if (mountfs(fs->fs_vfstype, mntfromname,
    204   1.12   mycroft 				    fs->fs_file, init_flags, options,
    205   1.61  christos 				    fs->fs_mntops, !forceall, NULL, 0))
    206   1.12   mycroft 					rval = 1;
    207   1.12   mycroft 			}
    208  1.105    simonb 		} else {
    209   1.12   mycroft 			if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
    210   1.94  christos 				err(EXIT_FAILURE, "getmntinfo");
    211   1.12   mycroft 			for (i = 0; i < mntsize; i++) {
    212   1.32     lukem 				if (checkvfsname(mntbuf[i].f_fstypename,
    213   1.32     lukem 				    vfslist))
    214   1.12   mycroft 					continue;
    215   1.13   mycroft 				prmount(&mntbuf[i]);
    216   1.12   mycroft 			}
    217    1.1       cgd 		}
    218   1.98  christos 		return rval;
    219   1.12   mycroft 	case 1:
    220   1.40       cgd 		if (vfslist != NULL) {
    221    1.1       cgd 			usage();
    222   1.40       cgd 			/* NOTREACHED */
    223   1.40       cgd 		}
    224    1.1       cgd 
    225   1.74       erh 		/*
    226   1.74       erh 		 * Create a canonical version of the device or mount path
    227   1.74       erh 		 * passed to us.  It's ok for this to fail.  It's also ok
    228   1.74       erh 		 * for the result to be exactly the same as the original.
    229   1.74       erh 		 */
    230   1.74       erh 		canonical_path = realpath(*argv, canonical_path_buf);
    231   1.74       erh 
    232  1.103   mlelstv 		if (init_flags & FLG_UPDATE) {
    233   1.74       erh 			/*
    234   1.77     lukem 			 * Try looking up the canonical path first,
    235   1.74       erh 			 * then try exactly what the user entered.
    236   1.74       erh 			 */
    237   1.74       erh 			if ((canonical_path == NULL ||
    238   1.94  christos 			    (mntbuf = getmntpt(canonical_path)) == NULL) &&
    239   1.94  christos 			    (mntbuf = getmntpt(*argv)) == NULL) {
    240   1.94  christos out:
    241   1.94  christos 				errx(EXIT_FAILURE,
    242   1.94  christos 				    "Unknown special file or file system `%s'",
    243   1.12   mycroft 				    *argv);
    244   1.74       erh 			}
    245   1.68       cgd 			mntfromname = mntbuf->f_mntfromname;
    246   1.42      ross 			if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) {
    247   1.68       cgd 				if (strcmp(fs->fs_spec, "from_mount") != 0)
    248   1.68       cgd 					mntfromname = fs->fs_spec;
    249   1.42      ross 				/* ignore the fstab file options.  */
    250   1.42      ross 				fs->fs_mntops = NULL;
    251   1.68       cgd 			}
    252   1.42      ross 			mntonname  = mntbuf->f_mntonname;
    253   1.42      ross 			fstypename = mntbuf->f_fstypename;
    254   1.42      ross 			mountopts  = NULL;
    255   1.12   mycroft 		} else {
    256   1.74       erh 			/*
    257   1.77     lukem 			 * Try looking up the canonical path first,
    258   1.74       erh 			 * then try exactly what the user entered.
    259   1.74       erh 			 */
    260   1.77     lukem 			if (canonical_path == NULL ||
    261   1.77     lukem 			    ((fs = getfsfile(canonical_path)) == NULL &&
    262   1.77     lukem 			     (fs = getfsspec(canonical_path)) == NULL))
    263   1.74       erh 			{
    264   1.74       erh 				if ((fs = getfsfile(*argv)) == NULL &&
    265   1.94  christos 				    (fs = getfsspec(*argv)) == NULL) {
    266   1.94  christos 					goto out;
    267   1.74       erh 				}
    268   1.74       erh 			}
    269   1.12   mycroft 			if (BADTYPE(fs->fs_type))
    270   1.94  christos 				errx(EXIT_FAILURE,
    271   1.94  christos 				    "Unknown file system type for `%s'",
    272   1.12   mycroft 				    *argv);
    273   1.68       cgd 			if (strcmp(fs->fs_spec, "from_mount") == 0) {
    274   1.74       erh 				if ((canonical_path == NULL ||
    275   1.94  christos 				    (mntbuf = getmntpt(canonical_path))
    276   1.94  christos 				     == NULL) &&
    277   1.94  christos 				    (mntbuf = getmntpt(*argv)) == NULL)
    278   1.94  christos 					goto out;
    279   1.68       cgd 				mntfromname = mntbuf->f_mntfromname;
    280   1.68       cgd 			} else
    281   1.68       cgd 				mntfromname = fs->fs_spec;
    282   1.42      ross 			mntonname   = fs->fs_file;
    283   1.42      ross 			fstypename  = fs->fs_vfstype;
    284   1.42      ross 			mountopts   = fs->fs_mntops;
    285   1.12   mycroft 		}
    286   1.95  christos 		mntfromname = getfsspecname(buf, sizeof(buf), mntfromname);
    287   1.95  christos 		if (mntfromname == NULL)
    288   1.95  christos 			err(EXIT_FAILURE, "%s", buf);
    289   1.42      ross 		rval = mountfs(fstypename, mntfromname,
    290   1.61  christos 		    mntonname, init_flags, options, mountopts, 0, NULL, 0);
    291   1.12   mycroft 		break;
    292   1.12   mycroft 	case 2:
    293    1.1       cgd 		/*
    294   1.12   mycroft 		 * If -t flag has not been specified, and spec contains either
    295   1.12   mycroft 		 * a ':' or a '@' then assume that an NFS filesystem is being
    296   1.12   mycroft 		 * specified ala Sun.
    297    1.1       cgd 		 */
    298   1.95  christos 		mntfromname = getfsspecname(buf, sizeof(buf), argv[0]);
    299   1.95  christos 		if (mntfromname == NULL)
    300   1.95  christos 			err(EXIT_FAILURE, "%s", buf);
    301   1.48       abs 		if (vfslist == NULL) {
    302   1.87     pooka 			if (strpbrk(argv[0], ":@") != NULL) {
    303   1.48       abs 				vfstype = "nfs";
    304   1.87     pooka 			} else {
    305   1.94  christos 				vfstype = getfslab(mntfromname);
    306   1.48       abs 				if (vfstype == NULL)
    307   1.48       abs 					vfstype = ffs_fstype;
    308   1.48       abs 			}
    309   1.48       abs 		}
    310   1.94  christos 		rval = mountfs(vfstype, mntfromname, argv[1], init_flags,
    311   1.94  christos 		    options, NULL, 0, NULL, 0);
    312   1.12   mycroft 		break;
    313   1.12   mycroft 	default:
    314   1.12   mycroft 		usage();
    315    1.1       cgd 	}
    316    1.1       cgd 
    317   1.89      yamt #if 0	/* disabled because it interferes the service. */
    318   1.12   mycroft 	/*
    319   1.12   mycroft 	 * If the mount was successfully, and done by root, tell mountd the
    320   1.12   mycroft 	 * good news.  Pid checks are probably unnecessary, but don't hurt.
    321   1.12   mycroft 	 */
    322   1.12   mycroft 	if (rval == 0 && getuid() == 0 &&
    323   1.12   mycroft 	    (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
    324   1.29  christos 		int pid;
    325   1.29  christos 
    326   1.29  christos 		if (fscanf(mountdfp, "%d", &pid) == 1 &&
    327   1.53     enami 		    pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
    328   1.94  christos 			err(EXIT_FAILURE, "signal mountd");
    329   1.12   mycroft 		(void)fclose(mountdfp);
    330    1.1       cgd 	}
    331   1.89      yamt #endif
    332    1.1       cgd 
    333   1.98  christos 	return rval;
    334    1.1       cgd }
    335    1.1       cgd 
    336   1.12   mycroft int
    337   1.76   xtraeme hasopt(const char *mntopts, const char *option)
    338    1.1       cgd {
    339   1.12   mycroft 	int negative, found;
    340   1.12   mycroft 	char *opt, *optbuf;
    341    1.1       cgd 
    342   1.12   mycroft 	if (option[0] == 'n' && option[1] == 'o') {
    343   1.12   mycroft 		negative = 1;
    344   1.12   mycroft 		option += 2;
    345   1.12   mycroft 	} else
    346   1.12   mycroft 		negative = 0;
    347   1.94  christos 	optbuf = estrdup(mntopts);
    348   1.12   mycroft 	found = 0;
    349   1.12   mycroft 	for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
    350   1.12   mycroft 		if (opt[0] == 'n' && opt[1] == 'o') {
    351   1.12   mycroft 			if (!strcasecmp(opt + 2, option))
    352   1.12   mycroft 				found = negative;
    353   1.12   mycroft 		} else if (!strcasecmp(opt, option))
    354   1.12   mycroft 			found = !negative;
    355   1.12   mycroft 	}
    356   1.12   mycroft 	free(optbuf);
    357  1.106  christos 	return found;
    358    1.1       cgd }
    359    1.1       cgd 
    360   1.52  jdolecek static int
    361   1.99       ast mountfs(const char *vfstype, const char *spec, const char *name,
    362   1.94  christos     int flags, const char *options, const char *mntopts,
    363   1.94  christos     int skipmounted, char *buf, size_t buflen)
    364    1.1       cgd {
    365   1.12   mycroft 	/* List of directories containing mount_xxx subcommands. */
    366   1.12   mycroft 	static const char *edirs[] = {
    367   1.72  christos #ifdef RESCUEDIR
    368   1.72  christos 		RESCUEDIR,
    369   1.60     lukem #endif
    370   1.12   mycroft 		_PATH_SBIN,
    371   1.12   mycroft 		_PATH_USRSBIN,
    372   1.12   mycroft 		NULL
    373   1.12   mycroft 	};
    374   1.82  christos 	const char ** volatile argv, **edir;
    375   1.69  christos 	struct statvfs *sfp, sf;
    376   1.12   mycroft 	pid_t pid;
    377   1.61  christos 	int pfd[2];
    378   1.36  drochner 	int argc, numfs, i, status, maxargc;
    379   1.33  christos 	char *optbuf, execname[MAXPATHLEN + 1], execbase[MAXPATHLEN],
    380   1.33  christos 	    mntpath[MAXPATHLEN];
    381   1.82  christos 	volatile int getargs;
    382    1.1       cgd 
    383   1.12   mycroft 	if (realpath(name, mntpath) == NULL) {
    384   1.94  christos 		warn("realpath `%s'", name);
    385  1.106  christos 		return 1;
    386   1.12   mycroft 	}
    387    1.1       cgd 
    388   1.12   mycroft 	name = mntpath;
    389    1.1       cgd 
    390   1.35   mycroft 	optbuf = NULL;
    391   1.35   mycroft 	if (mntopts)
    392   1.35   mycroft 		catopt(&optbuf, mntopts);
    393   1.81  christos 
    394   1.81  christos 	if (options) {
    395   1.35   mycroft 		catopt(&optbuf, options);
    396   1.81  christos 		getargs = strstr(options, "getargs") != NULL;
    397   1.81  christos 	} else
    398   1.81  christos 		getargs = 0;
    399   1.81  christos 
    400   1.35   mycroft 	if (!mntopts && !options)
    401   1.35   mycroft 		catopt(&optbuf, "rw");
    402   1.12   mycroft 
    403   1.92     pooka 	if (getargs == 0 && strcmp(name, "/") == 0 && !hasopt(optbuf, "union"))
    404  1.103   mlelstv 		flags |= FLG_UPDATE;
    405   1.22       cgd 	else if (skipmounted) {
    406   1.36  drochner 		if ((numfs = getmntinfo(&sfp, MNT_WAIT)) == 0) {
    407   1.36  drochner 			warn("getmntinfo");
    408  1.106  christos 			return 1;
    409   1.21       cgd 		}
    410   1.36  drochner 		for(i = 0; i < numfs; i++) {
    411   1.91     pooka 			const char *mountedtype = sfp[i].f_fstypename;
    412   1.91     pooka 			size_t cmplen = sizeof(sfp[i].f_fstypename);
    413   1.91     pooka 
    414   1.91     pooka 			/* remove "puffs|" from comparisons, if present */
    415   1.91     pooka #define TYPESIZE (sizeof(PUFFS_TYPEPREFIX)-1)
    416   1.91     pooka 			if (strncmp(mountedtype,
    417   1.91     pooka 			    PUFFS_TYPEPREFIX, TYPESIZE) == 0) {
    418   1.91     pooka 				mountedtype += TYPESIZE;
    419   1.91     pooka 				cmplen -= TYPESIZE;
    420   1.91     pooka 			}
    421   1.91     pooka 
    422   1.53     enami 			/*
    423   1.53     enami 			 * XXX can't check f_mntfromname,
    424   1.53     enami 			 * thanks to mfs, union, etc.
    425   1.53     enami 			 */
    426   1.36  drochner 			if (strncmp(name, sfp[i].f_mntonname, MNAMELEN) == 0 &&
    427   1.91     pooka 			    strncmp(vfstype, mountedtype, cmplen) == 0) {
    428  1.108       kre 				if (noise || verbose)
    429   1.53     enami 					(void)printf("%s on %s type %.*s: "
    430   1.53     enami 					    "%s\n",
    431   1.53     enami 					    sfp[i].f_mntfromname,
    432   1.53     enami 					    sfp[i].f_mntonname,
    433   1.84  christos 					    (int)sizeof(sfp[i].f_fstypename),
    434   1.53     enami 					    sfp[i].f_fstypename,
    435   1.53     enami 					    "already mounted");
    436  1.106  christos 				return 0;
    437   1.36  drochner 			}
    438   1.21       cgd 		}
    439   1.21       cgd 	}
    440  1.103   mlelstv 	if (flags & FLG_FORCE)
    441   1.35   mycroft 		catopt(&optbuf, "force");
    442  1.103   mlelstv 	if (flags & FLG_RDONLY)
    443   1.35   mycroft 		catopt(&optbuf, "ro");
    444  1.103   mlelstv 	/* make -w override -r */
    445  1.103   mlelstv 	if (flags & FLG_RDWRITE)
    446  1.103   mlelstv 		catopt(&optbuf, "rw");
    447   1.33  christos 
    448  1.103   mlelstv 	if (flags & FLG_UPDATE) {
    449   1.35   mycroft 		catopt(&optbuf, "update");
    450   1.30  christos 		/* Figure out the fstype only if we defaulted to ffs */
    451   1.69  christos 		if (vfstype == ffs_fstype && statvfs(name, &sf) != -1)
    452   1.30  christos 			vfstype = sf.f_fstypename;
    453   1.30  christos 	}
    454   1.12   mycroft 
    455   1.35   mycroft 	maxargc = 64;
    456   1.94  christos 	argv = ecalloc(maxargc, sizeof(*argv));
    457   1.35   mycroft 
    458   1.90     pooka 	if (getargs &&
    459   1.90     pooka 	    strncmp(vfstype, PUFFS_TYPEPREFIX, sizeof(PUFFS_TYPEPREFIX)-1) == 0)
    460   1.90     pooka 		(void)snprintf(execbase, sizeof(execbase), "mount_puffs");
    461   1.90     pooka 	else if (hasopt(optbuf, "rump"))
    462   1.88     pooka 		(void)snprintf(execbase, sizeof(execbase), "rump_%s", vfstype);
    463   1.88     pooka 	else
    464   1.88     pooka 		(void)snprintf(execbase, sizeof(execbase), "mount_%s", vfstype);
    465   1.12   mycroft 	argc = 0;
    466   1.33  christos 	argv[argc++] = execbase;
    467   1.35   mycroft 	if (optbuf)
    468   1.35   mycroft 		mangle(optbuf, &argc, &argv, &maxargc);
    469   1.12   mycroft 	argv[argc++] = spec;
    470   1.12   mycroft 	argv[argc++] = name;
    471   1.12   mycroft 	argv[argc] = NULL;
    472   1.12   mycroft 
    473   1.81  christos 	if ((verbose && buf == NULL) || debug) {
    474   1.35   mycroft 		(void)printf("exec:");
    475   1.35   mycroft 		for (i = 0; i < argc; i++)
    476   1.12   mycroft 			(void)printf(" %s", argv[i]);
    477   1.12   mycroft 		(void)printf("\n");
    478  1.108       kre 		if (debug) {
    479  1.108       kre 			/*
    480  1.108       kre 			 * Don't proceed to attempt to
    481  1.108       kre 			 * print fs data, nothing has been
    482  1.108       kre 			 * mounted, anything printed would
    483  1.108       kre 			 * be for some other filesystem.
    484  1.108       kre 			 */
    485  1.108       kre 			return 0;
    486  1.108       kre 		}
    487   1.12   mycroft 	}
    488    1.5   mycroft 
    489   1.61  christos 	if (buf) {
    490   1.61  christos 		if (pipe(pfd) == -1)
    491   1.61  christos 			warn("Cannot create pipe");
    492   1.61  christos 	}
    493   1.61  christos 
    494  1.100     pooka 	switch (pid = fork()) {
    495   1.12   mycroft 	case -1:				/* Error. */
    496  1.100     pooka 		warn("fork");
    497   1.35   mycroft 		if (optbuf)
    498   1.35   mycroft 			free(optbuf);
    499   1.80  christos 		free(argv);
    500  1.106  christos 		return 1;
    501   1.35   mycroft 
    502   1.12   mycroft 	case 0:					/* Child. */
    503   1.34  christos 		if (debug)
    504   1.34  christos 			_exit(0);
    505   1.34  christos 
    506   1.61  christos 		if (buf) {
    507   1.61  christos 			(void)close(pfd[0]);
    508   1.61  christos 			(void)close(STDOUT_FILENO);
    509   1.61  christos 			if (dup2(pfd[1], STDOUT_FILENO) == -1)
    510   1.61  christos 				warn("Cannot open fd to mount program");
    511   1.61  christos 		}
    512   1.61  christos 
    513   1.12   mycroft 		/* Go find an executable. */
    514   1.12   mycroft 		edir = edirs;
    515   1.12   mycroft 		do {
    516   1.12   mycroft 			(void)snprintf(execname,
    517   1.33  christos 			    sizeof(execname), "%s/%s", *edir, execbase);
    518   1.78  christos 			(void)execv(execname, __UNCONST(argv));
    519   1.12   mycroft 			if (errno != ENOENT)
    520   1.12   mycroft 				warn("exec %s for %s", execname, name);
    521   1.12   mycroft 		} while (*++edir != NULL);
    522    1.1       cgd 
    523   1.12   mycroft 		if (errno == ENOENT)
    524  1.102  christos 			warn("exec %s for %s: %s", execbase, name, execbase);
    525   1.34  christos 		_exit(1);
    526   1.12   mycroft 		/* NOTREACHED */
    527   1.35   mycroft 
    528   1.12   mycroft 	default:				/* Parent. */
    529   1.35   mycroft 		if (optbuf)
    530   1.35   mycroft 			free(optbuf);
    531   1.80  christos 		free(argv);
    532    1.1       cgd 
    533   1.81  christos 		if (buf || getargs) {
    534   1.61  christos 			char tbuf[1024], *ptr;
    535   1.61  christos 			int nread;
    536   1.64     enami 
    537   1.61  christos 			if (buf == NULL) {
    538   1.61  christos 				ptr = tbuf;
    539   1.61  christos 				buflen = sizeof(tbuf) - 1;
    540   1.61  christos 			} else {
    541   1.61  christos 				ptr = buf;
    542   1.61  christos 				buflen--;
    543   1.61  christos 			}
    544   1.61  christos 			(void)close(pfd[1]);
    545   1.61  christos 			(void)signal(SIGPIPE, SIG_IGN);
    546   1.61  christos 			while ((nread = read(pfd[0], ptr, buflen)) > 0) {
    547   1.61  christos 				buflen -= nread;
    548   1.61  christos 				ptr += nread;
    549   1.61  christos 			}
    550   1.61  christos 			*ptr = '\0';
    551   1.61  christos 			if (buflen == 0) {
    552   1.61  christos 				while (read(pfd[0], &nread, sizeof(nread)) > 0)
    553   1.61  christos 					continue;
    554   1.61  christos 			}
    555   1.61  christos 			if (buf == NULL)
    556   1.64     enami 				(void)fprintf(stdout, "%s", tbuf);
    557   1.61  christos 		}
    558   1.61  christos 
    559   1.94  christos 		if (waitpid(pid, &status, 0) == -1) {
    560   1.12   mycroft 			warn("waitpid");
    561  1.106  christos 			return 1;
    562    1.1       cgd 		}
    563   1.12   mycroft 
    564   1.12   mycroft 		if (WIFEXITED(status)) {
    565   1.12   mycroft 			if (WEXITSTATUS(status) != 0)
    566  1.106  christos 				return WEXITSTATUS(status);
    567   1.12   mycroft 		} else if (WIFSIGNALED(status)) {
    568   1.17       jtc 			warnx("%s: %s", name, strsignal(WTERMSIG(status)));
    569  1.106  christos 			return 1;
    570    1.1       cgd 		}
    571   1.12   mycroft 
    572   1.61  christos 		if (buf == NULL) {
    573  1.108       kre 			if (verbose || noise) {
    574   1.94  christos 				if (statvfs(name, &sf) == -1) {
    575   1.69  christos 					warn("statvfs %s", name);
    576  1.106  christos 					return 1;
    577   1.61  christos 				}
    578   1.61  christos 				prmount(&sf);
    579   1.12   mycroft 			}
    580    1.1       cgd 		}
    581   1.12   mycroft 		break;
    582    1.1       cgd 	}
    583   1.12   mycroft 
    584  1.106  christos 	return 0;
    585    1.1       cgd }
    586    1.1       cgd 
    587   1.52  jdolecek static void
    588   1.76   xtraeme prmount(struct statvfs *sfp)
    589   1.13   mycroft {
    590   1.12   mycroft 	int flags;
    591   1.52  jdolecek 	const struct opt *o;
    592   1.32     lukem 	struct passwd *pw;
    593   1.12   mycroft 	int f;
    594    1.1       cgd 
    595   1.53     enami 	(void)printf("%s on %s type %.*s", sfp->f_mntfromname,
    596   1.84  christos 	    sfp->f_mntonname, (int)sizeof(sfp->f_fstypename),
    597   1.84  christos 	    sfp->f_fstypename);
    598    1.1       cgd 
    599   1.69  christos 	flags = sfp->f_flag & MNT_VISFLAGMASK;
    600   1.99       ast 	for (f = 0, o = optnames; flags && o <
    601   1.58  christos 	    &optnames[sizeof(optnames)/sizeof(optnames[0])]; o++)
    602   1.12   mycroft 		if (flags & o->o_opt) {
    603   1.58  christos 			if (!o->o_silent || verbose)
    604   1.24       cgd 				(void)printf("%s%s", !f++ ? " (" : ", ",
    605   1.24       cgd 				    o->o_name);
    606   1.12   mycroft 			flags &= ~o->o_opt;
    607   1.12   mycroft 		}
    608   1.24       cgd 	if (flags)
    609   1.27        pk 		(void)printf("%sunknown flag%s %#x", !f++ ? " (" : ", ",
    610   1.24       cgd 		    flags & (flags - 1) ? "s" : "", flags);
    611   1.32     lukem 	if (sfp->f_owner) {
    612   1.32     lukem 		(void)printf("%smounted by ", !f++ ? " (" : ", ");
    613   1.32     lukem 		if ((pw = getpwuid(sfp->f_owner)) != NULL)
    614   1.32     lukem 			(void)printf("%s", pw->pw_name);
    615   1.32     lukem 		else
    616   1.32     lukem 			(void)printf("%d", sfp->f_owner);
    617   1.32     lukem 	}
    618   1.71     enami 	if (verbose)
    619   1.71     enami 		(void)printf("%sfsid: 0x%x/0x%x",
    620   1.71     enami 		    !f++ ? " (" /* ) */: ", ",
    621   1.71     enami 		    sfp->f_fsidx.__fsid_val[0], sfp->f_fsidx.__fsid_val[1]);
    622   1.71     enami 
    623   1.61  christos 	if (verbose) {
    624   1.69  christos 		(void)printf("%s", !f++ ? " (" : ", ");
    625   1.70   hannken 		(void)printf("reads: sync %" PRIu64 " async %" PRIu64 "",
    626   1.69  christos 		    sfp->f_syncreads, sfp->f_asyncreads);
    627   1.70   hannken 		(void)printf(", writes: sync %" PRIu64 " async %" PRIu64 "",
    628   1.69  christos 		    sfp->f_syncwrites, sfp->f_asyncwrites);
    629   1.61  christos 		if (verbose > 1) {
    630   1.61  christos 			char buf[2048];
    631   1.63     enami 
    632   1.61  christos 			if (getmntargs(sfp, buf, sizeof(buf)))
    633   1.63     enami 				printf(", [%s: %s]", sfp->f_fstypename, buf);
    634   1.61  christos 		}
    635   1.63     enami 		printf(")\n");
    636   1.61  christos 	} else
    637   1.50        is 		(void)printf("%s", f ? ")\n" : "\n");
    638   1.61  christos }
    639   1.61  christos 
    640   1.61  christos static int
    641   1.76   xtraeme getmntargs(struct statvfs *sfs, char *buf, size_t buflen)
    642   1.61  christos {
    643   1.64     enami 
    644   1.61  christos 	if (mountfs(sfs->f_fstypename, sfs->f_mntfromname, sfs->f_mntonname, 0,
    645   1.61  christos 	    "getargs", NULL, 0, buf, buflen))
    646  1.106  christos 		return 0;
    647   1.61  christos 	else {
    648   1.61  christos 		if (*buf == '\0')
    649  1.106  christos 			return 0;
    650   1.61  christos 		if ((buf = strchr(buf, '\n')) != NULL)
    651   1.61  christos 			*buf = '\0';
    652  1.106  christos 		return 1;
    653   1.61  christos 	}
    654    1.1       cgd }
    655    1.1       cgd 
    656   1.69  christos static struct statvfs *
    657   1.76   xtraeme getmntpt(const char *name)
    658    1.1       cgd {
    659   1.69  christos 	struct statvfs *mntbuf;
    660   1.12   mycroft 	int i, mntsize;
    661    1.1       cgd 
    662    1.1       cgd 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
    663   1.12   mycroft 	for (i = 0; i < mntsize; i++)
    664   1.12   mycroft 		if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
    665   1.12   mycroft 		    strcmp(mntbuf[i].f_mntonname, name) == 0)
    666  1.106  christos 			return &mntbuf[i];
    667  1.106  christos 	return NULL;
    668    1.1       cgd }
    669    1.1       cgd 
    670   1.52  jdolecek static void
    671   1.76   xtraeme catopt(char **sp, const char *o)
    672   1.12   mycroft {
    673   1.67    itojun 	char *s, *n;
    674   1.12   mycroft 
    675   1.35   mycroft 	s = *sp;
    676   1.35   mycroft 	if (s) {
    677   1.94  christos 		easprintf(&n, "%s,%s", s, o);
    678   1.67    itojun 		free(s);
    679   1.67    itojun 		s = n;
    680   1.12   mycroft 	} else
    681   1.94  christos 		s = estrdup(o);
    682   1.35   mycroft 	*sp = s;
    683    1.1       cgd }
    684    1.1       cgd 
    685   1.35   mycroft static void
    686   1.82  christos mangle(char *options, int *argcp, const char ** volatile *argvp, int *maxargcp)
    687    1.1       cgd {
    688   1.12   mycroft 	char *p, *s;
    689   1.35   mycroft 	int argc, maxargc;
    690   1.67    itojun 	const char **argv, **nargv;
    691    1.1       cgd 
    692   1.12   mycroft 	argc = *argcp;
    693   1.35   mycroft 	argv = *argvp;
    694   1.35   mycroft 	maxargc = *maxargcp;
    695   1.35   mycroft 
    696   1.35   mycroft 	for (s = options; (p = strsep(&s, ",")) != NULL;) {
    697   1.35   mycroft 		/* Always leave space for one more argument and the NULL. */
    698   1.35   mycroft 		if (argc >= maxargc - 4) {
    699   1.94  christos 			nargv = erealloc(argv, (maxargc << 1) * sizeof(nargv));
    700   1.67    itojun 			argv = nargv;
    701   1.35   mycroft 			maxargc <<= 1;
    702   1.35   mycroft 		}
    703   1.44      ross 		if (*p != '\0') {
    704   1.12   mycroft 			if (*p == '-') {
    705   1.12   mycroft 				argv[argc++] = p;
    706   1.12   mycroft 				p = strchr(p, '=');
    707   1.12   mycroft 				if (p) {
    708   1.12   mycroft 					*p = '\0';
    709   1.12   mycroft 					argv[argc++] = p+1;
    710    1.1       cgd 				}
    711  1.103   mlelstv 			} else {
    712   1.12   mycroft 				argv[argc++] = "-o";
    713   1.12   mycroft 				argv[argc++] = p;
    714    1.1       cgd 			}
    715   1.44      ross 		}
    716   1.35   mycroft 	}
    717   1.12   mycroft 
    718   1.12   mycroft 	*argcp = argc;
    719   1.35   mycroft 	*argvp = argv;
    720   1.35   mycroft 	*maxargcp = maxargc;
    721   1.48       abs }
    722   1.48       abs 
    723   1.53     enami /* Deduce the filesystem type from the disk label. */
    724   1.53     enami static const char *
    725   1.76   xtraeme getfslab(const char *str)
    726   1.48       abs {
    727   1.73   thorpej 	static struct dkwedge_info dkw;
    728   1.48       abs 	struct disklabel dl;
    729   1.48       abs 	int fd;
    730   1.48       abs 	int part;
    731   1.48       abs 	const char *vfstype;
    732   1.48       abs 	u_char fstype;
    733   1.53     enami 	char buf[MAXPATHLEN + 1];
    734   1.51       abs 	char *sp, *ep;
    735   1.48       abs 
    736   1.51       abs 	if ((fd = open(str, O_RDONLY)) == -1) {
    737   1.51       abs 		/*
    738   1.51       abs 		 * Iff we get EBUSY try the raw device. Since mount always uses
    739   1.51       abs 		 * the block device we know we are never passed a raw device.
    740   1.51       abs 		 */
    741   1.51       abs 		if (errno != EBUSY)
    742   1.94  christos 			err(EXIT_FAILURE, "cannot open `%s'", str);
    743   1.51       abs 		strlcpy(buf, str, MAXPATHLEN);
    744   1.51       abs 		if ((sp = strrchr(buf, '/')) != NULL)
    745   1.51       abs 			++sp;
    746   1.51       abs 		else
    747   1.51       abs 			sp = buf;
    748   1.53     enami 		for (ep = sp + strlen(sp) + 1;  ep > sp; ep--)
    749   1.53     enami 			*ep = *(ep - 1);
    750   1.51       abs 		*sp = 'r';
    751   1.51       abs 
    752   1.51       abs 		/* Silently fail here - mount call can display error */
    753   1.51       abs 		if ((fd = open(buf, O_RDONLY)) == -1)
    754  1.106  christos 			return NULL;
    755   1.51       abs 	}
    756   1.49       abs 
    757   1.73   thorpej 	/* Check to see if this is a wedge. */
    758   1.73   thorpej 	if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) {
    759   1.73   thorpej 		/* Yup, this is easy. */
    760  1.106  christos 		close(fd);
    761  1.107  christos 		if (*dkw.dkw_ptype)
    762  1.106  christos 			return dkw.dkw_ptype;
    763  1.106  christos 		return NULL;
    764   1.73   thorpej 	}
    765   1.73   thorpej 
    766   1.51       abs 	if (ioctl(fd, DIOCGDINFO, &dl) == -1) {
    767   1.54     enami 		(void) close(fd);
    768  1.106  christos 		return NULL;
    769   1.49       abs 	}
    770   1.48       abs 
    771   1.48       abs 	(void) close(fd);
    772   1.48       abs 
    773   1.48       abs 	part = str[strlen(str) - 1] - 'a';
    774   1.48       abs 
    775   1.48       abs 	if (part < 0 || part >= dl.d_npartitions)
    776  1.106  christos 		return NULL;
    777   1.48       abs 
    778   1.48       abs 	/* Return NULL for unknown types - caller can fall back to ffs */
    779   1.48       abs 	if ((fstype = dl.d_partitions[part].p_fstype) >= FSMAXMOUNTNAMES)
    780   1.48       abs 		vfstype = NULL;
    781   1.48       abs 	else
    782   1.48       abs 		vfstype = mountnames[fstype];
    783   1.48       abs 
    784  1.106  christos 	return vfstype;
    785    1.1       cgd }
    786    1.1       cgd 
    787   1.52  jdolecek static void
    788   1.76   xtraeme usage(void)
    789    1.1       cgd {
    790    1.1       cgd 
    791   1.94  christos 	(void)fprintf(stderr, "Usage: %s [-Aadfruvw] [-t type]\n"
    792   1.94  christos 	    "\t%s [-dfruvw] special | node\n"
    793   1.94  christos 	    "\t%s [-dfruvw] [-o options] [-t type] special node\n",
    794   1.94  christos 	    getprogname(), getprogname(), getprogname());
    795   1.12   mycroft 	exit(1);
    796    1.1       cgd }
    797