From nobody Thu Oct 01 21:25:51 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hwlMM5kg5z6tWWY for ; Thu, 01 Oct 2026 21:25:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hwlMM5YTGz4MpN for ; Thu, 01 Oct 2026 21:25:51 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790889951; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=PdGNtyIb233kKxQaOH8iu3/dhhHiiDTlza+NkvtldSY=; b=VmfvNIOkQu1DSUt69IUWcK9cmKrFjq7H/bcHpE4NvROUFVlKmkNWJ6eIrJLBfnGQWNINks n+cWY6kMV9wgTPImj0ucMogFicIDvFhYEuPfTLbINRvH18C4NE6ncndx7qwABzM0rawz0t aIGcJEItpqdQh0afvCHPO65wioNEa4c6yttnOnrI5aXcXPUlK1J4qEdGC5oThjH++zj612 +tznteQ05HBlwIlOSw/Oj9h0/Qv9AnYMk3d5tV0fKDyIFAzHT6cujuOxjJqaRMOSIW5yMr TeHqHc2Q/xrzc6NQR+a0MvTXt0JyW6aH9iNyzqAZh6tqNpecsp5fCFLUz7A2RA== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1790889951; b=sD5TROgPK4IefObGd9e9Wht2WNq+u3iYc9VjJ6BTRbt5lBaY8WtFHS78s8+owxp+3TJSHZ vdHlVxtJ0HVRYKPy1gyk9I4sstYZBC1/LRjIIpw8xFmKAppFLjzz+NZewRNLbs6kzXH/Um 8FqhYXRQJF+9+RKqAGKcmgMRzB5lbJ1i8NCJD1FM9wMKWbykRXITmkIG25SHhVJL5JlnLp 8IQ7VM0tK4KXe8ZPWzBbZ9Y6pBW7ojifskCEEyClsXm844rEpQIUSG7myg7APeNhcRQHaS Hq8kAIl8jpNDkDQSMbB5u7+/ipML3+TEC8e4GhshnYzHTUEgkpkD8cH6Lo954Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790889951; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=PdGNtyIb233kKxQaOH8iu3/dhhHiiDTlza+NkvtldSY=; b=XVDpE/olf8iBKCXhVk0FCYcVLvkYbcnsfKOp2kMgqAXB/iw86ex/mpC7oNjELaXNLU2dKp XqQXF4swpeMzfztrY8VjXPyeu2PP8Na495SbHKszKgN9D33YoUV0fQaAHQN/uDI00Ygwcp DlO/qcdEnOXT2nDQx/SPjPb6jjn89/pTUjIcTrGxXlYjDKY7eMU4oikvnQYVq+PSGXkfgM 8IeYcbSCbwhNPbBhH8A69M0ELri2Svq/17cskW1R4KbMcCSHQRJhYacffB1vrbv+Em8QsN WG8x7hkdsK1/XzMMUjQ/gt6qlBmSxyUfwfK67Tr9RF6h9svE6CJgBlxmW89Tlw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hwlMM4L8gzq4W for ; Thu, 01 Oct 2026 21:25:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3a8dc by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 01 Oct 2026 21:25:51 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Maxim Sobolev Subject: git: 43b0384bc7e8 - main - mountpoint(1): new utility, implemented as a stat(1) hardlink List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: sobomax X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 43b0384bc7e87df5bd164ce833617e68824f4828 Auto-Submitted: auto-generated Date: Thu, 01 Oct 2026 21:25:51 +0000 Message-Id: <6abecfdf.3a8dc.610fc5a7@gitrepo.freebsd.org> The branch main has been updated by sobomax: URL: https://cgit.FreeBSD.org/src/commit/?id=43b0384bc7e87df5bd164ce833617e68824f4828 commit 43b0384bc7e87df5bd164ce833617e68824f4828 Author: Maxim Sobolev AuthorDate: 2026-10-01 21:25:37 +0000 Commit: Maxim Sobolev CommitDate: 2026-10-01 21:25:37 +0000 mountpoint(1): new utility, implemented as a stat(1) hardlink Add mountpoint(1), a simple utility to tell whether the file pointed to by the argument is a mount point. It prints whether it is, unless -q is given, and exits 0 if it is, 1 if it is not, and 2 on error. The answer comes from the kernel with a single stat(2): the root vnode of a mounted file system is reported with SFBSD_MNTPOINT in st_bsdflags. Unlike comparing realpath(3) of the argument with that of statfs(2)'s f_mntonname, this works for arbitrarily deep hierarchies, and after chroot(2) or inside a jail. A chroot or jail root is reported as a mount point only if it is one. The argument does not have to be a directory: file systems such as nullfs(5) can be mounted over regular files and sockets, and stat(2) reports those mount points as well. Since all that is needed is one stat(2) call, make mountpoint a hardlink to stat(1), the same way readlink(1) is, and document it in stat.1. Add ATF tests, including chroot(8) and jail(8) roots that are and are not mount points, nullfs roots, file systems mounted inside the root, both from the host and from within the jail, and a nullfs mount of a file over a file. Suggested by: kib Differential revision: https://reviews.freebsd.org/D59906 Sponsored by: Sippy Software, Inc. MFC after: 2 weeks --- usr.bin/stat/Makefile | 5 +- usr.bin/stat/stat.1 | 61 +++++- usr.bin/stat/stat.c | 48 ++++ usr.bin/stat/tests/Makefile | 1 + usr.bin/stat/tests/mountpoint_test.sh | 401 ++++++++++++++++++++++++++++++++++ 5 files changed, 511 insertions(+), 5 deletions(-) diff --git a/usr.bin/stat/Makefile b/usr.bin/stat/Makefile index 1694310a7a6b..10eaf16914ea 100644 --- a/usr.bin/stat/Makefile +++ b/usr.bin/stat/Makefile @@ -2,8 +2,9 @@ PROG= stat -LINKS= ${BINDIR}/stat ${BINDIR}/readlink -MLINKS= stat.1 readlink.1 +LINKS= ${BINDIR}/stat ${BINDIR}/readlink \ + ${BINDIR}/stat ${BINDIR}/mountpoint +MLINKS= stat.1 readlink.1 stat.1 mountpoint.1 HAS_TESTS= SUBDIR.${MK_TESTS}+= tests diff --git a/usr.bin/stat/stat.1 b/usr.bin/stat/stat.1 index 55e64de0767e..0780b40e11e0 100644 --- a/usr.bin/stat/stat.1 +++ b/usr.bin/stat/stat.1 @@ -29,12 +29,13 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd September 9, 2025 +.Dd October 1, 2026 .Dt STAT 1 .Os .Sh NAME .Nm stat , -.Nm readlink +.Nm readlink , +.Nm mountpoint .Nd display file status .Sh SYNOPSIS .Nm @@ -45,6 +46,9 @@ .Nm readlink .Op Fl fn .Op Ar +.Nm mountpoint +.Op Fl q +.Ar file .Sh DESCRIPTION The .Nm @@ -75,9 +79,34 @@ corresponding to .Ar file . In this case, the argument does not need to be a symbolic link. .Pp +When invoked as +.Nm mountpoint , +the utility checks whether +.Ar file +is the root of a mounted file system. +This is usually a directory, but file systems such as +.Xr nullfs 5 +can also be mounted over regular files and sockets. +Symbolic links are followed. +Unless the +.Fl q +option is given, a message stating whether +.Ar file +is a mount point is written to the standard output. +Error messages are written to the standard error even with +.Fl q . +.Pp The information displayed is obtained by calling .Xr lstat 2 with the given argument and evaluating the returned structure. +When invoked as +.Nm mountpoint , +.Xr stat 2 +is called instead and the +.Dv SFBSD_MNTPOINT +flag in the +.Fa st_bsdflags +field is checked. The default format displays the .Fa st_dev , .Fa st_ino , @@ -197,6 +226,11 @@ fail. When run as .Nm readlink , error messages are automatically suppressed. +When run as +.Nm mountpoint , +.Fl q +suppresses the normal output instead; +error messages are still written to the standard error. .It Fl f Ar format Display information using the specified format. See the @@ -513,6 +547,12 @@ which default to .Cm S . .Sh EXIT STATUS .Ex -std stat readlink +.Pp +The +.Nm mountpoint +utility exits 0 if +.Ar file +is a mount point, 1 if it is not, and 2 if an error occurred. .Sh EXAMPLES If no options are specified, the default format is "%d %i %Sp %l %Su %Sg %r %z \e"%Sa\e" \e"%Sm\e" \e"%Sc\e" \e"%SB\e" %k %b %#Xf %N". @@ -620,6 +660,19 @@ To display the same in UTC: $ TZ= stat -f %Sm -t %Y%m%d%H%M%S /tmp/foo 20070427181533 .Ed +.Pp +To check whether a directory is a mount point: +.Bd -literal -offset indent +\*[Gt] mountpoint /dev +/dev is a mount point +\*[Gt] mountpoint /usr/bin +/usr/bin is not a mount point +.Ed +.Pp +To mount a file system only if nothing is mounted there yet: +.Bd -literal -offset indent +$ mountpoint -q /mnt || mount /dev/md0 /mnt +.Ed .Sh SEE ALSO .Xr file 1 , .Xr ls 1 , @@ -627,7 +680,9 @@ $ TZ= stat -f %Sm -t %Y%m%d%H%M%S /tmp/foo .Xr readlink 2 , .Xr stat 2 , .Xr printf 3 , -.Xr strftime 3 +.Xr strftime 3 , +.Xr nullfs 5 , +.Xr mount 8 .Sh HISTORY The .Nm diff --git a/usr.bin/stat/stat.c b/usr.bin/stat/stat.c index 0707c762d100..7466212ec72a 100644 --- a/usr.bin/stat/stat.c +++ b/usr.bin/stat/stat.c @@ -139,6 +139,8 @@ #define SHOW_sizerdev 'Z' static void usage(const char *); +static int mountpoint_main(int, char *[]); +static void mountpoint_usage(void) __dead2; static void output(const struct stat *, const char *, const char *, int); static int format1(const struct stat *, /* stat info */ const char *, /* the file name */ @@ -185,6 +187,9 @@ main(int argc, char *argv[]) statfmt = NULL; timefmt = NULL; + if (strcmp(getprogname(), "mountpoint") == 0) + return (mountpoint_main(argc, argv)); + if (strcmp(getprogname(), "readlink") == 0) { am_readlink = 1; options = "fn"; @@ -392,6 +397,49 @@ usage(const char *synopsis) exit(1); } +/* + * When invoked as mountpoint, report whether the file is the root of a + * mounted file system. Exit with 0 if it is, 1 if it is not and + * 2 on error. + */ +static int +mountpoint_main(int argc, char *argv[]) +{ + struct stat st; + int ch, mounted, quiet; + + quiet = 0; + while ((ch = getopt(argc, argv, "q")) != -1) + switch (ch) { + case 'q': + quiet = 1; + break; + default: + mountpoint_usage(); + } + argc -= optind; + argv += optind; + if (argc != 1) + mountpoint_usage(); + + if (stat(argv[0], &st) == -1) + err(2, "%s", argv[0]); + + mounted = (st.st_bsdflags & SFBSD_MNTPOINT) != 0; + if (!quiet) + printf("%s is %sa mount point\n", argv[0], + mounted ? "" : "not "); + return (mounted ? 0 : 1); +} + +static void +mountpoint_usage(void) +{ + + (void)fprintf(stderr, "usage: %s [-q] file\n", getprogname()); + exit(2); +} + /* * Parses a format string. */ diff --git a/usr.bin/stat/tests/Makefile b/usr.bin/stat/tests/Makefile index d48648c55916..02ed0d9409c3 100644 --- a/usr.bin/stat/tests/Makefile +++ b/usr.bin/stat/tests/Makefile @@ -1,3 +1,4 @@ +ATF_TESTS_SH+= mountpoint_test ATF_TESTS_SH+= readlink_test ATF_TESTS_SH+= stat_test diff --git a/usr.bin/stat/tests/mountpoint_test.sh b/usr.bin/stat/tests/mountpoint_test.sh new file mode 100644 index 000000000000..667eb404c49f --- /dev/null +++ b/usr.bin/stat/tests/mountpoint_test.sh @@ -0,0 +1,401 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2026 Maksym Sobolev +# + +# Mount a file system and record its mount point for mp_cleanup. +mp_mount() +{ + local mntpt + + for mntpt; do :; done + [ -e "$mntpt" ] || atf_check mkdir -p "$mntpt" + echo "$PWD/$mntpt" >> mounts + atf_check mount "$@" +} + +mp_cleanup() +{ + [ -f mounts ] || return 0 + tail -r mounts | while read mntpt; do + umount -f "$mntpt" 2>/dev/null + done + return 0 +} + +# Populate a minimal root with sh, mountpoint and the given programs, +# together with the shared libraries they need. +mp_mkroot() +{ + local root lib prog + + root=$1 + shift + atf_check mkdir -p "$root/bin" "$root/libexec" "$root/mnt" + atf_check cp /libexec/ld-elf.so.1 "$root/libexec/" + for prog in sh mountpoint "$@"; do + prog=$(command -v "$prog") || atf_fail "$prog not found" + atf_check cp "$prog" "$root/bin/" + for lib in $(ldd -f '%p\n' "$prog" | grep '^/'); do + atf_check mkdir -p "$root${lib%/*}" + atf_check cp "$lib" "$root$lib" + done + done +} + +mp_require_jail() +{ + if [ "$(sysctl -n security.jail.jailed)" != 0 ]; then + atf_skip "Cannot create jails from within a jail" + fi +} + +# Run "mountpoint path" inside root, entered via chroot(8) or jail(8) +# as selected by mode, and check that it reports rc. jail(8) does not +# pass the exit status of the command through, so it is echoed back. +mp_check() +{ + local mode root path rc not + + mode=$1 + root=$2 + path=$3 + rc=$4 + not= + [ "$rc" -eq 0 ] || not="not " + case "$mode" in + chroot) + set -- chroot "$root" /bin/sh + ;; + jail) + set -- jail -c path="$PWD/$root" command=/bin/sh + ;; + esac + atf_check -o inline:"$path is ${not}a mount point\nrc=$rc\n" \ + "$@" -c "/bin/mountpoint $path; echo rc=\$?" +} + +atf_test_case not_mountpoint +not_mountpoint_head() +{ + atf_set "descr" "Verify that a plain directory or file is not " \ + "reported as a mount point" +} + +not_mountpoint_body() +{ + atf_check mkdir dir + atf_check -s exit:1 -o inline:"dir is not a mount point\n" \ + mountpoint dir + atf_check -s exit:1 mountpoint -q dir + atf_check touch file + atf_check -s exit:1 -o inline:"file is not a mount point\n" \ + mountpoint file +} + +atf_test_case errors +errors_head() +{ + atf_set "descr" "Verify that errors are reported with exit status 2" +} + +errors_body() +{ + atf_check -s exit:2 -e match:"No such file" mountpoint nonexistent + atf_check -s exit:2 -e match:"usage" mountpoint + atf_check -s exit:2 -e match:"usage" mountpoint a b + atf_check -s exit:2 -e match:"usage" mountpoint -x . +} + +atf_test_case mountpoint cleanup +mountpoint_head() +{ + atf_set "descr" "Verify that a mounted file system root is " \ + "reported as a mount point, also through a symlink" + atf_set "require.user" "root" +} + +mountpoint_body() +{ + mp_mount -t tmpfs tmpfs mnt + atf_check -o inline:"mnt is a mount point\n" mountpoint mnt + atf_check -o empty mountpoint -q mnt + atf_check ln -s mnt link + atf_check -o inline:"link is a mount point\n" mountpoint link + atf_check mkdir mnt/sub + atf_check -s exit:1 -o inline:"mnt/sub is not a mount point\n" \ + mountpoint mnt/sub +} + +mountpoint_cleanup() +{ + mp_cleanup +} + +atf_test_case file_mountpoint cleanup +file_mountpoint_head() +{ + atf_set "descr" "Verify that a regular file with a file system " \ + "mounted over it is reported as a mount point" + atf_set "require.user" "root" + atf_set "require.kmods" "nullfs" +} + +file_mountpoint_body() +{ + atf_check touch src dst + mp_mount -t nullfs "$PWD/src" dst + atf_check -o inline:"dst is a mount point\n" mountpoint dst + atf_check ln -s dst link + atf_check -o inline:"link is a mount point\n" mountpoint link + atf_check -s exit:1 -o inline:"src is not a mount point\n" \ + mountpoint src +} + +file_mountpoint_cleanup() +{ + mp_cleanup +} + +# The root is a plain directory on top of a mount point. Neither the +# root nor its ".." may be reported as a mount point, so the mount point +# above the root does not leak in. +root_not_mountpoint_body() +{ + mp_mount -t tmpfs tmpfs outer + mp_mkroot outer/root + mp_check $1 outer/root / 1 + mp_check $1 outer/root /.. 1 + mp_check $1 outer/root /bin 1 +} + +# The root is itself a mount point. +root_mountpoint_body() +{ + mp_mount -t tmpfs tmpfs root + mp_mkroot root + mp_check $1 root / 0 + mp_check $1 root /.. 0 + mp_check $1 root /bin 1 +} + +# The root is a nullfs mount, as is common for jails. +root_nullfs_body() +{ + mp_mkroot src + mp_mount -t nullfs "$PWD/src" root + mp_check $1 root / 0 + mp_check $1 root /bin 1 +} + +# The root is a plain directory with a file system mounted inside it. +submount_body() +{ + mp_mkroot root + mp_mount -t tmpfs tmpfs root/mnt + mp_check $1 root / 1 + mp_check $1 root /mnt 0 + mp_check $1 root /mnt/.. 1 +} + +atf_test_case chroot_root_not_mountpoint cleanup +chroot_root_not_mountpoint_head() +{ + atf_set "descr" "Verify that a chroot root which is not a mount " \ + "point is not reported as one" + atf_set "require.user" "root" +} + +chroot_root_not_mountpoint_body() +{ + root_not_mountpoint_body chroot +} + +chroot_root_not_mountpoint_cleanup() +{ + mp_cleanup +} + +atf_test_case chroot_root_mountpoint cleanup +chroot_root_mountpoint_head() +{ + atf_set "descr" "Verify that a chroot root which is a mount point " \ + "is reported as one" + atf_set "require.user" "root" +} + +chroot_root_mountpoint_body() +{ + root_mountpoint_body chroot +} + +chroot_root_mountpoint_cleanup() +{ + mp_cleanup +} + +atf_test_case chroot_root_nullfs cleanup +chroot_root_nullfs_head() +{ + atf_set "descr" "Verify that a chroot root which is a nullfs " \ + "mount is reported as a mount point" + atf_set "require.user" "root" + atf_set "require.kmods" "nullfs" +} + +chroot_root_nullfs_body() +{ + root_nullfs_body chroot +} + +chroot_root_nullfs_cleanup() +{ + mp_cleanup +} + +atf_test_case chroot_submount cleanup +chroot_submount_head() +{ + atf_set "descr" "Verify that a file system mounted inside a chroot " \ + "is reported as a mount point" + atf_set "require.user" "root" +} + +chroot_submount_body() +{ + submount_body chroot +} + +chroot_submount_cleanup() +{ + mp_cleanup +} + +atf_test_case jail_root_not_mountpoint cleanup +jail_root_not_mountpoint_head() +{ + atf_set "descr" "Verify that a jail root which is not a mount " \ + "point is not reported as one" + atf_set "require.user" "root" + atf_set "require.progs" "jail" +} + +jail_root_not_mountpoint_body() +{ + mp_require_jail + root_not_mountpoint_body jail +} + +jail_root_not_mountpoint_cleanup() +{ + mp_cleanup +} + +atf_test_case jail_root_mountpoint cleanup +jail_root_mountpoint_head() +{ + atf_set "descr" "Verify that a jail root which is a mount point " \ + "is reported as one" + atf_set "require.user" "root" + atf_set "require.progs" "jail" +} + +jail_root_mountpoint_body() +{ + mp_require_jail + root_mountpoint_body jail +} + +jail_root_mountpoint_cleanup() +{ + mp_cleanup +} + +atf_test_case jail_root_nullfs cleanup +jail_root_nullfs_head() +{ + atf_set "descr" "Verify that a jail root which is a nullfs mount " \ + "is reported as a mount point" + atf_set "require.user" "root" + atf_set "require.progs" "jail" + atf_set "require.kmods" "nullfs" +} + +jail_root_nullfs_body() +{ + mp_require_jail + root_nullfs_body jail +} + +jail_root_nullfs_cleanup() +{ + mp_cleanup +} + +atf_test_case jail_submount cleanup +jail_submount_head() +{ + atf_set "descr" "Verify that a file system mounted inside a jail " \ + "from the host is reported as a mount point" + atf_set "require.user" "root" + atf_set "require.progs" "jail" +} + +jail_submount_body() +{ + mp_require_jail + submount_body jail +} + +jail_submount_cleanup() +{ + mp_cleanup +} + +atf_test_case jail_mount_inside cleanup +jail_mount_inside_head() +{ + atf_set "descr" "Verify that a file system mounted from within " \ + "a jail is reported as a mount point there" + atf_set "require.user" "root" + atf_set "require.progs" "jail" +} + +jail_mount_inside_body() +{ + local out + + mp_require_jail + mp_mkroot root mount umount + echo "$PWD/root/mnt" >> mounts + out="/mnt is a mount point\nrc=0\n/ is not a mount point\nrc=1\n" + atf_check -o inline:"$out" jail -c path="$PWD/root" \ + allow.mount allow.mount.tmpfs enforce_statfs=1 \ + command=/bin/sh -c "/bin/mount -t tmpfs tmpfs /mnt && + /bin/mountpoint /mnt; echo rc=\$?; + /bin/mountpoint /; echo rc=\$?; + /bin/umount /mnt" +} + +jail_mount_inside_cleanup() +{ + mp_cleanup +} + +atf_init_test_cases() +{ + atf_add_test_case not_mountpoint + atf_add_test_case errors + atf_add_test_case mountpoint + atf_add_test_case file_mountpoint + atf_add_test_case chroot_root_not_mountpoint + atf_add_test_case chroot_root_mountpoint + atf_add_test_case chroot_root_nullfs + atf_add_test_case chroot_submount + atf_add_test_case jail_root_not_mountpoint + atf_add_test_case jail_root_mountpoint + atf_add_test_case jail_root_nullfs + atf_add_test_case jail_submount + atf_add_test_case jail_mount_inside +}