Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 11 Apr 2017 21:55:40 +0000 (UTC)
From:      Maxim Sobolev <sobomax@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r316718 - head/sbin/mksnap_ffs
Message-ID:  <201704112155.v3BLtepk065823@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sobomax
Date: Tue Apr 11 21:55:39 2017
New Revision: 316718
URL: https://svnweb.freebsd.org/changeset/base/316718

Log:
  Work around an issue with mksnap_ffs not working in chroot'ed environment.
  The problem is that the statfs(2) system call used to determine the relevant
  mount point returns path within real root in the f_mntonname, causing
  nmount(2) system call to fail with ENOENT.
  
  Use a bit of heuristics to skip over few starting path elements when it
  happens until we hit an actual mount point.
  
  For this to work properly the whole mount should be accessible within the
  chroot, it's going to still fail if chroot only has access to a part of the
  mounted fs.
  
  Reviewed by:	mckusick
  Approved by:	mckusick
  MFC after:	2 weeks

Modified:
  head/sbin/mksnap_ffs/mksnap_ffs.c

Modified: head/sbin/mksnap_ffs/mksnap_ffs.c
==============================================================================
--- head/sbin/mksnap_ffs/mksnap_ffs.c	Tue Apr 11 20:28:15 2017	(r316717)
+++ head/sbin/mksnap_ffs/mksnap_ffs.c	Tue Apr 11 21:55:39 2017	(r316718)
@@ -58,6 +58,33 @@ usage(void)
 	errx(EX_USAGE, "usage: mksnap_ffs snapshot_name");
 }
 
+static int
+isdir(const char *path)
+{
+	struct stat stbuf;
+
+	if (stat(path, &stbuf) < 0)
+		return (-1);
+        if (!S_ISDIR(stbuf.st_mode))
+		return (0);
+	return (1);
+}
+
+static int
+issamefs(const char *path, struct statfs *stfsp)
+{
+	struct statfs stfsbuf;
+
+	if (isdir(path) != 1)
+		return (-1);
+	if (statfs(path, &stfsbuf) < 0)
+		return (-1);
+	if ((stfsbuf.f_fsid.val[0] != stfsp->f_fsid.val[0]) ||
+	    (stfsbuf.f_fsid.val[1] != stfsp->f_fsid.val[1]))
+		return (0);
+	return (1);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -96,16 +123,33 @@ main(int argc, char **argv)
 	}
 	if (statfs(path, &stfsbuf) < 0)
 		err(1, "%s", path);
-	if (stat(path, &stbuf) < 0)
+	switch (isdir(path)) {
+	case -1:
 		err(1, "%s", path);
-	if (!S_ISDIR(stbuf.st_mode))
+	case 0:
 		errx(1, "%s: Not a directory", path);
+	default:
+		break;
+	}
 	if (access(path, W_OK) < 0)
 		err(1, "Lack write permission in %s", path);
 	if ((stbuf.st_mode & S_ISTXT) && stbuf.st_uid != getuid())
 		errx(1, "Lack write permission in %s: Sticky bit set", path);
 
 	/*
+	 * Work around an issue when mksnap_ffs is started in chroot'ed
+	 * environment and f_mntonname contains absolute path within
+	 * real root.
+	 */
+	for (cp = stfsbuf.f_mntonname; issamefs(cp, &stfsbuf) != 1;
+	    cp = strchrnul(cp + 1, '/')) {
+		if (cp[0] == '\0')
+			errx(1, "%s: Not a mount point", stfsbuf.f_mntonname);
+	}
+	if (cp != stfsbuf.f_mntonname)
+		strlcpy(stfsbuf.f_mntonname, cp, sizeof(stfsbuf.f_mntonname));
+
+	/*
 	 * Having verified access to the directory in which the
 	 * snapshot is to be built, proceed with creating it.
 	 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201704112155.v3BLtepk065823>