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