minix/tests/fs/vfs/t_union.c
Lionel Sambuc 11be35a165 Importing NetBSD "Kyua" test framework
To do so, a few dependencies have been imported:

 * external/bsd/lutok
 * external/mit/lua
 * external/public-domain/sqlite
 * external/public-domain/xz

The Kyua framework is the new generation of ATF (Automated Test
Framework), it is composed of:

 * external/bsd/atf
 * external/bsd/kyua-atf-compat
 * external/bsd/kyua-cli
 * external/bsd/kyua-tester
 * tests

Kyua/ATF being written in C++, it depends on libstdc++ which is
provided by GCC. As this is not part of the sources, Kyua is only
compiled when the native GCC utils are installed.

To install Kyua do the following:

 * In a cross-build enviromnent, add the following to the build.sh
   commandline: -V MKBINUTILS=yes -V MKGCCCMDS=yes

WARNING:
  At this point the import is still experimental, and not supported
  on native builds (a.k.a make build).

Change-Id: I26aee23c5bbd2d64adcb7c1beb98fe0d479d7ada
2013-07-23 20:43:41 +02:00

204 lines
4.6 KiB
C

/* $NetBSD: t_union.c,v 1.8 2011/08/07 06:01:51 hannken Exp $ */
#include <sys/types.h>
#include <sys/mount.h>
#include <atf-c.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <rump/rump.h>
#include <rump/rump_syscalls.h>
#include <miscfs/union/union.h>
#include "../../h_macros.h"
#include "../common/h_fsmacros.h"
#define MSTR "magic bus"
static void
xput_tfile(const char *mp, const char *path)
{
char pathb[MAXPATHLEN];
int fd;
strcpy(pathb, mp);
strcat(pathb, "/");
strcat(pathb, path);
RL(fd = rump_sys_open(pathb, O_CREAT | O_RDWR, 0777));
if (rump_sys_write(fd, MSTR, sizeof(MSTR)) != sizeof(MSTR))
atf_tc_fail_errno("write to testfile");
RL(rump_sys_close(fd));
}
static int
xread_tfile(const char *mp, const char *path)
{
char pathb[MAXPATHLEN];
char buf[128];
int fd;
strcpy(pathb, mp);
strcat(pathb, "/");
strcat(pathb, path);
fd = rump_sys_open(pathb, O_RDONLY);
if (fd == -1)
return errno;
if (rump_sys_read(fd, buf, sizeof(buf)) == -1)
atf_tc_fail_errno("read tfile");
RL(rump_sys_close(fd));
if (strcmp(buf, MSTR) == 0)
return 0;
return EPROGMISMATCH;
}
/*
* Mount a unionfs for testing. Before calling, "mp" contains
* the upper layer. Lowerpath is constructed so that the directory
* contains rumpfs.
*/
static void
mountunion(const char *mp, char *lowerpath)
{
struct union_args unionargs;
sprintf(lowerpath, "/lower");
rump_sys_mkdir(lowerpath, 0777);
/* mount the union with our testfs as the upper layer */
memset(&unionargs, 0, sizeof(unionargs));
unionargs.target = lowerpath;
unionargs.mntflags = UNMNT_BELOW;
if (rump_sys_mount(MOUNT_UNION, mp, 0,
&unionargs, sizeof(unionargs)) == -1) {
if (errno == EOPNOTSUPP) {
atf_tc_skip("fs does not support VOP_WHITEOUT");
} else {
atf_tc_fail_errno("union mount");
}
}
}
#if 0
static void
toggleroot(void)
{
static int status;
status ^= MNT_RDONLY;
printf("0x%x\n", status);
RL(rump_sys_mount(MOUNT_RUMPFS, "/", status | MNT_UPDATE, NULL, 0));
}
#endif
#define TFILE "tensti"
#define TDIR "testdir"
#define TDFILE TDIR "/indir"
static void
basic(const atf_tc_t *tc, const char *mp)
{
char lowerpath[MAXPATHLEN];
char dbuf[8192];
struct stat sb;
struct dirent *dp;
int error, fd, dsize;
mountunion(mp, lowerpath);
/* create a file in the lower layer */
xput_tfile(lowerpath, TFILE);
/* first, test we can read the old file from the new namespace */
error = xread_tfile(mp, TFILE);
if (error != 0)
atf_tc_fail("union compare failed: %d (%s)",
error, strerror(error));
/* then, test upper layer writes don't affect the lower layer */
xput_tfile(mp, "kiekko");
if ((error = xread_tfile(lowerpath, "kiekko")) != ENOENT)
atf_tc_fail("invisibility failed: %d (%s)",
error, strerror(error));
/* check that we can whiteout stuff in the upper layer */
FSTEST_ENTER();
RL(rump_sys_unlink(TFILE));
ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TFILE, &sb) == -1);
FSTEST_EXIT();
/* check that the removed node is not in the directory listing */
RL(fd = rump_sys_open(mp, O_RDONLY));
RL(dsize = rump_sys_getdents(fd, dbuf, sizeof(dbuf)));
for (dp = (struct dirent *)dbuf;
(char *)dp < dbuf + dsize;
dp = _DIRENT_NEXT(dp)) {
if (strcmp(dp->d_name, TFILE) == 0 && dp->d_type != DT_WHT)
atf_tc_fail("removed file non-white-outed");
}
RL(rump_sys_close(fd));
RL(rump_sys_unmount(mp, 0));
}
static void
whiteout(const atf_tc_t *tc, const char *mp)
{
char lower[MAXPATHLEN];
struct stat sb;
void *fsarg;
/*
* XXX: use ffs here to make sure any screwups in rumpfs don't
* affect the test
*/
RL(ffs_fstest_newfs(tc, &fsarg, "daimage", 1024*1024*5, NULL));
RL(ffs_fstest_mount(tc, fsarg, "/lower", 0));
/* create a file in the lower layer */
RL(rump_sys_chdir("/lower"));
RL(rump_sys_mkdir(TDIR, 0777));
RL(rump_sys_mkdir(TDFILE, 0777));
RL(rump_sys_chdir("/"));
RL(ffs_fstest_unmount(tc, "/lower", 0));
RL(ffs_fstest_mount(tc, fsarg, "/lower", MNT_RDONLY));
mountunion(mp, lower);
FSTEST_ENTER();
ATF_REQUIRE_ERRNO(ENOTEMPTY, rump_sys_rmdir(TDIR) == -1);
RL(rump_sys_rmdir(TDFILE));
RL(rump_sys_rmdir(TDIR));
ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDFILE, &sb) == -1);
ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDIR, &sb) == -1);
RL(rump_sys_mkdir(TDIR, 0777));
RL(rump_sys_stat(TDIR, &sb));
ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDFILE, &sb) == -1);
FSTEST_EXIT();
RL(rump_sys_unmount(mp, 0));
}
ATF_TC_FSAPPLY(basic, "check basic union functionality");
ATF_TC_FSAPPLY(whiteout, "create whiteout in upper layer");
ATF_TP_ADD_TCS(tp)
{
ATF_TP_FSAPPLY(basic);
ATF_TP_FSAPPLY(whiteout);
return atf_no_error();
}