From owner-svn-src-head@freebsd.org Tue Apr 11 21:55:41 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 39A05D3A9BF; Tue, 11 Apr 2017 21:55:41 +0000 (UTC) (envelope-from sobomax@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id E502EDD8; Tue, 11 Apr 2017 21:55:40 +0000 (UTC) (envelope-from sobomax@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v3BLtenj065824; Tue, 11 Apr 2017 21:55:40 GMT (envelope-from sobomax@FreeBSD.org) Received: (from sobomax@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v3BLtepk065823; Tue, 11 Apr 2017 21:55:40 GMT (envelope-from sobomax@FreeBSD.org) Message-Id: <201704112155.v3BLtepk065823@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: sobomax set sender to sobomax@FreeBSD.org using -f From: Maxim Sobolev Date: Tue, 11 Apr 2017 21:55:40 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r316718 - head/sbin/mksnap_ffs X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 11 Apr 2017 21:55:41 -0000 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. */