1314817Sngie/* $NetBSD: h_quota2_tests.c,v 1.5 2017/01/13 21:30:39 christos Exp $ */ 2272343Sngie 3272343Sngie/* 4272343Sngie * rump server for advanced quota tests 5272343Sngie * this one includes functions to run against the filesystem before 6272343Sngie * starting to handle rump requests from clients. 7272343Sngie */ 8272343Sngie 9272343Sngie#include "../common/h_fsmacros.h" 10272343Sngie 11272343Sngie#include <err.h> 12272343Sngie#include <semaphore.h> 13272343Sngie#include <sys/types.h> 14272343Sngie#include <sys/mount.h> 15272343Sngie 16272343Sngie#include <stdlib.h> 17272343Sngie#include <unistd.h> 18272343Sngie 19272343Sngie#include <ufs/ufs/ufsmount.h> 20272343Sngie#include <dev/fssvar.h> 21272343Sngie 22272343Sngie#include <rump/rump.h> 23272343Sngie#include <rump/rump_syscalls.h> 24272343Sngie 25314817Sngie#include "h_macros.h" 26272343Sngie 27272343Sngieint background = 0; 28272343Sngie 29272343Sngie#define TEST_NONROOT_ID 1 30272343Sngie 31272343Sngiestatic int 32272343Sngiequota_test0(const char *testopts) 33272343Sngie{ 34272343Sngie static char buf[512]; 35272343Sngie int fd; 36272343Sngie int error; 37272343Sngie unsigned int i; 38272343Sngie int chowner = 1; 39272343Sngie for (i =0; testopts && i < strlen(testopts); i++) { 40272343Sngie switch(testopts[i]) { 41272343Sngie case 'C': 42272343Sngie chowner = 0; 43272343Sngie break; 44272343Sngie default: 45272343Sngie errx(1, "test4: unknown option %c", testopts[i]); 46272343Sngie } 47272343Sngie } 48272343Sngie if (chowner) 49272343Sngie rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); 50272343Sngie rump_sys_chmod(".", 0777); 51272343Sngie if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { 52272343Sngie error = errno; 53272343Sngie warn("rump_sys_setegid"); 54272343Sngie return error; 55272343Sngie } 56272343Sngie if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { 57272343Sngie error = errno; 58272343Sngie warn("rump_sys_seteuid"); 59272343Sngie return error; 60272343Sngie } 61272343Sngie fd = rump_sys_open("test_fillup", O_CREAT | O_RDWR, 0644); 62272343Sngie if (fd < 0) { 63272343Sngie error = errno; 64272343Sngie warn("rump_sys_open"); 65272343Sngie } else { 66272343Sngie while (rump_sys_write(fd, buf, sizeof(buf)) == sizeof(buf)) 67272343Sngie error = 0; 68272343Sngie error = errno; 69272343Sngie } 70272343Sngie rump_sys_close(fd); 71272343Sngie rump_sys_seteuid(0); 72272343Sngie rump_sys_setegid(0); 73272343Sngie return error; 74272343Sngie} 75272343Sngie 76272343Sngiestatic int 77272343Sngiequota_test1(const char *testopts) 78272343Sngie{ 79272343Sngie static char buf[512]; 80272343Sngie int fd; 81272343Sngie int error; 82272343Sngie rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); 83272343Sngie rump_sys_chmod(".", 0777); 84272343Sngie if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { 85272343Sngie error = errno; 86272343Sngie warn("rump_sys_setegid"); 87272343Sngie return error; 88272343Sngie } 89272343Sngie if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { 90272343Sngie error = errno; 91272343Sngie warn("rump_sys_seteuid"); 92272343Sngie return error; 93272343Sngie } 94272343Sngie fd = rump_sys_open("test_fillup", O_CREAT | O_RDWR, 0644); 95272343Sngie if (fd < 0) { 96272343Sngie error = errno; 97272343Sngie warn("rump_sys_open"); 98272343Sngie } else { 99272343Sngie /* 100272343Sngie * write up to the soft limit, wait a bit, an try to 101272343Sngie * keep on writing 102272343Sngie */ 103272343Sngie int i; 104272343Sngie 105272343Sngie /* write 2k: with the directory this makes 2.5K */ 106272343Sngie for (i = 0; i < 4; i++) { 107272343Sngie error = rump_sys_write(fd, buf, sizeof(buf)); 108272343Sngie if (error != sizeof(buf)) 109272343Sngie err(1, "write failed early"); 110272343Sngie } 111272343Sngie sleep(2); 112272343Sngie /* now try to write an extra .5k */ 113272343Sngie if (rump_sys_write(fd, buf, sizeof(buf)) != sizeof(buf)) 114272343Sngie error = errno; 115272343Sngie else 116272343Sngie error = 0; 117272343Sngie } 118272343Sngie rump_sys_close(fd); 119272343Sngie rump_sys_seteuid(0); 120272343Sngie rump_sys_setegid(0); 121272343Sngie return error; 122272343Sngie} 123272343Sngie 124272343Sngiestatic int 125272343Sngiequota_test2(const char *testopts) 126272343Sngie{ 127272343Sngie static char buf[512]; 128272343Sngie int fd; 129272343Sngie int error; 130272343Sngie int i; 131272343Sngie rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); 132272343Sngie rump_sys_chmod(".", 0777); 133272343Sngie if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { 134272343Sngie error = errno; 135272343Sngie warn("rump_sys_setegid"); 136272343Sngie return error; 137272343Sngie } 138272343Sngie if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { 139272343Sngie error = errno; 140272343Sngie warn("rump_sys_seteuid"); 141272343Sngie return error; 142272343Sngie } 143272343Sngie 144272343Sngie for (i = 0; ; i++) { 145272343Sngie sprintf(buf, "file%d", i); 146272343Sngie fd = rump_sys_open(buf, O_CREAT | O_RDWR, 0644); 147272343Sngie if (fd < 0) 148272343Sngie break; 149272343Sngie sprintf(buf, "test file no %d", i); 150272343Sngie rump_sys_write(fd, buf, strlen(buf)); 151272343Sngie rump_sys_close(fd); 152272343Sngie } 153272343Sngie error = errno; 154272343Sngie 155272343Sngie rump_sys_close(fd); 156272343Sngie rump_sys_seteuid(0); 157272343Sngie rump_sys_setegid(0); 158272343Sngie return error; 159272343Sngie} 160272343Sngie 161272343Sngiestatic int 162272343Sngiequota_test3(const char *testopts) 163272343Sngie{ 164272343Sngie static char buf[512]; 165272343Sngie int fd; 166272343Sngie int error; 167272343Sngie int i; 168272343Sngie rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); 169272343Sngie rump_sys_chmod(".", 0777); 170272343Sngie if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { 171272343Sngie error = errno; 172272343Sngie warn("rump_sys_setegid"); 173272343Sngie return error; 174272343Sngie } 175272343Sngie if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { 176272343Sngie error = errno; 177272343Sngie warn("rump_sys_seteuid"); 178272343Sngie return error; 179272343Sngie } 180272343Sngie 181272343Sngie /* 182272343Sngie * create files one past the soft limit: one less as we already own the 183272343Sngie * root directory 184272343Sngie */ 185272343Sngie for (i = 0; i < 4; i++) { 186272343Sngie sprintf(buf, "file%d", i); 187272343Sngie fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644); 188272343Sngie if (fd < 0) 189272343Sngie err(1, "file create failed early"); 190272343Sngie sprintf(buf, "test file no %d", i); 191272343Sngie rump_sys_write(fd, buf, strlen(buf)); 192272343Sngie rump_sys_close(fd); 193272343Sngie } 194272343Sngie /* now create an extra file after grace time: this should fail */ 195272343Sngie sleep(2); 196272343Sngie sprintf(buf, "file%d", i); 197272343Sngie fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644); 198272343Sngie if (fd < 0) 199272343Sngie error = errno; 200272343Sngie else 201272343Sngie error = 0; 202272343Sngie 203272343Sngie rump_sys_close(fd); 204272343Sngie rump_sys_seteuid(0); 205272343Sngie rump_sys_setegid(0); 206272343Sngie return error; 207272343Sngie} 208272343Sngie 209272343Sngiestatic int 210272343Sngiequota_test4(const char *testopts) 211272343Sngie{ 212272343Sngie static char buf[512]; 213272343Sngie int fd, fssfd; 214272343Sngie struct fss_set fss; 215272343Sngie unsigned int i; 216272343Sngie int unl=0; 217272343Sngie int unconf=0; 218272343Sngie 219272343Sngie /* 220272343Sngie * take an internal snapshot of the filesystem, and create a new 221272343Sngie * file with some data 222272343Sngie */ 223272343Sngie rump_sys_chown(".", 0, 0); 224272343Sngie rump_sys_chmod(".", 0777); 225272343Sngie 226272343Sngie for (i =0; testopts && i < strlen(testopts); i++) { 227272343Sngie switch(testopts[i]) { 228272343Sngie case 'L': 229272343Sngie unl++; 230272343Sngie break; 231272343Sngie case 'C': 232272343Sngie unconf++; 233272343Sngie break; 234272343Sngie default: 235272343Sngie errx(1, "test4: unknown option %c", testopts[i]); 236272343Sngie } 237272343Sngie } 238272343Sngie 239272343Sngie /* first create the snapshot */ 240272343Sngie 241272343Sngie fd = rump_sys_open(FSTEST_MNTNAME "/le_snap", O_CREAT | O_RDWR, 0777); 242272343Sngie if (fd == -1) 243272343Sngie err(1, "create " FSTEST_MNTNAME "/le_snap"); 244272343Sngie rump_sys_close(fd); 245272343Sngie fssfd = rump_sys_open("/dev/rfss0", O_RDWR); 246272343Sngie if (fssfd == -1) 247272343Sngie err(1, "cannot open fss"); 248272343Sngie memset(&fss, 0, sizeof(fss)); 249272343Sngie fss.fss_mount = __UNCONST("/mnt"); 250272343Sngie fss.fss_bstore = __UNCONST(FSTEST_MNTNAME "/le_snap"); 251272343Sngie fss.fss_csize = 0; 252272343Sngie if (rump_sys_ioctl(fssfd, FSSIOCSET, &fss) == -1) 253272343Sngie err(1, "create snapshot"); 254272343Sngie if (unl) { 255272343Sngie if (rump_sys_unlink(FSTEST_MNTNAME "/le_snap") == -1) 256272343Sngie err(1, "unlink snapshot"); 257272343Sngie } 258272343Sngie 259272343Sngie /* now create some extra files */ 260272343Sngie 261272343Sngie for (i = 0; i < 4; i++) { 262272343Sngie sprintf(buf, "file%d", i); 263272343Sngie fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644); 264272343Sngie if (fd < 0) 265272343Sngie err(1, "create %s", buf); 266272343Sngie sprintf(buf, "test file no %d", i); 267272343Sngie rump_sys_write(fd, buf, strlen(buf)); 268272343Sngie rump_sys_close(fd); 269272343Sngie } 270272343Sngie if (unconf) 271272343Sngie if (rump_sys_ioctl(fssfd, FSSIOCCLR, NULL) == -1) 272272343Sngie err(1, "unconfigure snapshot"); 273272343Sngie return 0; 274272343Sngie} 275272343Sngie 276272343Sngiestatic int 277272343Sngiequota_test5(const char *testopts) 278272343Sngie{ 279272343Sngie static char buf[512]; 280272343Sngie int fd; 281272343Sngie int remount = 0; 282272343Sngie int unlnk = 0; 283272343Sngie int log = 0; 284272343Sngie unsigned int i; 285272343Sngie 286272343Sngie for (i =0; testopts && i < strlen(testopts); i++) { 287272343Sngie switch(testopts[i]) { 288272343Sngie case 'L': 289272343Sngie log++; 290272343Sngie break; 291272343Sngie case 'R': 292272343Sngie remount++; 293272343Sngie break; 294272343Sngie case 'U': 295272343Sngie unlnk++; 296272343Sngie break; 297272343Sngie default: 298272343Sngie errx(1, "test4: unknown option %c", testopts[i]); 299272343Sngie } 300272343Sngie } 301272343Sngie if (remount) { 302272343Sngie struct ufs_args uargs; 303272343Sngie uargs.fspec = __UNCONST("/diskdev"); 304272343Sngie /* remount the fs read/write */ 305272343Sngie if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, 306272343Sngie MNT_UPDATE | (log ? MNT_LOG : 0), 307272343Sngie &uargs, sizeof(uargs)) == -1) 308272343Sngie err(1, "mount ffs rw %s", FSTEST_MNTNAME); 309272343Sngie } 310272343Sngie 311272343Sngie if (unlnk) { 312272343Sngie /* 313272343Sngie * open and unlink a file 314272343Sngie */ 315272343Sngie 316272343Sngie fd = rump_sys_open("unlinked_file", 317272343Sngie O_EXCL| O_CREAT | O_RDWR, 0644); 318272343Sngie if (fd < 0) 319272343Sngie err(1, "create %s", "unlinked_file"); 320272343Sngie sprintf(buf, "test unlinked_file"); 321272343Sngie rump_sys_write(fd, buf, strlen(buf)); 322272343Sngie if (rump_sys_unlink("unlinked_file") == -1) 323272343Sngie err(1, "unlink unlinked_file"); 324272343Sngie if (rump_sys_fsync(fd) == -1) 325272343Sngie err(1, "fsync unlinked_file"); 326272343Sngie rump_sys_reboot(RUMP_RB_NOSYNC, NULL); 327272343Sngie errx(1, "reboot failed"); 328272343Sngie return 1; 329272343Sngie } 330272343Sngie return 0; 331272343Sngie} 332272343Sngie 333272343Sngiestruct quota_test { 334272343Sngie int (*func)(const char *); 335272343Sngie const char *desc; 336272343Sngie}; 337272343Sngie 338272343Sngiestruct quota_test quota_tests[] = { 339272343Sngie { quota_test0, "write up to hard limit"}, 340272343Sngie { quota_test1, "write beyond the soft limit after grace time"}, 341272343Sngie { quota_test2, "create file up to hard limit"}, 342272343Sngie { quota_test3, "create file beyond the soft limit after grace time"}, 343272343Sngie { quota_test4, "take a snapshot and add some data"}, 344272343Sngie { quota_test5, "open and unlink a file"}, 345272343Sngie}; 346272343Sngie 347272343Sngiestatic void 348272343Sngieusage(void) 349272343Sngie{ 350272343Sngie unsigned int test; 351272343Sngie fprintf(stderr, "usage: %s [-b] [-l] test# diskimage bindurl\n", 352272343Sngie getprogname()); 353272343Sngie fprintf(stderr, "available tests:\n"); 354272343Sngie for (test = 0; test < sizeof(quota_tests) / sizeof(quota_tests[0]); 355272343Sngie test++) 356272343Sngie fprintf(stderr, "\t%d: %s\n", test, quota_tests[test].desc); 357272343Sngie exit(1); 358272343Sngie} 359272343Sngie 360272343Sngiestatic void 361272343Sngiedie(const char *reason, int error) 362272343Sngie{ 363272343Sngie 364272343Sngie warnx("%s: %s", reason, strerror(error)); 365272343Sngie if (background) 366272343Sngie rump_daemonize_done(error); 367272343Sngie exit(1); 368272343Sngie} 369272343Sngie 370272343Sngiestatic sem_t sigsem; 371272343Sngiestatic void 372272343Sngiesigreboot(int sig) 373272343Sngie{ 374272343Sngie 375272343Sngie sem_post(&sigsem); 376272343Sngie} 377272343Sngie 378272343Sngieint 379272343Sngiemain(int argc, char **argv) 380272343Sngie{ 381272343Sngie int error; 382272343Sngie u_long test; 383272343Sngie char *end; 384272343Sngie struct ufs_args uargs; 385272343Sngie const char *filename; 386272343Sngie const char *serverurl; 387272343Sngie const char *topts = NULL; 388272343Sngie int mntopts = 0; 389272343Sngie int ch; 390272343Sngie 391272343Sngie while ((ch = getopt(argc, argv, "blo:r")) != -1) { 392272343Sngie switch(ch) { 393272343Sngie case 'b': 394272343Sngie background = 1; 395272343Sngie break; 396272343Sngie case 'l': 397272343Sngie mntopts |= MNT_LOG; 398272343Sngie break; 399272343Sngie case 'r': 400272343Sngie mntopts |= MNT_RDONLY; 401272343Sngie break; 402272343Sngie case 'o': 403272343Sngie topts = optarg; 404272343Sngie break; 405272343Sngie default: 406272343Sngie usage(); 407272343Sngie } 408272343Sngie } 409272343Sngie argc -= optind; 410272343Sngie argv += optind; 411272343Sngie 412272343Sngie if (argc != 3) 413272343Sngie usage(); 414272343Sngie 415272343Sngie filename = argv[1]; 416272343Sngie serverurl = argv[2]; 417272343Sngie 418272343Sngie test = strtoul(argv[0], &end, 10); 419272343Sngie if (*end != '\0') { 420272343Sngie usage(); 421272343Sngie } 422272343Sngie if (test > sizeof(quota_tests) / sizeof(quota_tests[0])) { 423272343Sngie usage(); 424272343Sngie } 425272343Sngie 426272343Sngie if (background) { 427272343Sngie error = rump_daemonize_begin(); 428272343Sngie if (error) 429272343Sngie errx(1, "rump daemonize: %s", strerror(error)); 430272343Sngie } 431272343Sngie 432272343Sngie error = rump_init(); 433272343Sngie if (error) 434272343Sngie die("rump init failed", error); 435272343Sngie 436272343Sngie if (rump_sys_mkdir(FSTEST_MNTNAME, 0777) == -1) 437272343Sngie err(1, "mount point create"); 438272343Sngie rump_pub_etfs_register("/diskdev", filename, RUMP_ETFS_BLK); 439272343Sngie uargs.fspec = __UNCONST("/diskdev"); 440272343Sngie if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, mntopts, 441272343Sngie &uargs, sizeof(uargs)) == -1) 442272343Sngie die("mount ffs", errno); 443272343Sngie 444272343Sngie if (rump_sys_chdir(FSTEST_MNTNAME) == -1) 445272343Sngie err(1, "cd %s", FSTEST_MNTNAME); 446272343Sngie error = quota_tests[test].func(topts); 447272343Sngie if (error) { 448272343Sngie fprintf(stderr, " test %lu: %s returned %d: %s\n", 449272343Sngie test, quota_tests[test].desc, error, strerror(error)); 450272343Sngie } 451272343Sngie if (rump_sys_chdir("/") == -1) 452272343Sngie err(1, "cd /"); 453272343Sngie 454272343Sngie error = rump_init_server(serverurl); 455272343Sngie if (error) 456272343Sngie die("rump server init failed", error); 457272343Sngie if (background) 458272343Sngie rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS); 459272343Sngie 460272343Sngie sem_init(&sigsem, 0, 0); 461272343Sngie signal(SIGTERM, sigreboot); 462272343Sngie signal(SIGINT, sigreboot); 463272343Sngie sem_wait(&sigsem); 464272343Sngie 465272343Sngie rump_sys_reboot(0, NULL); 466272343Sngie /*NOTREACHED*/ 467272343Sngie return 0; 468272343Sngie} 469