Home | History | Annotate | Line # | Download | only in ffs
h_quota2_tests.c revision 1.2
      1 /*	$NetBSD: h_quota2_tests.c,v 1.2 2011/03/06 17:08:40 bouyer Exp $	*/
      2 
      3 /*
      4  * rump server for advanced quota tests
      5  * this one includes functions to run against the filesystem before
      6  * starting to handle rump requests from clients.
      7  */
      8 
      9 #include "../common/h_fsmacros.h"
     10 
     11 #include <err.h>
     12 #include <semaphore.h>
     13 #include <sys/types.h>
     14 #include <sys/mount.h>
     15 
     16 #include <stdlib.h>
     17 #include <unistd.h>
     18 
     19 #include <ufs/ufs/ufsmount.h>
     20 #include <dev/fssvar.h>
     21 
     22 #include <rump/rump.h>
     23 #include <rump/rump_syscalls.h>
     24 
     25 #include "../../h_macros.h"
     26 
     27 int background = 0;
     28 
     29 #define TEST_NONROOT_ID 1
     30 
     31 static int
     32 quota_test0(const char *testopts)
     33 {
     34 	static char buf[512];
     35 	int fd;
     36 	int error;
     37 	rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID);
     38 	rump_sys_chmod(".", 0777);
     39 	if (rump_sys_setegid(TEST_NONROOT_ID) != 0) {
     40 		error = errno;
     41 		perror("rump_sys_setegid");
     42 		return error;
     43 	}
     44 	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
     45 		error = errno;
     46 		perror("rump_sys_seteuid");
     47 		return error;
     48 	}
     49 	fd = rump_sys_open("test_fillup", O_CREAT | O_RDWR, 0644);
     50 	if (fd < 0) {
     51 		error = errno;
     52 		perror("rump_sys_open");
     53 	} else {
     54 		while (rump_sys_write(fd, buf, sizeof(buf)) == sizeof(buf))
     55 			error = 0;
     56 		error = errno;
     57 	}
     58 	rump_sys_close(fd);
     59 	rump_sys_seteuid(0);
     60 	rump_sys_setegid(0);
     61 	return error;
     62 }
     63 
     64 static int
     65 quota_test1(const char *testopts)
     66 {
     67 	static char buf[512];
     68 	int fd;
     69 	int error;
     70 	rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID);
     71 	rump_sys_chmod(".", 0777);
     72 	if (rump_sys_setegid(TEST_NONROOT_ID) != 0) {
     73 		error = errno;
     74 		perror("rump_sys_setegid");
     75 		return error;
     76 	}
     77 	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
     78 		error = errno;
     79 		perror("rump_sys_seteuid");
     80 		return error;
     81 	}
     82 	fd = rump_sys_open("test_fillup", O_CREAT | O_RDWR, 0644);
     83 	if (fd < 0) {
     84 		error = errno;
     85 		perror("rump_sys_open");
     86 	} else {
     87 		/*
     88 		 * write up to the soft limit, wait a bit, an try to
     89 		 * keep on writing
     90 		 */
     91 		int i;
     92 
     93 		/* write 2k: with the directory this makes 2.5K */
     94 		for (i = 0; i < 4; i++) {
     95 			error = rump_sys_write(fd, buf, sizeof(buf));
     96 			if (error != sizeof(buf))
     97 				err(1, "write failed early");
     98 		}
     99 		sleep(2);
    100 		/* now try to write an extra .5k */
    101 		if (rump_sys_write(fd, buf, sizeof(buf)) != sizeof(buf))
    102 			error = errno;
    103 		else
    104 			error = 0;
    105 	}
    106 	rump_sys_close(fd);
    107 	rump_sys_seteuid(0);
    108 	rump_sys_setegid(0);
    109 	return error;
    110 }
    111 
    112 static int
    113 quota_test2(const char *testopts)
    114 {
    115 	static char buf[512];
    116 	int fd;
    117 	int error;
    118 	int i;
    119 	rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID);
    120 	rump_sys_chmod(".", 0777);
    121 	if (rump_sys_setegid(TEST_NONROOT_ID) != 0) {
    122 		error = errno;
    123 		perror("rump_sys_setegid");
    124 		return error;
    125 	}
    126 	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
    127 		error = errno;
    128 		perror("rump_sys_seteuid");
    129 		return error;
    130 	}
    131 
    132 	for (i = 0; ; i++) {
    133 		sprintf(buf, "file%d", i);
    134 		fd = rump_sys_open(buf, O_CREAT | O_RDWR, 0644);
    135 		if (fd < 0)
    136 			break;
    137 		sprintf(buf, "test file no %d", i);
    138 		rump_sys_write(fd, buf, strlen(buf));
    139 		rump_sys_close(fd);
    140 	}
    141 	error = errno;
    142 
    143 	rump_sys_close(fd);
    144 	rump_sys_seteuid(0);
    145 	rump_sys_setegid(0);
    146 	return error;
    147 }
    148 
    149 static int
    150 quota_test3(const char *testopts)
    151 {
    152 	static char buf[512];
    153 	int fd;
    154 	int error;
    155 	int i;
    156 	rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID);
    157 	rump_sys_chmod(".", 0777);
    158 	if (rump_sys_setegid(TEST_NONROOT_ID) != 0) {
    159 		error = errno;
    160 		perror("rump_sys_setegid");
    161 		return error;
    162 	}
    163 	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
    164 		error = errno;
    165 		perror("rump_sys_seteuid");
    166 		return error;
    167 	}
    168 
    169 	/*
    170 	 * create files one past the soft limit: one less as we already own the
    171 	 * root directory
    172 	 */
    173 	for (i = 0; i < 4; i++) {
    174 		sprintf(buf, "file%d", i);
    175 		fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644);
    176 		if (fd < 0)
    177 			err(1, "file create failed early");
    178 		sprintf(buf, "test file no %d", i);
    179 		rump_sys_write(fd, buf, strlen(buf));
    180 		rump_sys_close(fd);
    181 	}
    182 	/* now create an extra file after grace time: this should fail */
    183 	sleep(2);
    184 	sprintf(buf, "file%d", i);
    185 	fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644);
    186 	if (fd < 0)
    187 		error = errno;
    188 	else
    189 		error = 0;
    190 
    191 	rump_sys_close(fd);
    192 	rump_sys_seteuid(0);
    193 	rump_sys_setegid(0);
    194 	return error;
    195 }
    196 
    197 static int
    198 quota_test4(const char *testopts)
    199 {
    200 	static char buf[512];
    201 	int fd, fssfd;
    202 	struct fss_set fss;
    203 	unsigned int i;
    204 	int unl=0;
    205 	int unconf=0;
    206 
    207 	/*
    208 	 * take an internal snapshot of the filesystem, and create a new
    209 	 * file with some data
    210 	 */
    211 	rump_sys_chown(".", 0, 0);
    212 	rump_sys_chmod(".", 0777);
    213 
    214 	for (i =0; testopts && i < strlen(testopts); i++) {
    215 		switch(testopts[i]) {
    216 		case 'L':
    217 			unl++;
    218 			break;
    219 		case 'C':
    220 			unconf++;
    221 			break;
    222 		default:
    223 			errx(1, "test4: unknown option %c", testopts[i]);
    224 		}
    225 	}
    226 
    227 	/* first create the snapshot */
    228 
    229 	 fd = rump_sys_open(FSTEST_MNTNAME "/le_snap", O_CREAT | O_RDWR, 0777);
    230 	 if (fd == -1)
    231 		err(1, "create " FSTEST_MNTNAME "/le_snap");
    232 	 rump_sys_close(fd);
    233 	 fssfd = rump_sys_open("/dev/rfss0", O_RDWR);
    234 	 if (fssfd == -1)
    235 		err(1, "cannot open fss");
    236 	memset(&fss, 0, sizeof(fss));
    237 	fss.fss_mount = __UNCONST("/mnt");
    238 	fss.fss_bstore = __UNCONST(FSTEST_MNTNAME "/le_snap");
    239 	fss.fss_csize = 0;
    240 	if (rump_sys_ioctl(fssfd, FSSIOCSET, &fss) == -1)
    241 		err(1, "create snapshot");
    242 	if (unl) {
    243 		if (rump_sys_unlink(FSTEST_MNTNAME "/le_snap") == -1)
    244 			err(1, "unlink snapshot");
    245 	}
    246 
    247 	/* now create some extra files */
    248 
    249 	for (i = 0; i < 4; i++) {
    250 		sprintf(buf, "file%d", i);
    251 		fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644);
    252 		if (fd < 0)
    253 			err(1, "create %s", buf);
    254 		sprintf(buf, "test file no %d", i);
    255 		rump_sys_write(fd, buf, strlen(buf));
    256 		rump_sys_close(fd);
    257 	}
    258 	if (unconf)
    259 		if (rump_sys_ioctl(fssfd, FSSIOCCLR, NULL) == -1)
    260 			err(1, "unconfigure snapshot");
    261 	return 0;
    262 }
    263 
    264 static int
    265 quota_test5(const char *testopts)
    266 {
    267 	static char buf[512];
    268 	int fd;
    269 	int remount = 0;
    270 	int unlnk = 0;
    271 	int log = 0;
    272 	unsigned int i;
    273 
    274 	for (i =0; testopts && i < strlen(testopts); i++) {
    275 		switch(testopts[i]) {
    276 		case 'L':
    277 			log++;
    278 			break;
    279 		case 'R':
    280 			remount++;
    281 			break;
    282 		case 'U':
    283 			unlnk++;
    284 			break;
    285 		default:
    286 			errx(1, "test4: unknown option %c", testopts[i]);
    287 		}
    288 	}
    289 	if (remount) {
    290 		struct ufs_args uargs;
    291 		uargs.fspec = __UNCONST("/diskdev");
    292 		/* remount the fs read/write */
    293 		if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME,
    294 		    MNT_UPDATE | (log ? MNT_LOG : 0),
    295 		    &uargs, sizeof(uargs)) == -1)
    296 			err(1, "mount ffs rw %s", FSTEST_MNTNAME);
    297 	}
    298 
    299 	if (unlnk) {
    300 		/*
    301 		 * open and unlink a file
    302 		 */
    303 
    304 		fd = rump_sys_open("unlinked_file",
    305 		    O_EXCL| O_CREAT | O_RDWR, 0644);
    306 		if (fd < 0)
    307 			err(1, "create %s", "unlinked_file");
    308 		sprintf(buf, "test unlinked_file");
    309 		rump_sys_write(fd, buf, strlen(buf));
    310 		if (rump_sys_unlink("unlinked_file") == -1)
    311 			err(1, "unlink unlinked_file");
    312 		if (rump_sys_fsync(fd) == -1)
    313 			err(1, "fsync unlinked_file");
    314 		rump_sys_reboot(RUMP_RB_NOSYNC, NULL);
    315 		errx(1, "reboot failed");
    316 		return 1;
    317 	}
    318 	return 0;
    319 }
    320 
    321 struct quota_test {
    322 	int (*func)(const char *);
    323 	const char *desc;
    324 };
    325 
    326 struct quota_test quota_tests[] = {
    327 	{ quota_test0, "write up to hard limit"},
    328 	{ quota_test1, "write beyond the soft limit after grace time"},
    329 	{ quota_test2, "create file up to hard limit"},
    330 	{ quota_test3, "create file beyond the soft limit after grace time"},
    331 	{ quota_test4, "take a snapshot and add some data"},
    332 	{ quota_test5, "open and unlink a file"},
    333 };
    334 
    335 static void
    336 usage(void)
    337 {
    338 	unsigned int test;
    339 	fprintf(stderr, "usage: %s [-b] [-l] test# diskimage bindurl\n",
    340 	    getprogname());
    341 	fprintf(stderr, "available tests:\n");
    342 	for (test = 0; test < sizeof(quota_tests) / sizeof(quota_tests[0]);
    343 	    test++)
    344 		fprintf(stderr, "\t%d: %s\n", test, quota_tests[test].desc);
    345 	exit(1);
    346 }
    347 
    348 static void
    349 die(const char *reason, int error)
    350 {
    351 
    352 	warnx("%s: %s", reason, strerror(error));
    353 	if (background)
    354 		rump_daemonize_done(error);
    355 	exit(1);
    356 }
    357 
    358 static sem_t sigsem;
    359 static void
    360 sigreboot(int sig)
    361 {
    362 
    363 	sem_post(&sigsem);
    364 }
    365 
    366 int
    367 main(int argc, char **argv)
    368 {
    369 	int error;
    370 	u_long test;
    371 	char *end;
    372 	struct ufs_args uargs;
    373 	const char *filename;
    374 	const char *serverurl;
    375 	const char *topts = NULL;
    376 	int mntopts = 0;
    377 	int ch;
    378 
    379 	while ((ch = getopt(argc, argv, "blo:r")) != -1) {
    380 		switch(ch) {
    381 		case 'b':
    382 			background = 1;
    383 			break;
    384 		case 'l':
    385 			mntopts |= MNT_LOG;
    386 			break;
    387 		case 'r':
    388 			mntopts |= MNT_RDONLY;
    389 			break;
    390 		case 'o':
    391 			topts = optarg;
    392 			break;
    393 		default:
    394 			usage();
    395 		}
    396 	}
    397 	argc -= optind;
    398 	argv += optind;
    399 
    400 	if (argc != 3)
    401 		usage();
    402 
    403 	filename = argv[1];
    404 	serverurl = argv[2];
    405 
    406 	test = strtoul(argv[0], &end, 10);
    407 	if (*end != '\0') {
    408 		usage();
    409 	}
    410 	if (test > sizeof(quota_tests) / sizeof(quota_tests[0])) {
    411 		usage();
    412 	}
    413 
    414 	if (background) {
    415 		error = rump_daemonize_begin();
    416 		if (error)
    417 			errx(1, "rump daemonize: %s", strerror(error));
    418 	}
    419 
    420 	error = rump_init();
    421 	if (error)
    422 		die("rump init failed", error);
    423 
    424 	if (rump_sys_mkdir(FSTEST_MNTNAME, 0777) == -1)
    425 		err(1, "mount point create");
    426 	rump_pub_etfs_register("/diskdev", filename, RUMP_ETFS_BLK);
    427 	uargs.fspec = __UNCONST("/diskdev");
    428 	if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, mntopts,
    429 	    &uargs, sizeof(uargs)) == -1)
    430 		die("mount ffs", errno);
    431 
    432 	if (rump_sys_chdir(FSTEST_MNTNAME) == -1)
    433 		err(1, "cd %s", FSTEST_MNTNAME);
    434 	error = quota_tests[test].func(topts);
    435 	if (error) {
    436 		fprintf(stderr, " test %lu: %s returned %d: %s\n",
    437 		    test, quota_tests[test].desc, error, strerror(error));
    438 	}
    439 	if (rump_sys_chdir("/") == -1)
    440 		err(1, "cd /");
    441 
    442 	error = rump_init_server(serverurl);
    443 	if (error)
    444 		die("rump server init failed", error);
    445 	if (background)
    446 		rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS);
    447 
    448 	sem_init(&sigsem, 0, 0);
    449 	signal(SIGTERM, sigreboot);
    450 	signal(SIGINT, sigreboot);
    451 	sem_wait(&sigsem);
    452 
    453 	rump_sys_reboot(0, NULL);
    454 	/*NOTREACHED*/
    455 	return 0;
    456 }
    457