[CFT] Fix DEVFS aliases in subdirectories.

Justin T. Gibbs gibbs at scsiguy.com
Fri Jun 10 21:42:09 UTC 2011


DEVFS aliases don't work correctly when generated symlinks are not
in the DEVFS root.  For example, here's a system that provides aliases
to devices based on their physical path in a SAS enclosure:

ls -l /dev/enc\@n50015b2080006ef9/type\@0/slot\@2/elmdesc\@Disk_02/*

lrwxr-xr-x  1 root  wheel  15 Jun  9 22:44 
/dev/enc at n50015b2080006ef9/type at 0/slot at 2/elmdesc at Disk_02/da6 -> 
../../../../da6
lrwxr-xr-x  1 root  wheel  17 Jun  9 22:44 
/dev/enc at n50015b2080006ef9/type at 0/slot at 2/elmdesc at Disk_02/pass7 -> 
../../../../pass7

The aliased devs are far from the root and so must have "../" entries
added in order to function correctly.  I considered making the symlink
paths absolute, but that complicates jail handling.

Are there any objections to the attached change?

Thanks,
Justin

-------------- next part --------------
Change 480877 by justing at justing-ns1 on 2011/03/03 15:48:17

	sys/fs/devfs/devfs_devs.c:
		Correct the devfs alias code to insert the correct number
		of "../"s in the target of a symlink when creating them in
		subdirectories of a devfs.

Affected files ...

... //depot/SpectraBSD/head/sys/fs/devfs/devfs_devs.c#6 edit

Differences ...

==== //depot/SpectraBSD/head/sys/fs/devfs/devfs_devs.c#6 (text) ====

@@ -488,7 +488,7 @@
 	struct devfs_dirent *de;
 	struct devfs_dirent *dd;
 	struct cdev *pdev;
-	int de_flags, j;
+	int de_flags;
 	char *q, *s;
 
 	sx_assert(&dm->dm_lock, SX_XLOCKED);
@@ -584,14 +584,43 @@
 
 		de = devfs_newdirent(s, q - s);
 		if (cdp->cdp_c.si_flags & SI_ALIAS) {
+			char *slash;
+			int depth;
+			int namelen;
+			int buflen;
+			int i;
+
+			/*
+			 * Determine depth of the link.
+			 */
+			slash = cdp->cdp_c.si_name;
+			depth = 0;
+			while ((slash = strchr(slash, '/')) != NULL) {
+				slash++;
+				depth++;
+			}
+
 			de->de_uid = 0;
 			de->de_gid = 0;
 			de->de_mode = 0755;
 			de->de_dirent->d_type = DT_LNK;
 			pdev = cdp->cdp_c.si_parent;
-			j = strlen(pdev->si_name) + 1;
-			de->de_symlink = malloc(j, M_DEVFS, M_WAITOK);
-			bcopy(pdev->si_name, de->de_symlink, j);
+			namelen = strlen(pdev->si_name) + 1;
+			buflen = (depth * 3/* "../" */) + namelen;
+			de->de_symlink = malloc(buflen, M_DEVFS, M_WAITOK);
+
+			/*
+			 * Our parent's path is relative to the root,
+			 * so our symlinked path must be relative to
+			 * the root.
+			 */
+			slash = de->de_symlink;
+			for (i = 0; i < depth; i++) {
+				bcopy("../", slash, 3);
+				slash += 3;
+			}
+
+			bcopy(pdev->si_name, slash, namelen);
 		} else {
 			de->de_uid = cdp->cdp_c.si_uid;
 			de->de_gid = cdp->cdp_c.si_gid;


More information about the freebsd-fs mailing list