[RFC] Teaching mount(8) to use nmount()

Craig Rodrigues rodrigc at crodrigues.org
Fri Oct 7 19:46:20 PDT 2005


Hi,

The mount(8) command-line program that is used in FreeBSD behaves more
or less as follows:

The mount program will process the command-line arguments,
and then fork() and do one of the following:

-> The filesystem to mount is UFS, either by specifying "-t ufs" or
   omitting the -t flag entirely. 
   An internal function
   mount_ufs() which in turn calls the "old-style" mount() syscall
   to actually mount the filesystem

-> If you specify some other filesystem, "-t myfoofs", then
   the mount program will exec() a copy of "mount_myfoofs", passing
   the command-line parameters that are necessary to mount the FS.

If someone comes along with a new filesystem, they then need
to create a new mount_mynewfs binary, in order to mount
the filesystem with mount -t mynewfs.

This is OK, but leads to a plethora of mount_* binaries which 
are probably unnecessary.  I think that the mount program
should eventually do the following:

-> for most filesystems (including UFS), the
   mount program should parse command-line arguments, and invoke
   the new nmount() syscall
-> for very exceptional cases (not to be encouraged), like NFS, SMBFS, etc.,
   instead of calling nmount() directly, we can fork() a new
   mount_nfs, mount_smbfs, etc. binary and do the mount


Since I don't know how all the existing mount programs work, and I
don't know the dependencies on how UFS mounting works, I propose
an interim behavior for mount:

    if (filesystem_to_mount == "ufs" ) {
          call special mount_ufs() function
    } else if (filesystem_to_mount == something that needs an external binary) {
          fork() and exec("mount_somefoofs");
    } else {
          call nmount()
    } 

When things get cleaned up, we can eliminate the special mount_ufs()
function, and just have everything call nmount(), except for
the special cases which need their own mount program.

In the list of filesystems which need an external binary, I put all
the mount_* binaries I could find on my FreeBSD box except the ones for
mount_std, mount_devfs, mount_fdescfs, mount_linprocfs, mount_procfs because:
  -> all these binaries are copies of mount_std, mount_std checks 
     argv[0] to see how it was invoked.
        if argv[0] == "mount_std"  it is an error
        else { strip out the mount_ part of argv[0], and nmount() that
               filesystem }

  -> so mount_std and friends are basically thin wrappers around nmount
    
I would appreciate any comments on the attached patch. 
-- 
Craig Rodrigues        
rodrigc at crodrigues.org
-------------- next part --------------
? ktrace.out
? mount
? mount.8.gz
Index: Makefile
===================================================================
RCS file: /home/ncvs/src/sbin/mount/Makefile,v
retrieving revision 1.16
diff -u -u -r1.16 Makefile
--- Makefile	7 Oct 2005 02:22:48 -0000	1.16
+++ Makefile	8 Oct 2005 02:23:29 -0000
@@ -2,7 +2,7 @@
 # $FreeBSD: src/sbin/mount/Makefile,v 1.16 2005/10/07 02:22:48 rodrigc Exp $
 
 PROG=	mount
-SRCS=	mount.c mount_ufs.c getmntopts.c vfslist.c
+SRCS=	mount.c mount_fs.c mount_ufs.c getmntopts.c vfslist.c
 WARNS?=	3
 MAN=	mount.8
 # We do NOT install the getmntopts.3 man page.
Index: extern.h
===================================================================
RCS file: /home/ncvs/src/sbin/mount/extern.h,v
retrieving revision 1.5
diff -u -u -r1.5 extern.h
--- extern.h	7 Oct 2005 02:18:20 -0000	1.5
+++ extern.h	8 Oct 2005 02:23:29 -0000
@@ -32,3 +32,4 @@
 
 /* mount_ufs.c */
 int mount_ufs(int, char * const []);
+int mount_fs(const char *, int, char * const []);
Index: mount.c
===================================================================
RCS file: /home/ncvs/src/sbin/mount/mount.c,v
retrieving revision 1.71
diff -u -u -r1.71 mount.c
--- mount.c	7 Oct 2005 02:22:04 -0000	1.71
+++ mount.c	8 Oct 2005 02:23:29 -0000
@@ -120,6 +120,67 @@
 	0
 };
 
+static int
+use_mountprog(const char *vfstype)
+{
+	/* XXX: We need to get away from implementing external mount
+	 *      programs for every filesystem, and move towards having
+	 *	each filesystem properly implement the nmount() system call.
+	 */
+	unsigned int i;
+	const char *fs[] = {
+	"cd9660", "ext2fs", "mfs", "msdosfs", "nfs", "nfs4", "ntfs",
+	"nwfs", "nullfs", "portalfs", "reiserfs", "smbfs", "udf", "umapfs",
+	"unionfs",
+	NULL
+	};
+
+	for (i=0; fs[i] != NULL; ++i) {
+		if (strcmp(vfstype, fs[i]) == 0)
+			return 1;
+	}
+	
+	return 0;
+}
+
+static int
+exec_mountprog(const char *vfstype, const char *name, const char *execname,
+	char *const argv[])
+{
+	pid_t pid;
+	int status;
+
+	switch (pid = fork()) {
+	case -1:				/* Error. */
+		warn("fork");
+		exit (1);
+	case 0:					/* Child. */
+		/* Go find an executable. */
+		execvP(execname, _PATH_SYSPATH, argv);
+		if (errno == ENOENT) {
+			warn("exec %s not found in %s", execname,
+			    _PATH_SYSPATH);
+		}
+		exit(1);
+	default:				/* Parent. */
+		if (waitpid(pid, &status, 0) < 0) {
+			warn("waitpid");
+			return (1);
+		}
+
+		if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status) != 0)
+				return (WEXITSTATUS(status));
+		} else if (WIFSIGNALED(status)) {
+			warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
+			return (1);
+		}
+		break;
+	}
+
+	return (0);
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -385,8 +446,7 @@
 {
 	const char *argv[100];
 	struct statfs sf;
-	pid_t pid;
-	int argc, i, status;
+	int argc, i, ret;
 	char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX];
 
 #if __GNUC__
@@ -447,50 +507,26 @@
 		return (0);
 	}
 
-	switch (pid = fork()) {
-	case -1:				/* Error. */
-		warn("fork");
-		free(optbuf);
-		return (1);
-	case 0:					/* Child. */
-		if (strcmp(vfstype, "ufs") == 0)
-			exit(mount_ufs(argc, (char * const *) argv));
-
-		/* Go find an executable. */
-		execvP(execname, _PATH_SYSPATH, (char * const *)argv);
-		if (errno == ENOENT) {
-			warn("exec mount_%s not found in %s", vfstype,
-			    _PATH_SYSPATH);
-		}
-		exit(1);
-		/* NOTREACHED */
-	default:				/* Parent. */
-		free(optbuf);
+	if (strcmp(vfstype, "ufs")==0) {
+		ret = mount_ufs(argc, (char * const *) argv);
+	} else if (use_mountprog(vfstype)) {
+		ret = exec_mountprog(vfstype, name, execname,
+			 (char * const *)argv);
+	} else {
+		ret = mount_fs(vfstype, argc,(char * const *)argv); 
+	}
 
-		if (waitpid(pid, &status, 0) < 0) {
-			warn("waitpid");
-			return (1);
-		}
+	free(optbuf);
 
-		if (WIFEXITED(status)) {
-			if (WEXITSTATUS(status) != 0)
-				return (WEXITSTATUS(status));
-		} else if (WIFSIGNALED(status)) {
-			warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
+	if (verbose) {
+		if (statfs(name, &sf) < 0) {
+			warn("statfs %s", name);
 			return (1);
 		}
-
-		if (verbose) {
-			if (statfs(name, &sf) < 0) {
-				warn("statfs %s", name);
-				return (1);
-			}
-			if (fstab_style)
-				putfsent(&sf);
-			else
-				prmount(&sf);
-		}
-		break;
+		if (fstab_style)
+			putfsent(&sf);
+		else
+			prmount(&sf);
 	}
 
 	return (0);
Index: mount_fs.c
===================================================================
RCS file: mount_fs.c
diff -N mount_fs.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mount_fs.c	8 Oct 2005 02:23:29 -0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mount_fs.c	8.6 (Berkeley) 4/26/95";
+#endif
+static const char rcsid[] =
+	"$Id$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+#include "mntopts.h"
+
+struct mntopt mopts[] = {
+	MOPT_STDOPTS,
+	MOPT_END
+};
+
+extern int getmnt_silent;
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr,
+		"usage: mount_xfs [-t fstype] [-o options] target_fs mount_point\n");
+	exit(1);
+}
+
+int
+mount_fs(const char *vfstype, int argc, char * const argv[])
+{
+	struct iovec *iov;
+	int iovlen;
+	int mntflags = 0;
+	int ch;
+	char *dev, *dir, mntpath[MAXPATHLEN];
+	char fstype[32];
+	char *p, *val;
+	int ret;
+	int i;
+	printf("argc is: %d\n", argc); for (i=0; i < argc; ++i) { printf("%d: %s\n", argc, argv[i]); }
+	strncpy(fstype, vfstype, sizeof(fstype));
+
+	getmnt_silent = 1;
+	iov = NULL;
+	iovlen = 0;
+
+	optind = optreset = 1;		/* Reset for parse of new argv. */
+	while ((ch = getopt(argc, argv, "o:")) != -1) {
+		switch(ch) {
+		case 'o':
+			getmntopts(optarg, mopts, &mntflags, 0);
+			p = strchr(optarg, '=');
+			val = "";
+			if (p != NULL) {
+				*p = '\0';
+				val = p + 1;
+			}
+			build_iovec(&iov, &iovlen, optarg, val, -1);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	printf("argc is: %d\n", argc);
+	if (argc != 2)
+		usage();
+
+	dev = argv[0];
+	dir = argv[1];
+
+	(void)checkpath(dir, mntpath);
+	(void)rmslashes(dev, dev);
+
+	build_iovec(&iov, &iovlen, "fstype", fstype, -1);
+	build_iovec(&iov, &iovlen, "fspath", mntpath, -1);
+	build_iovec(&iov, &iovlen, "from", dev, -1);
+	
+	ret = nmount(iov, iovlen, mntflags);
+	if (ret < 0)
+		err(1, "%s", dev);
+
+	return (ret);
+}


More information about the freebsd-arch mailing list