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