shithub: unionfs

Download patch

ref: 0f4c61a67f143d93d4201bc803578d7cc160c439
parent: c1f1f16b8835d7c0f0ea6ba446da8a6f34edd364
author: kvik <kvik@a-b.xyz>
date: Sun Apr 19 22:28:30 EDT 2020

To avoid looping into itself due to its mountpoint being one
of the unioned branches unionfs used to simply drop any cyclic
branches it found.  This kept it from jamming but is far from
being an ideal solution.  Very commonly one wants to do
something like:

	unionfs -m /root -- /root /altroot

To avoid the /root branch being dropped one would have to
resort to manual trickery such as:

	bind /root /mnt/tmproot
	unionfs -m /root -- /mnt/tmproot /altroot

We now do basically this same trick internally, so that the
first command above works as expected.

--- a/unionfs.c
+++ b/unionfs.c
@@ -695,6 +695,19 @@
 	.destroyfid = destroyfid,
 };
 
+char*
+pivot(char *p)
+{
+	static n = 0;
+	char *q;
+
+	if((q = smprint("/mnt/union.%d.%d", getpid(), n++)) == nil)
+		sysfatal("smprint: %r");
+	if(bind(p, q, MREPL) < 0)
+		sysfatal("bind: %r");
+	return q;
+}
+
 void
 usage(void)
 {
@@ -706,7 +719,7 @@
 main(int argc, char *argv[])
 {
 	int c, i, mflag, stdio;
-	char *mtpt, *srvname;
+	char *mtpt, *srvname, *branch, *p;
 	Dir *d;
 	Union *u;
 
@@ -752,18 +765,22 @@
 			c++;
 			continue;
 		}
-		if(mtpt && strcmp(argv[i], mtpt) == 0){
-			fprint(2, "%s: mountpoint cycle, skipping branch %s\n", argv0, argv[i]);
+
+		branch = mkpath(argv[i], nil);
+		if((d = dirstat(branch)) == nil){
+			fprint(2, "%s: %s does not exist, skipping\n", argv0, branch);
+			free(branch);
 			continue;
 		}
-		if((d = dirstat(argv[i])) == nil){
-			fprint(2, "%s: %s does not exist, skipping\n", argv0, argv[i]);
-			continue;
-		}
 		free(d);
+		if(mtpt && strcmp(branch, mtpt) == 0){
+			p = pivot(branch);
+			free(branch);
+			branch = p;
+		}
 		u = emalloc(sizeof(*u));
 		u->create = c == 1 ? c : 0;
-		u->root = mkpath(argv[i], nil);
+		u->root = branch;
 		unionlink(unionlist, u);
 	}
 	if(unionlist->next == &u0)
--- a/unionfs.man
+++ b/unionfs.man
@@ -73,21 +73,15 @@
 	/rc/bin /$objtype/bin
 .EE
 .PP
-Compile the system, redirecting all the build
+Compile the system, redirecting all build
 artifacts to a
 .IR ramfs (4):
 .PP
 .EX
-; ramfs
-; bind /sys/src /mnt/src
-; unionfs -m /sys/src /tmp /mnt/src
+; ramfs -m /tmp
+; unionfs -m /sys/src /tmp /sys/src
 ; @{cd /sys/src; mk install}
 .EE
-.PP
-The temporary bind is necessary for
-avoiding a cycle caused by unioned tree
-.I /sys/src
-being the same as the mountpoint.
 .SH SEE ALSO
 .IR bind (1),
 .IR bind (2),