[RFC] mount(8) can figure out fstype

Craig Rodrigues rodrigc at crodrigues.org
Thu Jan 18 13:49:38 UTC 2007


Hi,

This is a different version of the patch I posted here:
http://lists.freebsd.org/pipermail/freebsd-arch/2006-July/005439.html

One of the pet peeves I have with FreeBSD is that
if I have a device with a local filesystem that I want to mount,
I need to explicitly know what type of filesystem is on the
device in order to mount it from the command-line.

For example,

mount -t cd9660
mount -t udf
mount -t ext2fs
mount -t msdosfs

Where this is particularly annoying is if I have multiple
USB thumb drives with different filesystems on them.

What I usually end up doing is something like:
file - < /dev/ad0s4

to figure out the filesystem type, and then mount -t [whatever] to mount it.

What I would like to do is:

mount /dev/ad0s4 /mnt

and if I do not specify a filesystem type with -t, the mount
program should "magically" figure out how to mount the disk.
This is closer to how the mount program behaves on Linux for example.

In this patch, I only modified the userland mount program.
If the user does not specify "-t vfstype" to mount,
the mount program gets a list of local filesystems from the vfs.conflist
sysctl.  It then tries to mount the filesystem, always
starting with "ufs", and then iterating through the list if 
the nmount() fails with EINVAL.

Using this patch, I have been able to do:
mount /dev/blah /mnt

and mount a UFS, cd9660, or FAT filesystem, depending on what filesystem
is on the /dev/blah device.

Comments?
-- 
Craig Rodrigues        
rodrigc at crodrigues.org
-------------- next part --------------
Index: mount.c
===================================================================
RCS file: /home/ncvs/src/sbin/mount/mount.c,v
retrieving revision 1.92
diff -u -u -r1.92 mount.c
--- mount.c	14 Nov 2006 01:07:42 -0000	1.92
+++ mount.c	18 Jan 2007 13:41:53 -0000
@@ -139,6 +139,9 @@
 	NULL
 	};
 
+	if (vfstype == NULL)
+		return (0);
+
 	for (i = 0; fs[i] != NULL; ++i) {
 		if (strcmp(vfstype, fs[i]) == 0)
 			return (1);
@@ -219,7 +222,7 @@
 	ro = 0;
 	options = NULL;
 	vfslist = NULL;
-	vfstype = "ufs";
+	vfstype = NULL;
 	while ((ch = getopt(argc, argv, "adF:flo:prt:uvw")) != -1)
 		switch (ch) {
 		case 'a':
@@ -516,7 +519,7 @@
 		optbuf = catopt(optbuf, "update");
 
 	/* Compatibility glue. */
-	if (strcmp(vfstype, "msdos") == 0)
+	if (vfstype != NULL && strcmp(vfstype, "msdos") == 0)
 		vfstype = "msdosfs";
 
 	/* Construct the name of the appropriate mount command */
@@ -532,8 +535,11 @@
 	if (debug) {
 		if (use_mountprog(vfstype))
 			printf("exec: mount_%s", vfstype);
-		else
-			printf("mount -t %s", vfstype);
+		else {
+			printf("mount ");
+			if (vfstype != NULL)
+				printf("-t %s", vfstype);
+		};
 		for (i = 1; i < argc; i++)
 			(void)printf(" %s", argv[i]);
 		(void)printf("\n");
Index: mount_fs.c
===================================================================
RCS file: /home/ncvs/src/sbin/mount/mount_fs.c,v
retrieving revision 1.3
diff -u -u -r1.3 mount_fs.c
--- mount_fs.c	7 Dec 2006 03:24:43 -0000	1.3
+++ mount_fs.c	18 Jan 2007 13:41:53 -0000
@@ -50,8 +50,10 @@
 
 #include <sys/param.h>
 #include <sys/mount.h>
+#include <sys/sysctl.h>
 
 #include <err.h>
+#include <errno.h>
 #include <getopt.h>
 #include <libgen.h>
 #include <stdio.h>
@@ -62,6 +64,8 @@
 #include "extern.h"
 #include "mntopts.h"
 
+extern int debug, verbose;
+
 struct mntopt mopts[] = {
 	MOPT_STDOPTS,
 	MOPT_END
@@ -75,8 +79,9 @@
 	exit(1);
 }
 
-int
-mount_fs(const char *vfstype, int argc, char *argv[])
+static int
+do_mount_fs(const char *vfstype, int argc, char *argv[], int *nmount_errno,
+    char *msg, size_t msg_len)
 {
 	struct iovec *iov;
 	int iovlen;
@@ -131,8 +136,83 @@
 	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
 	
 	ret = nmount(iov, iovlen, mntflags);
+	if (nmount_errno != NULL)
+		*nmount_errno = errno;
 	if (ret < 0)
-		err(1, "%s %s", dev, errmsg);
+		snprintf(msg, msg_len, "%s : %s : %s", dev, errmsg,
+		    strerror(errno));
+
+	return (ret);
+}
+
+static int
+mount_fs_try(int argc, char *argv[])
+{
+	struct xvfsconf *vfsp;
+	char msg[512];
+	unsigned int cnt, i;
+	int ret, j, nmount_errno;
+	size_t buflen;
+
+	/* First, see if mounting mounting with vfstype "ufs" works. */
+	ret = do_mount_fs("ufs", argc, argv, &nmount_errno, msg, sizeof(msg));
+	if (ret == 0)
+		return (0);
+
+	/* Get a list of registered vfs types */
+	if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0)
+		err(1, "sysctl(vfs.conflist)");
+	vfsp = malloc(buflen);
+	if (vfsp == NULL)
+		errx(1, "malloc failed");
+	if (sysctlbyname("vfs.conflist", vfsp, &buflen, NULL, 0) < 0)
+		err(1, "sysctl(vfs.conflist)");
+	cnt = buflen / sizeof(struct xvfsconf);
+
+	for (i = 0; i < cnt; i++) {
+		 /* We already tried "ufs" above, so skip it. */ 
+		if (strcmp("ufs", vfsp[i].vfc_name) == 0)
+			continue;
+		/*
+		 * Only try local filesystems.  Skip network, synthetic,
+		 * and loopback filesystems.
+		 */
+		if (vfsp[i].vfc_flags &
+		    (VFCF_NETWORK | VFCF_SYNTHETIC | VFCF_LOOPBACK))
+			continue;
+
+		if (debug || verbose) {
+			printf("mount -t %s ", vfsp[i].vfc_name);
+			for (j = 1; j < argc; j++)
+                        	(void)printf(" %s", argv[j]);
+	                (void)printf("\n");
+		}
+		ret = do_mount_fs(vfsp[i].vfc_name, argc, argv, &nmount_errno,
+		    msg, sizeof(msg));
+		if (ret == 0 || nmount_errno != EINVAL)
+			break;
+	}
+	free(vfsp);
+
+	if (ret < 0)
+		printf("%s", msg);
+	return (ret);
+}
+
+int
+mount_fs(const char *vfstype, int argc, char *argv[])
+{
+	char msg[512];
+	int ret, nmount_errno;
+
+	if (vfstype != NULL) {
+		ret = do_mount_fs(vfstype, argc, argv, &nmount_errno, msg,
+		    sizeof(msg));
+		if (ret < 0)
+			printf("%s", msg);
+	}
+	else
+		ret = mount_fs_try(argc, argv);
 
 	return (ret);
 }


More information about the freebsd-current mailing list