root/user/usertests.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copyin
  2. copyout
  3. copyinstr1
  4. copyinstr2
  5. copyinstr3
  6. rwsbrk
  7. truncate1
  8. truncate2
  9. truncate3
  10. iputtest
  11. exitiputtest
  12. openiputtest
  13. opentest
  14. writetest
  15. writebig
  16. createtest
  17. dirtest
  18. exectest
  19. pipe1
  20. killstatus
  21. preempt
  22. exitwait
  23. reparent
  24. twochildren
  25. forkfork
  26. forkforkfork
  27. reparent2
  28. mem
  29. sharedfd
  30. fourfiles
  31. createdelete
  32. unlinkread
  33. linktest
  34. concreate
  35. linkunlink
  36. subdir
  37. bigwrite
  38. bigfile
  39. fourteen
  40. rmdot
  41. dirfile
  42. iref
  43. forktest
  44. sbrkbasic
  45. sbrkmuch
  46. kernmem
  47. MAXVAplus
  48. sbrkfail
  49. sbrkarg
  50. validatetest
  51. bsstest
  52. bigargtest
  53. fsfull
  54. argptest
  55. stacktest
  56. nowrite
  57. pgbug
  58. sbrkbugs
  59. sbrklast
  60. sbrk8000
  61. badarg
  62. lazy_alloc
  63. lazy_unmap
  64. lazy_copy
  65. bigdir
  66. manywrites
  67. badwrite
  68. execout
  69. diskfull
  70. outofinodes
  71. run
  72. runtests
  73. countfree
  74. drivetests
  75. main

   1 #include "kernel/param.h"
   2 #include "kernel/types.h"
   3 #include "kernel/stat.h"
   4 #include "user/user.h"
   5 #include "kernel/fs.h"
   6 #include "kernel/fcntl.h"
   7 #include "kernel/syscall.h"
   8 #include "kernel/memlayout.h"
   9 #include "kernel/riscv.h"
  10 
  11 //
  12 // Tests xv6 system calls.  usertests without arguments runs them all
  13 // and usertests <name> runs <name> test. The test runner creates for
  14 // each test a process and based on the exit status of the process,
  15 // the test runner reports "OK" or "FAILED".  Some tests result in
  16 // kernel printing usertrap messages, which can be ignored if test
  17 // prints "OK".
  18 //
  19 
  20 #define BUFSZ  ((MAXOPBLOCKS+2)*BSIZE)
  21 
  22 char buf[BUFSZ];
  23 
  24 //
  25 // Section with tests that run fairly quickly.  Use -q if you want to
  26 // run just those.  Without -q usertests also runs the ones that take a
  27 // fair amount of time.
  28 //
  29 
  30 // what if you pass ridiculous pointers to system calls
  31 // that read user memory with copyin?
  32 void
  33 copyin(char *s)
  34 {
  35   uint64 addrs[] = { 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
  36                      0xffffffffffffffff };
  37 
  38   for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
  39     uint64 addr = addrs[ai];
  40     
  41     int fd = open("copyin1", O_CREATE|O_WRONLY);
  42     if(fd < 0){
  43       printf("open(copyin1) failed\n");
  44       exit(1);
  45     }
  46     int n = write(fd, (void*)addr, 8192);
  47     if(n >= 0){
  48       printf("write(fd, %p, 8192) returned %d, not -1\n", (void*)addr, n);
  49       exit(1);
  50     }
  51     close(fd);
  52     unlink("copyin1");
  53     
  54     n = write(1, (char*)addr, 8192);
  55     if(n > 0){
  56       printf("write(1, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
  57       exit(1);
  58     }
  59     
  60     int fds[2];
  61     if(pipe(fds) < 0){
  62       printf("pipe() failed\n");
  63       exit(1);
  64     }
  65     n = write(fds[1], (char*)addr, 8192);
  66     if(n > 0){
  67       printf("write(pipe, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
  68       exit(1);
  69     }
  70     close(fds[0]);
  71     close(fds[1]);
  72   }
  73 }
  74 
  75 // what if you pass ridiculous pointers to system calls
  76 // that write user memory with copyout?
  77 void
  78 copyout(char *s)
  79 {
  80   uint64 addrs[] = { 0LL, 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
  81                      0xffffffffffffffff };
  82 
  83   for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
  84     uint64 addr = addrs[ai];
  85 
  86     int fd = open("README", 0);
  87     if(fd < 0){
  88       printf("open(README) failed\n");
  89       exit(1);
  90     }
  91     int n = read(fd, (void*)addr, 8192);
  92     if(n > 0){
  93       printf("read(fd, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
  94       exit(1);
  95     }
  96     close(fd);
  97 
  98     int fds[2];
  99     if(pipe(fds) < 0){
 100       printf("pipe() failed\n");
 101       exit(1);
 102     }
 103     n = write(fds[1], "x", 1);
 104     if(n != 1){
 105       printf("pipe write failed\n");
 106       exit(1);
 107     }
 108     n = read(fds[0], (void*)addr, 8192);
 109     if(n > 0){
 110       printf("read(pipe, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
 111       exit(1);
 112     }
 113     close(fds[0]);
 114     close(fds[1]);
 115   }
 116 }
 117 
 118 // what if you pass ridiculous string pointers to system calls?
 119 void
 120 copyinstr1(char *s)
 121 {
 122   uint64 addrs[] = { 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
 123                      0xffffffffffffffff };
 124 
 125   for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
 126     uint64 addr = addrs[ai];
 127 
 128     int fd = open((char *)addr, O_CREATE|O_WRONLY);
 129     if(fd >= 0){
 130       printf("open(%p) returned %d, not -1\n", (void*)addr, fd);
 131       exit(1);
 132     }
 133   }
 134 }
 135 
 136 // what if a string system call argument is exactly the size
 137 // of the kernel buffer it is copied into, so that the null
 138 // would fall just beyond the end of the kernel buffer?
 139 void
 140 copyinstr2(char *s)
 141 {
 142   char b[MAXPATH+1];
 143 
 144   for(int i = 0; i < MAXPATH; i++)
 145     b[i] = 'x';
 146   b[MAXPATH] = '\0';
 147   
 148   int ret = unlink(b);
 149   if(ret != -1){
 150     printf("unlink(%s) returned %d, not -1\n", b, ret);
 151     exit(1);
 152   }
 153 
 154   int fd = open(b, O_CREATE | O_WRONLY);
 155   if(fd != -1){
 156     printf("open(%s) returned %d, not -1\n", b, fd);
 157     exit(1);
 158   }
 159 
 160   ret = link(b, b);
 161   if(ret != -1){
 162     printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
 163     exit(1);
 164   }
 165 
 166   char *args[] = { "xx", 0 };
 167   ret = exec(b, args);
 168   if(ret != -1){
 169     printf("exec(%s) returned %d, not -1\n", b, fd);
 170     exit(1);
 171   }
 172 
 173   int pid = fork();
 174   if(pid < 0){
 175     printf("fork failed\n");
 176     exit(1);
 177   }
 178   if(pid == 0){
 179     static char big[PGSIZE+1];
 180     for(int i = 0; i < PGSIZE; i++)
 181       big[i] = 'x';
 182     big[PGSIZE] = '\0';
 183     char *args2[] = { big, big, big, 0 };
 184     ret = exec("echo", args2);
 185     if(ret != -1){
 186       printf("exec(echo, BIG) returned %d, not -1\n", fd);
 187       exit(1);
 188     }
 189     exit(747); // OK
 190   }
 191 
 192   int st = 0;
 193   wait(&st);
 194   if(st != 747){
 195     printf("exec(echo, BIG) succeeded, should have failed\n");
 196     exit(1);
 197   }
 198 }
 199 
 200 // what if a string argument crosses over the end of last user page?
 201 void
 202 copyinstr3(char *s)
 203 {
 204   sbrk(8192);
 205   uint64 top = (uint64) sbrk(0);
 206   if((top % PGSIZE) != 0){
 207     sbrk(PGSIZE - (top % PGSIZE));
 208   }
 209   top = (uint64) sbrk(0);
 210   if(top % PGSIZE){
 211     printf("oops\n");
 212     exit(1);
 213   }
 214 
 215   char *b = (char *) (top - 1);
 216   *b = 'x';
 217 
 218   int ret = unlink(b);
 219   if(ret != -1){
 220     printf("unlink(%s) returned %d, not -1\n", b, ret);
 221     exit(1);
 222   }
 223 
 224   int fd = open(b, O_CREATE | O_WRONLY);
 225   if(fd != -1){
 226     printf("open(%s) returned %d, not -1\n", b, fd);
 227     exit(1);
 228   }
 229 
 230   ret = link(b, b);
 231   if(ret != -1){
 232     printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
 233     exit(1);
 234   }
 235 
 236   char *args[] = { "xx", 0 };
 237   ret = exec(b, args);
 238   if(ret != -1){
 239     printf("exec(%s) returned %d, not -1\n", b, fd);
 240     exit(1);
 241   }
 242 }
 243 
 244 // See if the kernel refuses to read/write user memory that the
 245 // application doesn't have anymore, because it returned it.
 246 void
 247 rwsbrk(char *s)
 248 {
 249   int fd, n;
 250   
 251   uint64 a = (uint64) sbrk(8192);
 252 
 253   if(a == (uint64) SBRK_ERROR) {
 254     printf("sbrk(rwsbrk) failed\n");
 255     exit(1);
 256   }
 257   
 258   if (sbrk(-8192) == SBRK_ERROR) {
 259     printf("sbrk(rwsbrk) shrink failed\n");
 260     exit(1);
 261   }
 262 
 263   fd = open("rwsbrk", O_CREATE|O_WRONLY);
 264   if(fd < 0){
 265     printf("open(rwsbrk) failed\n");
 266     exit(1);
 267   }
 268   n = write(fd, (void*)(a+PGSIZE), 1024);
 269   if(n >= 0){
 270     printf("write(fd, %p, 1024) returned %d, not -1\n", (void*)a+PGSIZE, n);
 271     exit(1);
 272   }
 273   close(fd);
 274   unlink("rwsbrk");
 275 
 276   fd = open("README", O_RDONLY);
 277   if(fd < 0){
 278     printf("open(README) failed\n");
 279     exit(1);
 280   }
 281   n = read(fd, (void*)(a+PGSIZE), 10);
 282   if(n >= 0){
 283     printf("read(fd, %p, 10) returned %d, not -1\n", (void*)a+PGSIZE, n);
 284     exit(1);
 285   }
 286   close(fd);
 287   
 288   exit(0);
 289 }
 290 
 291 // test O_TRUNC.
 292 void
 293 truncate1(char *s)
 294 {
 295   char buf[32];
 296   
 297   unlink("truncfile");
 298   int fd1 = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC);
 299   write(fd1, "abcd", 4);
 300   close(fd1);
 301 
 302   int fd2 = open("truncfile", O_RDONLY);
 303   int n = read(fd2, buf, sizeof(buf));
 304   if(n != 4){
 305     printf("%s: read %d bytes, wanted 4\n", s, n);
 306     exit(1);
 307   }
 308 
 309   fd1 = open("truncfile", O_WRONLY|O_TRUNC);
 310 
 311   int fd3 = open("truncfile", O_RDONLY);
 312   n = read(fd3, buf, sizeof(buf));
 313   if(n != 0){
 314     printf("aaa fd3=%d\n", fd3);
 315     printf("%s: read %d bytes, wanted 0\n", s, n);
 316     exit(1);
 317   }
 318 
 319   n = read(fd2, buf, sizeof(buf));
 320   if(n != 0){
 321     printf("bbb fd2=%d\n", fd2);
 322     printf("%s: read %d bytes, wanted 0\n", s, n);
 323     exit(1);
 324   }
 325   
 326   write(fd1, "abcdef", 6);
 327 
 328   n = read(fd3, buf, sizeof(buf));
 329   if(n != 6){
 330     printf("%s: read %d bytes, wanted 6\n", s, n);
 331     exit(1);
 332   }
 333 
 334   n = read(fd2, buf, sizeof(buf));
 335   if(n != 2){
 336     printf("%s: read %d bytes, wanted 2\n", s, n);
 337     exit(1);
 338   }
 339 
 340   unlink("truncfile");
 341 
 342   close(fd1);
 343   close(fd2);
 344   close(fd3);
 345 }
 346 
 347 // write to an open FD whose file has just been truncated.
 348 // this causes a write at an offset beyond the end of the file.
 349 // such writes fail on xv6 (unlike POSIX) but at least
 350 // they don't crash.
 351 void
 352 truncate2(char *s)
 353 {
 354   unlink("truncfile");
 355 
 356   int fd1 = open("truncfile", O_CREATE|O_TRUNC|O_WRONLY);
 357   write(fd1, "abcd", 4);
 358 
 359   int fd2 = open("truncfile", O_TRUNC|O_WRONLY);
 360 
 361   int n = write(fd1, "x", 1);
 362   if(n != -1){
 363     printf("%s: write returned %d, expected -1\n", s, n);
 364     exit(1);
 365   }
 366 
 367   unlink("truncfile");
 368   close(fd1);
 369   close(fd2);
 370 }
 371 
 372 void
 373 truncate3(char *s)
 374 {
 375   int pid, xstatus;
 376 
 377   close(open("truncfile", O_CREATE|O_TRUNC|O_WRONLY));
 378   
 379   pid = fork();
 380   if(pid < 0){
 381     printf("%s: fork failed\n", s);
 382     exit(1);
 383   }
 384 
 385   if(pid == 0){
 386     for(int i = 0; i < 100; i++){
 387       char buf[32];
 388       int fd = open("truncfile", O_WRONLY);
 389       if(fd < 0){
 390         printf("%s: open failed\n", s);
 391         exit(1);
 392       }
 393       int n = write(fd, "1234567890", 10);
 394       if(n != 10){
 395         printf("%s: write got %d, expected 10\n", s, n);
 396         exit(1);
 397       }
 398       close(fd);
 399       fd = open("truncfile", O_RDONLY);
 400       read(fd, buf, sizeof(buf));
 401       close(fd);
 402     }
 403     exit(0);
 404   }
 405 
 406   for(int i = 0; i < 150; i++){
 407     int fd = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC);
 408     if(fd < 0){
 409       printf("%s: open failed\n", s);
 410       exit(1);
 411     }
 412     int n = write(fd, "xxx", 3);
 413     if(n != 3){
 414       printf("%s: write got %d, expected 3\n", s, n);
 415       exit(1);
 416     }
 417     close(fd);
 418   }
 419 
 420   wait(&xstatus);
 421   unlink("truncfile");
 422   exit(xstatus);
 423 }
 424   
 425 
 426 // does chdir() call iput(p->cwd) in a transaction?
 427 void
 428 iputtest(char *s)
 429 {
 430   if(mkdir("iputdir") < 0){
 431     printf("%s: mkdir failed\n", s);
 432     exit(1);
 433   }
 434   if(chdir("iputdir") < 0){
 435     printf("%s: chdir iputdir failed\n", s);
 436     exit(1);
 437   }
 438   if(unlink("../iputdir") < 0){
 439     printf("%s: unlink ../iputdir failed\n", s);
 440     exit(1);
 441   }
 442   if(chdir("/") < 0){
 443     printf("%s: chdir / failed\n", s);
 444     exit(1);
 445   }
 446 }
 447 
 448 // does exit() call iput(p->cwd) in a transaction?
 449 void
 450 exitiputtest(char *s)
 451 {
 452   int pid, xstatus;
 453 
 454   pid = fork();
 455   if(pid < 0){
 456     printf("%s: fork failed\n", s);
 457     exit(1);
 458   }
 459   if(pid == 0){
 460     if(mkdir("iputdir") < 0){
 461       printf("%s: mkdir failed\n", s);
 462       exit(1);
 463     }
 464     if(chdir("iputdir") < 0){
 465       printf("%s: child chdir failed\n", s);
 466       exit(1);
 467     }
 468     if(unlink("../iputdir") < 0){
 469       printf("%s: unlink ../iputdir failed\n", s);
 470       exit(1);
 471     }
 472     exit(0);
 473   }
 474   wait(&xstatus);
 475   exit(xstatus);
 476 }
 477 
 478 // does the error path in open() for attempt to write a
 479 // directory call iput() in a transaction?
 480 // needs a hacked kernel that pauses just after the namei()
 481 // call in sys_open():
 482 //    if((ip = namei(path)) == 0)
 483 //      return -1;
 484 //    {
 485 //      int i;
 486 //      for(i = 0; i < 10000; i++)
 487 //        yield();
 488 //    }
 489 void
 490 openiputtest(char *s)
 491 {
 492   int pid, xstatus;
 493 
 494   if(mkdir("oidir") < 0){
 495     printf("%s: mkdir oidir failed\n", s);
 496     exit(1);
 497   }
 498   pid = fork();
 499   if(pid < 0){
 500     printf("%s: fork failed\n", s);
 501     exit(1);
 502   }
 503   if(pid == 0){
 504     int fd = open("oidir", O_RDWR);
 505     if(fd >= 0){
 506       printf("%s: open directory for write succeeded\n", s);
 507       exit(1);
 508     }
 509     exit(0);
 510   }
 511   pause(1);
 512   if(unlink("oidir") != 0){
 513     printf("%s: unlink failed\n", s);
 514     exit(1);
 515   }
 516   wait(&xstatus);
 517   exit(xstatus);
 518 }
 519 
 520 // simple file system tests
 521 
 522 void
 523 opentest(char *s)
 524 {
 525   int fd;
 526 
 527   fd = open("echo", 0);
 528   if(fd < 0){
 529     printf("%s: open echo failed!\n", s);
 530     exit(1);
 531   }
 532   close(fd);
 533   fd = open("doesnotexist", 0);
 534   if(fd >= 0){
 535     printf("%s: open doesnotexist succeeded!\n", s);
 536     exit(1);
 537   }
 538 }
 539 
 540 void
 541 writetest(char *s)
 542 {
 543   int fd;
 544   int i;
 545   enum { N=100, SZ=10 };
 546   
 547   fd = open("small", O_CREATE|O_RDWR);
 548   if(fd < 0){
 549     printf("%s: error: creat small failed!\n", s);
 550     exit(1);
 551   }
 552   for(i = 0; i < N; i++){
 553     if(write(fd, "aaaaaaaaaa", SZ) != SZ){
 554       printf("%s: error: write aa %d new file failed\n", s, i);
 555       exit(1);
 556     }
 557     if(write(fd, "bbbbbbbbbb", SZ) != SZ){
 558       printf("%s: error: write bb %d new file failed\n", s, i);
 559       exit(1);
 560     }
 561   }
 562   close(fd);
 563   fd = open("small", O_RDONLY);
 564   if(fd < 0){
 565     printf("%s: error: open small failed!\n", s);
 566     exit(1);
 567   }
 568   i = read(fd, buf, N*SZ*2);
 569   if(i != N*SZ*2){
 570     printf("%s: read failed\n", s);
 571     exit(1);
 572   }
 573   close(fd);
 574 
 575   if(unlink("small") < 0){
 576     printf("%s: unlink small failed\n", s);
 577     exit(1);
 578   }
 579 }
 580 
 581 void
 582 writebig(char *s)
 583 {
 584   int i, fd, n;
 585 
 586   fd = open("big", O_CREATE|O_RDWR);
 587   if(fd < 0){
 588     printf("%s: error: creat big failed!\n", s);
 589     exit(1);
 590   }
 591 
 592   for(i = 0; i < MAXFILE; i++){
 593     ((int*)buf)[0] = i;
 594     if(write(fd, buf, BSIZE) != BSIZE){
 595       printf("%s: error: write big file failed i=%d\n", s, i);
 596       exit(1);
 597     }
 598   }
 599 
 600   close(fd);
 601 
 602   fd = open("big", O_RDONLY);
 603   if(fd < 0){
 604     printf("%s: error: open big failed!\n", s);
 605     exit(1);
 606   }
 607 
 608   n = 0;
 609   for(;;){
 610     i = read(fd, buf, BSIZE);
 611     if(i == 0){
 612       if(n != MAXFILE){
 613         printf("%s: read only %d blocks from big", s, n);
 614         exit(1);
 615       }
 616       break;
 617     } else if(i != BSIZE){
 618       printf("%s: read failed %d\n", s, i);
 619       exit(1);
 620     }
 621     if(((int*)buf)[0] != n){
 622       printf("%s: read content of block %d is %d\n", s,
 623              n, ((int*)buf)[0]);
 624       exit(1);
 625     }
 626     n++;
 627   }
 628   close(fd);
 629   if(unlink("big") < 0){
 630     printf("%s: unlink big failed\n", s);
 631     exit(1);
 632   }
 633 }
 634 
 635 // many creates, followed by unlink test
 636 void
 637 createtest(char *s)
 638 {
 639   int i, fd;
 640   enum { N=52 };
 641 
 642   char name[3];
 643   name[0] = 'a';
 644   name[2] = '\0';
 645   for(i = 0; i < N; i++){
 646     name[1] = '0' + i;
 647     fd = open(name, O_CREATE|O_RDWR);
 648     close(fd);
 649   }
 650   name[0] = 'a';
 651   name[2] = '\0';
 652   for(i = 0; i < N; i++){
 653     name[1] = '0' + i;
 654     unlink(name);
 655   }
 656 }
 657 
 658 void dirtest(char *s)
 659 {
 660   if(mkdir("dir0") < 0){
 661     printf("%s: mkdir failed\n", s);
 662     exit(1);
 663   }
 664 
 665   if(chdir("dir0") < 0){
 666     printf("%s: chdir dir0 failed\n", s);
 667     exit(1);
 668   }
 669 
 670   if(chdir("..") < 0){
 671     printf("%s: chdir .. failed\n", s);
 672     exit(1);
 673   }
 674 
 675   if(unlink("dir0") < 0){
 676     printf("%s: unlink dir0 failed\n", s);
 677     exit(1);
 678   }
 679 }
 680 
 681 void
 682 exectest(char *s)
 683 {
 684   int fd, xstatus, pid;
 685   char *echoargv[] = { "echo", "OK", 0 };
 686   char buf[3];
 687 
 688   unlink("echo-ok");
 689   pid = fork();
 690   if(pid < 0) {
 691      printf("%s: fork failed\n", s);
 692      exit(1);
 693   }
 694   if(pid == 0) {
 695     close(1);
 696     fd = open("echo-ok", O_CREATE|O_WRONLY);
 697     if(fd < 0) {
 698       printf("%s: create failed\n", s);
 699       exit(1);
 700     }
 701     if(fd != 1) {
 702       printf("%s: wrong fd\n", s);
 703       exit(1);
 704     }
 705     if(exec("echo", echoargv) < 0){
 706       printf("%s: exec echo failed\n", s);
 707       exit(1);
 708     }
 709     // won't get to here
 710   }
 711   if (wait(&xstatus) != pid) {
 712     printf("%s: wait failed!\n", s);
 713   }
 714   if(xstatus != 0)
 715     exit(xstatus);
 716 
 717   fd = open("echo-ok", O_RDONLY);
 718   if(fd < 0) {
 719     printf("%s: open failed\n", s);
 720     exit(1);
 721   }
 722   if (read(fd, buf, 2) != 2) {
 723     printf("%s: read failed\n", s);
 724     exit(1);
 725   }
 726   unlink("echo-ok");
 727   if(buf[0] == 'O' && buf[1] == 'K')
 728     exit(0);
 729   else {
 730     printf("%s: wrong output\n", s);
 731     exit(1);
 732   }
 733 
 734 }
 735 
 736 // simple fork and pipe read/write
 737 
 738 void
 739 pipe1(char *s)
 740 {
 741   int fds[2], pid, xstatus;
 742   int seq, i, n, cc, total;
 743   enum { N=5, SZ=1033 };
 744   
 745   if(pipe(fds) != 0){
 746     printf("%s: pipe() failed\n", s);
 747     exit(1);
 748   }
 749   pid = fork();
 750   seq = 0;
 751   if(pid == 0){
 752     close(fds[0]);
 753     for(n = 0; n < N; n++){
 754       for(i = 0; i < SZ; i++)
 755         buf[i] = seq++;
 756       if(write(fds[1], buf, SZ) != SZ){
 757         printf("%s: pipe1 oops 1\n", s);
 758         exit(1);
 759       }
 760     }
 761     exit(0);
 762   } else if(pid > 0){
 763     close(fds[1]);
 764     total = 0;
 765     cc = 1;
 766     while((n = read(fds[0], buf, cc)) > 0){
 767       for(i = 0; i < n; i++){
 768         if((buf[i] & 0xff) != (seq++ & 0xff)){
 769           printf("%s: pipe1 oops 2\n", s);
 770           return;
 771         }
 772       }
 773       total += n;
 774       cc = cc * 2;
 775       if(cc > sizeof(buf))
 776         cc = sizeof(buf);
 777     }
 778     if(total != N * SZ){
 779       printf("%s: pipe1 oops 3 total %d\n", s, total);
 780       exit(1);
 781     }
 782     close(fds[0]);
 783     wait(&xstatus);
 784     exit(xstatus);
 785   } else {
 786     printf("%s: fork() failed\n", s);
 787     exit(1);
 788   }
 789 }
 790 
 791 
 792 // test if child is killed (status = -1)
 793 void
 794 killstatus(char *s)
 795 {
 796   int xst;
 797   
 798   for(int i = 0; i < 100; i++){
 799     int pid1 = fork();
 800     if(pid1 < 0){
 801       printf("%s: fork failed\n", s);
 802       exit(1);
 803     }
 804     if(pid1 == 0){
 805       while(1) {
 806         getpid();
 807       }
 808       exit(0);
 809     }
 810     pause(1);
 811     kill(pid1);
 812     wait(&xst);
 813     if(xst != -1) {
 814        printf("%s: status should be -1\n", s);
 815        exit(1);
 816     }
 817   }
 818   exit(0);
 819 }
 820 
 821 // meant to be run w/ at most two CPUs
 822 void
 823 preempt(char *s)
 824 {
 825   int pid1, pid2, pid3;
 826   int pfds[2];
 827 
 828   pid1 = fork();
 829   if(pid1 < 0) {
 830     printf("%s: fork failed", s);
 831     exit(1);
 832   }
 833   if(pid1 == 0)
 834     for(;;)
 835       ;
 836 
 837   pid2 = fork();
 838   if(pid2 < 0) {
 839     printf("%s: fork failed\n", s);
 840     exit(1);
 841   }
 842   if(pid2 == 0)
 843     for(;;)
 844       ;
 845 
 846   pipe(pfds);
 847   pid3 = fork();
 848   if(pid3 < 0) {
 849      printf("%s: fork failed\n", s);
 850      exit(1);
 851   }
 852   if(pid3 == 0){
 853     close(pfds[0]);
 854     if(write(pfds[1], "x", 1) != 1)
 855       printf("%s: preempt write error", s);
 856     close(pfds[1]);
 857     for(;;)
 858       ;
 859   }
 860 
 861   close(pfds[1]);
 862   if(read(pfds[0], buf, sizeof(buf)) != 1){
 863     printf("%s: preempt read error", s);
 864     return;
 865   }
 866   close(pfds[0]);
 867   printf("kill... ");
 868   kill(pid1);
 869   kill(pid2);
 870   kill(pid3);
 871   printf("wait... ");
 872   wait(0);
 873   wait(0);
 874   wait(0);
 875 }
 876 
 877 // try to find any races between exit and wait
 878 void
 879 exitwait(char *s)
 880 {
 881   int i, pid;
 882 
 883   for(i = 0; i < 100; i++){
 884     pid = fork();
 885     if(pid < 0){
 886       printf("%s: fork failed\n", s);
 887       exit(1);
 888     }
 889     if(pid){
 890       int xstate;
 891       if(wait(&xstate) != pid){
 892         printf("%s: wait wrong pid\n", s);
 893         exit(1);
 894       }
 895       if(i != xstate) {
 896         printf("%s: wait wrong exit status\n", s);
 897         exit(1);
 898       }
 899     } else {
 900       exit(i);
 901     }
 902   }
 903 }
 904 
 905 // try to find races in the reparenting
 906 // code that handles a parent exiting
 907 // when it still has live children.
 908 void
 909 reparent(char *s)
 910 {
 911   int master_pid = getpid();
 912   for(int i = 0; i < 200; i++){
 913     int pid = fork();
 914     if(pid < 0){
 915       printf("%s: fork failed\n", s);
 916       exit(1);
 917     }
 918     if(pid){
 919       if(wait(0) != pid){
 920         printf("%s: wait wrong pid\n", s);
 921         exit(1);
 922       }
 923     } else {
 924       int pid2 = fork();
 925       if(pid2 < 0){
 926         kill(master_pid);
 927         exit(1);
 928       }
 929       exit(0);
 930     }
 931   }
 932   exit(0);
 933 }
 934 
 935 // what if two children exit() at the same time?
 936 void
 937 twochildren(char *s)
 938 {
 939   for(int i = 0; i < 1000; i++){
 940     int pid1 = fork();
 941     if(pid1 < 0){
 942       printf("%s: fork failed\n", s);
 943       exit(1);
 944     }
 945     if(pid1 == 0){
 946       exit(0);
 947     } else {
 948       int pid2 = fork();
 949       if(pid2 < 0){
 950         printf("%s: fork failed\n", s);
 951         exit(1);
 952       }
 953       if(pid2 == 0){
 954         exit(0);
 955       } else {
 956         wait(0);
 957         wait(0);
 958       }
 959     }
 960   }
 961 }
 962 
 963 // concurrent forks to try to expose locking bugs.
 964 void
 965 forkfork(char *s)
 966 {
 967   enum { N=2 };
 968   
 969   for(int i = 0; i < N; i++){
 970     int pid = fork();
 971     if(pid < 0){
 972       printf("%s: fork failed", s);
 973       exit(1);
 974     }
 975     if(pid == 0){
 976       for(int j = 0; j < 200; j++){
 977         int pid1 = fork();
 978         if(pid1 < 0){
 979           exit(1);
 980         }
 981         if(pid1 == 0){
 982           exit(0);
 983         }
 984         wait(0);
 985       }
 986       exit(0);
 987     }
 988   }
 989 
 990   int xstatus;
 991   for(int i = 0; i < N; i++){
 992     wait(&xstatus);
 993     if(xstatus != 0) {
 994       printf("%s: fork in child failed", s);
 995       exit(1);
 996     }
 997   }
 998 }
 999 
1000 void
1001 forkforkfork(char *s)
1002 {
1003   unlink("stopforking");
1004 
1005   int pid = fork();
1006   if(pid < 0){
1007     printf("%s: fork failed", s);
1008     exit(1);
1009   }
1010   if(pid == 0){
1011     while(1){
1012       int fd = open("stopforking", 0);
1013       if(fd >= 0){
1014         exit(0);
1015       }
1016       if(fork() < 0){
1017         close(open("stopforking", O_CREATE|O_RDWR));
1018       }
1019     }
1020 
1021     exit(0);
1022   }
1023 
1024   pause(20); // two seconds
1025   close(open("stopforking", O_CREATE|O_RDWR));
1026   wait(0);
1027   pause(10); // one second
1028 }
1029 
1030 // regression test. does reparent() violate the parent-then-child
1031 // locking order when giving away a child to init, so that exit()
1032 // deadlocks against init's wait()? also used to trigger a "panic:
1033 // release" due to exit() releasing a different p->parent->lock than
1034 // it acquired.
1035 void
1036 reparent2(char *s)
1037 {
1038   for(int i = 0; i < 800; i++){
1039     int pid1 = fork();
1040     if(pid1 < 0){
1041       printf("fork failed\n");
1042       exit(1);
1043     }
1044     if(pid1 == 0){
1045       fork();
1046       fork();
1047       exit(0);
1048     }
1049     wait(0);
1050   }
1051 
1052   exit(0);
1053 }
1054 
1055 // allocate all mem, free it, and allocate again
1056 void
1057 mem(char *s)
1058 {
1059   void *m1, *m2;
1060   int pid;
1061 
1062   if((pid = fork()) == 0){
1063     m1 = 0;
1064     while((m2 = malloc(10001)) != 0){
1065       *(char**)m2 = m1;
1066       m1 = m2;
1067     }
1068     while(m1){
1069       m2 = *(char**)m1;
1070       free(m1);
1071       m1 = m2;
1072     }
1073     m1 = malloc(1024*20);
1074     if(m1 == 0){
1075       printf("%s: couldn't allocate mem?!!\n", s);
1076       exit(1);
1077     }
1078     free(m1);
1079     exit(0);
1080   } else {
1081     int xstatus;
1082     wait(&xstatus);
1083     if(xstatus == -1){
1084       // probably page fault, so might be lazy lab,
1085       // so OK.
1086       exit(0);
1087     }
1088     exit(xstatus);
1089   }
1090 }
1091 
1092 // More file system tests
1093 
1094 // two processes write to the same file descriptor
1095 // is the offset shared? does inode locking work?
1096 void
1097 sharedfd(char *s)
1098 {
1099   int fd, pid, i, n, nc, np;
1100   enum { N = 1000, SZ=10};
1101   char buf[SZ];
1102 
1103   unlink("sharedfd");
1104   fd = open("sharedfd", O_CREATE|O_RDWR);
1105   if(fd < 0){
1106     printf("%s: cannot open sharedfd for writing", s);
1107     exit(1);
1108   }
1109   pid = fork();
1110   memset(buf, pid==0?'c':'p', sizeof(buf));
1111   for(i = 0; i < N; i++){
1112     if(write(fd, buf, sizeof(buf)) != sizeof(buf)){
1113       printf("%s: write sharedfd failed\n", s);
1114       exit(1);
1115     }
1116   }
1117   if(pid == 0) {
1118     exit(0);
1119   } else {
1120     int xstatus;
1121     wait(&xstatus);
1122     if(xstatus != 0)
1123       exit(xstatus);
1124   }
1125   
1126   close(fd);
1127   fd = open("sharedfd", 0);
1128   if(fd < 0){
1129     printf("%s: cannot open sharedfd for reading\n", s);
1130     exit(1);
1131   }
1132   nc = np = 0;
1133   while((n = read(fd, buf, sizeof(buf))) > 0){
1134     for(i = 0; i < sizeof(buf); i++){
1135       if(buf[i] == 'c')
1136         nc++;
1137       if(buf[i] == 'p')
1138         np++;
1139     }
1140   }
1141   close(fd);
1142   unlink("sharedfd");
1143   if(nc == N*SZ && np == N*SZ){
1144     exit(0);
1145   } else {
1146     printf("%s: nc/np test fails\n", s);
1147     exit(1);
1148   }
1149 }
1150 
1151 // four processes write different files at the same
1152 // time, to test block allocation.
1153 void
1154 fourfiles(char *s)
1155 {
1156   int fd, pid, i, j, n, total, pi;
1157   char *names[] = { "f0", "f1", "f2", "f3" };
1158   char *fname;
1159   enum { N=12, NCHILD=4, SZ=500 };
1160   
1161   for(pi = 0; pi < NCHILD; pi++){
1162     fname = names[pi];
1163     unlink(fname);
1164 
1165     pid = fork();
1166     if(pid < 0){
1167       printf("%s: fork failed\n", s);
1168       exit(1);
1169     }
1170 
1171     if(pid == 0){
1172       fd = open(fname, O_CREATE | O_RDWR);
1173       if(fd < 0){
1174         printf("%s: create failed\n", s);
1175         exit(1);
1176       }
1177 
1178       memset(buf, '0'+pi, SZ);
1179       for(i = 0; i < N; i++){
1180         if((n = write(fd, buf, SZ)) != SZ){
1181           printf("write failed %d\n", n);
1182           exit(1);
1183         }
1184       }
1185       exit(0);
1186     }
1187   }
1188 
1189   int xstatus;
1190   for(pi = 0; pi < NCHILD; pi++){
1191     wait(&xstatus);
1192     if(xstatus != 0)
1193       exit(xstatus);
1194   }
1195 
1196   for(i = 0; i < NCHILD; i++){
1197     fname = names[i];
1198     fd = open(fname, 0);
1199     total = 0;
1200     while((n = read(fd, buf, sizeof(buf))) > 0){
1201       for(j = 0; j < n; j++){
1202         if(buf[j] != '0'+i){
1203           printf("%s: wrong char\n", s);
1204           exit(1);
1205         }
1206       }
1207       total += n;
1208     }
1209     close(fd);
1210     if(total != N*SZ){
1211       printf("wrong length %d\n", total);
1212       exit(1);
1213     }
1214     unlink(fname);
1215   }
1216 }
1217 
1218 // four processes create and delete different files in same directory
1219 void
1220 createdelete(char *s)
1221 {
1222   enum { N = 20, NCHILD=4 };
1223   int pid, i, fd, pi;
1224   char name[32];
1225 
1226   for(pi = 0; pi < NCHILD; pi++){
1227     pid = fork();
1228     if(pid < 0){
1229       printf("%s: fork failed\n", s);
1230       exit(1);
1231     }
1232 
1233     if(pid == 0){
1234       name[0] = 'p' + pi;
1235       name[2] = '\0';
1236       for(i = 0; i < N; i++){
1237         name[1] = '0' + i;
1238         fd = open(name, O_CREATE | O_RDWR);
1239         if(fd < 0){
1240           printf("%s: create failed\n", s);
1241           exit(1);
1242         }
1243         close(fd);
1244         if(i > 0 && (i % 2 ) == 0){
1245           name[1] = '0' + (i / 2);
1246           if(unlink(name) < 0){
1247             printf("%s: unlink failed\n", s);
1248             exit(1);
1249           }
1250         }
1251       }
1252       exit(0);
1253     }
1254   }
1255 
1256   int xstatus;
1257   for(pi = 0; pi < NCHILD; pi++){
1258     wait(&xstatus);
1259     if(xstatus != 0)
1260       exit(1);
1261   }
1262 
1263   name[0] = name[1] = name[2] = 0;
1264   for(i = 0; i < N; i++){
1265     for(pi = 0; pi < NCHILD; pi++){
1266       name[0] = 'p' + pi;
1267       name[1] = '0' + i;
1268       fd = open(name, 0);
1269       if((i == 0 || i >= N/2) && fd < 0){
1270         printf("%s: oops createdelete %s didn't exist\n", s, name);
1271         exit(1);
1272       } else if((i >= 1 && i < N/2) && fd >= 0){
1273         printf("%s: oops createdelete %s did exist\n", s, name);
1274         exit(1);
1275       }
1276       if(fd >= 0)
1277         close(fd);
1278     }
1279   }
1280 
1281   for(i = 0; i < N; i++){
1282     for(pi = 0; pi < NCHILD; pi++){
1283       name[0] = 'p' + pi;
1284       name[1] = '0' + i;
1285       unlink(name);
1286     }
1287   }
1288 }
1289 
1290 // can I unlink a file and still read it?
1291 void
1292 unlinkread(char *s)
1293 {
1294   enum { SZ = 5 };
1295   int fd, fd1;
1296 
1297   fd = open("unlinkread", O_CREATE | O_RDWR);
1298   if(fd < 0){
1299     printf("%s: create unlinkread failed\n", s);
1300     exit(1);
1301   }
1302   write(fd, "hello", SZ);
1303   close(fd);
1304 
1305   fd = open("unlinkread", O_RDWR);
1306   if(fd < 0){
1307     printf("%s: open unlinkread failed\n", s);
1308     exit(1);
1309   }
1310   if(unlink("unlinkread") != 0){
1311     printf("%s: unlink unlinkread failed\n", s);
1312     exit(1);
1313   }
1314 
1315   fd1 = open("unlinkread", O_CREATE | O_RDWR);
1316   write(fd1, "yyy", 3);
1317   close(fd1);
1318 
1319   if(read(fd, buf, sizeof(buf)) != SZ){
1320     printf("%s: unlinkread read failed", s);
1321     exit(1);
1322   }
1323   if(buf[0] != 'h'){
1324     printf("%s: unlinkread wrong data\n", s);
1325     exit(1);
1326   }
1327   if(write(fd, buf, 10) != 10){
1328     printf("%s: unlinkread write failed\n", s);
1329     exit(1);
1330   }
1331   close(fd);
1332   unlink("unlinkread");
1333 }
1334 
1335 void
1336 linktest(char *s)
1337 {
1338   enum { SZ = 5 };
1339   int fd;
1340 
1341   unlink("lf1");
1342   unlink("lf2");
1343 
1344   fd = open("lf1", O_CREATE|O_RDWR);
1345   if(fd < 0){
1346     printf("%s: create lf1 failed\n", s);
1347     exit(1);
1348   }
1349   if(write(fd, "hello", SZ) != SZ){
1350     printf("%s: write lf1 failed\n", s);
1351     exit(1);
1352   }
1353   close(fd);
1354 
1355   if(link("lf1", "lf2") < 0){
1356     printf("%s: link lf1 lf2 failed\n", s);
1357     exit(1);
1358   }
1359   unlink("lf1");
1360 
1361   if(open("lf1", 0) >= 0){
1362     printf("%s: unlinked lf1 but it is still there!\n", s);
1363     exit(1);
1364   }
1365 
1366   fd = open("lf2", 0);
1367   if(fd < 0){
1368     printf("%s: open lf2 failed\n", s);
1369     exit(1);
1370   }
1371   if(read(fd, buf, sizeof(buf)) != SZ){
1372     printf("%s: read lf2 failed\n", s);
1373     exit(1);
1374   }
1375   close(fd);
1376 
1377   if(link("lf2", "lf2") >= 0){
1378     printf("%s: link lf2 lf2 succeeded! oops\n", s);
1379     exit(1);
1380   }
1381 
1382   unlink("lf2");
1383   if(link("lf2", "lf1") >= 0){
1384     printf("%s: link non-existent succeeded! oops\n", s);
1385     exit(1);
1386   }
1387 
1388   if(link(".", "lf1") >= 0){
1389     printf("%s: link . lf1 succeeded! oops\n", s);
1390     exit(1);
1391   }
1392 }
1393 
1394 // test concurrent create/link/unlink of the same file
1395 void
1396 concreate(char *s)
1397 {
1398   enum { N = 40 };
1399   char file[3];
1400   int i, pid, n, fd;
1401   char fa[N];
1402   struct {
1403     ushort inum;
1404     char name[DIRSIZ];
1405   } de;
1406 
1407   file[0] = 'C';
1408   file[2] = '\0';
1409   for(i = 0; i < N; i++){
1410     file[1] = '0' + i;
1411     unlink(file);
1412     pid = fork();
1413     if(pid && (i % 3) == 1){
1414       link("C0", file);
1415     } else if(pid == 0 && (i % 5) == 1){
1416       link("C0", file);
1417     } else {
1418       fd = open(file, O_CREATE | O_RDWR);
1419       if(fd < 0){
1420         printf("concreate create %s failed\n", file);
1421         exit(1);
1422       }
1423       close(fd);
1424     }
1425     if(pid == 0) {
1426       exit(0);
1427     } else {
1428       int xstatus;
1429       wait(&xstatus);
1430       if(xstatus != 0)
1431         exit(1);
1432     }
1433   }
1434 
1435   memset(fa, 0, sizeof(fa));
1436   fd = open(".", 0);
1437   n = 0;
1438   while(read(fd, &de, sizeof(de)) > 0){
1439     if(de.inum == 0)
1440       continue;
1441     if(de.name[0] == 'C' && de.name[2] == '\0'){
1442       i = de.name[1] - '0';
1443       if(i < 0 || i >= sizeof(fa)){
1444         printf("%s: concreate weird file %s\n", s, de.name);
1445         exit(1);
1446       }
1447       if(fa[i]){
1448         printf("%s: concreate duplicate file %s\n", s, de.name);
1449         exit(1);
1450       }
1451       fa[i] = 1;
1452       n++;
1453     }
1454   }
1455   close(fd);
1456 
1457   if(n != N){
1458     printf("%s: concreate not enough files in directory listing\n", s);
1459     exit(1);
1460   }
1461 
1462   for(i = 0; i < N; i++){
1463     file[1] = '0' + i;
1464     pid = fork();
1465     if(pid < 0){
1466       printf("%s: fork failed\n", s);
1467       exit(1);
1468     }
1469     if(((i % 3) == 0 && pid == 0) ||
1470        ((i % 3) == 1 && pid != 0)){
1471       close(open(file, 0));
1472       close(open(file, 0));
1473       close(open(file, 0));
1474       close(open(file, 0));
1475       close(open(file, 0));
1476       close(open(file, 0));
1477     } else {
1478       unlink(file);
1479       unlink(file);
1480       unlink(file);
1481       unlink(file);
1482       unlink(file);
1483       unlink(file);
1484     }
1485     if(pid == 0)
1486       exit(0);
1487     else
1488       wait(0);
1489   }
1490 }
1491 
1492 // another concurrent link/unlink/create test,
1493 // to look for deadlocks.
1494 void
1495 linkunlink(char *s)
1496 {
1497   int pid, i;
1498 
1499   unlink("x");
1500   pid = fork();
1501   if(pid < 0){
1502     printf("%s: fork failed\n", s);
1503     exit(1);
1504   }
1505 
1506   unsigned int x = (pid ? 1 : 97);
1507   for(i = 0; i < 100; i++){
1508     x = x * 1103515245 + 12345;
1509     if((x % 3) == 0){
1510       close(open("x", O_RDWR | O_CREATE));
1511     } else if((x % 3) == 1){
1512       link("cat", "x");
1513     } else {
1514       unlink("x");
1515     }
1516   }
1517 
1518   if(pid)
1519     wait(0);
1520   else
1521     exit(0);
1522 }
1523 
1524 
1525 void
1526 subdir(char *s)
1527 {
1528   int fd, cc;
1529 
1530   unlink("ff");
1531   if(mkdir("dd") != 0){
1532     printf("%s: mkdir dd failed\n", s);
1533     exit(1);
1534   }
1535 
1536   fd = open("dd/ff", O_CREATE | O_RDWR);
1537   if(fd < 0){
1538     printf("%s: create dd/ff failed\n", s);
1539     exit(1);
1540   }
1541   write(fd, "ff", 2);
1542   close(fd);
1543 
1544   if(unlink("dd") >= 0){
1545     printf("%s: unlink dd (non-empty dir) succeeded!\n", s);
1546     exit(1);
1547   }
1548 
1549   if(mkdir("/dd/dd") != 0){
1550     printf("%s: subdir mkdir dd/dd failed\n", s);
1551     exit(1);
1552   }
1553 
1554   fd = open("dd/dd/ff", O_CREATE | O_RDWR);
1555   if(fd < 0){
1556     printf("%s: create dd/dd/ff failed\n", s);
1557     exit(1);
1558   }
1559   write(fd, "FF", 2);
1560   close(fd);
1561 
1562   fd = open("dd/dd/../ff", 0);
1563   if(fd < 0){
1564     printf("%s: open dd/dd/../ff failed\n", s);
1565     exit(1);
1566   }
1567   cc = read(fd, buf, sizeof(buf));
1568   if(cc != 2 || buf[0] != 'f'){
1569     printf("%s: dd/dd/../ff wrong content\n", s);
1570     exit(1);
1571   }
1572   close(fd);
1573 
1574   if(link("dd/dd/ff", "dd/dd/ffff") != 0){
1575     printf("%s: link dd/dd/ff dd/dd/ffff failed\n", s);
1576     exit(1);
1577   }
1578 
1579   if(unlink("dd/dd/ff") != 0){
1580     printf("%s: unlink dd/dd/ff failed\n", s);
1581     exit(1);
1582   }
1583   if(open("dd/dd/ff", O_RDONLY) >= 0){
1584     printf("%s: open (unlinked) dd/dd/ff succeeded\n", s);
1585     exit(1);
1586   }
1587 
1588   if(chdir("dd") != 0){
1589     printf("%s: chdir dd failed\n", s);
1590     exit(1);
1591   }
1592   if(chdir("dd/../../dd") != 0){
1593     printf("%s: chdir dd/../../dd failed\n", s);
1594     exit(1);
1595   }
1596   if(chdir("dd/../../../dd") != 0){
1597     printf("%s: chdir dd/../../../dd failed\n", s);
1598     exit(1);
1599   }
1600   if(chdir("./..") != 0){
1601     printf("%s: chdir ./.. failed\n", s);
1602     exit(1);
1603   }
1604 
1605   fd = open("dd/dd/ffff", 0);
1606   if(fd < 0){
1607     printf("%s: open dd/dd/ffff failed\n", s);
1608     exit(1);
1609   }
1610   if(read(fd, buf, sizeof(buf)) != 2){
1611     printf("%s: read dd/dd/ffff wrong len\n", s);
1612     exit(1);
1613   }
1614   close(fd);
1615 
1616   if(open("dd/dd/ff", O_RDONLY) >= 0){
1617     printf("%s: open (unlinked) dd/dd/ff succeeded!\n", s);
1618     exit(1);
1619   }
1620 
1621   if(open("dd/ff/ff", O_CREATE|O_RDWR) >= 0){
1622     printf("%s: create dd/ff/ff succeeded!\n", s);
1623     exit(1);
1624   }
1625   if(open("dd/xx/ff", O_CREATE|O_RDWR) >= 0){
1626     printf("%s: create dd/xx/ff succeeded!\n", s);
1627     exit(1);
1628   }
1629   if(open("dd", O_CREATE) >= 0){
1630     printf("%s: create dd succeeded!\n", s);
1631     exit(1);
1632   }
1633   if(open("dd", O_RDWR) >= 0){
1634     printf("%s: open dd rdwr succeeded!\n", s);
1635     exit(1);
1636   }
1637   if(open("dd", O_WRONLY) >= 0){
1638     printf("%s: open dd wronly succeeded!\n", s);
1639     exit(1);
1640   }
1641   if(link("dd/ff/ff", "dd/dd/xx") == 0){
1642     printf("%s: link dd/ff/ff dd/dd/xx succeeded!\n", s);
1643     exit(1);
1644   }
1645   if(link("dd/xx/ff", "dd/dd/xx") == 0){
1646     printf("%s: link dd/xx/ff dd/dd/xx succeeded!\n", s);
1647     exit(1);
1648   }
1649   if(link("dd/ff", "dd/dd/ffff") == 0){
1650     printf("%s: link dd/ff dd/dd/ffff succeeded!\n", s);
1651     exit(1);
1652   }
1653   if(mkdir("dd/ff/ff") == 0){
1654     printf("%s: mkdir dd/ff/ff succeeded!\n", s);
1655     exit(1);
1656   }
1657   if(mkdir("dd/xx/ff") == 0){
1658     printf("%s: mkdir dd/xx/ff succeeded!\n", s);
1659     exit(1);
1660   }
1661   if(mkdir("dd/dd/ffff") == 0){
1662     printf("%s: mkdir dd/dd/ffff succeeded!\n", s);
1663     exit(1);
1664   }
1665   if(unlink("dd/xx/ff") == 0){
1666     printf("%s: unlink dd/xx/ff succeeded!\n", s);
1667     exit(1);
1668   }
1669   if(unlink("dd/ff/ff") == 0){
1670     printf("%s: unlink dd/ff/ff succeeded!\n", s);
1671     exit(1);
1672   }
1673   if(chdir("dd/ff") == 0){
1674     printf("%s: chdir dd/ff succeeded!\n", s);
1675     exit(1);
1676   }
1677   if(chdir("dd/xx") == 0){
1678     printf("%s: chdir dd/xx succeeded!\n", s);
1679     exit(1);
1680   }
1681 
1682   if(unlink("dd/dd/ffff") != 0){
1683     printf("%s: unlink dd/dd/ff failed\n", s);
1684     exit(1);
1685   }
1686   if(unlink("dd/ff") != 0){
1687     printf("%s: unlink dd/ff failed\n", s);
1688     exit(1);
1689   }
1690   if(unlink("dd") == 0){
1691     printf("%s: unlink non-empty dd succeeded!\n", s);
1692     exit(1);
1693   }
1694   if(unlink("dd/dd") < 0){
1695     printf("%s: unlink dd/dd failed\n", s);
1696     exit(1);
1697   }
1698   if(unlink("dd") < 0){
1699     printf("%s: unlink dd failed\n", s);
1700     exit(1);
1701   }
1702 }
1703 
1704 // test writes that are larger than the log.
1705 void
1706 bigwrite(char *s)
1707 {
1708   int fd, sz;
1709 
1710   unlink("bigwrite");
1711   for(sz = 499; sz < (MAXOPBLOCKS+2)*BSIZE; sz += 471){
1712     fd = open("bigwrite", O_CREATE | O_RDWR);
1713     if(fd < 0){
1714       printf("%s: cannot create bigwrite\n", s);
1715       exit(1);
1716     }
1717     int i;
1718     for(i = 0; i < 2; i++){
1719       int cc = write(fd, buf, sz);
1720       if(cc != sz){
1721         printf("%s: write(%d) ret %d\n", s, sz, cc);
1722         exit(1);
1723       }
1724     }
1725     close(fd);
1726     unlink("bigwrite");
1727   }
1728 }
1729 
1730 
1731 void
1732 bigfile(char *s)
1733 {
1734   enum { N = 20, SZ=600 };
1735   int fd, i, total, cc;
1736 
1737   unlink("bigfile.dat");
1738   fd = open("bigfile.dat", O_CREATE | O_RDWR);
1739   if(fd < 0){
1740     printf("%s: cannot create bigfile", s);
1741     exit(1);
1742   }
1743   for(i = 0; i < N; i++){
1744     memset(buf, i, SZ);
1745     if(write(fd, buf, SZ) != SZ){
1746       printf("%s: write bigfile failed\n", s);
1747       exit(1);
1748     }
1749   }
1750   close(fd);
1751 
1752   fd = open("bigfile.dat", 0);
1753   if(fd < 0){
1754     printf("%s: cannot open bigfile\n", s);
1755     exit(1);
1756   }
1757   total = 0;
1758   for(i = 0; ; i++){
1759     cc = read(fd, buf, SZ/2);
1760     if(cc < 0){
1761       printf("%s: read bigfile failed\n", s);
1762       exit(1);
1763     }
1764     if(cc == 0)
1765       break;
1766     if(cc != SZ/2){
1767       printf("%s: short read bigfile\n", s);
1768       exit(1);
1769     }
1770     if(buf[0] != i/2 || buf[SZ/2-1] != i/2){
1771       printf("%s: read bigfile wrong data\n", s);
1772       exit(1);
1773     }
1774     total += cc;
1775   }
1776   close(fd);
1777   if(total != N*SZ){
1778     printf("%s: read bigfile wrong total\n", s);
1779     exit(1);
1780   }
1781   unlink("bigfile.dat");
1782 }
1783 
1784 void
1785 fourteen(char *s)
1786 {
1787   int fd;
1788 
1789   // DIRSIZ is 14.
1790 
1791   if(mkdir("12345678901234") != 0){
1792     printf("%s: mkdir 12345678901234 failed\n", s);
1793     exit(1);
1794   }
1795   if(mkdir("12345678901234/123456789012345") != 0){
1796     printf("%s: mkdir 12345678901234/123456789012345 failed\n", s);
1797     exit(1);
1798   }
1799   fd = open("123456789012345/123456789012345/123456789012345", O_CREATE);
1800   if(fd < 0){
1801     printf("%s: create 123456789012345/123456789012345/123456789012345 failed\n", s);
1802     exit(1);
1803   }
1804   close(fd);
1805   fd = open("12345678901234/12345678901234/12345678901234", 0);
1806   if(fd < 0){
1807     printf("%s: open 12345678901234/12345678901234/12345678901234 failed\n", s);
1808     exit(1);
1809   }
1810   close(fd);
1811 
1812   if(mkdir("12345678901234/12345678901234") == 0){
1813     printf("%s: mkdir 12345678901234/12345678901234 succeeded!\n", s);
1814     exit(1);
1815   }
1816   if(mkdir("123456789012345/12345678901234") == 0){
1817     printf("%s: mkdir 12345678901234/123456789012345 succeeded!\n", s);
1818     exit(1);
1819   }
1820 
1821   // clean up
1822   unlink("123456789012345/12345678901234");
1823   unlink("12345678901234/12345678901234");
1824   unlink("12345678901234/12345678901234/12345678901234");
1825   unlink("123456789012345/123456789012345/123456789012345");
1826   unlink("12345678901234/123456789012345");
1827   unlink("12345678901234");
1828 }
1829 
1830 void
1831 rmdot(char *s)
1832 {
1833   if(mkdir("dots") != 0){
1834     printf("%s: mkdir dots failed\n", s);
1835     exit(1);
1836   }
1837   if(chdir("dots") != 0){
1838     printf("%s: chdir dots failed\n", s);
1839     exit(1);
1840   }
1841   if(unlink(".") == 0){
1842     printf("%s: rm . worked!\n", s);
1843     exit(1);
1844   }
1845   if(unlink("..") == 0){
1846     printf("%s: rm .. worked!\n", s);
1847     exit(1);
1848   }
1849   if(chdir("/") != 0){
1850     printf("%s: chdir / failed\n", s);
1851     exit(1);
1852   }
1853   if(unlink("dots/.") == 0){
1854     printf("%s: unlink dots/. worked!\n", s);
1855     exit(1);
1856   }
1857   if(unlink("dots/..") == 0){
1858     printf("%s: unlink dots/.. worked!\n", s);
1859     exit(1);
1860   }
1861   if(unlink("dots") != 0){
1862     printf("%s: unlink dots failed!\n", s);
1863     exit(1);
1864   }
1865 }
1866 
1867 void
1868 dirfile(char *s)
1869 {
1870   int fd;
1871 
1872   fd = open("dirfile", O_CREATE);
1873   if(fd < 0){
1874     printf("%s: create dirfile failed\n", s);
1875     exit(1);
1876   }
1877   close(fd);
1878   if(chdir("dirfile") == 0){
1879     printf("%s: chdir dirfile succeeded!\n", s);
1880     exit(1);
1881   }
1882   fd = open("dirfile/xx", 0);
1883   if(fd >= 0){
1884     printf("%s: create dirfile/xx succeeded!\n", s);
1885     exit(1);
1886   }
1887   fd = open("dirfile/xx", O_CREATE);
1888   if(fd >= 0){
1889     printf("%s: create dirfile/xx succeeded!\n", s);
1890     exit(1);
1891   }
1892   if(mkdir("dirfile/xx") == 0){
1893     printf("%s: mkdir dirfile/xx succeeded!\n", s);
1894     exit(1);
1895   }
1896   if(unlink("dirfile/xx") == 0){
1897     printf("%s: unlink dirfile/xx succeeded!\n", s);
1898     exit(1);
1899   }
1900   if(link("README", "dirfile/xx") == 0){
1901     printf("%s: link to dirfile/xx succeeded!\n", s);
1902     exit(1);
1903   }
1904   if(unlink("dirfile") != 0){
1905     printf("%s: unlink dirfile failed!\n", s);
1906     exit(1);
1907   }
1908 
1909   fd = open(".", O_RDWR);
1910   if(fd >= 0){
1911     printf("%s: open . for writing succeeded!\n", s);
1912     exit(1);
1913   }
1914   fd = open(".", 0);
1915   if(write(fd, "x", 1) > 0){
1916     printf("%s: write . succeeded!\n", s);
1917     exit(1);
1918   }
1919   close(fd);
1920 }
1921 
1922 // test that iput() is called at the end of _namei().
1923 // also tests empty file names.
1924 void
1925 iref(char *s)
1926 {
1927   int i, fd;
1928 
1929   for(i = 0; i < NINODE + 1; i++){
1930     if(mkdir("irefd") != 0){
1931       printf("%s: mkdir irefd failed\n", s);
1932       exit(1);
1933     }
1934     if(chdir("irefd") != 0){
1935       printf("%s: chdir irefd failed\n", s);
1936       exit(1);
1937     }
1938 
1939     mkdir("");
1940     link("README", "");
1941     fd = open("", O_CREATE);
1942     if(fd >= 0)
1943       close(fd);
1944     fd = open("xx", O_CREATE);
1945     if(fd >= 0)
1946       close(fd);
1947     unlink("xx");
1948   }
1949 
1950   // clean up
1951   for(i = 0; i < NINODE + 1; i++){
1952     chdir("..");
1953     unlink("irefd");
1954   }
1955 
1956   chdir("/");
1957 }
1958 
1959 // test that fork fails gracefully
1960 // the forktest binary also does this, but it runs out of proc entries first.
1961 // inside the bigger usertests binary, we run out of memory first.
1962 void
1963 forktest(char *s)
1964 {
1965   enum{ N = 1000 };
1966   int n, pid;
1967 
1968   for(n=0; n<N; n++){
1969     pid = fork();
1970     if(pid < 0)
1971       break;
1972     if(pid == 0)
1973       exit(0);
1974   }
1975 
1976   if (n == 0) {
1977     printf("%s: no fork at all!\n", s);
1978     exit(1);
1979   }
1980 
1981   if(n == N){
1982     printf("%s: fork claimed to work 1000 times!\n", s);
1983     exit(1);
1984   }
1985 
1986   for(; n > 0; n--){
1987     if(wait(0) < 0){
1988       printf("%s: wait stopped early\n", s);
1989       exit(1);
1990     }
1991   }
1992 
1993   if(wait(0) != -1){
1994     printf("%s: wait got too many\n", s);
1995     exit(1);
1996   }
1997 }
1998 
1999 void
2000 sbrkbasic(char *s)
2001 {
2002   enum { TOOMUCH=1024*1024*1024};
2003   int i, pid, xstatus;
2004   char *c, *a, *b;
2005 
2006   // does sbrk() return the expected failure value?
2007   pid = fork();
2008   if(pid < 0){
2009     printf("fork failed in sbrkbasic\n");
2010     exit(1);
2011   }
2012   if(pid == 0){
2013     a = sbrk(TOOMUCH);
2014     if(a == (char*)SBRK_ERROR){
2015       // it's OK if this fails.
2016       exit(0);
2017     }
2018     
2019     for(b = a; b < a+TOOMUCH; b += PGSIZE){
2020       *b = 99;
2021     }
2022     
2023     // we should not get here! either sbrk(TOOMUCH)
2024     // should have failed, or (with lazy allocation)
2025     // a pagefault should have killed this process.
2026     exit(1);
2027   }
2028 
2029   wait(&xstatus);
2030   if(xstatus == 1){
2031     printf("%s: too much memory allocated!\n", s);
2032     exit(1);
2033   }
2034 
2035   // can one sbrk() less than a page?
2036   a = sbrk(0);
2037   for(i = 0; i < 5000; i++){
2038     b = sbrk(1);
2039     if(b != a){
2040       printf("%s: sbrk test failed %d %p %p\n", s, i, a, b);
2041       exit(1);
2042     }
2043     *b = 1;
2044     a = b + 1;
2045   }
2046   pid = fork();
2047   if(pid < 0){
2048     printf("%s: sbrk test fork failed\n", s);
2049     exit(1);
2050   }
2051   c = sbrk(1);
2052   c = sbrk(1);
2053   if(c != a + 1){
2054     printf("%s: sbrk test failed post-fork\n", s);
2055     exit(1);
2056   }
2057   if(pid == 0)
2058     exit(0);
2059   wait(&xstatus);
2060   exit(xstatus);
2061 }
2062 
2063 void
2064 sbrkmuch(char *s)
2065 {
2066   enum { BIG=100*1024*1024 };
2067   char *c, *oldbrk, *a, *lastaddr, *p;
2068   uint64 amt;
2069 
2070   oldbrk = sbrk(0);
2071 
2072   // can one grow address space to something big?
2073   a = sbrk(0);
2074   amt = BIG - (uint64)a;
2075   p = sbrk(amt);
2076   if (p != a) {
2077     printf("%s: sbrk test failed to grow big address space; enough phys mem?\n", s);
2078     exit(1);
2079   }
2080 
2081   lastaddr = (char*) (BIG-1);
2082   *lastaddr = 99;
2083 
2084   // can one de-allocate?
2085   a = sbrk(0);
2086   c = sbrk(-PGSIZE);
2087   if(c == (char*)SBRK_ERROR){
2088     printf("%s: sbrk could not deallocate\n", s);
2089     exit(1);
2090   }
2091   c = sbrk(0);
2092   if(c != a - PGSIZE){
2093     printf("%s: sbrk deallocation produced wrong address, a %p c %p\n", s, a, c);
2094     exit(1);
2095   }
2096 
2097   // can one re-allocate that page?
2098   a = sbrk(0);
2099   c = sbrk(PGSIZE);
2100   if(c != a || sbrk(0) != a + PGSIZE){
2101     printf("%s: sbrk re-allocation failed, a %p c %p\n", s, a, c);
2102     exit(1);
2103   }
2104   if(*lastaddr == 99){
2105     // should be zero
2106     printf("%s: sbrk de-allocation didn't really deallocate\n", s);
2107     exit(1);
2108   }
2109 
2110   a = sbrk(0);
2111   c = sbrk(-(sbrk(0) - oldbrk));
2112   if(c != a){
2113     printf("%s: sbrk downsize failed, a %p c %p\n", s, a, c);
2114     exit(1);
2115   }
2116 }
2117 
2118 // can we read the kernel's memory?
2119 void
2120 kernmem(char *s)
2121 {
2122   char *a;
2123   int pid;
2124 
2125   for(a = (char*)(KERNBASE); a < (char*) (KERNBASE+2000000); a += 50000){
2126     pid = fork();
2127     if(pid < 0){
2128       printf("%s: fork failed\n", s);
2129       exit(1);
2130     }
2131     if(pid == 0){
2132       printf("%s: oops could read %p = %x\n", s, a, *a);
2133       exit(1);
2134     }
2135     int xstatus;
2136     wait(&xstatus);
2137     if(xstatus != -1)  // did kernel kill child?
2138       exit(1);
2139   }
2140 }
2141 
2142 // user code should not be able to write to addresses above MAXVA.
2143 void
2144 MAXVAplus(char *s)
2145 {
2146   volatile uint64 a = MAXVA;
2147   for( ; a != 0; a <<= 1){
2148     int pid;
2149     pid = fork();
2150     if(pid < 0){
2151       printf("%s: fork failed\n", s);
2152       exit(1);
2153     }
2154     if(pid == 0){
2155       *(char*)a = 99;
2156       printf("%s: oops wrote %p\n", s, (void*)a);
2157       exit(1);
2158     }
2159     int xstatus;
2160     wait(&xstatus);
2161     if(xstatus != -1)  // did kernel kill child?
2162       exit(1);
2163   }
2164 }
2165 
2166 // if we run the system out of memory, does it clean up the last
2167 // failed allocation?
2168 void
2169 sbrkfail(char *s)
2170 {
2171   enum { BIG=100*1024*1024 };
2172   int i, xstatus;
2173   int fds[2];
2174   char scratch;
2175   char *c, *a;
2176   int pids[10];
2177   int pid;
2178   int failed;
2179 
2180   failed = 0;
2181   if(pipe(fds) != 0){
2182     printf("%s: pipe() failed\n", s);
2183     exit(1);
2184   }
2185   for(i = 0; i < sizeof(pids)/sizeof(pids[0]); i++){
2186     if((pids[i] = fork()) == 0){
2187       // allocate a lot of memory
2188       if (sbrk(BIG - (uint64)sbrk(0)) ==  (char*)SBRK_ERROR)
2189         write(fds[1], "0", 1);
2190       else
2191         write(fds[1], "1", 1);
2192       // sit around until killed
2193       for(;;) pause(1000);
2194     }
2195     if(pids[i] != -1) {
2196       read(fds[0], &scratch, 1);
2197       if(scratch == '0')
2198         failed = 1;
2199     }
2200   }
2201   if(!failed) {
2202     printf("%s: no allocation failed; allocate more?\n", s);
2203   }
2204   
2205   // if those failed allocations freed up the pages they did allocate,
2206   // we'll be able to allocate here
2207   c = sbrk(PGSIZE);
2208   for(i = 0; i < sizeof(pids)/sizeof(pids[0]); i++){
2209     if(pids[i] == -1)
2210       continue;
2211     kill(pids[i]);
2212     wait(0);
2213   }
2214   if(c == (char*)SBRK_ERROR){
2215     printf("%s: failed sbrk leaked memory\n", s);
2216     exit(1);
2217   }
2218 
2219   // test running fork with the above allocated page 
2220   pid = fork();
2221   if(pid < 0){
2222     printf("%s: fork failed\n", s);
2223     exit(1);
2224   }
2225   if(pid == 0){
2226     // allocate a lot of memory. this should produce an error
2227     a = sbrk(10*BIG);
2228     if(a == (char*)SBRK_ERROR){
2229       exit(0);
2230     }   
2231     printf("%s: allocate a lot of memory succeeded %d\n", s, 10*BIG);
2232     exit(1);
2233   }
2234   wait(&xstatus);
2235   if(xstatus != 0)
2236     exit(1);
2237 }
2238 
2239   
2240 // test reads/writes from/to allocated memory
2241 void
2242 sbrkarg(char *s)
2243 {
2244   char *a;
2245   int fd, n;
2246 
2247   a = sbrk(PGSIZE);
2248   fd = open("sbrk", O_CREATE|O_WRONLY);
2249   unlink("sbrk");
2250   if(fd < 0)  {
2251     printf("%s: open sbrk failed\n", s);
2252     exit(1);
2253   }
2254   if ((n = write(fd, a, PGSIZE)) < 0) {
2255     printf("%s: write sbrk failed\n", s);
2256     exit(1);
2257   }
2258   close(fd);
2259 
2260   // test writes to allocated memory
2261   a = sbrk(PGSIZE);
2262   if(pipe((int *) a) != 0){
2263     printf("%s: pipe() failed\n", s);
2264     exit(1);
2265   } 
2266 }
2267 
2268 void
2269 validatetest(char *s)
2270 {
2271   int hi;
2272   uint64 p;
2273 
2274   hi = 1100*1024;
2275   for(p = 0; p <= (uint)hi; p += PGSIZE){
2276     // try to crash the kernel by passing in a bad string pointer
2277     if(link("nosuchfile", (char*)p) != -1){
2278       printf("%s: link should not succeed\n", s);
2279       exit(1);
2280     }
2281   }
2282 }
2283 
2284 // does uninitialized data start out zero?
2285 char uninit[10000];
2286 void
2287 bsstest(char *s)
2288 {
2289   int i;
2290 
2291   for(i = 0; i < sizeof(uninit); i++){
2292     if(uninit[i] != '\0'){
2293       printf("%s: bss test failed\n", s);
2294       exit(1);
2295     }
2296   }
2297 }
2298 
2299 // does exec return an error if the arguments
2300 // are larger than a page? or does it write
2301 // below the stack and wreck the instructions/data?
2302 void
2303 bigargtest(char *s)
2304 {
2305   int pid, fd, xstatus;
2306 
2307   unlink("bigarg-ok");
2308   pid = fork();
2309   if(pid == 0){
2310     static char *args[MAXARG];
2311     int i;
2312     char big[400];
2313     memset(big, ' ', sizeof(big));
2314     big[sizeof(big)-1] = '\0';
2315     for(i = 0; i < MAXARG-1; i++)
2316       args[i] = big;
2317     args[MAXARG-1] = 0;
2318     // this exec() should fail (and return) because the
2319     // arguments are too large.
2320     exec("echo", args);
2321     fd = open("bigarg-ok", O_CREATE);
2322     close(fd);
2323     exit(0);
2324   } else if(pid < 0){
2325     printf("%s: bigargtest: fork failed\n", s);
2326     exit(1);
2327   }
2328   
2329   wait(&xstatus);
2330   if(xstatus != 0)
2331     exit(xstatus);
2332   fd = open("bigarg-ok", 0);
2333   if(fd < 0){
2334     printf("%s: bigarg test failed!\n", s);
2335     exit(1);
2336   }
2337   close(fd);
2338 }
2339 
2340 // what happens when the file system runs out of blocks?
2341 // answer: balloc panics, so this test is not useful.
2342 void
2343 fsfull()
2344 {
2345   int nfiles;
2346   int fsblocks = 0;
2347 
2348   printf("fsfull test\n");
2349 
2350   for(nfiles = 0; ; nfiles++){
2351     char name[64];
2352     name[0] = 'f';
2353     name[1] = '0' + nfiles / 1000;
2354     name[2] = '0' + (nfiles % 1000) / 100;
2355     name[3] = '0' + (nfiles % 100) / 10;
2356     name[4] = '0' + (nfiles % 10);
2357     name[5] = '\0';
2358     printf("writing %s\n", name);
2359     int fd = open(name, O_CREATE|O_RDWR);
2360     if(fd < 0){
2361       printf("open %s failed\n", name);
2362       break;
2363     }
2364     int total = 0;
2365     while(1){
2366       int cc = write(fd, buf, BSIZE);
2367       if(cc < BSIZE)
2368         break;
2369       total += cc;
2370       fsblocks++;
2371     }
2372     printf("wrote %d bytes\n", total);
2373     close(fd);
2374     if(total == 0)
2375       break;
2376   }
2377 
2378   while(nfiles >= 0){
2379     char name[64];
2380     name[0] = 'f';
2381     name[1] = '0' + nfiles / 1000;
2382     name[2] = '0' + (nfiles % 1000) / 100;
2383     name[3] = '0' + (nfiles % 100) / 10;
2384     name[4] = '0' + (nfiles % 10);
2385     name[5] = '\0';
2386     unlink(name);
2387     nfiles--;
2388   }
2389 
2390   printf("fsfull test finished\n");
2391 }
2392 
2393 void argptest(char *s)
2394 {
2395   int fd;
2396   fd = open("init", O_RDONLY);
2397   if (fd < 0) {
2398     printf("%s: open failed\n", s);
2399     exit(1);
2400   }
2401   read(fd, sbrk(0) - 1, -1);
2402   close(fd);
2403 }
2404 
2405 // check that there's an invalid page beneath
2406 // the user stack, to catch stack overflow.
2407 void
2408 stacktest(char *s)
2409 {
2410   int pid;
2411   int xstatus;
2412   
2413   pid = fork();
2414   if(pid == 0) {
2415     char *sp = (char *) r_sp();
2416     sp -= USERSTACK*PGSIZE;
2417     // the *sp should cause a trap.
2418     printf("%s: stacktest: read below stack %d\n", s, *sp);
2419     exit(1);
2420   } else if(pid < 0){
2421     printf("%s: fork failed\n", s);
2422     exit(1);
2423   }
2424   wait(&xstatus);
2425   if(xstatus == -1)  // kernel killed child?
2426     exit(0);
2427   else
2428     exit(xstatus);
2429 }
2430 
2431 // check that writes to a few forbidden addresses
2432 // cause a fault, e.g. process's text and TRAMPOLINE.
2433 void
2434 nowrite(char *s)
2435 {
2436   int pid;
2437   int xstatus;
2438   uint64 addrs[] = { 0, 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
2439                      0xffffffffffffffff };
2440   
2441   for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
2442     pid = fork();
2443     if(pid == 0) {
2444       volatile int *addr = (int *) addrs[ai];
2445       *addr = 10;
2446       printf("%s: write to %p did not fail!\n", s, addr);
2447       exit(0);
2448     } else if(pid < 0){
2449       printf("%s: fork failed\n", s);
2450       exit(1);
2451     }
2452     wait(&xstatus);
2453     if(xstatus == 0){
2454       // kernel did not kill child!
2455       exit(1);
2456     }
2457   }
2458   exit(0);
2459 }
2460 
2461 // regression test. copyin(), copyout(), and copyinstr() used to cast
2462 // the virtual page address to uint, which (with certain wild system
2463 // call arguments) resulted in a kernel page faults.
2464 void *big = (void*) 0xeaeb0b5b00002f5e;
2465 void
2466 pgbug(char *s)
2467 {
2468   char *argv[1];
2469   argv[0] = 0;
2470   exec(big, argv);
2471   pipe(big);
2472 
2473   exit(0);
2474 }
2475 
2476 // regression test. does the kernel panic if a process sbrk()s its
2477 // size to be less than a page, or zero, or reduces the break by an
2478 // amount too small to cause a page to be freed?
2479 void
2480 sbrkbugs(char *s)
2481 {
2482   int pid = fork();
2483   if(pid < 0){
2484     printf("fork failed\n");
2485     exit(1);
2486   }
2487   if(pid == 0){
2488     int sz = (uint64) sbrk(0);
2489     // free all user memory; there used to be a bug that
2490     // would not adjust p->sz correctly in this case,
2491     // causing exit() to panic.
2492     sbrk(-sz);
2493     // user page fault here.
2494     exit(0);
2495   }
2496   wait(0);
2497 
2498   pid = fork();
2499   if(pid < 0){
2500     printf("fork failed\n");
2501     exit(1);
2502   }
2503   if(pid == 0){
2504     int sz = (uint64) sbrk(0);
2505     // set the break to somewhere in the very first
2506     // page; there used to be a bug that would incorrectly
2507     // free the first page.
2508     sbrk(-(sz - 3500));
2509     exit(0);
2510   }
2511   wait(0);
2512 
2513   pid = fork();
2514   if(pid < 0){
2515     printf("fork failed\n");
2516     exit(1);
2517   }
2518   if(pid == 0){
2519     // set the break in the middle of a page.
2520     sbrk((10*PGSIZE + 2048) - (uint64)sbrk(0));
2521 
2522     // reduce the break a bit, but not enough to
2523     // cause a page to be freed. this used to cause
2524     // a panic.
2525     sbrk(-10);
2526 
2527     exit(0);
2528   }
2529   wait(0);
2530 
2531   exit(0);
2532 }
2533 
2534 // if process size was somewhat more than a page boundary, and then
2535 // shrunk to be somewhat less than that page boundary, can the kernel
2536 // still copyin() from addresses in the last page?
2537 void
2538 sbrklast(char *s)
2539 {
2540   uint64 top = (uint64) sbrk(0);
2541   if((top % PGSIZE) != 0)
2542     sbrk(PGSIZE - (top % PGSIZE));
2543   sbrk(PGSIZE);
2544   sbrk(10);
2545   sbrk(-20);
2546   top = (uint64) sbrk(0);
2547   char *p = (char *) (top - 64);
2548   p[0] = 'x';
2549   p[1] = '\0';
2550   int fd = open(p, O_RDWR|O_CREATE);
2551   write(fd, p, 1);
2552   close(fd);
2553   fd = open(p, O_RDWR);
2554   p[0] = '\0';
2555   read(fd, p, 1);
2556   if(p[0] != 'x')
2557     exit(1);
2558 }
2559 
2560 
2561 // does sbrk handle signed int32 wrap-around with
2562 // negative arguments?
2563 void
2564 sbrk8000(char *s)
2565 {
2566   sbrk(0x80000004);
2567   volatile char *top = sbrk(0);
2568   *(top-1) = *(top-1) + 1;
2569 }
2570 
2571 
2572 
2573 // regression test. test whether exec() leaks memory if one of the
2574 // arguments is invalid. the test passes if the kernel doesn't panic.
2575 void
2576 badarg(char *s)
2577 {
2578   for(int i = 0; i < 50000; i++){
2579     char *argv[2];
2580     argv[0] = (char*)0xffffffff;
2581     argv[1] = 0;
2582     exec("echo", argv);
2583   }
2584   
2585   exit(0);
2586 }
2587 
2588 #define REGION_SZ (1024 * 1024 * 1024)
2589 
2590 // Touch a page every 64 pages, which with lazy allocation
2591 // causes one page to be allocated.
2592 void
2593 lazy_alloc(char *s)
2594 {
2595   char *i, *prev_end, *new_end;
2596   
2597   prev_end = sbrklazy(REGION_SZ);
2598   if (prev_end == (char *) SBRK_ERROR) {
2599     printf("sbrklazy() failed\n");
2600     exit(1);
2601   }
2602   new_end = prev_end + REGION_SZ;
2603 
2604   for (i = prev_end + PGSIZE; i < new_end; i += 64 * PGSIZE)
2605     *(char **)i = i;
2606 
2607   for (i = prev_end + PGSIZE; i < new_end; i += 64 * PGSIZE) {
2608     if (*(char **)i != i) {
2609       printf("failed to read value from memory\n");
2610       exit(1);
2611     }
2612   }
2613 
2614   exit(0);
2615 }
2616 
2617 // Touch a page every 64 pages in region, which with lazy allocation
2618 // causes one page to be allocated. Check that freeing the region
2619 // frees the allocated pages.
2620 void
2621 lazy_unmap(char *s)
2622 {
2623   int pid;
2624   char *i, *prev_end, *new_end;
2625 
2626   prev_end = sbrklazy(REGION_SZ);
2627   if (prev_end == (char*)SBRK_ERROR) {
2628     printf("sbrklazy() failed\n");
2629     exit(1);
2630   }
2631   new_end = prev_end + REGION_SZ;
2632 
2633   for (i = prev_end + PGSIZE; i < new_end; i += PGSIZE * PGSIZE)
2634     *(char **)i = i;
2635 
2636   for (i = prev_end + PGSIZE; i < new_end; i += PGSIZE * PGSIZE) {
2637     pid = fork();
2638     if (pid < 0) {
2639       printf("error forking\n");
2640       exit(1);
2641     } else if (pid == 0) {
2642       sbrklazy(-1L * REGION_SZ);
2643       *(char **)i = i;
2644       exit(0);
2645     } else {
2646       int status;
2647       wait(&status);
2648       if (status == 0) {
2649         printf("memory not unmapped\n");
2650         exit(1);
2651       }
2652     }
2653   }
2654 
2655   exit(0);
2656 }
2657 
2658 void
2659 lazy_copy(char *s)
2660 {
2661   // copyinstr on lazy page
2662   {
2663     char *p = sbrk(0);
2664     sbrklazy(4*PGSIZE);
2665     open(p + 8192, 0);
2666   }
2667   
2668   {
2669     void *xx = sbrk(0);
2670     void *ret = sbrk(-(((uint64) xx)+1));
2671     if(ret != xx){
2672       printf("sbrk(sbrk(0)+1) returned %p, not old sz\n", ret);
2673       exit(1);
2674     }
2675   }
2676 
2677   
2678   // read() and write() to these addresses should fail.
2679   unsigned long bad[] = {
2680     0x3fffffc000,
2681     0x3fffffd000,
2682     0x3fffffe000,
2683     0x3ffffff000,
2684     0x4000000000,
2685     0x8000000000,
2686   };
2687   for(int i = 0; i < sizeof(bad)/sizeof(bad[0]); i++){
2688     int fd = open("README", 0);
2689     if(fd < 0) { printf("cannot open README\n"); exit(1); }
2690     if(read(fd, (char*)bad[i], 512) >= 0) { printf("read succeeded\n");  exit(1); }
2691     close(fd);
2692     fd = open("junk", O_CREATE|O_RDWR|O_TRUNC);
2693     if(fd < 0) { printf("cannot open junk\n"); exit(1); }
2694     if(write(fd, (char*)bad[i], 512) >= 0) { printf("write succeeded\n"); exit(1); }
2695     close(fd);
2696   }
2697 
2698   exit(0);
2699 }
2700 
2701 struct test {
2702   void (*f)(char *);
2703   char *s;
2704 } quicktests[] = {
2705   {copyin, "copyin"},
2706   {copyout, "copyout"},
2707   {copyinstr1, "copyinstr1"},
2708   {copyinstr2, "copyinstr2"},
2709   {copyinstr3, "copyinstr3"},
2710   {rwsbrk, "rwsbrk" },
2711   {truncate1, "truncate1"},
2712   {truncate2, "truncate2"},
2713   {truncate3, "truncate3"},
2714   {openiputtest, "openiput"},
2715   {exitiputtest, "exitiput"},
2716   {iputtest, "iput"},
2717   {opentest, "opentest"},
2718   {writetest, "writetest"},
2719   {writebig, "writebig"},
2720   {createtest, "createtest"},
2721   {dirtest, "dirtest"},
2722   {exectest, "exectest"},
2723   {pipe1, "pipe1"},
2724   {killstatus, "killstatus"},
2725   {preempt, "preempt"},
2726   {exitwait, "exitwait"},
2727   {reparent, "reparent" },
2728   {twochildren, "twochildren"},
2729   {forkfork, "forkfork"},
2730   {forkforkfork, "forkforkfork"},
2731   {reparent2, "reparent2"},
2732   {mem, "mem"},
2733   {sharedfd, "sharedfd"},
2734   {fourfiles, "fourfiles"},
2735   {createdelete, "createdelete"},
2736   {unlinkread, "unlinkread"},
2737   {linktest, "linktest"},
2738   {concreate, "concreate"},
2739   {linkunlink, "linkunlink"},
2740   {subdir, "subdir"},
2741   {bigwrite, "bigwrite"},
2742   {bigfile, "bigfile"},
2743   {fourteen, "fourteen"},
2744   {rmdot, "rmdot"},
2745   {dirfile, "dirfile"},
2746   {iref, "iref"},
2747   {forktest, "forktest"},
2748   {sbrkbasic, "sbrkbasic"},
2749   {sbrkmuch, "sbrkmuch"},
2750   {kernmem, "kernmem"},
2751   {MAXVAplus, "MAXVAplus"},
2752   {sbrkfail, "sbrkfail"},
2753   {sbrkarg, "sbrkarg"},
2754   {validatetest, "validatetest"},
2755   {bsstest, "bsstest"},
2756   {bigargtest, "bigargtest"},
2757   {argptest, "argptest"},
2758   {stacktest, "stacktest"},
2759   {nowrite, "nowrite"},
2760   {pgbug, "pgbug" },
2761   {sbrkbugs, "sbrkbugs" },
2762   {sbrklast, "sbrklast"},
2763   {sbrk8000, "sbrk8000"},
2764   {badarg, "badarg" },
2765   {lazy_alloc, "lazy_alloc"},
2766   {lazy_unmap, "lazy_unmap"},
2767   {lazy_copy, "lazy_copy"},
2768   { 0, 0},
2769 };
2770 
2771 //
2772 // Section with tests that take a fair bit of time
2773 //
2774 
2775 // directory that uses indirect blocks
2776 void
2777 bigdir(char *s)
2778 {
2779   enum { N = 500 };
2780   int i, fd;
2781   char name[10];
2782 
2783   unlink("bd");
2784 
2785   fd = open("bd", O_CREATE);
2786   if(fd < 0){
2787     printf("%s: bigdir create failed\n", s);
2788     exit(1);
2789   }
2790   close(fd);
2791 
2792   for(i = 0; i < N; i++){
2793     name[0] = 'x';
2794     name[1] = '0' + (i / 64);
2795     name[2] = '0' + (i % 64);
2796     name[3] = '\0';
2797     if(link("bd", name) != 0){
2798       printf("%s: bigdir i=%d link(bd, %s) failed\n", s, i, name);
2799       exit(1);
2800     }
2801   }
2802 
2803   unlink("bd");
2804   for(i = 0; i < N; i++){
2805     name[0] = 'x';
2806     name[1] = '0' + (i / 64);
2807     name[2] = '0' + (i % 64);
2808     name[3] = '\0';
2809     if(unlink(name) != 0){
2810       printf("%s: bigdir unlink failed", s);
2811       exit(1);
2812     }
2813   }
2814 }
2815 
2816 // concurrent writes to try to provoke deadlock in the virtio disk
2817 // driver.
2818 void
2819 manywrites(char *s)
2820 {
2821   int nchildren = 4;
2822   int howmany = 30; // increase to look for deadlock
2823   
2824   for(int ci = 0; ci < nchildren; ci++){
2825     int pid = fork();
2826     if(pid < 0){
2827       printf("fork failed\n");
2828       exit(1);
2829     }
2830 
2831     if(pid == 0){
2832       char name[3];
2833       name[0] = 'b';
2834       name[1] = 'a' + ci;
2835       name[2] = '\0';
2836       unlink(name);
2837       
2838       for(int iters = 0; iters < howmany; iters++){
2839         for(int i = 0; i < ci+1; i++){
2840           int fd = open(name, O_CREATE | O_RDWR);
2841           if(fd < 0){
2842             printf("%s: cannot create %s\n", s, name);
2843             exit(1);
2844           }
2845           int sz = sizeof(buf);
2846           int cc = write(fd, buf, sz);
2847           if(cc != sz){
2848             printf("%s: write(%d) ret %d\n", s, sz, cc);
2849             exit(1);
2850           }
2851           close(fd);
2852         }
2853         unlink(name);
2854       }
2855 
2856       unlink(name);
2857       exit(0);
2858     }
2859   }
2860 
2861   for(int ci = 0; ci < nchildren; ci++){
2862     int st = 0;
2863     wait(&st);
2864     if(st != 0)
2865       exit(st);
2866   }
2867   exit(0);
2868 }
2869 
2870 // regression test. does write() with an invalid buffer pointer cause
2871 // a block to be allocated for a file that is then not freed when the
2872 // file is deleted? if the kernel has this bug, it will panic: balloc:
2873 // out of blocks. assumed_free may need to be raised to be more than
2874 // the number of free blocks. this test takes a long time.
2875 void
2876 badwrite(char *s)
2877 {
2878   int assumed_free = 600;
2879   
2880   unlink("junk");
2881   for(int i = 0; i < assumed_free; i++){
2882     int fd = open("junk", O_CREATE|O_WRONLY);
2883     if(fd < 0){
2884       printf("open junk failed\n");
2885       exit(1);
2886     }
2887     write(fd, (char*)0xffffffffffL, 1);
2888     close(fd);
2889     unlink("junk");
2890   }
2891 
2892   int fd = open("junk", O_CREATE|O_WRONLY);
2893   if(fd < 0){
2894     printf("open junk failed\n");
2895     exit(1);
2896   }
2897   if(write(fd, "x", 1) != 1){
2898     printf("write failed\n");
2899     exit(1);
2900   }
2901   close(fd);
2902   unlink("junk");
2903 
2904   exit(0);
2905 }
2906 
2907 // test the exec() code that cleans up if it runs out
2908 // of memory. it's really a test that such a condition
2909 // doesn't cause a panic.
2910 void
2911 execout(char *s)
2912 {
2913   for(int avail = 0; avail < 15; avail++){
2914     int pid = fork();
2915     if(pid < 0){
2916       printf("fork failed\n");
2917       exit(1);
2918     } else if(pid == 0){
2919       // allocate all of memory.
2920       while(1){
2921         char *a = sbrk(PGSIZE);
2922         if(a == SBRK_ERROR)
2923           break;
2924         *(a + PGSIZE - 1) = 1;
2925       }
2926 
2927       // free a few pages, in order to let exec() make some
2928       // progress.
2929       for(int i = 0; i < avail; i++)
2930         sbrk(-PGSIZE);
2931       
2932       close(1);
2933       char *args[] = { "echo", "x", 0 };
2934       exec("echo", args);
2935       exit(0);
2936     } else {
2937       wait((int*)0);
2938     }
2939   }
2940 
2941   exit(0);
2942 }
2943 
2944 // can the kernel tolerate running out of disk space?
2945 void
2946 diskfull(char *s)
2947 {
2948   int fi;
2949   int done = 0;
2950 
2951   unlink("diskfulldir");
2952   
2953   for(fi = 0; done == 0 && '0' + fi < 0177; fi++){
2954     char name[32];
2955     name[0] = 'b';
2956     name[1] = 'i';
2957     name[2] = 'g';
2958     name[3] = '0' + fi;
2959     name[4] = '\0';
2960     unlink(name);
2961     int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
2962     if(fd < 0){
2963       // oops, ran out of inodes before running out of blocks.
2964       printf("%s: could not create file %s\n", s, name);
2965       done = 1;
2966       break;
2967     }
2968     for(int i = 0; i < MAXFILE; i++){
2969       char buf[BSIZE];
2970       if(write(fd, buf, BSIZE) != BSIZE){
2971         done = 1;
2972         close(fd);
2973         break;
2974       }
2975     }
2976     close(fd);
2977   }
2978 
2979   // now that there are no free blocks, test that dirlink()
2980   // merely fails (doesn't panic) if it can't extend
2981   // directory content. one of these file creations
2982   // is expected to fail.
2983   int nzz = 128;
2984   for(int i = 0; i < nzz; i++){
2985     char name[32];
2986     name[0] = 'z';
2987     name[1] = 'z';
2988     name[2] = '0' + (i / 32);
2989     name[3] = '0' + (i % 32);
2990     name[4] = '\0';
2991     unlink(name);
2992     int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
2993     if(fd < 0)
2994       break;
2995     close(fd);
2996   }
2997 
2998   // this mkdir() is expected to fail.
2999   if(mkdir("diskfulldir") == 0)
3000     printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n", s);
3001 
3002   unlink("diskfulldir");
3003 
3004   for(int i = 0; i < nzz; i++){
3005     char name[32];
3006     name[0] = 'z';
3007     name[1] = 'z';
3008     name[2] = '0' + (i / 32);
3009     name[3] = '0' + (i % 32);
3010     name[4] = '\0';
3011     unlink(name);
3012   }
3013 
3014   for(int i = 0; '0' + i < 0177; i++){
3015     char name[32];
3016     name[0] = 'b';
3017     name[1] = 'i';
3018     name[2] = 'g';
3019     name[3] = '0' + i;
3020     name[4] = '\0';
3021     unlink(name);
3022   }
3023 }
3024 
3025 void
3026 outofinodes(char *s)
3027 {
3028   int nzz = 32*32;
3029   for(int i = 0; i < nzz; i++){
3030     char name[32];
3031     name[0] = 'z';
3032     name[1] = 'z';
3033     name[2] = '0' + (i / 32);
3034     name[3] = '0' + (i % 32);
3035     name[4] = '\0';
3036     unlink(name);
3037     int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
3038     if(fd < 0){
3039       // failure is eventually expected.
3040       break;
3041     }
3042     close(fd);
3043   }
3044 
3045   for(int i = 0; i < nzz; i++){
3046     char name[32];
3047     name[0] = 'z';
3048     name[1] = 'z';
3049     name[2] = '0' + (i / 32);
3050     name[3] = '0' + (i % 32);
3051     name[4] = '\0';
3052     unlink(name);
3053   }
3054 }
3055 
3056 struct test slowtests[] = {
3057   {bigdir, "bigdir"},
3058   {manywrites, "manywrites"},
3059   {badwrite, "badwrite" },
3060   {execout, "execout"},
3061   {diskfull, "diskfull"},
3062   {outofinodes, "outofinodes"},
3063     
3064   { 0, 0},
3065 };
3066 
3067 //
3068 // drive tests
3069 //
3070 
3071 // run each test in its own process. run returns 1 if child's exit()
3072 // indicates success.
3073 int
3074 run(void f(char *), char *s) {
3075   int pid;
3076   int xstatus;
3077 
3078   printf("test %s: ", s);
3079   if((pid = fork()) < 0) {
3080     printf("runtest: fork error\n");
3081     exit(1);
3082   }
3083   if(pid == 0) {
3084     f(s);
3085     exit(0);
3086   } else {
3087     wait(&xstatus);
3088     if(xstatus != 0) 
3089       printf("FAILED\n");
3090     else
3091       printf("OK\n");
3092     return xstatus == 0;
3093   }
3094 }
3095 
3096 int
3097 runtests(struct test *tests, char *justone, int continuous) {
3098   int ntests = 0;
3099   for (struct test *t = tests; t->s != 0; t++) {
3100     if((justone == 0) || strcmp(t->s, justone) == 0) {
3101       ntests++;
3102       if(!run(t->f, t->s)){
3103         if(continuous != 2){
3104           printf("SOME TESTS FAILED\n");
3105           return -1;
3106         }
3107       }
3108     }
3109   }
3110   return ntests;
3111 }
3112 
3113 
3114 // use sbrk() to count how many free physical memory pages there are.
3115 int
3116 countfree()
3117 {
3118   int n = 0;
3119   uint64 sz0 = (uint64)sbrk(0);
3120   while(1){
3121     char *a = sbrk(PGSIZE);
3122     if(a == SBRK_ERROR){
3123       break;
3124     }
3125     n += 1;
3126   }
3127   sbrk(-((uint64)sbrk(0) - sz0));  
3128   return n;
3129 }
3130 
3131 int
3132 drivetests(int quick, int continuous, char *justone) {
3133   do {
3134     printf("usertests starting\n");
3135     int free0 = countfree();
3136     int free1 = 0;
3137     int ntests = 0;
3138     int n;
3139     n = runtests(quicktests, justone, continuous);
3140     if (n < 0) {
3141       if(continuous != 2) {
3142         return 1;
3143       }
3144     } else {
3145       ntests += n;
3146     }
3147     if(!quick) {
3148       if (justone == 0)
3149         printf("usertests slow tests starting\n");
3150       n = runtests(slowtests, justone, continuous);
3151       if (n < 0) {
3152         if(continuous != 2) {
3153           return 1;
3154         }
3155       } else {
3156         ntests += n;
3157       }
3158     }
3159     if((free1 = countfree()) < free0) {
3160       printf("FAILED -- lost some free pages %d (out of %d)\n", free1, free0);
3161       if(continuous != 2) {
3162         return 1;
3163       }
3164     }
3165     if (justone != 0 && ntests == 0) {
3166       printf("NO TESTS EXECUTED\n");
3167       return 1;
3168     }
3169   } while(continuous);
3170   return 0;
3171 }
3172 
3173 int
3174 main(int argc, char *argv[])
3175 {
3176   int continuous = 0;
3177   int quick = 0;
3178   char *justone = 0;
3179 
3180   if(argc == 2 && strcmp(argv[1], "-q") == 0){
3181     quick = 1;
3182   } else if(argc == 2 && strcmp(argv[1], "-c") == 0){
3183     continuous = 1;
3184   } else if(argc == 2 && strcmp(argv[1], "-C") == 0){
3185     continuous = 2;
3186   } else if(argc == 2 && argv[1][0] != '-'){
3187     justone = argv[1];
3188   } else if(argc > 1){
3189     printf("Usage: usertests [-c] [-C] [-q] [testname]\n");
3190     exit(1);
3191   }
3192   if (drivetests(quick, continuous, justone)) {
3193     exit(1);
3194   }
3195   printf("ALL TESTS PASSED\n");
3196   exit(0);
3197 }

/* [<][>][^][v][top][bottom][index][help] */