Subject: mounting by wedge name
To: None <tech-userlevel@netbsd.org>
From: Jeff Rizzo <riz@tastylime.net>
List: tech-userlevel
Date: 12/22/2007 18:55:57
This is a multi-part message in MIME format.
--------------060004070909080100020402
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

I've been working on various things lately to improve the state of
wedges and wedge-related things - one of the (valid) complaints is that
there is no way to 'nail down' wedge configuration currently.  With the
attached patch, however, one can specify the wedge's *name* to mount
from.  With the current DKWEDGE_AUTODISCOVER options, the name is set
according to the underlying disk-labelling method:

DKWEDGE_METHOD_GPT:  copied from the user-supplied label if it exists,
the partition GUID if not
DKWEDGE_METHOD_BSDLABEL:  set to the BSD disklabel partition name (e.g.
"wd0a", "sd1g")
DKWEDGE_METHOD_MBR: set to a bsd-style partition name beginning with the
'e' partition - up to 4 per disk (e.g., "wd0e" through "wd0h")

This is sufficient to ensure you're mounting the partition you
*intended* to mount.  Currently, the kernel requires manual intervention
if it tries to configure two wedges with the name wname.

Wedges-by-name are specified by wedge:<wedgename>, following some prior
art in the kernel from David Young.  With the attached patch, I can use
this line in my fstab:

wedge:b57b54a4-ad31-11dc-93e5-000c29746425 /foo ffs rw 1 2

to mount "/foo":

netbsd# mount /foo
netbsd# df -h /foo
Filesystem        Size       Used      Avail %Cap Mounted on
/dev/dk4          7.9G       2.0K       7.5G   0% /foo
netbsd#


or, I can do it on the command line:

netbsd# mount wedge:b57b54a4-ad31-11dc-93e5-000c29746425 /mnt
netbsd# df -h /mnt
Filesystem        Size       Used      Avail %Cap Mounted on
/dev/dk4          7.9G       2.0K       7.5G   0% /mnt


This is primarily a proof of concept;  assuming this meets with people's
general approval, there's a lot of tools left to convert (including most
of the mount_* commands - I've only done ffs and lfs so far) - but I
wanted to get some feedback before doing any more work on it. 

Is this a good approach?  How bad is my code?  :)

Known issues:
    - with this patch, wedge:/foo does not refer to an nfs mount.  :)
    - wedge names are specified as uint8_t [] (Unicode UTF-8), but this
patch treats them as char [].  What's the proper way to deal with utf-8?
    - I wasn't sure the best way to handle the string returned by
getwedgebyname() - suggestions?


What have I missed?  Suggestions gratefully accepted.
Thanks!

+j


--------------060004070909080100020402
Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0";
 name="mountbyname.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="mountbyname.diff"

Index: lib/libutil/Makefile
===================================================================
RCS file: /cvsroot/src/lib/libutil/Makefile,v
retrieving revision 1.56
diff -u -r1.56 Makefile
--- lib/libutil/Makefile	25 Sep 2007 01:13:56 -0000	1.56
+++ lib/libutil/Makefile	23 Dec 2007 00:54:25 -0000
@@ -9,7 +9,7 @@
 LIB=	util
 CPPFLAGS+=-DLIBC_SCCS
 SRCS=	efun.c getbootfile.c getlabelsector.c getmaxpartitions.c \
-	getmntopts.c getrawpartition.c \
+	getmntopts.c getrawpartition.c getwedgebyname.c \
 	disklabel_dkcksum.c disklabel_scan.c \
 	if_media.c \
 	login.c loginx.c login_cap.c login_tty.c logout.c logoutx.c \
@@ -21,7 +21,7 @@
 
 MAN=	efun.3 getbootfile.3 getlabelsector.3 getmaxpartitions.3 \
 	getmntopts.3 \
-	getrawpartition.3 \
+	getrawpartition.3 getwedgebyname.3 \
 	login.3 login_cap.3 loginx.3 \
 	disklabel_dkcksum.3 disklabel_scan.3 \
 	opendisk.3 openpty.3 parsedate.3 pidfile.3 pidlock.3 \
Index: lib/libutil/getwedgebyname.3
===================================================================
RCS file: lib/libutil/getwedgebyname.3
diff -N lib/libutil/getwedgebyname.3
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libutil/getwedgebyname.3	23 Dec 2007 00:54:26 -0000
@@ -0,0 +1,63 @@
+.\"	$NetBSD$
+.\"
+.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jeffrey C. Rizzo
+.\"
+.\" 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 NetBSD
+.\"        Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd December 22, 2007
+.Dt GETWEDGEBYNAME 3
+.Os
+.Sh NAME
+.Nm getwedgebyname
+.Nd get the device name of a named wedge
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In util.h
+.Ft char *
+.Fo getwedgebyname 
+.Fa "const char *wname"
+.Fc
+.Sh DESCRIPTION
+.Fn getwedgebyname
+returns the device name of the wedge named
+.Va wname ,
+or NULL if the name was not found or an error occurred.
+The caller is expected to
+.Fn free
+the returned pointer.
+.Sh HISTORY
+The
+.Nm
+function call appeared in
+.Nx 5.0 .
Index: lib/libutil/getwedgebyname.c
===================================================================
RCS file: lib/libutil/getwedgebyname.c
diff -N lib/libutil/getwedgebyname.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/libutil/getwedgebyname.c	23 Dec 2007 00:54:26 -0000
@@ -0,0 +1,119 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jeffrey C. Rizzo
+ *
+ * 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 NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/dkio.h>
+#include <sys/device.h>
+#include <sys/disk.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+static int findwedge(const char *, const char *);
+char *getwedgebyname(const char *);
+
+static int
+findwedge(const char *diskname, const char *wname)
+{
+	int fd;
+	struct dkwedge_info dkw;
+	static char dvname_store[MAXPATHLEN];	/* for opendisk(3) */
+
+	fd = opendisk(diskname, O_RDONLY, dvname_store,
+	    sizeof(dvname_store), 0);
+
+	if (fd == -1) {
+	    warn("%s", diskname);
+	    return 0;
+	}
+
+	if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == -1) {
+	    close(fd);
+	    return 0;
+	}
+
+	close(fd);
+	if (strcmp((char *)dkw.dkw_wname, wname) == 0) /* XXX */
+	    return 1;
+	else
+	    return 0;
+}
+
+char *
+getwedgebyname(const char *wname)
+{
+	size_t bufsize;
+	char *disknames, *disk, *lastp;
+	char *wedge;
+
+	if (sysctlbyname("hw.disknames", NULL, &bufsize, NULL, 0) == -1) {
+	    warn("%s: could not get buffer size", __func__);
+	    return NULL;
+	}
+
+	bufsize += 200; /* arbitrary wiggle room */
+	
+	if ((disknames = (char *)malloc(bufsize)) == NULL) {
+	    warn("Could not allocate buffer");
+	    return NULL;
+	}
+
+	if (sysctlbyname("hw.disknames", disknames, &bufsize, NULL,
+		0) == -1) {
+	    warn("Could not get names");
+	    return NULL;
+	}
+
+	for (disk = strtok_r(disknames, " ", &lastp);
+	    disk != NULL;
+	    disk = strtok_r(NULL, " ", &lastp))
+		if (findwedge(disk, wname)) {
+		    wedge = (char *)malloc(strlen(disk));
+		    strcpy(wedge, disk);
+		    free(disknames);
+		    return wedge;
+		}
+	return NULL;
+}
Index: include/util.h
===================================================================
RCS file: /cvsroot/src/include/util.h,v
retrieving revision 1.49
diff -u -r1.49 util.h
--- include/util.h	14 Dec 2007 16:36:19 -0000	1.49
+++ include/util.h	23 Dec 2007 00:54:26 -0000
@@ -72,6 +72,7 @@
 int		getlabelsector(void);
 int		getmaxpartitions(void);
 int		getrawpartition(void);
+char *		getwedgebyname(const char *);
 void		login(const struct utmp *);
 void		loginx(const struct utmpx *);
 int		login_tty(int);
Index: sbin/mount/Makefile
===================================================================
RCS file: /cvsroot/src/sbin/mount/Makefile,v
retrieving revision 1.29
diff -u -r1.29 Makefile
--- sbin/mount/Makefile	19 Aug 2004 23:02:27 -0000	1.29
+++ sbin/mount/Makefile	23 Dec 2007 00:54:26 -0000
@@ -6,5 +6,6 @@
 PROG=	mount
 MAN=	mount.8
 SRCS=	mount.c vfslist.c
+LDADD+=	-lutil
 
 .include <bsd.prog.mk>
Index: sbin/mount/mount.c
===================================================================
RCS file: /cvsroot/src/sbin/mount/mount.c,v
retrieving revision 1.84
diff -u -r1.84 mount.c
--- sbin/mount/mount.c	17 Jul 2007 23:56:01 -0000	1.84
+++ sbin/mount/mount.c	23 Dec 2007 00:54:26 -0000
@@ -56,12 +56,15 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <util.h>
 
 #define MOUNTNAMES
 #include <fcntl.h>
 #include <sys/disk.h>
 #include <sys/disklabel.h>
+#include <sys/dkio.h>
 #include <sys/ioctl.h>
+#include <sys/sysctl.h>
 
 #include "pathnames.h"
 #include "vfslist.h"
@@ -81,7 +84,6 @@
 static void	prmount(struct statvfs *);
 static void	usage(void);
 
-
 /* Map from mount otions to printable formats. */
 static const struct opt {
 	int o_opt;
@@ -92,6 +94,7 @@
 };
 
 static char ffs_fstype[] = "ffs";
+char		dvname_store[MAXPATHLEN];	/* for opendisk(3) */
 
 int
 main(int argc, char *argv[])
@@ -105,6 +108,7 @@
 	const char *mountopts, *fstypename;
 	char canonical_path_buf[MAXPATHLEN];
 	char *canonical_path;
+	char *special, specbuf[MAXPATHLEN];
 
 	/* started as "mount" */
 	all = forceall = init_flags = 0;
@@ -275,21 +279,38 @@
 		break;
 	case 2:
 		/*
+		 * Handle the wedge case first. XXX yes, this means
+		 * NFS mounts from machines named "wedge" will no
+		 * longer work correctly
+		 */
+		if (strncmp("wedge:", argv[0], strlen("wedge:")) == 0) {
+			special = getwedgebyname(argv[0] +
+				strlen("wedge:"));
+			if (special == NULL)
+				errx(1, "%s: unknown wedge name",
+					argv[0] + strlen("wedge:"));
+			snprintf(specbuf, MAXPATHLEN, "/dev/%s", special);
+			free(special);
+			special = specbuf;
+		} else
+			special = argv[0];
+
+		/*
 		 * If -t flag has not been specified, and spec contains either
 		 * a ':' or a '@' then assume that an NFS filesystem is being
 		 * specified ala Sun.
 		 */
 		if (vfslist == NULL) {
-			if (strpbrk(argv[0], ":@") != NULL)
+			if (strpbrk(special, ":@") != NULL)
 				vfstype = "nfs";
 			else {
-				vfstype = getfslab(argv[0]);
+				vfstype = getfslab(special);
 				if (vfstype == NULL)
 					vfstype = ffs_fstype;
 			}
 		}
 		rval = mountfs(vfstype,
-		    argv[0], argv[1], init_flags, options, NULL, 0, NULL, 0);
+		    special, argv[1], init_flags, options, NULL, 0, NULL, 0);
 		break;
 	default:
 		usage();
Index: sbin/mount_ffs/mount_ffs.c
===================================================================
RCS file: /cvsroot/src/sbin/mount_ffs/mount_ffs.c,v
retrieving revision 1.22
diff -u -r1.22 mount_ffs.c
--- sbin/mount_ffs/mount_ffs.c	16 Jul 2007 17:06:53 -0000	1.22
+++ sbin/mount_ffs/mount_ffs.c	23 Dec 2007 00:54:26 -0000
@@ -54,6 +54,7 @@
 
 #include <string.h>
 #include <unistd.h>
+#include <util.h>
 
 #include <mntopts.h>
 
@@ -88,6 +89,7 @@
 	struct ufs_args args;
 	int ch, mntflags;
 	char fs_name[MAXPATHLEN], canon_dev[MAXPATHLEN];
+	char *dn, dnbuf[MAXPATHLEN];
 	const char *errcause;
 	mntoptparse_t mp;
 
@@ -111,10 +113,21 @@
 	if (argc != 2)
 		ffs_usage();
 
-	if (realpath(argv[0], canon_dev) == NULL)     /* Check device path */
-		err(1, "realpath %s", argv[0]);
-	if (strncmp(argv[0], canon_dev, MAXPATHLEN)) {
-		warnx("\"%s\" is a relative path.", argv[0]);
+	if (strncmp("wedge:", argv[0], strlen("wedge:")) == 0) {
+		dn = getwedgebyname(argv[0] + strlen("wedge:"));
+		if (dn == NULL)
+			err(1, "No wedge named %s",
+				argv[0] + strlen("wedge:"));
+		snprintf(dnbuf, MAXPATHLEN, "/dev/%s", dn);
+		free(dn);
+		dn = dnbuf;
+	} else {
+		dn = argv[0];
+	}
+	if (realpath(dn, canon_dev) == NULL)     /* Check device path */
+		err(1, "realpath %s", dn);
+	if (strncmp(dn, canon_dev, MAXPATHLEN)) {
+		warnx("\"%s\" is a relative path.", dn);
 		warnx("using \"%s\" instead.", canon_dev);
 	}
 	args.fspec = canon_dev;
Index: sbin/mount_lfs/mount_lfs.c
===================================================================
RCS file: /cvsroot/src/sbin/mount_lfs/mount_lfs.c,v
retrieving revision 1.31
diff -u -r1.31 mount_lfs.c
--- sbin/mount_lfs/mount_lfs.c	17 Jul 2007 12:39:24 -0000	1.31
+++ sbin/mount_lfs/mount_lfs.c	23 Dec 2007 00:54:26 -0000
@@ -55,6 +55,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <paths.h>
+#include <util.h>
 
 #include <signal.h>
 
@@ -92,6 +93,7 @@
 	struct ufs_args args;
 	int ch, mntflags, noclean, mntsize, oldflags, i;
 	char fs_name[MAXPATHLEN], canon_dev[MAXPATHLEN];
+	char *dn, dnbuf[MAXPATHLEN];
 	char *options;
 	mntoptparse_t mp;
 
@@ -138,10 +140,21 @@
 	if (argc != 2)
 		usage();
 
-	if (realpath(argv[0], canon_dev) == NULL)     /* Check device path */
-		err(1, "realpath %s", argv[0]);
-	if (strncmp(argv[0], canon_dev, MAXPATHLEN)) {
-		warnx("\"%s\" is a relative path.", argv[0]);
+	if (strncmp("wedge:", argv[0], strlen("wedge:")) == 0) {
+		dn = getwedgebyname(argv[0] + strlen("wedge:"));
+		if (dn == NULL)
+			err(1, "No wedge named %s",
+				argv[0] + strlen("wedge:"));
+		snprintf(dnbuf, MAXPATHLEN, "/dev/%s", dn);
+		free(dn);
+		dn = dnbuf;
+	} else {
+		dn = argv[0];
+	}
+	if (realpath(dn, canon_dev) == NULL)     /* Check device path */
+		err(1, "realpath %s", dn);
+	if (strncmp(dn, canon_dev, MAXPATHLEN)) {
+		warnx("\"%s\" is a relative path.", dn);
 		warnx("using \"%s\" instead.", canon_dev);
 	}
 	args.fspec = canon_dev;

--------------060004070909080100020402--