1/* 2 This file contains a simple file system "shell" that lets you 3 manipulate a file system. There is a simple command table that 4 contains the available functions. It is very easy to extend. 5 6 7 THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED 8 OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR 9 NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED. 10 11 FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com). 12 13 Dominic Giampaolo 14 dbg@be.com 15*/ 16 17#include "compat.h" 18 19#include <errno.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <ctype.h> 23#include <string.h> 24#include <sys/time.h> 25 26#include "additional_commands.h" 27#include "argv.h" 28#include "external_commands.h" 29#include "kprotos.h" 30#include "path_util.h" 31#include "tracker.h" 32#include "xcp.h" 33 34#include <fs_attr.h> 35#include <fs_query.h> 36 37static bool sInteractiveMode = true; 38 39 40static int do_lat_fs(int argc, char **argv); 41static void do_fsh(void); 42static int remove_entry(int dir, const char *entry, bool recursive, bool force); 43 44 45static void 46print_usage(const char *program) 47{ 48 printf("----------------------------------------------------------------------\n"); 49 printf("Ultra neat-o userland filesystem testing shell thingy\n"); 50 printf("----------------------------------------------------------------------\n"); 51 printf("usage: %s [-n] [%%s:DISK_IMAGE=big_file|%%d:RANDOM_SEED]\n", 52 program); 53 printf(" %s --initialize [-n] %%s:DISK_IMAGE FS_PARAMETERS...\n", 54 program); 55 printf("\n"); 56} 57 58 59int 60main(int argc, char **argv) 61{ 62 int seed = 0; 63 char *disk_name = "big_file"; 64 myfs_info *myfs; 65 char *arg; 66 int argi = 1; 67 bool initialize = false; 68 69 if (argv[1] && strcmp(argv[1], "--help") == 0) { 70 print_usage(argv[0]); 71 exit(0); 72 } 73 74 // eat options 75 while (argi < argc && argv[argi][0] == '-') { 76 arg = argv[argi++]; 77 if (strcmp(arg, "-n") == 0) { 78 sInteractiveMode = false; 79 } else if (strcmp(arg, "--initialize") == 0) { 80 initialize = true; 81 } else { 82 print_usage(argv[0]); 83 exit(1); 84 } 85 } 86 87 if (argi >= argc) { 88 print_usage(argv[0]); 89 exit(1); 90 } 91 92 arg = argv[argi]; 93 94 if (initialize) { 95 const char *deviceName = arg; 96 initialize_fs(deviceName, argv + argi, argc - argi); 97 } else { 98 if (arg != NULL && !isdigit(arg[0])) 99 disk_name = arg; 100 else if (arg && isdigit(arg[0])) 101 seed = strtoul(arg, NULL, 0); 102 else 103 seed = getpid() * time(NULL) | 1; 104 printf("random seed == 0x%x\n", seed); 105 106 srand(seed); 107 108 myfs = init_fs(disk_name); 109 110 do_fsh(); 111 112 sys_chdir(1, -1, "/"); 113 if (sys_unmount(1, -1, "/myfs") != 0) { 114 printf("could not un-mount /myfs\n"); 115 return 5; 116 } 117 118 shutdown_block_cache(); 119 } 120 121 return 0; 122} 123 124 125static void 126make_random_name(char *buf, int len) 127{ 128 int i, max = (rand() % (len - 5 - 3)) + 2; 129 130 strcpy(buf, "/myfs/"); 131 for(i=0; i < max; i++) { 132 buf[i+6] = 'a' + (rand() % 26); 133 } 134 135 buf[i] = '\0'; 136} 137 138 139static void 140SubTime(struct timeval *a, struct timeval *b, struct timeval *c) 141{ 142 if ((long)(a->tv_usec - b->tv_usec) < 0) 143 { 144 a->tv_sec--; 145 a->tv_usec += 1000000; 146 } 147 148 c->tv_sec = a->tv_sec - b->tv_sec; 149 c->tv_usec = a->tv_usec - b->tv_usec; 150} 151 152 153 154int cur_fd = -1; 155 156 157static int 158do_close(int argc, char **argv) 159{ 160 int err; 161 162 err = sys_close(1, cur_fd); 163/* printf("close of fd %d returned: %d\n", cur_fd, err); */ 164 cur_fd = -1; 165 166 return err; 167} 168 169static int 170do_open(int argc, char **argv) 171{ 172 char name[64]; 173 174 if (cur_fd >= 0) 175 do_close(0, NULL); 176 177 if (argc < 2) 178 make_random_name(name, sizeof(name)); 179 else 180 sprintf(name, "/myfs/%s", &argv[1][0]); 181 182 cur_fd = sys_open(1, -1, name, MY_O_RDWR, MY_S_IFREG, 0); 183 if (cur_fd < 0) { 184 printf("error opening %s : %s (%d)\n", name, fs_strerror(cur_fd), cur_fd); 185 return cur_fd; 186 } else { 187 printf("opened: %s\n", name); 188 return 0; 189 } 190} 191 192static int 193do_make(int argc, char **argv) 194{ 195 char name[64]; 196 197 if (cur_fd >= 0) 198 do_close(0, NULL); 199 200 if (argc < 2) 201 make_random_name(name, sizeof(name)); 202 else if (argv[1][0] != '/') 203 sprintf(name, "/myfs/%s", &argv[1][0]); 204 else 205 strcpy(name, &argv[1][0]); 206 207 cur_fd = sys_open(1, -1, name, MY_O_RDWR | MY_O_CREAT, 0666, 0); 208 if (cur_fd < 0) { 209 printf("error creating: %s: %s\n", name, fs_strerror(cur_fd)); 210 return cur_fd; 211 } 212 213/* printf("created: %s (fd %d)\n", name, cur_fd); */ 214 215 return 0; 216} 217 218 219static status_t 220create_dir(const char *path, bool createParents) 221{ 222 // stat the entry 223 struct my_stat st; 224 status_t error = sys_rstat(true, -1, path, &st, false); 225 if (error == FS_OK) { 226 if (createParents && MY_S_ISDIR(st.mode)) 227 return FS_OK; 228 229 fprintf(stderr, "Cannot make dir, entry `%s' is in the way.\n", path); 230 return FS_FILE_EXISTS; 231 } 232 233 // the dir doesn't exist yet 234 // if we shall create all parents, do that first 235 if (createParents) { 236 // create the parent dir path 237 // eat the trailing '/'s 238 int len = strlen(path); 239 while (len > 0 && path[len - 1] == '/') 240 len--; 241 242 // eat the last path component 243 while (len > 0 && path[len - 1] != '/') 244 len--; 245 246 // eat the trailing '/'s 247 while (len > 0 && path[len - 1] == '/') 248 len--; 249 250 // Now either nothing remains, which means we had a single component, 251 // a root subdir -- in those cases we can just fall through (we should 252 // actually never be here in case of the root dir, but anyway) -- or 253 // there is something left, which we can call a parent directory and 254 // try to create it. 255 if (len > 0) { 256 char *parentPath = (char*)malloc(len + 1); 257 if (!parentPath) { 258 fprintf(stderr, "Failed to allocate memory for parent path.\n"); 259 return FS_NO_MEMORY; 260 } 261 memcpy(parentPath, path, len); 262 parentPath[len] = '\0'; 263 264 error = create_dir(parentPath, createParents); 265 266 free(parentPath); 267 268 if (error != FS_OK) 269 return error; 270 } 271 } 272 273 // make the directory 274 error = sys_mkdir(true, -1, path, MY_S_IRWXU); 275 if (error != FS_OK) { 276 fprintf(stderr, "Failed to make directory `%s': %s\n", path, 277 fs_strerror(error)); 278 return error; 279 } 280 281 return FS_OK; 282} 283 284 285static int 286do_mkdir(int argc, char **argv) 287{ 288 bool createParents = false; 289 290 // parse parameters 291 int argi = 1; 292 for (argi = 1; argi < argc; argi++) { 293 const char *arg = argv[argi]; 294 if (arg[0] != '-') 295 break; 296 297 if (arg[1] == '\0') { 298 fprintf(stderr, "Invalid option `-'\n"); 299 return FS_EINVAL; 300 } 301 302 for (int i = 1; arg[i]; i++) { 303 switch (arg[i]) { 304 case 'p': 305 createParents = true; 306 break; 307 default: 308 fprintf(stderr, "Unknown option `-%c'\n", arg[i]); 309 return FS_EINVAL; 310 } 311 } 312 } 313 314 if (argi >= argc) { 315 printf("usage: %s [ -p ] <dir>...\n", argv[0]); 316 return FS_EINVAL; 317 } 318 319 // create loop 320 for (; argi < argc; argi++) { 321 const char *dir = argv[argi]; 322 if (strlen(dir) == 0) { 323 fprintf(stderr, "An empty path is not a valid argument!\n"); 324 return FS_EINVAL; 325 } 326 327 status_t error = create_dir(dir, createParents); 328 if (error != FS_OK) 329 return error; 330 } 331 332 return FS_OK; 333} 334 335 336static int 337do_read_test(int argc, char **argv) 338{ 339 int i, err; 340 char *buff; 341 size_t len = 256; 342 343 344 if (cur_fd < 0) { 345 printf("no file open! (open or create one with open or make)\n"); 346 return FS_EINVAL; 347 } 348 349 if (argv[1] && isdigit(argv[1][0])) 350 len = strtoul(&argv[1][0], NULL, 0); 351 352 buff = (char*)malloc(len); 353 if (buff == NULL) { 354 printf("no memory for write buffer of %lu bytes\n", (unsigned long)len); 355 return FS_ENOMEM; 356 } 357 358 for (i = 0; (size_t)i < len; i++) 359 buff[i] = (char)0xff; 360 361 err = sys_read(1, cur_fd, buff, len); 362 363 if (len <= 1024) 364 hexdump(buff, len); 365 else { 366 printf("Hex dump shows only the first 1024 bytes:\n"); 367 hexdump(buff, 1024); 368 } 369 370 free(buff); 371 printf("read read %lu bytes and returned %d\n", (unsigned long)len, err); 372 373 return (err < 0 ? err : 0); 374} 375 376 377static int 378do_write_test(int argc, char **argv) 379{ 380 int i, err; 381 char *buff; 382 size_t len = 256; 383 384 if (cur_fd < 0) { 385 printf("no file open! (open or create one with open or make)\n"); 386 return FS_EINVAL; 387 } 388 389 if (argv[1] && isdigit(argv[1][0])) 390 len = strtoul(&argv[1][0], NULL, 0); 391 392 buff = (char*)malloc(len); 393 if (buff == NULL) { 394 printf("no memory for write buffer of %lu bytes\n", (unsigned long)len); 395 return FS_ENOMEM; 396 } 397 398 for (i = 0; (size_t)i < len; i++) 399 buff[i] = i; 400 401 err = sys_write(1, cur_fd, buff, len); 402 free(buff); 403 404 printf("write wrote %lu bytes and returned %d\n", (unsigned long)len, err); 405 406 return (err < 0 ? err : 0); 407} 408 409 410static int 411do_write_stream(int argc, char **argv) 412{ 413 size_t amount = 100000; 414 char buffer[4096]; 415 int length = sizeof(buffer); 416 int i, err = FS_OK; 417 418 if (cur_fd < 0) { 419 printf("no file open! (open or create one with open or make)\n"); 420 return FS_EINVAL; 421 } 422 423 if (argv[1] && isdigit(argv[1][0])) 424 amount = strtoul(&argv[1][0], NULL, 0); 425 426 for(i = 0; (size_t)i < sizeof(buffer); i++) 427 buffer[i] = i; 428 429 for (i = 0; (size_t)i < amount; i++) { 430 err = sys_write(1, cur_fd, buffer, length); 431 if (err < FS_OK) 432 break; 433 } 434 435 printf("write wrote %d bytes and returned %d\n", length, err); 436 437 return (err < 0 ? err : 0); 438} 439 440 441static int 442do_read_attr(int argc, char **argv) 443{ 444 char *attribute,*buffer; 445 size_t len = 256; 446 int i, err; 447 448 if (cur_fd < 0) { 449 printf("no file open! (open or create one with open or make)\n"); 450 return FS_EINVAL; 451 } 452 453 if (argc < 2) { 454 printf("usage: rdattr <attribute name> [bytes to write]\n"); 455 return FS_EINVAL; 456 } 457 458 attribute = argv[1]; 459 if (argv[2] && isdigit(*argv[2])) 460 len = strtoul(argv[2], NULL, 0); 461 if (len < 0) { 462 printf("invalid length for write attribute!\n"); 463 return FS_EINVAL; 464 } 465 466 buffer = (char*)malloc(len); 467 if (buffer == NULL) { 468 printf("no memory for write buffer of %lu bytes\n", (unsigned long)len); 469 return FS_ENOMEM; 470 } 471 472 for (i = 0; (size_t)i < len; i++) 473 buffer[i] = (char)0xff; 474 475 err = sys_read_attr(1, cur_fd, attribute, 'CSTR', buffer, len, 0); 476 477 if (err >= 0) 478 hexdump(buffer, err < 512 ? err : 512); 479 480 free(buffer); 481 printf("read read %lu bytes and returned %d (%s)\n", (unsigned long)len, err, fs_strerror(err)); 482 483 return (err < 0 ? err : 0); 484} 485 486 487static int 488do_write_attr(int argc, char **argv) 489{ 490 char *attribute,*buffer; 491 size_t len = 256; 492 int i, err; 493 494 if (cur_fd < 0) { 495 printf("no file open! (open or create one with open or make)\n"); 496 return FS_EINVAL; 497 } 498 499 if (argc < 2) { 500 printf("usage: wrattr <attribute name> [bytes to write]\n"); 501 return FS_EINVAL; 502 } 503 504 attribute = argv[1]; 505 if (argv[2] && isdigit(*argv[2])) 506 len = strtoul(argv[2], NULL, 0); 507 if (len < 0) { 508 printf("invalid length for write attribute!\n"); 509 return FS_EINVAL; 510 } 511 512 buffer = (char*)malloc(len); 513 if (buffer == NULL) { 514 printf("no memory for write buffer of %lu bytes\n", (unsigned long)len); 515 return FS_ENOMEM; 516 } 517 518 for (i = 0; (size_t)i < len; i++) 519 buffer[i] = i; 520 521 err = sys_write_attr(1, cur_fd, attribute, 'CSTR', buffer, len, 0); 522 free(buffer); 523 524 printf("write wrote %lu bytes and returned %d\n", (unsigned long)len, err); 525 526 return (err < 0 ? err : 0); 527} 528 529 530static int 531do_remove_attr(int argc, char **argv) 532{ 533 int err; 534 535 if (cur_fd < 0) { 536 printf("no file open! (open or create one with open or make)\n"); 537 return FS_EINVAL; 538 } 539 540 if (argc < 2) { 541 printf("usage: rmattr <attribute name>\n"); 542 return FS_EINVAL; 543 } 544 545 err = sys_remove_attr(1, cur_fd, argv[1]); 546 547 printf("remove_attr returned %d\n", err); 548 549 return err; 550} 551 552 553static int 554do_list_attr(int argc, char **argv) 555{ 556 if (argc < 2 && cur_fd < 0) { 557 fprintf(stderr, "Must specify a file!\n"); 558 return FS_EINVAL; 559 } 560 561 // open attr dir 562 int attrDir = -1; 563 if (argc >= 2) { 564 attrDir = sys_open_attr_dir(true, -1, argv[1]); 565 } else if (cur_fd >= 0) { 566 attrDir = sys_open_attr_dir(true, cur_fd, NULL); 567 } else { 568 fprintf(stderr, "Must specify a file!\n"); 569 return FS_EINVAL; 570 } 571 if (attrDir < 0) { 572 fprintf(stderr, "Failed to open attribute directory: %s\n", 573 fs_strerror(attrDir)); 574 return attrDir; 575 } 576 577 printf(" Type Size Name\n"); 578 printf("---------- -------- --------------------------------\n"); 579 580 // iterate through the attributes 581 char entryBuffer[sizeof(my_dirent) + B_ATTR_NAME_LENGTH]; 582 my_dirent *entry = (my_dirent *)entryBuffer; 583 while (sys_readdir(true, attrDir, entry, sizeof(entryBuffer), 1) > 0) { 584 // stat the attribute 585 my_attr_info info; 586 int error = sys_stat_attr(true, attrDir, NULL, entry->d_name, &info); 587 if (error == FS_OK) { 588 printf("0x%08lx %8lld %32s\n", info.type, (long long)info.size, 589 entry->d_name); 590 } else { 591 fprintf(stderr, "Failed to stat attribute `%s': %s\n", 592 entry->d_name, fs_strerror(error)); 593 } 594 } 595 596 // close the attr dir 597 sys_closedir(true, attrDir); 598 599 return FS_OK; 600} 601 602 603static void 604mode_bits_to_str(int mode, char *str) 605{ 606 int i; 607 608 strcpy(str, "----------"); 609 610 if (MY_S_ISDIR(mode)) 611 str[0] = 'd'; 612 else if (MY_S_ISLNK(mode)) 613 str[0] = 'l'; 614 else if (MY_S_ISBLK(mode)) 615 str[0] = 'b'; 616 else if (MY_S_ISCHR(mode)) 617 str[0] = 'c'; 618 619 for(i=7; i > 0; i-=3, mode >>= 3) { 620 if (mode & MY_S_IROTH) 621 str[i] = 'r'; 622 if (mode & MY_S_IWOTH) 623 str[i+1] = 'w'; 624 if (mode & MY_S_IXOTH) 625 str[i+2] = 'x'; 626 } 627} 628 629 630static int 631do_chdir(int argc, char **argv) 632{ 633 if (argc <= 1) { 634 fprintf(stderr, "No directory specified!\n"); 635 return FS_EINVAL; 636 } 637 638 // change dir 639 const char *dir = argv[1]; 640 int error = 0; 641 if (dir[0] == ':') { 642 // host environment 643 if (chdir(dir + 1) < 0) 644 error = from_platform_error(errno); 645 } else { 646 // emulated environment 647 error = sys_chdir(1, -1, dir); 648 } 649 650 if (error != 0) { 651 fprintf(stderr, "Failed to cd into `%s': %s\n", argv[1], 652 fs_strerror(error)); 653 } 654 655 return error; 656} 657 658 659static int 660do_dir(int argc, char **argv) 661{ 662 int dirfd, err, max_err = 10; 663 char dirname[128], buff[512], time_buf[64] = { '\0', }; 664 size_t len, count = 0; 665 struct my_dirent *dent; 666 struct my_stat st; 667 struct tm *tm; 668 char mode_str[16]; 669 670 dent = (struct my_dirent *)buff; 671 if (argc > 1) 672 strcpy(dirname, &argv[1][0]); 673 else 674 strcpy(dirname, "."); 675 676 if ((dirfd = sys_opendir(1, -1, dirname, 0)) < 0) { 677 printf("dir: error opening: %s\n", dirname); 678 return dirfd; 679 } 680 681 printf("Directory listing for: %s\n", dirname); 682 printf(" inode# mode bits uid gid size " 683 "Date Name\n"); 684 685 while (1) { 686 len = 1; 687 err = sys_readdir(1, dirfd, dent, sizeof(buff), len); 688 if (err < 0) { 689 printf("readdir failed for: %s\n", dent->d_name); 690 if (max_err-- <= 0) 691 break; 692 693 continue; 694 } 695 696 if (err == 0) 697 break; 698 699 err = sys_rstat(1, dirfd, dent->d_name, &st, false); 700 if (err != 0) { 701 // may happen for unresolvable links 702 printf("stat failed for: %s (%Ld)\n", dent->d_name, dent->d_ino); 703 continue; 704 } 705 706 tm = localtime(&st.mtime); 707 strftime(time_buf, sizeof(time_buf), "%b %d %I:%M", tm); 708 709 mode_bits_to_str(st.mode, mode_str); 710 711 printf("%12Ld %s %6d %6d %12Ld %s %s", st.ino, mode_str, 712 st.uid, st.gid, st.size, time_buf, dent->d_name); 713 714 // if the entry is a symlink, print its target 715 if (MY_S_ISLNK(st.mode)) { 716 char linkTo[B_PATH_NAME_LENGTH]; 717 ssize_t bytesRead = sys_readlink(true, dirfd, dent->d_name, linkTo, 718 sizeof(linkTo) - 1); 719 if (bytesRead >= 0) { 720 linkTo[bytesRead] = '\0'; 721 printf(" -> %s", linkTo); 722 } else { 723 printf(" -> (%s)", fs_strerror(bytesRead)); 724 } 725 } 726 727 printf("\n"); 728 729 count++; 730 } 731 732 if (err != 0) 733 printf("readdir failed on: %s\n", dent->d_name); 734 735 printf("%ld files in directory!\n", (long)count); 736 737printf("sys_closedir()...\n"); 738 sys_closedir(1, dirfd); 739printf("sys_closedir() done\n"); 740 741 return 0; // not really correct, but anyway... 742} 743 744 745static int 746do_ioctl(int argc, char **argv) 747{ 748 int fd; 749 int err; 750 751 if (argc < 2) { 752 printf("ioctl: too few arguments\n"); 753 return FS_EINVAL; 754 } 755 756 if ((fd = sys_open(1, -1, "/myfs/.", MY_O_RDONLY, S_IFREG, 0)) < 0) { 757 printf("ioctl: error opening '.'\n"); 758 return fd; 759 } 760 761 err = sys_ioctl(1, fd, atoi(argv[1]), 0, 0); 762 if (err < 0) { 763 printf("ioctl: error!\n"); 764 } 765 766 sys_close(1, fd); 767 768 return err; 769} 770 771 772static int 773do_fcntl(int argc, char **argv) 774{ 775 int err; 776 777 if (cur_fd < 0) { 778 printf("no file open! (open or create one with open or make)\n"); 779 return FS_EINVAL; 780 } 781 782 if (argc < 2) { 783 printf("fcntl: too few arguments\n"); 784 return FS_EINVAL; 785 } 786 787 err = sys_ioctl(1, cur_fd, atoi(argv[1]), 0, 0); 788 if (err < 0) { 789 printf("fcntl: error!\n"); 790 } 791 792 return err; 793} 794 795 796static int 797do_rmall(int argc, char **argv) 798{ 799 int dirfd, err, max_err = 10; 800 char dirname[128], fname[512], buff[512]; 801 size_t len,count = 0; 802 struct my_dirent *dent; 803 804 dent = (struct my_dirent *)buff; 805 806 strcpy(dirname, "/myfs/"); 807 if (argc > 1) 808 strcat(dirname, &argv[1][0]); 809 810 if ((dirfd = sys_opendir(1, -1, dirname, 0)) < 0) { 811 printf("dir: error opening: %s\n", dirname); 812 return dirfd; 813 } 814 815 while(1) { 816 len = 1; 817 err = sys_readdir(1, dirfd, dent, sizeof(buff), len); 818 if (err < 0) { 819 printf("readdir failed for: %s\n", dent->d_name); 820 if (max_err-- <= 0) 821 break; 822 823 continue; 824 } 825 826 if (err == 0) 827 break; 828 829 if (strcmp(dent->d_name, "..") == 0 || strcmp(dent->d_name, ".") == 0) 830 continue; 831 832 sprintf(fname, "%s/%s", dirname, dent->d_name); 833 err = sys_unlink(1, -1, fname); 834 if (err != 0) { 835 printf("unlink failed for: %s (%Ld)\n", fname, dent->d_ino); 836 } else 837 count++; 838 } 839 840 if (err != 0) { 841 printf("readdir failed on: %s\n", dent->d_name); 842 } 843 printf("%ld files removed!\n", (long)count); 844 845 sys_closedir(1, dirfd); 846 847 return 0; // not really correct, but anyway... 848} 849 850 851static int 852do_trunc(int argc, char **argv) 853{ 854 int err, new_size; 855 char fname[256]; 856 struct my_stat st; 857 858 strcpy(fname, "/myfs/"); 859 if (argc < 3) { 860 printf("usage: trunc fname newsize\n"); 861 return FS_EINVAL; 862 } 863 strcat(fname, argv[1]); 864 new_size = strtoul(argv[2], NULL, 0); 865 866 st.size = new_size; 867 err = sys_wstat(1, -1, fname, &st, WSTAT_SIZE, 0); 868 if (err != 0) { 869 printf("truncate to %d bytes failed for %s\n", new_size, fname); 870 } 871 872 return err; 873} 874 875 876static int 877do_seek(int argc, char **argv) 878{ 879 fs_off_t err; 880 fs_off_t pos; 881 882 if (cur_fd < 0) { 883 printf("no file open! (open or create one with open or make)\n"); 884 return FS_EINVAL; 885 } 886 887 888 if (argc < 2) { 889 printf("usage: seek pos\n"); 890 return FS_EINVAL; 891 } 892 pos = strtoul(&argv[1][0], NULL, 0); 893 894 err = sys_lseek(1, cur_fd, pos, MY_SEEK_SET); 895 if (err != pos) { 896 printf("seek to %Ld failed (%Ld)\n", pos, err); 897 } 898 899 return err; 900} 901 902 903int 904remove_dir_contents(int parentDir, const char *name, bool force) 905{ 906 // open the dir 907 int dir = sys_opendir(true, parentDir, name, true); 908 if (dir < 0) { 909 fprintf(stderr, "Failed to open dir `%s': %s\n", name, 910 fs_strerror(dir)); 911 return dir; 912 } 913 914 status_t error = FS_OK; 915 916 // iterate through the entries 917 ssize_t numRead; 918 char buffer[sizeof(my_dirent) + B_FILE_NAME_LENGTH]; 919 my_dirent *entry = (my_dirent*)buffer; 920 while ((numRead = sys_readdir(true, dir, entry, sizeof(buffer), 1)) > 0) { 921 // skip "." and ".." 922 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 923 continue; 924 925 error = remove_entry(dir, entry->d_name, true, force); 926 if (error != FS_OK) 927 break; 928 } 929 930 if (numRead < 0) { 931 fprintf(stderr, "Error while reading directory `%s': %s\n", name, 932 fs_strerror(numRead)); 933 return numRead; 934 } 935 936 // close 937 sys_closedir(true, dir); 938 939 return error; 940} 941 942 943static int 944remove_entry(int dir, const char *entry, bool recursive, bool force) 945{ 946 // stat the file 947 struct my_stat st; 948 status_t error = sys_rstat(true, dir, entry, &st, false); 949 if (error != FS_OK) { 950 if (force && error == FS_ENTRY_NOT_FOUND) 951 return FS_OK; 952 953 fprintf(stderr, "Failed to remove `%s': %s\n", entry, 954 fs_strerror(error)); 955 return error; 956 } 957 958 if (MY_S_ISDIR(st.mode)) { 959 if (!recursive) { 960 fprintf(stderr, "`%s' is a directory.\n", entry); 961 // TODO: get the full path 962 return FS_EISDIR; 963 } 964 965 // remove the contents 966 error = remove_dir_contents(dir, entry, force); 967 if (error != FS_OK) 968 return error; 969 970 // remove the directory 971 error = sys_rmdir(true, dir, entry); 972 if (error != FS_OK) { 973 fprintf(stderr, "Failed to remove directory `%s': %s\n", entry, 974 fs_strerror(error)); 975 return error; 976 } 977 } else { 978 // remove the entry 979 error = sys_unlink(true, dir, entry); 980 if (error != FS_OK) { 981 fprintf(stderr, "Failed to remove entry `%s': %s\n", entry, 982 fs_strerror(error)); 983 return error; 984 } 985 } 986 987 return FS_OK; 988} 989 990 991static int 992do_rm(int argc, char **argv) 993{ 994 if (cur_fd >= 0) 995 do_close(0, NULL); 996 997 bool recursive = false; 998 bool force = false; 999 1000 // parse parameters 1001 int argi = 1; 1002 for (argi = 1; argi < argc; argi++) { 1003 const char *arg = argv[argi]; 1004 if (arg[0] != '-') 1005 break; 1006 1007 if (arg[1] == '\0') { 1008 fprintf(stderr, "Invalid option `-'\n"); 1009 return FS_EINVAL; 1010 } 1011 1012 for (int i = 1; arg[i]; i++) { 1013 switch (arg[i]) { 1014 case 'f': 1015 force = true; 1016 break; 1017 case 'r': 1018 recursive = true; 1019 break; 1020 default: 1021 fprintf(stderr, "Unknown option `-%c'\n", arg[i]); 1022 return FS_EINVAL; 1023 } 1024 } 1025 } 1026 1027 // check params 1028 if (argi >= argc) { 1029 fprintf(stderr, "Usage: %s [ -r ] <file>...\n", argv[0]); 1030 return FS_EINVAL; 1031 } 1032 1033 // remove loop 1034 for (; argi < argc; argi++) { 1035 status_t error = remove_entry(-1, argv[argi], recursive, force); 1036 if (error != FS_OK) 1037 return error; 1038 } 1039 1040 return FS_OK; 1041} 1042 1043 1044static int 1045do_rmdir(int argc, char **argv) 1046{ 1047 int err; 1048 char name[256]; 1049 1050 if (cur_fd >= 0) 1051 do_close(0, NULL); 1052 1053 if (argc < 2) { 1054 printf("rm: need a file name to remove\n"); 1055 return FS_EINVAL; 1056 } 1057 1058 sprintf(name, "/myfs/%s", &argv[1][0]); 1059 1060 err = sys_rmdir(1, -1, name); 1061 if (err != 0) { 1062 printf("rmdir: error removing: %s: %s\n", name, fs_strerror(err)); 1063 } 1064 1065 return err; 1066} 1067 1068 1069static int 1070do_copy_to_myfs(char *host_file, char *bfile) 1071{ 1072 int bfd, err = 0; 1073 char myfs_name[1024]; 1074 FILE *fp; 1075 size_t amt; 1076 static char buff[4 * 1024]; 1077 1078 sprintf(myfs_name, "/myfs/%s", bfile); 1079 1080 fp = fopen(host_file, "rb"); 1081 if (fp == NULL) { 1082 printf("can't open host file: %s\n", host_file); 1083 return from_platform_error(errno); 1084 } 1085 1086 if ((bfd = sys_open(1, -1, myfs_name, MY_O_RDWR|MY_O_CREAT, 1087 MY_S_IFREG|MY_S_IRWXU, 0)) < 0) { 1088 fclose(fp); 1089 printf("error opening: %s\n", myfs_name); 1090 return bfd; 1091 } 1092 1093 while((amt = fread(buff, 1, sizeof(buff), fp)) == sizeof(buff)) { 1094 err = sys_write(1, bfd, buff, amt); 1095 if (err < 0) 1096 break; 1097 } 1098 1099 if (amt && err >= 0) { 1100 err = sys_write(1, bfd, buff, amt); 1101 } 1102 1103 if (err < 0) { 1104 printf("err == %d, amt == %ld\n", err, (long)amt); 1105 perror("write error"); 1106 } 1107 1108 sys_close(1, bfd); 1109 fclose(fp); 1110 1111 return (err < 0 ? err : 0); 1112} 1113 1114 1115static int 1116do_copy_from_myfs(char *bfile, char *host_file) 1117{ 1118 int bfd,err = 0; 1119 char myfs_name[1024]; 1120 FILE *fp; 1121 size_t amt; 1122 static char buff[4 * 1024]; 1123 1124 sprintf(myfs_name, "/myfs/%s", bfile); 1125 1126 fp = fopen(host_file, "wb"); 1127 if (fp == NULL) { 1128 printf("can't open host file: %s\n", host_file); 1129 return from_platform_error(errno); 1130 } 1131 1132 if ((bfd = sys_open(1, -1, myfs_name, MY_O_RDONLY, MY_S_IFREG, 0)) < 0) { 1133 fclose(fp); 1134 printf("error opening: %s\n", myfs_name); 1135 return bfd; 1136 } 1137 1138 while(1) { 1139 amt = sizeof(buff); 1140 err = sys_read(1, bfd, buff, amt); 1141 if (err < 0) 1142 break; 1143 1144 if (fwrite(buff, 1, err, fp) != amt) 1145 break; 1146 } 1147 1148 1149 if (err < 0) 1150 perror("read error"); 1151 1152 sys_close(1, bfd); 1153 fclose(fp); 1154 1155 return (err < 0 ? err : 0); 1156} 1157 1158 1159static int 1160do_copy(int argc, char **argv) 1161{ 1162 if (cur_fd >= 0) 1163 do_close(0, NULL); 1164 1165 if (argc < 3) { 1166 printf("copy needs two arguments!\n"); 1167 return FS_EINVAL; 1168 } 1169 1170 if (argv[1][0] == ':' && argv[2][0] != ':') { 1171 return do_copy_to_myfs(&argv[1][1], &argv[2][0]); 1172 } 1173 1174 if (argv[2][0] == ':' && argv[1][0] != ':') { 1175 return do_copy_from_myfs(&argv[1][0], &argv[2][1]); 1176 } 1177 1178 printf("can't copy around inside of the file system (only in and out)\n"); 1179 1180 return FS_EINVAL; 1181} 1182 1183 1184static int 1185copydir(char *fromPath,char *toPath) 1186{ 1187 int bfd, err = 0; 1188 char *myfs_name; //[1024]; 1189 char *from_name; //[1024]; 1190 int fd; 1191 size_t amt; 1192 char *buff; //[4 * 1024]; 1193 size_t bufferSize = 4 * 1024; 1194 DIR *from; 1195 dirent_t *dirent; 1196 1197 from = opendir(fromPath); 1198 if (from == NULL) { 1199 printf("could not open %s\n", fromPath); 1200 return FS_ENTRY_NOT_FOUND; 1201 } 1202 1203 myfs_name = (char*)malloc(1024); 1204 from_name = (char*)malloc(1024); 1205 buff = (char*)malloc(bufferSize); 1206 if (myfs_name == NULL || from_name == NULL || buff == NULL) { 1207 printf("out of memory\n"); 1208 return FS_NO_MEMORY; 1209 } 1210 1211 while ((dirent = readdir(from)) != NULL) { 1212 DIR *attrDirectory; 1213 dirent_t *attr; 1214 struct stat st; 1215 1216 if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) 1217 continue; 1218 1219 strcpy(from_name, fromPath); 1220 if (from_name[strlen(from_name) - 1] != '/') 1221 strcat(from_name, "/"); 1222 strcat(from_name, dirent->d_name); 1223 1224 if (stat(from_name, &st) != 0) 1225 continue; 1226 1227 if (st.st_mode & S_IFDIR) { 1228 char path[1024]; 1229 strcpy(path, toPath); 1230 strcat(path, "/"); 1231 strcat(path, dirent->d_name); 1232 1233 if ((err = sys_mkdir(1, -1, path, MY_S_IRWXU)) == FS_OK) 1234 copydir(from_name, path); 1235 else 1236 printf("Could not create directory %s: (%s)\n", path, fs_strerror(err)); 1237 } else { 1238 fd = open(from_name, O_RDONLY); 1239 if (fd < 0) { 1240 printf("can't open host file: %s\n", from_name); 1241 return fd; 1242 } 1243 1244 sprintf(myfs_name, "%s/%s", toPath, dirent->d_name); 1245 if ((bfd = sys_open(1, -1, myfs_name, MY_O_RDWR|MY_O_CREAT, 1246 MY_S_IFREG|MY_S_IRWXU, 0)) < 0) { 1247 close(fd); 1248 printf("error opening: %s\n", myfs_name); 1249 return bfd; 1250 } 1251 1252 // copy attributes first! 1253 if ((attrDirectory = fs_fopen_attr_dir(fd)) != NULL) { 1254 while ((attr = fs_read_attr_dir(attrDirectory)) != NULL) { 1255 struct attr_info attrInfo; 1256 int32 size = bufferSize, bytesRead; 1257 1258 if (fs_stat_attr(fd, attr->d_name, &attrInfo) != 0) 1259 continue; 1260 1261 if (attrInfo.size <= size) 1262 size = attrInfo.size - 1; 1263 else 1264 printf("truncating attribute: %s\n", attr->d_name); 1265 1266 bytesRead = fs_read_attr(fd, attr->d_name, attrInfo.type, 0, buff, size); 1267 if (bytesRead < size) { 1268 printf("could not read attribute %s: %s\n", attr->d_name, fs_strerror(bytesRead)); 1269 continue; 1270 } 1271 buff[size] = '\0'; 1272 1273 err = sys_write_attr(1, bfd, attr->d_name, attrInfo.type, buff, size, 0); 1274 if (err < FS_OK) { 1275 printf("write attr (\"%s\", type = %p, %p, %ld bytes) failed: %s\n", 1276 attr->d_name, (void *)attrInfo.type, buff, size, fs_strerror(err)); 1277 continue; 1278 } 1279 } 1280 fs_close_attr_dir(attrDirectory); 1281 } else 1282 puts("could not open attr-dir"); 1283 1284 while ((amt = read(fd, buff, bufferSize)) == bufferSize) { 1285 err = sys_write(1, bfd, buff, amt); 1286 if (err < 0) 1287 break; 1288 } 1289 1290 if (amt && err >= 0) { 1291 err = sys_write(1, bfd, buff, amt); 1292 } 1293 1294 if (err < 0) { 1295 printf("write error: err == %d, amt == %ld\n", err, (long)amt); 1296 } 1297 1298 sys_close(1, bfd); 1299 close(fd); 1300 } 1301 } 1302 closedir(from); 1303 1304 free(myfs_name); free(from_name); free(buff); 1305 return FS_OK; 1306} 1307 1308 1309static int 1310do_copytest(int argc, char **argv) 1311{ 1312 char *fromPath = "/boot/apps/internet/mozilla"; 1313 1314 if (argc > 2) { 1315 printf("usage: copytest <path>"); 1316 return FS_EINVAL; 1317 } else if (argc == 2) 1318 fromPath = argv[1]; 1319 else 1320 printf("copying from: %s\n", fromPath); 1321 1322 return copydir(fromPath, "/myfs"); 1323} 1324 1325 1326static int32 1327copydirthread(void *data) 1328{ 1329 char *args[] = {"cptest", (char *)data, NULL}; 1330 1331 do_copytest(2, args); 1332 return 0; 1333} 1334 1335 1336static int 1337do_threadtest(int argc, char **argv) 1338{ 1339 char *paths[] = {"/boot/home/mail/pinc - axeld/in", "/boot/home/mail/pinc - axeld/out", NULL}; 1340 int32 i; 1341 1342 for (i = 0; paths[i] != NULL; i++) { 1343 thread_id thread = spawn_thread(copydirthread, "copythread", B_NORMAL_PRIORITY, paths[i]); 1344 resume_thread(thread); 1345 } 1346 1347 //do_lat_fs(0,NULL); 1348 1349 return 0; 1350} 1351 1352 1353int32 gCopyNum; 1354 1355 1356static int32 1357copyfilethread(void *data) 1358{ 1359 char *args[] = {"cp", (char *)data, NULL, NULL}; 1360 1361 char name[32]; 1362 sprintf(name, "target%ld", gCopyNum++); 1363 args[2] = name; 1364 1365 do_copy(3, args); 1366 return 0; 1367} 1368 1369 1370static int 1371do_threadfiletest(int argc, char **argv) 1372{ 1373 char *paths[] = {":/video/Filme/Wallace & Gromit - A Close Shave.mpg",":/video/Filme/Wallace & Gromit - The Wrong Trousers.mpg",":/stuff/Simpsons/The Simpsons - 13.01 - Treehouse Of Horror XII.mpg",NULL}; 1374 int32 i; 1375 1376 for (i = 0;paths[i] != NULL;i++) { 1377 thread_id thread = spawn_thread(copyfilethread,"copythread",B_NORMAL_PRIORITY,paths[i]); 1378 resume_thread(thread); 1379 } 1380 1381 do_lat_fs(0,NULL); 1382 1383 return 0; 1384} 1385 1386 1387static int 1388do_tracker(int argc, char **argv) 1389{ 1390 static thread_id thread = -1; 1391 1392 if (thread < FS_OK) { 1393 puts("starting tracker..."); 1394 1395 thread = spawn_thread(tracker_loop, "tracker", B_NORMAL_PRIORITY, NULL); 1396 resume_thread(thread); 1397 } else { 1398 status_t status; 1399 puts("stopping tracker."); 1400 1401 write_port(gTrackerPort, FSH_KILL_TRACKER, NULL, 0); 1402 wait_for_thread(thread, &status); 1403 1404 thread = -1; 1405 } 1406 1407 return 0; 1408} 1409 1410 1411// #pragma mark - 1412 1413 1414static bool sRunStatTest; 1415static const char *sStatTestFile = "/myfs/stattest-file"; 1416 1417 1418static int32 1419stat_thread(void *data) 1420{ 1421 (void)data; 1422 1423 while (sRunStatTest) { 1424 struct my_stat st; 1425 sys_rstat(1, -1, sStatTestFile, &st, 0); 1426 } 1427 return 0; 1428} 1429 1430 1431static int32 1432create_remove_thread(void *data) 1433{ 1434 (void)data; 1435 1436 while (sRunStatTest) { 1437 int fd; 1438 if ((fd = sys_open(1, -1, sStatTestFile, MY_O_RDWR | MY_O_CREAT, 1439 S_IFREG | S_IRWXU, 0)) >= 0) { 1440 sys_close(1, fd); 1441 } 1442 1443 snooze(10000); 1444 sys_unlink(1, -1, sStatTestFile); 1445 } 1446 return 0; 1447} 1448 1449 1450static int 1451do_stattest(int argc, char **argv) 1452{ 1453 thread_id a = spawn_thread(stat_thread, "stat_thread", B_NORMAL_PRIORITY, NULL); 1454 thread_id b = spawn_thread(create_remove_thread, "create_remove_thread", B_NORMAL_PRIORITY, NULL); 1455 char buffer[1]; 1456 status_t status; 1457 1458 sRunStatTest = true; 1459 1460 resume_thread(a); 1461 resume_thread(b); 1462 1463 printf("This test will stop when you press <Enter>: "); 1464 fflush(stdout); 1465 1466 fgets(buffer, 1, stdin); 1467 1468 sRunStatTest = false; 1469 1470 wait_for_thread(a, &status); 1471 wait_for_thread(b, &status); 1472 1473 return 0; 1474} 1475 1476 1477// #pragma mark - 1478 1479 1480static int 1481do_attrtest(int argc, char **argv) 1482{ 1483 int iterations = 10240; 1484 int maxSize = 1024; 1485 char *buffer; 1486 char name[2]; 1487 int i; 1488 1489 if (cur_fd < 0) { 1490 printf("no file open! (open or create one with open or make)\n"); 1491 return FS_EINVAL; 1492 } 1493 if (argc > 1 && isdigit(*argv[1])) 1494 iterations = atol(argv[1]); 1495 if (argc > 2 && isdigit(*argv[2])) 1496 maxSize = atol(argv[2]); 1497 if ((argc > 1 && !isdigit(*argv[1])) || (argc > 2 && !isdigit(*argv[2]))) { 1498 printf("usage: attrs [number of iterations] [max attr size]\n"); 1499 return FS_EINVAL; 1500 } 1501 1502 buffer = (char*)malloc(1024); 1503 for (i = 0; i < 1024; i++) 1504 buffer[i] = i; 1505 1506 name[1] = '\0'; 1507 1508 printf("%d iterations...\n", iterations); 1509 1510 for (i = 0; i < iterations; i++) { 1511 int length = rand() % maxSize; 1512 int err; 1513 1514 name[0] = rand() % 26 + 'a'; 1515 1516 err = sys_write_attr(1, cur_fd, name, 'CSTR', buffer, length, 0); 1517 if (err < length) 1518 printf("error writing attribute: %s\n", fs_strerror(err)); 1519 } 1520 1521 free(buffer); 1522 1523 return 0; 1524} 1525 1526 1527static int 1528do_rename(int argc, char **argv) 1529{ 1530 int err; 1531 char oldname[128], newname[128]; 1532 1533 if (cur_fd >= 0) 1534 do_close(0, NULL); 1535 1536 if (argc < 3) { 1537 printf("rename needs two arguments!\n"); 1538 return FS_EINVAL; 1539 } 1540 1541 strcpy(oldname, "/myfs/"); 1542 strcpy(newname, "/myfs/"); 1543 1544 strcat(oldname, &argv[1][0]); 1545 strcat(newname, &argv[2][0]); 1546 1547 err = sys_rename(1, -1, oldname, -1, newname); 1548 if (err) 1549 printf("rename failed with err: %s\n", fs_strerror(err)); 1550 1551 return err; 1552} 1553 1554 1555static int 1556do_link(int argc, char **argv) 1557{ 1558 bool force = false; 1559 bool symbolic = false; 1560 bool dereference = true; 1561 1562 // parse parameters 1563 int argi = 1; 1564 for (argi = 1; argi < argc; argi++) { 1565 const char *arg = argv[argi]; 1566 if (arg[0] != '-') 1567 break; 1568 1569 if (arg[1] == '\0') { 1570 fprintf(stderr, "Invalid option `-'\n"); 1571 return FS_EINVAL; 1572 } 1573 1574 for (int i = 1; arg[i]; i++) { 1575 switch (arg[i]) { 1576 case 'f': 1577 force = true; 1578 break; 1579 case 's': 1580 symbolic = true; 1581 break; 1582 case 'n': 1583 dereference = false; 1584 break; 1585 default: 1586 fprintf(stderr, "Unknown option `-%c'\n", arg[i]); 1587 return FS_EINVAL; 1588 } 1589 } 1590 } 1591 1592 if (argc - argi != 2) { 1593 printf("usage: %s [Options] <source> <target>\n", argv[0]); 1594 return FS_EINVAL; 1595 } 1596 1597 const char *source = argv[argi]; 1598 const char *target = argv[argi + 1]; 1599 1600 // check, if the the target is an existing directory 1601 struct my_stat st; 1602 char targetBuffer[B_PATH_NAME_LENGTH]; 1603 status_t error = sys_rstat(true, -1, target, &st, dereference); 1604 if (error == FS_OK) { 1605 if (MY_S_ISDIR(st.mode)) { 1606 // get source leaf 1607 char leaf[B_FILE_NAME_LENGTH]; 1608 error = get_last_path_component(source, leaf, sizeof(leaf)); 1609 if (error != FS_OK) { 1610 fprintf(stderr, "Failed to get leaf name of source path: %s\n", 1611 fs_strerror(error)); 1612 return error; 1613 } 1614 1615 // compose a new path 1616 int len = strlen(target) + 1 + strlen(leaf); 1617 if (len > (int)sizeof(targetBuffer)) { 1618 fprintf(stderr, "Resulting target path is too long.\n"); 1619 return FS_EINVAL; 1620 } 1621 1622 strcpy(targetBuffer, target); 1623 strcat(targetBuffer, "/"); 1624 strcat(targetBuffer, leaf); 1625 target = targetBuffer; 1626 } 1627 } 1628 1629 // check, if the target exists 1630 error = sys_rstat(true, -1, target, &st, false); 1631 if (error == FS_OK) { 1632 if (!force) { 1633 fprintf(stderr, "Can't create link. `%s' is in the way.\n", target); 1634 return FS_FILE_EXISTS; 1635 } 1636 1637 // unlink the entry 1638 error = sys_unlink(true, -1, target); 1639 if (error != FS_OK) { 1640 fprintf(stderr, "Failed to remove `%s' to make way for link: " 1641 "%s\n", target, fs_strerror(error)); 1642 return error; 1643 } 1644 } 1645 1646 // finally create the link 1647 if (symbolic) 1648 error = sys_symlink(1, source, -1, target); 1649 else 1650 error = sys_link(1, -1, source, -1, target); 1651 if (error != FS_OK) 1652 printf("Failed to create link: %s\n", fs_strerror(error)); 1653 1654 return error; 1655} 1656 1657 1658static int 1659do_sync(int argc, char **argv) 1660{ 1661 int err; 1662 1663 err = sys_sync(); 1664 1665 if (err) 1666 printf("sync failed with err %s\n", fs_strerror(err)); 1667 1668 return err; 1669} 1670 1671 1672static int 1673do_relabel(int argc, char **argv) 1674{ 1675 if (argc < 2) { 1676 printf("usage: relabel <volume name>\n"); 1677 return FS_EINVAL; 1678 } 1679 1680 struct my_stat st; 1681 status_t error = sys_rstat(true, -1, "/myfs", &st, true); 1682 if (error == FS_OK) { 1683 fs_info info; 1684 strncpy(info.volume_name, argv[1], sizeof(info.volume_name)); 1685 info.volume_name[sizeof(info.volume_name) - 1] = '\0'; 1686 1687 error = sys_write_fs_info(true, st.dev, &info, WFSSTAT_NAME); 1688 } 1689 1690 if (error != FS_OK) 1691 printf("Could not create index: %s\n", fs_strerror(error)); 1692 1693 return error; 1694} 1695 1696 1697static int 1698do_mkindex(int argc, char **argv) 1699{ 1700 if (argc < 2) { 1701 printf("usage: mkindex <index>\n"); 1702 return FS_EINVAL; 1703 } 1704 1705 struct my_stat st; 1706 status_t error = sys_rstat(true, -1, "/myfs", &st, true); 1707 if (error == FS_OK) { 1708 error = sys_mkindex(true, st.dev, argv[1], B_STRING_TYPE, 0); 1709 } 1710 1711 if (error != FS_OK) 1712 printf("Could not create index: %s\n", fs_strerror(error)); 1713 1714 return error; 1715} 1716 1717 1718#define MAX_LIVE_QUERIES 10 1719void *gQueryCookie[MAX_LIVE_QUERIES] = {NULL}; 1720char *gQueryString[MAX_LIVE_QUERIES] = {NULL}; 1721 1722 1723static int 1724do_listqueries(int argc, char **argv) 1725{ 1726 int min, max; 1727 1728 if (argc == 2) 1729 min = max = atol(argv[1]); 1730 else { 1731 min = 0; 1732 max = MAX_LIVE_QUERIES - 1; 1733 } 1734 1735 // list all queries (or only the one asked for) 1736 1737 for (; min <= max; min++) { 1738 if (gQueryCookie[min] == NULL) 1739 continue; 1740 1741 printf("%d. (%p) %s\n", min, gQueryCookie[min], gQueryString[min]); 1742 } 1743 1744 return 0; 1745} 1746 1747 1748static int 1749do_stopquery(int argc, char **argv) 1750{ 1751 int err; 1752 int min, max; 1753 1754 if (gQueryCookie == NULL) { 1755 printf("no query running (use the 'startquery' command to start a query).\n"); 1756 return FS_EINVAL; 1757 } 1758 1759 if (argc == 2) 1760 min = max = atol(argv[1]); 1761 else { 1762 min = 0; 1763 max = MAX_LIVE_QUERIES - 1; 1764 } 1765 1766 // close all queries (or only the one asked for) 1767 1768 for (; min <= max; min++) { 1769 if (gQueryCookie[min] == NULL) 1770 continue; 1771 1772 err = sys_close_query(true, -1, "/myfs/.", gQueryCookie[min]); 1773 if (err < 0) { 1774 printf("could not close query: %s\n", fs_strerror(err)); 1775 return err; 1776 } 1777 gQueryCookie[min] = NULL; 1778 free(gQueryString[min]); 1779 } 1780 1781 return 0; 1782} 1783 1784 1785static int 1786do_startquery(int argc, char **argv) 1787{ 1788 char *query; 1789 int freeSlot; 1790 int err; 1791 1792 for (freeSlot = 0; freeSlot < MAX_LIVE_QUERIES; freeSlot++) { 1793 if (gQueryCookie[freeSlot] == NULL) 1794 break; 1795 } 1796 if (freeSlot == MAX_LIVE_QUERIES) { 1797 printf("All query slots are used, stop some\n"); 1798 return FS_EINVAL; 1799 } 1800 1801 if (argc != 2) { 1802 printf("query string expected\n"); 1803 return FS_EINVAL; 1804 } 1805 query = argv[1]; 1806 1807 err = sys_open_query(true, -1, "/myfs/.", query, B_LIVE_QUERY, freeSlot, freeSlot, &gQueryCookie[freeSlot]); 1808 if (err < 0) { 1809 printf("could not open query: %s\n", fs_strerror(err)); 1810 return err; 1811 } 1812 1813 printf("query number %d started - use the 'stopquery' command to stop it.\n", freeSlot); 1814 gQueryString[freeSlot] = strdup(query); 1815 1816 return 0; 1817} 1818 1819 1820static int 1821do_query(int argc, char **argv) 1822{ 1823 char buffer[2048]; 1824 struct my_dirent *dent = (struct my_dirent *)buffer; 1825 void *cookie; 1826 char *query; 1827 int max_err = 10; 1828 int err; 1829 1830 if (argc != 2) { 1831 printf("query string expected"); 1832 return FS_EINVAL; 1833 } 1834 query = argv[1]; 1835 1836 err = sys_open_query(true, -1, "/myfs/.", query, 0, 42, 42, &cookie); 1837 if (err < 0) { 1838 printf("could not open query: %s\n", fs_strerror(err)); 1839 return FS_EINVAL; 1840 } 1841 1842 while (true) { 1843 err = sys_read_query(true, -1, "/myfs/.", cookie, dent, sizeof(buffer), 1); 1844 if (err < 0) { 1845 printf("readdir failed for: %s\n", dent->d_name); 1846 if (max_err-- <= 0) 1847 break; 1848 1849 continue; 1850 } 1851 1852 if (err == 0) 1853 break; 1854 1855 printf("%s\n", dent->d_name); 1856 } 1857 1858 err = sys_close_query(true, -1, "/myfs/.", cookie); 1859 if (err < 0) { 1860 printf("could not close query: %s\n", fs_strerror(err)); 1861 return err; 1862 } 1863 1864 return 0; 1865} 1866 1867 1868#define MAX_ITER 512 1869#define NUM_READS 16 1870#define READ_SIZE 4096 1871 1872static int 1873do_cio(int argc, char **argv) 1874{ 1875 int i, j, fd; 1876 char fname[64]; 1877 fs_off_t pos; 1878 size_t len; 1879 static char buff[READ_SIZE]; 1880 struct timeval start, end, result; 1881 1882 strcpy(fname, "/myfs/"); 1883 if (argc == 1) 1884 strcpy(fname, "/myfs/fsh"); 1885 else 1886 strcat(fname, &argv[1][0]); 1887 1888 fd = sys_open(1, -1, fname, MY_O_RDONLY, MY_S_IFREG, 0); 1889 if (fd < 0) { 1890 printf("can't open %s\n", fname); 1891 return fd; 1892 } 1893 1894 gettimeofday(&start, NULL); 1895 1896 for (i = 0; i < MAX_ITER; i++) { 1897 for (j = 0; j < NUM_READS; j++) { 1898 len = sizeof(buff); 1899 if (sys_read(1, fd, buff, len) != (ssize_t)len) { 1900 perror("cio read"); 1901 break; 1902 } 1903 } 1904 1905 pos = 0; 1906 if (sys_lseek(1, fd, pos, MY_SEEK_SET) != pos) { 1907 perror("cio lseek"); 1908 break; 1909 } 1910 } 1911 1912 gettimeofday(&end, NULL); 1913 SubTime(&end, &start, &result); 1914 1915 printf("read %lu bytes in %2ld.%.6ld seconds\n", 1916 (unsigned long)((MAX_ITER * NUM_READS * sizeof(buff)) / 1024), 1917 result.tv_sec, result.tv_usec); 1918 1919 1920 sys_close(1, fd); 1921 1922 1923 return 0; 1924} 1925 1926 1927static int 1928mkfile(char *s, int sz) 1929{ 1930 int fd, len; 1931 int err = 0; 1932 char *buffer; 1933 1934 if ((fd = sys_open(1, -1, s, MY_O_RDWR|MY_O_CREAT, 1935 MY_S_IFREG|MY_S_IRWXU, 0)) < 0) { 1936 printf("error creating: %s\n", s); 1937 return fd; 1938 } 1939 1940 buffer = (char*)malloc(16 * 1024); 1941 if (buffer == NULL) 1942 return FS_ENOMEM; 1943 1944 len = sz; 1945 if (sz) { 1946 err = sys_write(1, fd, buffer, len); 1947 if (err != len) 1948 printf("error writing %d bytes to %s\n", sz, s); 1949 } 1950 if (sys_close(1, fd) != 0) 1951 printf("close failed?\n"); 1952 1953 free(buffer); 1954 1955 return (err < 0 ? err : 0); 1956} 1957 1958#define LAT_FS_ITER 1000 1959 1960 1961static int 1962do_lat_fs(int argc, char **argv) 1963{ 1964 int i, j, iter; 1965/* int sizes[] = { 0, 1024, 4096, 10*1024 }; */ 1966 int sizes[] = { 0, 1024 }; 1967 char name[64]; 1968 1969 iter = LAT_FS_ITER; 1970 1971 if (argc > 1) 1972 iter = strtoul(&argv[1][0], NULL, 0); 1973 1974 for (i = 0; (size_t)i < sizeof(sizes)/sizeof(int); i++) { 1975 printf("CREATING: %d files of %5d bytes each\n", iter, sizes[i]); 1976 for (j = 0; j < iter; ++j) { 1977 sprintf(name, "/myfs/%.5d", j); 1978 mkfile(name, sizes[i]); 1979 } 1980 1981 printf("DELETING: %d files of %5d bytes each\n", iter, sizes[i]); 1982 for (j = 0; j < iter; ++j) { 1983 sprintf(name, "/myfs/%.5d", j); 1984 if (sys_unlink(1, -1, name) != 0) 1985 printf("lat_fs: failed to remove: %s\n", name); 1986 } 1987 } 1988 1989 return 0; 1990} 1991 1992 1993static int 1994do_create(int argc, char **argv) 1995{ 1996 int j, iter = 100, err; 1997 int size = 0; 1998 char name[64]; 1999 2000 sprintf(name, "/myfs/test"); 2001 err = sys_mkdir(1, -1, name, MY_S_IRWXU); 2002 if (err && err != FS_EEXIST) 2003 printf("mkdir of %s returned: %s (%d)\n", name, fs_strerror(err), err); 2004 2005 if (argc > 1) 2006 iter = strtoul(&argv[1][0], NULL, 0); 2007 if (argc > 2) 2008 size = strtoul(&argv[2][0], NULL, 0); 2009 2010 printf("creating %d files (each %d bytes long)...\n", iter, size); 2011 2012 for (j = 0; j < iter; ++j) { 2013 sprintf(name, "/myfs/test/%.5d", j); 2014 /* printf("CREATING: %s (%5d)\n", name, size); */ 2015 mkfile(name, size); 2016 } 2017 2018 return 0; 2019} 2020 2021 2022static int 2023do_delete(int argc, char **argv) 2024{ 2025 int j, iter = 100; 2026 char name[64]; 2027 2028 if (argc > 1) 2029 iter = strtoul(&argv[1][0], NULL, 0); 2030 2031 for (j = 0; j < iter; ++j) { 2032 sprintf(name, "/myfs/test/%.5d", j); 2033 printf("DELETING: %s\n", name); 2034 if (sys_unlink(1, -1, name) != 0) 2035 printf("lat_fs: failed to remove: %s\n", name); 2036 } 2037 2038 return 0; 2039} 2040 2041 2042static int do_help(int argc, char **argv); 2043 2044 2045static cmd_entry builtin_commands[] = 2046{ 2047 { "cd", do_chdir, "change current directory" }, 2048 { "ls", do_dir, "print a directory listing" }, 2049 { "dir", do_dir, "print a directory listing (same as ls)" }, 2050 { "open", do_open, "open an existing file for read/write access" }, 2051 { "make", do_make, "create a file (optionally specifying a name)" }, 2052 { "close", do_close, "close the currently open file" }, 2053 { "mkdir", do_mkdir, "create a directory" }, 2054 { "rdtest", do_read_test, "read N bytes from the current file. default is 256" }, 2055 { "wrtest", do_write_test, "write N bytes to the current file. default is 256" }, 2056 { "wrstream", do_write_stream, "write N blocks of 4096 bytes to the current file. default is 100000" }, 2057 { "rm", do_rm, "remove the named file" }, 2058 { "rmall", do_rmall, "remove all the files. if no dirname, use '.'" }, 2059 { "rmdir", do_rmdir, "remove the named directory" }, 2060 { "cp", do_xcp, "similar to shell cp, can copy in, out, within, and outside the FS, supports attributes." }, 2061 { "copy", do_xcp, "same as cp" }, 2062 { "trunc", do_trunc, "truncate a file to the size specified" }, 2063 { "seek", do_seek, "seek to the position specified" }, 2064 { "mv", do_rename, "rename a file or directory" }, 2065 { "sync", do_sync, "call sync" }, 2066 { "relabel", do_relabel, "rename the volume" }, 2067 { "wrattr", do_write_attr, "write attribute \"name\" to the current file (N bytes [256])." }, 2068 { "rdattr", do_read_attr, "read attribute \"name\" from the current file (N bytes [256])." }, 2069 { "rmattr", do_remove_attr, "remove attribute \"name\" from the current file." }, 2070 { "listattr", do_list_attr, "lists all attributes of the given or current file." }, 2071 { "attrs", do_attrtest, "writes random attributes [a-z] up to 1023 bytes, N [10240] iterations." }, 2072 { "lat_fs", do_lat_fs, "simulate what the lmbench test lat_fs does" }, 2073 { "create", do_create, "create N files. default is 100" }, 2074 { "delete", do_delete, "delete N files. default is 100" }, 2075 { "mkindex", do_mkindex, "creates an index (type is currently always string)" }, 2076 { "query", do_query, "run a query on the file system" }, 2077 { "startquery", do_startquery, "run a live query on the file system (up to 10)" }, 2078 { "stopquery", do_stopquery, "stops live query N, or all of them if none is specified" }, 2079 { "lsquery", do_listqueries, "list all live queries" }, 2080 { "ioctl", do_ioctl, "execute ioctl() without an inode (okay, with the root node)" }, 2081 { "fcntl", do_fcntl, "execute ioctl() with the active inode" }, 2082 { "cptest", do_copytest, "copies all files from the given path" }, 2083 { "threads", do_threadtest, "copies several files, and does a lat_fs simulaneously" }, 2084 { "mfile", do_threadfiletest, "copies several big files simulaneously" }, 2085 { "tracker", do_tracker, "starts a Tracker like background thread that will listen to fs updates" }, 2086 { "cio", do_cio, "does a I/O speed test" }, 2087 { "stattest", do_stattest, "does an \"early\"/\"late\" stat test for files that are created or deleted" }, 2088 { "link", do_link, "creates the specified [sym]link on the device" }, 2089 { "ln", do_link, "creates the specified [sym]link on the device" }, 2090 2091 { NULL, NULL } 2092}; 2093 2094static cmd_entry help_commands[] = 2095{ 2096 { "help", do_help, "print this help message" }, 2097 { "?", do_help, "print this help message" }, 2098 { NULL, NULL } 2099}; 2100 2101static cmd_entry *fsh_commands[] = 2102{ 2103 builtin_commands, 2104 additional_commands, 2105 help_commands, 2106 NULL 2107}; 2108 2109static int 2110do_help(int argc, char **argv) 2111{ 2112 printf("commands fsh understands:\n"); 2113 for (cmd_entry **commands = fsh_commands; *commands; commands++) { 2114 cmd_entry *cmd = *commands; 2115 for (; cmd->name != NULL; cmd++) { 2116 printf("%8s - %s\n", cmd->name, cmd->help); 2117 } 2118 } 2119 2120 return 0; 2121} 2122 2123static char * 2124getline(char *prompt, char *input, int len) 2125{ 2126 if (sInteractiveMode) { 2127 printf("%s", prompt); fflush(stdout); 2128 2129 return fgets(input, len, stdin); 2130 } else 2131 return get_external_command(prompt, input, len); 2132} 2133 2134 2135// This might have been defined by additional_commands.h - so 2136// we can't do it earlier. 2137#ifndef FS_SHELL_PROMPT 2138# define FS_SHELL_PROMPT "fsh" 2139#endif 2140 2141 2142static void 2143do_fsh(void) 2144{ 2145#if 0 2146 char stack_filler[1024 * 1024 * 16 - 32 * 1024]; 2147 // actually emulating 12kB stack size (BeOS has 16 MB - ~20kB for the main thread) 2148#endif 2149 int argc, len; 2150 char *prompt = FS_SHELL_PROMPT ">> "; 2151 char input[20480], **argv; 2152 cmd_entry *cmd = NULL; 2153 2154 while(getline(prompt, input, sizeof(input)) != NULL) { 2155 argc = 0; 2156 argv = build_argv(input, &argc); 2157 if (argv == NULL || argc == 0) { 2158 continue; 2159 } 2160 2161 len = strlen(&argv[0][0]); 2162 2163 bool done = false; 2164 for (cmd_entry **commands = fsh_commands; 2165 !done && *commands; 2166 commands++) { 2167 cmd = *commands; 2168 for (; cmd->name != NULL; cmd++) { 2169 if (strncmp(cmd->name, &argv[0][0], len) == 0) { 2170 int result = cmd->func(argc, argv); 2171 2172 if (!sInteractiveMode) 2173 reply_to_external_command(to_platform_error(result)); 2174 2175 done = true; 2176 break; 2177 } 2178 } 2179 } 2180 2181 if (strncmp(&argv[0][0], "quit", 4) == 0 2182 || strncmp(&argv[0][0], "exit", 4) == 0) { 2183 if (!sInteractiveMode) 2184 reply_to_external_command(0); 2185 break; 2186 } 2187 2188 if ((cmd == NULL || cmd->name == NULL) && argv[0][0] != '\0') { 2189 printf("command `%s' not understood\n", &argv[0][0]); 2190 2191 if (!sInteractiveMode) 2192 reply_to_external_command(EINVAL); 2193 } 2194 2195 free(argv); 2196 } 2197 2198 if (!sInteractiveMode) 2199 external_command_cleanup(); 2200 2201 if (feof(stdin)) 2202 printf("\n"); 2203 2204 if (cur_fd != -1) 2205 do_close(0, NULL); 2206} 2207 2208