Пример #1
0
ATF_TC_BODY(key, tc)
{

	RZ(rump_init());

	RL(open("hostfile", O_RDWR | O_CREAT, 0777));

	RZ(rump_pub_etfs_register("/key", "hostfile", RUMP_ETFS_REG));
	ATF_REQUIRE_EQ(rump_pub_etfs_register("key", "hostfile", RUMP_ETFS_REG),
	    EINVAL);

	RL(rump_sys_open("/key", O_RDONLY));
	RL(rump_sys_open("////////key", O_RDONLY));

	RZ(rump_pub_etfs_register("////key//with/slashes", "hostfile",
	    RUMP_ETFS_REG));

	RL(rump_sys_open("/key//with/slashes", O_RDONLY));
	RL(rump_sys_open("key//with/slashes", O_RDONLY));
	ATF_REQUIRE_ERRNO(ENOENT,
	    rump_sys_open("/key/with/slashes", O_RDONLY) == -1);

	RL(rump_sys_mkdir("/a", 0777));
	ATF_REQUIRE_ERRNO(ENOENT,
	    rump_sys_open("/a/key//with/slashes", O_RDONLY) == -1);
}
Пример #2
0
ATF_TC_BODY(reregister_reg, tc)
{
	char buf[1024];
	int localfd, etcfd;
	ssize_t n;
	int tfd;

	etcfd = open("/etc/passwd", O_RDONLY);
	ATF_REQUIRE(etcfd != -1);

	localfd = open("./testfile", O_RDWR | O_CREAT, 0666);
	ATF_REQUIRE(localfd != -1);

	ATF_REQUIRE_EQ(write(localfd, TESTSTR1, TESTSTR1SZ), TESTSTR1SZ);
	/* testfile now contains test string */

	rump_init();

	ATF_REQUIRE_EQ(rump_pub_etfs_register(TESTPATH1, "/etc/passwd",
	    RUMP_ETFS_REG), 0);
	tfd = rump_sys_open(TESTPATH1, O_RDONLY);
	ATF_REQUIRE(tfd != -1);
	ATF_REQUIRE(rump_sys_read(tfd, buf, sizeof(buf)) > 0);
	rump_sys_close(tfd);
	rump_pub_etfs_remove(TESTPATH1);

	ATF_REQUIRE_EQ(rump_pub_etfs_register(TESTPATH2, "./testfile",
	    RUMP_ETFS_REG), 0);
	tfd = rump_sys_open(TESTPATH2, O_RDWR);
	ATF_REQUIRE(tfd != -1);
	memset(buf, 0, sizeof(buf));
	ATF_REQUIRE((n = rump_sys_read(tfd, buf, sizeof(buf))) > 0);

	/* check that we have what we expected */
	ATF_REQUIRE_STREQ(buf, TESTSTR1);

	/* ... while here, check that writing works too */
	ATF_REQUIRE_EQ(rump_sys_lseek(tfd, 0, SEEK_SET), 0);
	ATF_REQUIRE(TESTSTR1SZ <= TESTSTR2SZ);
	ATF_REQUIRE_EQ(rump_sys_write(tfd, TESTSTR2, TESTSTR2SZ), TESTSTR2SZ);

	memset(buf, 0, sizeof(buf));
	ATF_REQUIRE_EQ(lseek(localfd, 0, SEEK_SET), 0);
	ATF_REQUIRE(read(localfd, buf, sizeof(buf)) > 0);
	ATF_REQUIRE_STREQ(buf, TESTSTR2);
	close(etcfd);
	close(localfd);
}
Пример #3
0
ATF_TC_BODY(large_blk, tc)
{
	char buf[128];
	char cmpbuf[128];
	ssize_t n;
	int rv, tfd;

	/*
	 * mount mfs.  it would be nice if this would not be required,
	 * but a) tmpfs doesn't "support" sparse files b) we don't really
	 * know what fs atf workdir is on anyway.
	 */
	if (mkdir("mfsdir", 0777) == -1)
		atf_tc_fail_errno("mkdir failed");
	if (system("mount_mfs -s 64m -o nosuid,nodev mfs mfsdir") != 0)
		atf_tc_skip("could not mount mfs");

	/* create a 8TB sparse file */
	rv = system("dd if=/dev/zero of=" IMG_ON_MFS " bs=1 count=1 seek=8t");
	ATF_REQUIRE_EQ(rv, 0);

	/*
	 * map it and issue write at 6TB, then unmap+remap and check
	 * we get the same stuff back
	 */

	rump_init();
	ATF_REQUIRE_EQ(rump_pub_etfs_register(TESTPATH1, IMG_ON_MFS,
	    RUMP_ETFS_BLK), 0);
	tfd = rump_sys_open(TESTPATH1, O_RDWR);
	ATF_REQUIRE(tfd != -1);
	memset(buf, 12, sizeof(buf));
	n = rump_sys_pwrite(tfd, buf, sizeof(buf), 6*1024*1024*1024ULL*1024ULL);
	ATF_REQUIRE_EQ(n, sizeof(buf));
	ATF_REQUIRE_EQ(rump_sys_close(tfd), 0);
	ATF_REQUIRE_EQ(rump_pub_etfs_remove(TESTPATH1), 0);

	ATF_REQUIRE_EQ(rump_pub_etfs_register(TESTPATH2, IMG_ON_MFS,
	    RUMP_ETFS_BLK), 0);
	tfd = rump_sys_open(TESTPATH2, O_RDWR);
	ATF_REQUIRE(tfd != -1);
	memset(buf, 0, sizeof(buf));
	n = rump_sys_pread(tfd, buf, sizeof(buf), 6*1024*1024*1024ULL*1024ULL);
	ATF_REQUIRE_EQ(n, sizeof(buf));

	memset(cmpbuf, 12, sizeof(cmpbuf));
	ATF_REQUIRE_EQ(memcmp(cmpbuf, buf, 128), 0);
}
Пример #4
0
static void *
cleaner(void *arg)
{
	char thepath[MAXPATHLEN];
	struct lfstestargs *args = arg;
	const char *the_argv[7];
	char buf[64];

	/* this inspired by the cleaner code.  fixme */
	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"; /* don't fork() & detach */
	the_argv[2] = "-S";
	the_argv[3] = buf;
	the_argv[4] = args->ta_mntpath;
	the_argv[5] = NULL;

	/* xxxatf */
	optind = 1;
	opterr = 1;

	lfs_cleaner_main(5, __UNCONST(the_argv));

	return NULL;
}
Пример #5
0
ATF_TC_BODY(reregister_blk, tc)
{
	char buf[512 * 128];
	char cmpbuf[512 * 128];
	int rv, tfd;

	/* first, create some image files */
	rv = system("dd if=/dev/zero bs=512 count=64 "
	    "| tr '\\0' '\\1' > disk1.img");
	ATF_REQUIRE_EQ(rv, 0);

	rv = system("dd if=/dev/zero bs=512 count=128 "
	    "| tr '\\0' '\\2' > disk2.img");
	ATF_REQUIRE_EQ(rv, 0);

	rump_init();

	ATF_REQUIRE_EQ(rump_pub_etfs_register(TESTPATH1, "./disk1.img",
	    RUMP_ETFS_BLK), 0);
	tfd = rump_sys_open(TESTPATH1, O_RDONLY);
	ATF_REQUIRE(tfd != -1);
	ATF_REQUIRE_EQ(rump_sys_read(tfd, buf, sizeof(buf)), 64*512);
	memset(cmpbuf, 1, sizeof(cmpbuf));
	ATF_REQUIRE_EQ(memcmp(buf, cmpbuf, 64*512), 0);
	ATF_REQUIRE_EQ(rump_sys_close(tfd), 0);
	ATF_REQUIRE_EQ(rump_pub_etfs_remove(TESTPATH1), 0);

	ATF_REQUIRE_EQ(rump_pub_etfs_register(TESTPATH2, "./disk2.img",
	    RUMP_ETFS_BLK), 0);
	tfd = rump_sys_open(TESTPATH2, O_RDONLY);
	ATF_REQUIRE(tfd != -1);
	ATF_REQUIRE_EQ(rump_sys_read(tfd, buf, sizeof(buf)), 128*512);
	memset(cmpbuf, 2, sizeof(cmpbuf));
	ATF_REQUIRE_EQ(memcmp(buf, cmpbuf, 128*512), 0);
	ATF_REQUIRE_EQ(rump_sys_close(tfd), 0);
	ATF_REQUIRE_EQ(rump_pub_etfs_remove(TESTPATH2), 0);
}
Пример #6
0
static void
rumprun_config_blk(const char *blk_index)
{
	char *blk_type = NULL;
	char *blk_mountpoint = NULL;
	char *blk_fstype = NULL;
	int rv;
	char key[32],
	     hostpath[32];

	rv = xs_read_blkconfig(blk_index, &blk_type, &blk_mountpoint,
		&blk_fstype);
	if (rv != 0)
		return;

	snprintf(key, sizeof key, "/dev/xenblk%s", blk_index);
	snprintf(hostpath, sizeof hostpath, "blk%s", blk_index);
	/* XXX: will "leak" etfs registration if later step fails */
	if ((rv = rump_pub_etfs_register(key, hostpath, RUMP_ETFS_BLK)) != 0) {
		warnx("rumprun_config: etfs_register failed: %d", rv);
		goto out;
	}

	if (blk_mountpoint == NULL)
		goto out;

	if ((strcmp(blk_fstype, "ffs") != 0) &&
		(strcmp(blk_fstype, "cd9660") != 0)) {
		warnx("rumprun_config: xenblk%s: unsupported fstype %s",
			blk_index, blk_fstype);
		goto out;
	}

	printf("rumprun_config: mounting xenblk%s on %s as %s\n",
		blk_index, blk_mountpoint, blk_fstype);
	if ((rv = mkdir(blk_mountpoint, 0777)) != 0) {
		warn("rumprun_config: mkdir failed");
		goto out;
	}

	if (strcmp(blk_fstype, "ffs") == 0) {
		struct ufs_args mntargs = { .fspec = key };
		if (mount(MOUNT_FFS, blk_mountpoint, 0, &mntargs, sizeof(mntargs)) != 0) {
			warn("rumprun_config: mount_ffs failed");
			goto out;
		}
	}
	else if(strcmp(blk_fstype, "cd9660") == 0) {
Пример #7
0
int
main(int argc, char *argv[])
{
	struct rump_ufs_args args;
	char imgpath[MAXPATHLEN+1];
	union u u;
	char buf[8192];
	int fd;

	/*
	 * the driver doesn't support endian swapping, so pick image
	 * with matching endianness.
	 */
	u.i = 0x12345678;
	if (u.c == 0x12) {
		snprintf(imgpath, sizeof(imgpath),
		    "%s/%s", argv[1], "sysvbfs_be.img");
	} else {
		snprintf(imgpath, sizeof(imgpath),
		    "%s/%s", argv[1], "sysvbfs_le.img");
	}
		

        rump_init();

#define MYFSDEV "/de-vice"
	rump_pub_etfs_register(MYFSDEV, imgpath, RUMP_ETFS_BLK);
	args.fspec =  (void *)(uintptr_t)MYFSDEV;

	if (rump_sys_mkdir("/mnt", 0755) == -1)
		die("mkdir /mnt");
	if (rump_sys_mount(RUMP_MOUNT_SYSVBFS, "/mnt", RUMP_MNT_RDONLY,
	    &args, sizeof(args)) == -1)
		die("mount");
	if ((fd = rump_sys_open("/mnt/README", 0)) == -1)
		die("open file");
	memset(buf, 0, sizeof(buf));
	if (rump_sys_read(fd, buf, sizeof(buf)) <= 0)
		die("read version");
	if (strcmp(buf, EXPECTED) != 0)
		die("got unexpected result");
	rump_sys_close(fd);
	if (rump_sys_unmount("/mnt", 0) == -1)
		die("unmount failed");

	return 0;
}
Пример #8
0
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;

	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;
}
Пример #9
0
static char *
configetfs(const char *path, int hard)
{
	char buf[32];
	char epath[32];
	char *p;
	int rv;

	snprintf(epath, sizeof(epath), "XENBLK_%s", path);
	snprintf(buf, sizeof(buf), "/dev/%s", path);
	rv = rump_pub_etfs_register(buf, epath, RUMP_ETFS_BLK);
	if (rv != 0) {
		if (!hard)
			return NULL;
		errx(1, "etfs register for \"%s\" failed: %d", path, rv);
	}

	if ((p = strdup(buf)) == NULL)
		err(1, "failed to allocate pathbuf");
	return p;
}
Пример #10
0
int
msdosfs_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 msdosfstestargs *args;

	size /= 512; size -= (size % 63);
	snprintf(cmd, 1024, "newfs_msdos -C %"PRId64"s %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;

	snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.msdosfs", num);
	snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image);
	args->ta_uargs.fspec = args->ta_devpath;
	args->ta_uargs.mask = 0755;

	res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK);
	if (res != 0) {
		free(args);
		return res;
	}

	*buf = args;
	num++;

	return 0;
}
Пример #11
0
int
main(int argc, char *argv[])
{
	struct ulfs_args args;
	char canon_dev[UKFS_DEVICE_MAXPATHLEN], canon_dir[MAXPATHLEN];
	char rawdev[MAXPATHLEN];
	struct p2k_mount *p2m;
	pthread_t cleanerthread;
	struct ukfs_part *part;
	int mntflags;
	int rv;

	setprogname(argv[0]);
	puffs_unmountonsignal(SIGINT, true);
	puffs_unmountonsignal(SIGTERM, true);

	if (argc >= 3) {
		UKFS_DEVICE_ARGVPROBE(&part);
		if (part != ukfs_part_none) {
			errx(1, "lfs does not currently support "
			    "embedded partitions");
		}
	}
	mount_lfs_parseargs(argc, argv, &args, &mntflags, canon_dev, canon_dir);

	/* Reset getopt for lfs_cleaner_main.  */
	optreset = 1;
	optind = 1;

	p2m = p2k_init(0);
	if (!p2m)
		err(1, "init p2k");
	/*
	 * XXX: this particular piece inspired by the cleaner code.
	 * obviously FIXXXME along with the cleaner.
	 */
	sprintf(rawdev, "/dev/r%s", canon_dev+5);
	rump_pub_etfs_register(rawdev, canon_dev, RUMP_ETFS_CHR);

	/*
	 * We basically have two choices:
	 *  1) run the cleaner in another process and do rump ipc syscalls
	 *  2) run it off a thread in this process and do rump syscalls
	 *     as function calls.
	 *
	 * opt for "2" for now
	 */
#ifdef CLEANER_TESTING
	ukfs_mount(MOUNT_LFS, canon_dev, canon_dir, mntflags,
	    &args, sizeof(args));
	cleaner(canon_dir);
#endif
	if (p2k_setup_diskfs(p2m, MOUNT_LFS, canon_dev, part, canon_dir,
	    mntflags, &args, sizeof(args)) == -1)
		err(1, "mount");
	ukfs_part_release(part);

#ifndef CLEANER_TESTING
	if ((mntflags & MNT_RDONLY) == 0) {
		if (pthread_create(&cleanerthread, NULL,
		    cleaner, canon_dir) == -1)
			err(1, "cannot start cleaner");
	}
#endif

	rv = p2k_mainloop(p2m);
	if (rv == -1)
		err(1, "fs service");

	return 0;
}
Пример #12
0
void
__franken_fdinit_create()
{
	int fd, ret, flags;
	int root = 0;
	char key[16], rkey[16], num[16];
	int n_reg = 0, n_block = 0;
	struct ufs_args ufs;

	if (__franken_fd[0].valid) {
		mkkey(key, num, "/dev/vfile", n_reg++, 0);
		rump_pub_etfs_register(key, num, RUMP_ETFS_REG);
		fd = rump___sysimpl_open(key, O_RDONLY);
		if (fd != -1) {
			rump___sysimpl_dup2(fd, 0);
			rump___sysimpl_close(fd);
		}
	}
	if (__franken_fd[1].valid) {
		mkkey(key, num, "/dev/vfile", n_reg++, 1);
		rump_pub_etfs_register(key, num, RUMP_ETFS_REG);
		fd = rump___sysimpl_open(key, O_WRONLY);
		if (fd != -1) {
			rump___sysimpl_dup2(fd, 1);
			rump___sysimpl_close(fd);
		}
	}

	if (__franken_fd[2].valid) {
		mkkey(key, num, "/dev/vfile", n_reg++, 2);
		rump_pub_etfs_register(key, num, RUMP_ETFS_REG);
		fd = rump___sysimpl_open(key, O_WRONLY);
		if (fd != -1) {
			rump___sysimpl_dup2(fd, 2);
			rump___sysimpl_close(fd);
		}
	}

	for (fd = 3; fd < MAXFD; fd++) {
		if (__franken_fd[fd].valid == 0)
			break;
		switch (__franken_fd[fd].st.st_mode & S_IFMT) {
		case S_IFREG:
			mkkey(key, num, "/dev/vfile", n_reg++, fd);
			rump_pub_etfs_register(key, num, RUMP_ETFS_REG);
			flags = __franken_fd[fd].flags & O_ACCMODE;
			rump___sysimpl_open(key, flags);
			break;
		case S_IFBLK:
			mkkey(key, num, "/dev/block", n_block, fd);
			mkkey(rkey, num, "/dev/rblock", n_block, fd);
			n_block++;
			rump_pub_etfs_register_withsize(key, num,
				RUMP_ETFS_BLK, 0, __franken_fd[fd].st.st_size);
			rump_pub_etfs_register_withsize(rkey, num,
				RUMP_ETFS_CHR, 0, __franken_fd[fd].st.st_size);
			if (root == 0) {
				ufs.fspec = key;
				flags = __franken_fd[fd].flags & O_ACCMODE;
				if (flags == O_RDWR)
					flags = MNT_LOG;
				else
					flags = MNT_RDONLY;
				ret = rump___sysimpl_mount50("ffs", "/", flags, &ufs, sizeof(struct ufs_args));
				if (ret == 0) {
					root = 1;
				} else {
					if (flags == MNT_LOG)
						flags = 0;
					ret = rump___sysimpl_mount50("ext2fs", "/", flags, &ufs, sizeof(struct ufs_args));
					if (ret == 0) {
						root = 1;
					}
				}
				if (root == 1)
					atexit(unmount_atexit);
			}
			break;
		case S_IFSOCK:
			mkkey(key, num, "virt", fd, fd);
			ret = rump_pub_netconfig_ifcreate(key);
			if (ret == 0) {
				ret = rump___sysimpl_socket30(AF_INET6, SOCK_STREAM, 0);
				if (ret != -1) {
					rump_pub_netconfig_auto_ipv6(key);
					rump___sysimpl_close(ret);
				}
				ret = rump___sysimpl_socket30(AF_INET, SOCK_STREAM, 0);
				if (ret != -1) {
					rump_pub_netconfig_dhcp_ipv4_oneshot(key);
					rump___sysimpl_close(ret);
				}
			}
			break;
		}
	}
}
Пример #13
0
int
main(int argc, char *argv[])
{
	const char *ethername, *ethername_ro;
	const char *serveraddr, *serveraddr_ro;
	const char *netmask;
	const char *exportpath;
	const char *imagename;
	char ifname[IFNAMSIZ], ifname_ro[IFNAMSIZ];
	void *fsarg;
	pthread_t t;
	int rv;

	/* for netcfg */
	noatf = 1;

	/* use defaults? */
	if (argc == 1) {
		ethername = "etherbus";
		ethername_ro = "etherbus_ro";
		serveraddr = "10.3.2.1";
		serveraddr_ro = "10.4.2.1";
		netmask = "255.255.255.0";
		exportpath = "/myexport";
		imagename = "ffs.img";
	} else {
		ethername = argv[1];
		ethername_ro = argv[2];
		serveraddr = argv[3];
		serveraddr_ro = argv[4];
		netmask = argv[5];
		exportpath = argv[6];
		imagename = argv[7];
	}

	rump_init();
	svc_fdset_init(SVC_FDSET_MT);

	rv = rump_pub_etfs_register("/etc/exports", "./exports", RUMP_ETFS_REG);
	if (rv) {
		errx(1, "register /etc/exports: %s", strerror(rv));
	}

	/* mini-mtree for mountd */
	static const char *const dirs[] = { "/var", "/var/run", "/var/db" };
	for (size_t i = 0; i < __arraycount(dirs); i++)
		if (rump_sys_mkdir(dirs[i], 0777) == -1)
			err(1, "can't mkdir `%s'", dirs[i]);

	if (ffs_fstest_newfs(NULL, &fsarg,
	    imagename, FSTEST_IMGSIZE, NULL) != 0)
		err(1, "newfs failed");
	if (ffs_fstest_mount(NULL, fsarg, exportpath, 0) != 0)
		err(1, "mount failed");

#if 0
	/*
	 * Serve from host instead of dedicated mount?
	 * THIS IS MORE EVIL THAN MURRAY THE DEMONIC TALKING SKULL!
	 */

	if (ukfs_modload("/usr/lib/librumpfs_syspuffs.so") < 1)
		errx(1, "modload");

	mount_syspuffs_parseargs(__arraycount(pnullarg), pnullarg,
	    &args, &mntflags, canon_dev, canon_dir);
	if ((ukfs = ukfs_mount(MOUNT_PUFFS, "/", UKFS_DEFAULTMP, MNT_RDONLY,
	    &args, sizeof(args))) == NULL)
		err(1, "mount");

	if (ukfs_modload("/usr/lib/librumpfs_nfsserver.so") < 1)
		errx(1, "modload");
#endif

	if (sem_init(&gensem, 1, 0) == -1)
		err(1, "gensem init");

	/* create interface */
	netcfg_rump_makeshmif(ethername, ifname);
	netcfg_rump_if(ifname, serveraddr, netmask);

	netcfg_rump_makeshmif(ethername_ro, ifname_ro);
	netcfg_rump_if(ifname_ro, serveraddr_ro, netmask);

	/*
	 * No syslogging, thanks.
	 * XXX: "0" does not modify the mask, so pick something
	 * which is unlikely to cause any logging
	 */
	setlogmask(0x10000000);

	if (pthread_create(&t, NULL, rpcbind_main, NULL) == -1)
		err(1, "rpcbind");
	sem_wait(&gensem);

	if (pthread_create(&t, NULL, mountd_main, NULL) == -1)
		err(1, "mountd");
	sem_wait(&gensem);

	rv = 0;
	/* signal the other process we're almost done */
	if (write(3, &rv, 4) != 4)
		errx(1, "magic write failed");

	{
	char *nfsargv[] = { __UNCONST("nfsd"), NULL };
	nfsd_main(1, nfsargv);
	}
	/*NOTREACHED*/

	return 0;
}
Пример #14
0
/*
 * Tries to mount an image.
 * if the fstype is not given try every supported types.
 */
int
fsu_mount(int *argc, char **argv[], int mode)
{
	fsu_fs_t *fst;
	struct fsu_fsalias_s *alias;
	struct mount_data_s mntd;
	int idx, fflag, rv, verbose;
	int ch, stopopts;
	char *mntopts, afsdev[PATH_MAX], *puffsexec, *specopts;
	char *tmp;
	char *fsdevice, *fstype;
	struct stat sb;
#ifdef WITH_SYSPUFFS
	const char options[] = GETOPT_PREFIX"f:o:p:s:t:v";
#else
	const char options[] = GETOPT_PREFIX"f:o:s:t:v";
#endif

	alias = NULL;
	fsdevice = fstype = mntopts = puffsexec = specopts = NULL;
	fst = NULL;
	verbose = fflag = 0;
	stopopts = 0;
	memset(&mntd, 0, sizeof(mntd));
	mntd.mntd_fsdevice = mntd.mntd_canon_dev;

	rump_init();
	opterr = 0;
	/*
	 * [-o mnt_args] [-t fstype] [-p puffsexec] fsdevice
	 */
	while ((ch = getopt(*argc, *argv, options)) != -1) {
		switch (ch) {
		case 'f':
			if (fsdevice == NULL)
				fsdevice = optarg;
			fflag = 1;
			break;
		case 'o':
			if (mntopts == NULL)
				mntopts = optarg;
			break;
#ifdef WITH_SYSPUFFS
		case 'p':
			if (puffsexec == NULL) {
				puffsexec = optarg;
				for (fst = fslist; fst->fs_name != NULL; ++fst)
					if (fst->fs_name == MOUNT_PUFFS)
						break;

				if (fstype == NULL)
					fstype = MOUNT_PUFFS;
				else if (strcmp(fstype, MOUNT_PUFFS) != 0) {
					warnx("-p is only for puffs");
					return -1;
				}
			}
			break;
#endif
		case 's':
			if (specopts == NULL)
				specopts = optarg;
			break;
		case 't':
			if (fstype == NULL)
				fstype = optarg;
			break;
		case 'v':
			++verbose;
			break;
		case '?':
		default:
			--optind;
			stopopts = 1;
			break;
		}
		if (stopopts)
			break;
	}
	idx = optind;
	optind = 1;
#ifdef HAVE_GETOPT_OPTRESET
	optreset = 1;
#endif
	if (mntopts == NULL)
		mntopts = getenv("FSU_MNTOPTS");

	if (mode == MOUNT_READONLY) {
		if (mntopts == NULL)
			mntopts = __UNCONST("ro");
		else {
			tmp = malloc(strlen(mntopts) + 4);
			if (tmp == NULL) {
				warn(NULL);
				opterr = 1;
				return -1;
			}
			snprintf(tmp, strlen(mntopts) + 4, "%s,ro", mntopts);
			mntopts = tmp;
		}
	}

	if (fstype == NULL)
		fstype = getenv("FSU_TYPE");

	if (fstype != NULL && fst == NULL) {
		for (fst = fslist; fst->fs_name != NULL; ++fst)
			if (strcmp(fstype, fst->fs_name) == 0)
				break;

		if (fst->fs_name == NULL) {
			fprintf(stderr, "%s: filesystem not supported\n",
			    fstype);
			opterr = 1;
			return -1;
		}
	}

	if (fsdevice == NULL) {
		fsdevice = getenv("FSU_DEVICE");
		if (fsdevice == NULL) {
			if (idx < *argc && strcmp((*argv)[idx], "--") != 0)
				fsdevice = (*argv)[idx++];
			else {
				errno = 0;
				opterr = 1;
				return -1;
			}
		}
	}

	rv = 0;
	if (!fflag) {
		rv = -1;
		build_alias_list();
		alias = get_alias(fsdevice);
		if (alias != NULL)
			rv = mount_alias(alias, mntopts, specopts, &mntd,
			    verbose);
		free_alias_list();
	}
	if (fflag || alias == NULL) {
		if (realpath(fsdevice, afsdev) != NULL)
			fsdevice = afsdev;
		rv = stat(fsdevice, &sb);
		if (rv == -1)
			warn("%s", fsdevice);
		else if (!(S_ISREG(sb.st_mode) || S_ISBLK(sb.st_mode))) {
			warnx("%s: Not a regular file or block device",
			    fsdevice);
			rv = -1;
		} else {
			rv = rump_pub_etfs_register(RUMPFSDEV, fsdevice,
			    RUMP_ETFS_BLK);
			if (rv != 0) {
				warnx("%s: rump_pub_etfs_register failed "
						"(error=%d)", fsdevice, rv);
			} else {
				mntd.mntd_fsdevice = fsdevice;
				fsdevice = strdup(RUMPFSDEV);
				rv = mount_fstype(fst, fsdevice, mntopts,
				    puffsexec, specopts, &mntd, verbose);
				if (rv == -1) {
					warnx("%s: "
					    "Invalid or unknown filesystem type"
					    ", retry with -v for details",
					    mntd.mntd_fsdevice);
				}
			}
		}
	}

	free(mntd.mntd_argv);
	mntd.mntd_argv = NULL;
	mntd.mntd_argv_size = 0;

	/* Remove the arguments used by fsu_mount and reset getopt*/
	if ((*argv)[idx] != NULL && strcmp((*argv)[idx], "--") == 0)
		++idx;

	if (--idx > 0) {
		(*argv)[idx] = (*argv)[0];
		*argv += idx;
		*argc -= idx;
		optind = 1;
#ifdef HAVE_GETOPT_OPTRESET
		optreset = 1;
#endif
	}

	optind = 1;
#ifdef HAVE_GETOPT_OPTRESET
	optreset = 1;
#endif
	opterr = 1;
	return rv;
}