#include <sys/mount.h>
#include <sys/stat.h>
#include <atf-c.h>
#include <ctype.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ufs/ufs/ufsmount.h>
#include <rump/rump.h>
#include <rump/rump_syscallshotgun.h>
#include <rump/rump_syscalls.h>
#include "h_fsmacros.h"
#include "mount_lfs.h"
#define USE_KERNEL_CLEANER
struct lfstestargs {
struct ufs_args ta_uargs;
pthread_t ta_cleanerthread;
sem_t ta_cleanerloop;
char ta_devpath[MAXPATHLEN];
char ta_imgpath[MAXPATHLEN];
char ta_mntpath[MAXPATHLEN];
char ta_hostpath[MAXPATHLEN];
};
static const char *image_filename;
int
lfs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, off_t size,
void *fspriv)
{
char cmd[1024];
int res;
static unsigned int num = 0;
struct lfstestargs *args;
image_filename = image;
size /= 512;
snprintf(cmd, 1024, "newfs_lfs -D -F -s %"PRId64" ./%s >/dev/null",
size, image);
res = system(cmd);
if (res != 0)
return res;
res = rump_init();
if (res != 0)
return res;
args = calloc(1, sizeof(*args));
if (args == NULL)
return -1;
strcpy(args->ta_hostpath, image);
snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.lfs", num);
snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image);
args->ta_uargs.fspec = args->ta_devpath;
sem_init(&args->ta_cleanerloop, 0, 0);
res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK);
if (res != 0) {
free(args);
return res;
}
*buf = args;
num++;
return 0;
}
int
lfs_fstest_delfs(const atf_tc_t *tc, void *buf)
{
int res;
struct lfstestargs *args = buf;
res = rump_pub_etfs_remove(args->ta_devpath);
if (res != 0)
return res;
res = unlink(args->ta_imgpath);
if (res != 0)
return res;
pthread_join(args->ta_cleanerthread, NULL);
free(args);
return 0;
}
#ifndef USE_KERNEL_CLEANER
static void *
cleaner(void *arg)
{
char thepath[MAXPATHLEN];
struct lfstestargs *args = arg;
const char *the_argv[9];
char buf[64];
rump_pub_lwproc_newlwp(rump_sys_getpid());
sprintf(thepath, "/dev/r%s", args->ta_devpath+5);
rump_pub_etfs_register(thepath, args->ta_hostpath, RUMP_ETFS_CHR);
sprintf(buf, "%p", &args->ta_cleanerloop);
the_argv[0] = "megamaid";
the_argv[1] = "-D";
the_argv[2] = "-S";
the_argv[3] = buf;
the_argv[4] = "-J";
the_argv[5] = thepath;
the_argv[6] = args->ta_mntpath;
the_argv[7] = NULL;
optind = 1;
opterr = 1;
lfs_cleaner_main(7, __UNCONST(the_argv));
rump_pub_lwproc_releaselwp();
return NULL;
}
#endif
int
lfs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags)
{
struct lfstestargs *args = buf;
int res;
#ifdef USE_KERNEL_CLEANER
struct lfs_autoclean_params autoclean;
int fd;
#endif
res = rump_sys_mkdir(path, 0777);
if (res == -1)
return res;
res = rump_sys_mount(MOUNT_LFS, path, flags, &args->ta_uargs,
sizeof(args->ta_uargs));
if (res == -1) {
fprintf(stderr, "sys_mount errno=%d\n", errno);
return res;
}
#ifdef USE_KERNEL_CLEANER
fd = rump_sys_open(path, O_RDONLY);
autoclean.size = sizeof(autoclean);
autoclean.mode = LFS_CLEANMODE_GREEDY;
autoclean.thresh = -1;
autoclean.target = -1;
res = rump_sys_fcntl(fd, LFCNAUTOCLEAN, &autoclean);
if (res) {
fprintf(stderr, "LFCNAUTOCLEAN errno=%d\n", errno);
return res;
}
res = rump_sys_close(fd);
if (res)
return res;
#else
strcpy(args->ta_mntpath, path);
res = pthread_create(&args->ta_cleanerthread, NULL, cleaner, args);
if (res)
return res;
sem_wait(&args->ta_cleanerloop);
#endif
return 0;
}
int
lfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags)
{
int res, errors;
FILE *pipe, *err;
char s[MAXPATHLEN], cmd[1024];
res = rump_sys_unmount(path, flags);
if (res == -1) {
return res;
}
sprintf(cmd, "fsck_lfs -n -a -f %s", image_filename);
pipe = popen(cmd, "r");
errors = 0;
err = NULL;
while (fgets(s, MAXPATHLEN, pipe) != NULL) {
if (isdigit((int)s[0]))
continue;
if (isspace((int)s[0]) || s[0] == '*')
continue;
if (strncmp(s, "Alternate", 9) == 0)
continue;
if (strncmp(s, "ROLL ", 5) == 0)
continue;
fprintf(stderr, "FSCK: %s", s);
if (err == NULL)
err = fopen("/tmp/err.out", "w");
fprintf(err, "FSCK: %s", s);
++errors;
}
pclose(pipe);
if (err)
fclose(err);
if (errors)
return -1;
res = rump_sys_rmdir(path);
return res;
}