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