h_quota2_tests.c revision 1.3
1/*	$NetBSD: h_quota2_tests.c,v 1.3 2011/06/11 18:03:17 christos 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
27int background = 0;
28
29#define TEST_NONROOT_ID 1
30
31static int
32quota_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		warn("rump_sys_setegid");
42		return error;
43	}
44	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
45		error = errno;
46		warn("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		warn("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
64static int
65quota_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		warn("rump_sys_setegid");
75		return error;
76	}
77	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
78		error = errno;
79		warn("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		warn("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
112static int
113quota_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		warn("rump_sys_setegid");
124		return error;
125	}
126	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
127		error = errno;
128		warn("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
149static int
150quota_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		warn("rump_sys_setegid");
161		return error;
162	}
163	if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) {
164		error = errno;
165		warn("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
197static int
198quota_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
264static int
265quota_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
321struct quota_test {
322	int (*func)(const char *);
323	const char *desc;
324};
325
326struct 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
335static void
336usage(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
348static void
349die(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
358static sem_t sigsem;
359static void
360sigreboot(int sig)
361{
362
363	sem_post(&sigsem);
364}
365
366int
367main(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