ref: 0f4c61a67f143d93d4201bc803578d7cc160c439
parent: c1f1f16b8835d7c0f0ea6ba446da8a6f34edd364
author: kvik <[email protected]>
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),