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
This commit is contained in:
Maxim Sobolev 2017-04-11 21:55:39 +00:00
parent 9e507a6a00
commit 591e89c89b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=316718

View file

@ -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,15 +123,32 @@ 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.