11.6Sbad/*	$NetBSD: t_basic.c,v 1.6 2024/07/28 12:55:59 bad Exp $	*/
21.1Spooka
31.1Spooka#include <sys/types.h>
41.1Spooka#include <sys/mount.h>
51.1Spooka
61.1Spooka#include <atf-c.h>
71.1Spooka#include <err.h>
81.1Spooka#include <errno.h>
91.1Spooka#include <fcntl.h>
101.1Spooka#include <stdio.h>
111.1Spooka#include <unistd.h>
121.1Spooka#include <string.h>
131.1Spooka#include <stdlib.h>
141.1Spooka
151.1Spooka#include <rump/rump.h>
161.1Spooka#include <rump/rump_syscalls.h>
171.1Spooka
181.1Spooka#include <miscfs/nullfs/null.h>
191.1Spooka#include <fs/tmpfs/tmpfs_args.h>
201.1Spooka
211.4Schristos#include "h_macros.h"
221.1Spooka
231.1SpookaATF_TC(basic);
241.1SpookaATF_TC_HEAD(basic, tc)
251.1Spooka{
261.1Spooka	atf_tc_set_md_var(tc, "descr", "basic nullfs functionality");
271.1Spooka}
281.1Spooka
291.1Spooka#define MSTR "magic bus"
301.1Spooka
311.1Spookastatic void
321.1Spookaxput_tfile(const char *path, const char *mstr)
331.1Spooka{
341.1Spooka	int fd;
351.1Spooka
361.1Spooka	fd = rump_sys_open(path, O_CREAT | O_RDWR, 0777);
371.1Spooka	if (fd == -1)
381.1Spooka		atf_tc_fail_errno("create %s", path);
391.1Spooka	if (rump_sys_write(fd, MSTR, sizeof(MSTR)) != sizeof(MSTR))
401.1Spooka		atf_tc_fail_errno("write to testfile");
411.1Spooka	rump_sys_close(fd);
421.1Spooka}
431.1Spooka
441.1Spookastatic int
451.1Spookaxread_tfile(const char *path, const char *mstr)
461.1Spooka{
471.1Spooka	char buf[128];
481.1Spooka	int fd;
491.1Spooka
501.1Spooka	fd = rump_sys_open(path, O_RDONLY);
511.1Spooka	if (fd == -1)
521.1Spooka		return errno;
531.1Spooka	if (rump_sys_read(fd, buf, sizeof(buf)) == -1)
541.1Spooka		atf_tc_fail_errno("read tfile");
551.1Spooka	rump_sys_close(fd);
561.1Spooka	if (strcmp(buf, MSTR) == 0)
571.1Spooka		return 0;
581.1Spooka	return EPROGMISMATCH;
591.1Spooka}
601.1Spooka
611.3Spookastatic void
621.3Spookamountnull(const char *what, const char *mp, int flags)
631.3Spooka{
641.3Spooka	struct null_args nargs;
651.3Spooka
661.3Spooka	memset(&nargs, 0, sizeof(nargs));
671.3Spooka	nargs.nulla_target = __UNCONST(what);
681.3Spooka	if (rump_sys_mount(MOUNT_NULL, mp, flags, &nargs, sizeof(nargs)) == -1)
691.3Spooka		atf_tc_fail_errno("could not mount nullfs");
701.3Spooka
711.3Spooka}
721.3Spooka
731.1SpookaATF_TC_BODY(basic, tc)
741.1Spooka{
751.1Spooka	struct tmpfs_args targs;
761.1Spooka	struct stat sb;
771.1Spooka	int error;
781.1Spooka
791.1Spooka	rump_init();
801.1Spooka	if (rump_sys_mkdir("/td1", 0777) == -1)
811.6Sbad		atf_tc_fail_errno("mkdir /td1");
821.1Spooka	if (rump_sys_mkdir("/td2", 0777) == -1)
831.6Sbad		atf_tc_fail_errno("mkdir /td2");
841.1Spooka
851.1Spooka	/* use tmpfs because rumpfs doesn't support regular files */
861.1Spooka	memset(&targs, 0, sizeof(targs));
871.1Spooka	targs.ta_version = TMPFS_ARGS_VERSION;
881.1Spooka	targs.ta_root_mode = 0777;
891.1Spooka	if (rump_sys_mount(MOUNT_TMPFS, "/td1", 0, &targs, sizeof(targs)) == -1)
901.1Spooka		atf_tc_fail_errno("could not mount tmpfs td1");
911.1Spooka
921.3Spooka	mountnull("/td1", "/td2", 0);
931.1Spooka
941.1Spooka	/* test unnull -> null */
951.1Spooka	xput_tfile("/td1/tensti", "jeppe");
961.1Spooka	error = xread_tfile("/td2/tensti", "jeppe");
971.1Spooka	if (error != 0)
981.1Spooka		atf_tc_fail("null compare failed: %d (%s)",
991.1Spooka		    error, strerror(error));
1001.1Spooka
1011.1Spooka	/* test null -> unnull */
1021.1Spooka	xput_tfile("/td2/kiekko", "keppi");
1031.1Spooka	error = xread_tfile("/td1/kiekko", "keppi");
1041.1Spooka	if (error != 0)
1051.1Spooka		atf_tc_fail("unnull compare failed: %d (%s)",
1061.1Spooka		    error, strerror(error));
1071.1Spooka
1081.1Spooka	/* test unnull -> null overwrite */
1091.1Spooka	xput_tfile("/td1/tensti", "se oolannin sota");
1101.1Spooka	error = xread_tfile("/td2/tensti", "se oolannin sota");
1111.1Spooka	if (error != 0)
1121.1Spooka		atf_tc_fail("unnull compare failed: %d (%s)",
1131.1Spooka		    error, strerror(error));
1141.1Spooka
1151.1Spooka	/* test that /td2 is unaffected in "real life" */
1161.1Spooka	if (rump_sys_unmount("/td2", 0) == -1)
1171.1Spooka		atf_tc_fail_errno("cannot unmount nullfs");
1181.1Spooka	if ((error = rump_sys_stat("/td2/tensti", &sb)) != -1
1191.1Spooka	    || errno != ENOENT) {
1201.1Spooka		atf_tc_fail("stat tensti should return ENOENT, got %d", error);
1211.1Spooka	}
1221.1Spooka	if ((error = rump_sys_stat("/td2/kiekko", &sb)) != -1
1231.1Spooka	    || errno != ENOENT) {
1241.1Spooka		atf_tc_fail("stat kiekko should return ENOENT, got %d", error);
1251.1Spooka	}
1261.1Spooka
1271.1Spooka	/* done */
1281.1Spooka}
1291.1Spooka
1301.3SpookaATF_TC(twistymount);
1311.3SpookaATF_TC_HEAD(twistymount, tc)
1321.3Spooka{
1331.3Spooka
1341.3Spooka	/* this is expected to fail until the PR is fixed */
1351.3Spooka	atf_tc_set_md_var(tc, "descr", "\"recursive\" mounts deadlock"
1361.5Sjruoho	    " (PR kern/43439)");
1371.3Spooka}
1381.3Spooka
1391.3Spooka/*
1401.5Sjruoho * Mapping to identifiers in PR kern/43439:
1411.3Spooka *  /td		= /home/current/pkgsrc
1421.3Spooka *  /td/dist	= /home/current/pkgsrc/distiles
1431.3Spooka *  /mp		= /usr/pkgsrc
1441.3Spooka *  /mp/dist	= /usr/pkgsrc/distfiles -- "created" by first null mount
1451.3Spooka */
1461.3Spooka
1471.3SpookaATF_TC_BODY(twistymount, tc)
1481.3Spooka{
1491.3Spooka	rump_init();
1501.3Spooka
1511.3Spooka	if (rump_sys_mkdir("/td", 0777) == -1)
1521.6Sbad		atf_tc_fail_errno("mkdir /td");
1531.3Spooka	if (rump_sys_mkdir("/td/dist", 0777) == -1)
1541.6Sbad		atf_tc_fail_errno("mkdir /td/dist");
1551.3Spooka	if (rump_sys_mkdir("/mp", 0777) == -1)
1561.6Sbad		atf_tc_fail_errno("mkdir /mp");
1571.3Spooka
1581.3Spooka	/* MNT_RDONLY doesn't matter, but just for compat with the PR */
1591.3Spooka	mountnull("/td", "/mp", MNT_RDONLY);
1601.3Spooka	mountnull("/td/dist", "/mp/dist", 0);
1611.3Spooka
1621.3Spooka	/* if we didn't get a locking-against-meself panic, we passed */
1631.3Spooka}
1641.3Spooka
1651.1SpookaATF_TP_ADD_TCS(tp)
1661.1Spooka{
1671.3Spooka
1681.1Spooka	ATF_TP_ADD_TC(tp, basic);
1691.3Spooka	ATF_TP_ADD_TC(tp, twistymount);
1701.3Spooka
1711.3Spooka	return atf_no_error();
1721.1Spooka}
173