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 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 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 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 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 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 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 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 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 372 sigreboot(int sig) 373 { 374 375 sem_post(&sigsem); 376 } 377 378 int 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