1 /* 2 * Copyright 2007-2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "compatibility.h" 8 9 #include "fssh.h" 10 11 #include <stdarg.h> 12 #include <stdio.h> 13 #include <string.h> 14 #include <time.h> 15 #include <unistd.h> 16 #include <stdlib.h> 17 18 #include <vector> 19 20 #include "command_cp.h" 21 #include "driver_settings.h" 22 #include "external_commands.h" 23 #include "fd.h" 24 #include "fssh_dirent.h" 25 #include "fssh_errno.h" 26 #include "fssh_errors.h" 27 #include "fssh_fs_info.h" 28 #include "fssh_fcntl.h" 29 #include "fssh_module.h" 30 #include "fssh_node_monitor.h" 31 #include "fssh_stat.h" 32 #include "fssh_string.h" 33 #include "fssh_type_constants.h" 34 #include "module.h" 35 #include "partition_support.h" 36 #include "path_util.h" 37 #include "syscalls.h" 38 #include "vfs.h" 39 40 41 extern fssh_module_info *modules[]; 42 43 44 extern fssh_file_system_module_info gRootFileSystem; 45 46 namespace FSShell { 47 48 const char* kMountPoint = "/myfs"; 49 50 // command line args 51 static int sArgc; 52 static const char* const* sArgv; 53 54 static mode_t sUmask = 0022; 55 56 57 static fssh_status_t 58 init_kernel() 59 { 60 fssh_status_t error; 61 62 // init module subsystem 63 error = module_init(NULL); 64 if (error != FSSH_B_OK) { 65 fprintf(stderr, "module_init() failed: %s\n", fssh_strerror(error)); 66 return error; 67 } 68 69 // init driver settings 70 error = driver_settings_init(); 71 if (error != FSSH_B_OK) { 72 fprintf(stderr, "initializing driver settings failed: %s\n", 73 fssh_strerror(error)); 74 return error; 75 } 76 77 // register built-in modules, i.e. the rootfs and the client FS 78 register_builtin_module(&gRootFileSystem.info); 79 for (int i = 0; modules[i]; i++) 80 register_builtin_module(modules[i]); 81 82 // init VFS 83 error = vfs_init(NULL); 84 if (error != FSSH_B_OK) { 85 fprintf(stderr, "initializing VFS failed: %s\n", fssh_strerror(error)); 86 return error; 87 } 88 89 // init kernel IO context 90 gKernelIOContext = (io_context*)vfs_new_io_context(NULL); 91 if (!gKernelIOContext) { 92 fprintf(stderr, "creating IO context failed!\n"); 93 return FSSH_B_NO_MEMORY; 94 } 95 96 // mount root FS 97 fssh_dev_t rootDev = _kern_mount("/", NULL, "rootfs", 0, NULL, 0); 98 if (rootDev < 0) { 99 fprintf(stderr, "mounting rootfs failed: %s\n", fssh_strerror(rootDev)); 100 return rootDev; 101 } 102 103 // set cwd to "/" 104 error = _kern_setcwd(-1, "/"); 105 if (error != FSSH_B_OK) { 106 fprintf(stderr, "setting cwd failed: %s\n", fssh_strerror(error)); 107 return error; 108 } 109 110 // create mount point for the client FS 111 error = _kern_create_dir(-1, kMountPoint, 0775); 112 if (error != FSSH_B_OK) { 113 fprintf(stderr, "creating mount point failed: %s\n", 114 fssh_strerror(error)); 115 return error; 116 } 117 118 return FSSH_B_OK; 119 } 120 121 122 // #pragma mark - Command 123 124 Command::Command(const char* name, const char* description) 125 : fName(name), 126 fDescription(description) 127 { 128 } 129 130 131 Command::Command(command_function* function, const char* name, 132 const char* description) 133 : fName(name), 134 fDescription(description), 135 fFunction(function) 136 { 137 } 138 139 140 Command::~Command() 141 { 142 } 143 144 145 const char* 146 Command::Name() const 147 { 148 return fName.c_str(); 149 } 150 151 152 const char* 153 Command::Description() const 154 { 155 return fDescription.c_str(); 156 } 157 158 159 fssh_status_t 160 Command::Do(int argc, const char* const* argv) 161 { 162 if (!fFunction) { 163 fprintf(stderr, "No function given for command \"%s\"\n", Name()); 164 return FSSH_B_BAD_VALUE; 165 } 166 167 return (*fFunction)(argc, argv); 168 } 169 170 171 // #pragma mark - CommandManager 172 173 CommandManager::CommandManager() 174 { 175 } 176 177 178 CommandManager* 179 CommandManager::Default() 180 { 181 if (!sManager) 182 sManager = new CommandManager; 183 return sManager; 184 } 185 186 187 void 188 CommandManager::AddCommand(Command* command) 189 { 190 // The command name may consist of several aliases. Split them and 191 // register the command for each of them. 192 char _names[1024]; 193 char* names = _names; 194 strcpy(names, command->Name()); 195 196 char* cookie; 197 while (char* name = strtok_r(names, " /", &cookie)) { 198 fCommands[name] = command; 199 names = NULL; 200 } 201 } 202 203 204 void 205 CommandManager::AddCommand(command_function* function, const char* name, 206 const char* description) 207 { 208 AddCommand(new Command(function, name, description)); 209 } 210 211 212 void 213 CommandManager::AddCommands(command_function* function, const char* name, 214 const char* description, ...) 215 { 216 va_list args; 217 va_start(args, description); 218 219 while (function) { 220 AddCommand(function, name, description); 221 222 function = va_arg(args, command_function*); 223 if (function) { 224 name = va_arg(args, const char*); 225 description = va_arg(args, const char*); 226 } 227 } 228 229 va_end(args); 230 } 231 232 233 Command* 234 CommandManager::FindCommand(const char* name) const 235 { 236 CommandMap::const_iterator it = fCommands.find(name); 237 if (it == fCommands.end()) 238 return NULL; 239 240 return it->second; 241 } 242 243 244 void 245 CommandManager::ListCommands() const 246 { 247 for (CommandMap::const_iterator it = fCommands.begin(); 248 it != fCommands.end(); ++it) { 249 const char* name = it->first.c_str(); 250 Command* command = it->second; 251 printf("%-16s - %s\n", name, command->Description()); 252 } 253 } 254 255 256 CommandManager* CommandManager::sManager = NULL; 257 258 259 // #pragma mark - Command support functions 260 261 262 static bool 263 get_permissions(const char* modeString, fssh_mode_t& _permissions) 264 { 265 // currently only octal mode is supported 266 if (strlen(modeString) != 3) 267 return false; 268 269 fssh_mode_t permissions = 0; 270 for (int i = 0; i < 3; i++) { 271 char c = modeString[i]; 272 if (c < '0' || c > '7') 273 return false; 274 permissions = (permissions << 3) | (c - '0'); 275 } 276 277 _permissions = permissions; 278 return true; 279 } 280 281 282 static fssh_dev_t 283 get_volume_id() 284 { 285 struct fssh_stat st; 286 fssh_status_t error = _kern_read_stat(-1, kMountPoint, false, &st, 287 sizeof(st)); 288 if (error != FSSH_B_OK) { 289 fprintf(stderr, "Error: Failed to stat() mount point: %s\n", 290 fssh_strerror(error)); 291 return error; 292 } 293 294 return st.fssh_st_dev; 295 } 296 297 298 static const char * 299 byte_string(int64_t numBlocks, int64_t blockSize) 300 { 301 double blocks = 1. * numBlocks * blockSize; 302 static char string[64]; 303 304 if (blocks < 1024) 305 sprintf(string, "%" FSSH_B_PRId64, numBlocks * blockSize); 306 else { 307 const char* units[] = {"K", "M", "G", NULL}; 308 int i = -1; 309 310 do { 311 blocks /= 1024.0; 312 i++; 313 } while (blocks >= 1024 && units[i + 1]); 314 315 sprintf(string, "%.1f%s", blocks, units[i]); 316 } 317 318 return string; 319 } 320 321 322 void 323 print_flag(uint32_t deviceFlags, uint32_t testFlag, const char *yes, 324 const char *no) 325 { 326 printf("%s", (deviceFlags & testFlag) != 0 ? yes : no); 327 } 328 329 330 static void 331 list_entry(const char* file, const char* name = NULL) 332 { 333 // construct path, if a leaf name is given 334 std::string path; 335 if (name) { 336 path = file; 337 path += '/'; 338 path += name; 339 file = path.c_str(); 340 } else 341 name = file; 342 343 // stat the file 344 struct fssh_stat st; 345 fssh_status_t error = _kern_read_stat(-1, file, false, &st, sizeof(st)); 346 if (error != FSSH_B_OK) { 347 fprintf(stderr, "Error: Failed to stat() \"%s\": %s\n", file, 348 fssh_strerror(error)); 349 return; 350 } 351 352 // get time 353 struct tm time; 354 time_t fileTime = st.fssh_st_mtime; 355 localtime_r(&fileTime, &time); 356 357 // get permissions 358 std::string permissions; 359 fssh_mode_t mode = st.fssh_st_mode; 360 // user 361 permissions += ((mode & FSSH_S_IRUSR) ? 'r' : '-'); 362 permissions += ((mode & FSSH_S_IWUSR) ? 'w' : '-'); 363 if (mode & FSSH_S_ISUID) 364 permissions += 's'; 365 else 366 permissions += ((mode & FSSH_S_IXUSR) ? 'x' : '-'); 367 // group 368 permissions += ((mode & FSSH_S_IRGRP) ? 'r' : '-'); 369 permissions += ((mode & FSSH_S_IWGRP) ? 'w' : '-'); 370 if (mode & FSSH_S_ISGID) 371 permissions += 's'; 372 else 373 permissions += ((mode & FSSH_S_IXGRP) ? 'x' : '-'); 374 // others 375 permissions += ((mode & FSSH_S_IROTH) ? 'r' : '-'); 376 permissions += ((mode & FSSH_S_IWOTH) ? 'w' : '-'); 377 permissions += ((mode & FSSH_S_IXOTH) ? 'x' : '-'); 378 379 // get file type 380 char fileType = '?'; 381 if (FSSH_S_ISREG(mode)) { 382 fileType = '-'; 383 } else if (FSSH_S_ISLNK(mode)) { 384 fileType = 'l'; 385 } else if (FSSH_S_ISBLK(mode)) { 386 fileType = 'b'; 387 } else if (FSSH_S_ISDIR(mode)) { 388 fileType = 'd'; 389 } else if (FSSH_S_ISCHR(mode)) { 390 fileType = 'c'; 391 } else if (FSSH_S_ISFIFO(mode)) { 392 fileType = 'f'; 393 } else if (FSSH_S_ISINDEX(mode)) { 394 fileType = 'i'; 395 } 396 397 // get link target 398 std::string nameSuffix; 399 if (FSSH_S_ISLNK(mode)) { 400 char buffer[FSSH_B_PATH_NAME_LENGTH]; 401 fssh_size_t size = sizeof(buffer) - 1; 402 error = _kern_read_link(-1, file, buffer, &size); 403 if (error != FSSH_B_OK) 404 snprintf(buffer, sizeof(buffer), "(%s)", fssh_strerror(error)); 405 406 buffer[size] = '\0'; 407 nameSuffix += " -> "; 408 nameSuffix += buffer; 409 } 410 411 printf("%c%s %2d %2d %10" FSSH_B_PRIdOFF 412 " %d-%02d-%02d %02d:%02d:%02d %s%s\n", 413 fileType, permissions.c_str(), (int)st.fssh_st_uid, (int)st.fssh_st_gid, 414 st.fssh_st_size, 415 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday, 416 time.tm_hour, time.tm_min, time.tm_sec, 417 name, nameSuffix.c_str()); 418 } 419 420 421 static fssh_status_t 422 create_dir(const char *path, bool createParents) 423 { 424 // stat the entry 425 struct fssh_stat st; 426 fssh_status_t error = _kern_read_stat(-1, path, false, &st, sizeof(st)); 427 if (error == FSSH_B_OK) { 428 if (createParents && FSSH_S_ISDIR(st.fssh_st_mode)) 429 return FSSH_B_OK; 430 431 fprintf(stderr, "Error: Cannot make dir, entry \"%s\" is in the way.\n", 432 path); 433 return FSSH_B_FILE_EXISTS; 434 } 435 436 // the dir doesn't exist yet 437 // if we shall create all parents, do that first 438 if (createParents) { 439 // create the parent dir path 440 // eat the trailing '/'s 441 int len = strlen(path); 442 while (len > 0 && path[len - 1] == '/') 443 len--; 444 445 // eat the last path component 446 while (len > 0 && path[len - 1] != '/') 447 len--; 448 449 // eat the trailing '/'s 450 while (len > 0 && path[len - 1] == '/') 451 len--; 452 453 // Now either nothing remains, which means we had a single component, 454 // a root subdir -- in those cases we can just fall through (we should 455 // actually never be here in case of the root dir, but anyway) -- or 456 // there is something left, which we can call a parent directory and 457 // try to create it. 458 if (len > 0) { 459 char *parentPath = (char*)malloc(len + 1); 460 if (!parentPath) { 461 fprintf(stderr, "Error: Failed to allocate memory for parent " 462 "path.\n"); 463 return FSSH_B_NO_MEMORY; 464 } 465 memcpy(parentPath, path, len); 466 parentPath[len] = '\0'; 467 468 error = create_dir(parentPath, createParents); 469 470 free(parentPath); 471 472 if (error != FSSH_B_OK) 473 return error; 474 } 475 } 476 477 // make the directory 478 error = _kern_create_dir(-1, 479 path, (FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask); 480 if (error != FSSH_B_OK) { 481 fprintf(stderr, "Error: Failed to make directory \"%s\": %s\n", path, 482 fssh_strerror(error)); 483 return error; 484 } 485 486 return FSSH_B_OK; 487 } 488 489 490 static fssh_status_t remove_entry(int dir, const char *entry, bool recursive, 491 bool force); 492 493 494 static fssh_status_t 495 remove_dir_contents(int parentDir, const char *name, bool force) 496 { 497 // open the dir 498 int dir = _kern_open_dir(parentDir, name); 499 if (dir < 0) { 500 fprintf(stderr, "Error: Failed to open dir \"%s\": %s\n", name, 501 fssh_strerror(dir)); 502 return dir; 503 } 504 505 fssh_status_t error = FSSH_B_OK; 506 507 // iterate through the entries 508 fssh_ssize_t numRead; 509 char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH]; 510 fssh_dirent *entry = (fssh_dirent*)buffer; 511 while ((numRead = _kern_read_dir(dir, entry, sizeof(buffer), 1)) > 0) { 512 // skip "." and ".." 513 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 514 continue; 515 516 error = remove_entry(dir, entry->d_name, true, force); 517 if (error != FSSH_B_OK) 518 break; 519 } 520 521 if (numRead < 0) { 522 fprintf(stderr, "Error: Failed to read directory \"%s\": %s\n", name, 523 fssh_strerror(numRead)); 524 error = numRead; 525 } 526 527 // close 528 _kern_close(dir); 529 530 return error; 531 } 532 533 534 static fssh_status_t 535 remove_entry(int dir, const char *entry, bool recursive, bool force) 536 { 537 // stat the file 538 struct fssh_stat st; 539 fssh_status_t error = _kern_read_stat(dir, entry, false, &st, sizeof(st)); 540 if (error != FSSH_B_OK) { 541 if (force && error == FSSH_B_ENTRY_NOT_FOUND) 542 return FSSH_B_OK; 543 544 fprintf(stderr, "Error: Failed to remove \"%s\": %s\n", entry, 545 fssh_strerror(error)); 546 return error; 547 } 548 549 if (FSSH_S_ISDIR(st.fssh_st_mode)) { 550 if (!recursive) { 551 fprintf(stderr, "Error: \"%s\" is a directory.\n", entry); 552 // TODO: get the full path 553 return FSSH_EISDIR; 554 } 555 556 // remove the contents 557 error = remove_dir_contents(dir, entry, force); 558 if (error != FSSH_B_OK) 559 return error; 560 561 // remove the directory 562 error = _kern_remove_dir(dir, entry); 563 if (error != FSSH_B_OK) { 564 fprintf(stderr, "Error: Failed to remove directory \"%s\": %s\n", 565 entry, fssh_strerror(error)); 566 return error; 567 } 568 } else { 569 // remove the entry 570 error = _kern_unlink(dir, entry); 571 if (error != FSSH_B_OK) { 572 fprintf(stderr, "Error: Failed to remove entry \"%s\": %s\n", entry, 573 fssh_strerror(error)); 574 return error; 575 } 576 } 577 578 return FSSH_B_OK; 579 } 580 581 582 static fssh_status_t 583 move_entry(int dir, const char *entry, int targetDir, const char* target, 584 bool force) 585 { 586 // stat the file 587 struct fssh_stat st; 588 fssh_status_t status = _kern_read_stat(dir, entry, false, &st, sizeof(st)); 589 if (status != FSSH_B_OK) { 590 if (force && status == FSSH_B_ENTRY_NOT_FOUND) 591 return FSSH_B_OK; 592 593 fprintf(stderr, "Error: Failed to move \"%s\": %s\n", entry, 594 fssh_strerror(status)); 595 return status; 596 } 597 598 return _kern_rename(dir, entry, targetDir, target); 599 } 600 601 602 // #pragma mark - Commands 603 604 605 static fssh_status_t 606 command_cd(int argc, const char* const* argv) 607 { 608 if (argc != 2) { 609 fprintf(stderr, "Usage: %s <directory>\n", argv[0]); 610 return FSSH_B_BAD_VALUE; 611 } 612 const char* directory = argv[1]; 613 614 fssh_status_t error = FSSH_B_OK; 615 if (directory[0] == ':') { 616 if (chdir(directory + 1) < 0) 617 error = fssh_get_errno(); 618 } else 619 error = _kern_setcwd(-1, directory); 620 621 if (error != FSSH_B_OK) { 622 fprintf(stderr, "Error: cd %s: %s\n", directory, fssh_strerror(error)); 623 return error; 624 } 625 626 return FSSH_B_OK; 627 } 628 629 630 static fssh_status_t 631 command_chmod(int argc, const char* const* argv) 632 { 633 bool recursive = false; 634 635 // parse parameters 636 int argi = 1; 637 for (argi = 1; argi < argc; argi++) { 638 const char *arg = argv[argi]; 639 if (arg[0] != '-') 640 break; 641 642 if (arg[1] == '\0') { 643 fprintf(stderr, "Error: Invalid option \"-\"\n"); 644 return FSSH_B_BAD_VALUE; 645 } 646 647 for (int i = 1; arg[i]; i++) { 648 switch (arg[i]) { 649 case 'R': 650 recursive = true; 651 fprintf(stderr, "Sorry, recursive mode not supported " 652 "yet.\n"); 653 return FSSH_B_BAD_VALUE; 654 default: 655 fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); 656 return FSSH_B_BAD_VALUE; 657 } 658 } 659 } 660 661 // get mode 662 fssh_mode_t permissions; 663 if (argi + 1 >= argc || !get_permissions(argv[argi++], permissions)) { 664 printf("Usage: %s [ -R ] <octal mode> <file>...\n", argv[0]); 665 return FSSH_B_BAD_VALUE; 666 } 667 668 fssh_struct_stat st; 669 st.fssh_st_mode = permissions; 670 671 // chmod loop 672 for (; argi < argc; argi++) { 673 const char *file = argv[argi]; 674 if (strlen(file) == 0) { 675 fprintf(stderr, "Error: An empty path is not a valid argument!\n"); 676 return FSSH_B_BAD_VALUE; 677 } 678 679 fssh_status_t error = _kern_write_stat(-1, file, false, &st, sizeof(st), 680 FSSH_B_STAT_MODE); 681 if (error != FSSH_B_OK) { 682 fprintf(stderr, "Error: Failed to change mode of \"%s\"!\n", file); 683 return error; 684 } 685 } 686 687 return FSSH_B_OK; 688 } 689 690 691 static fssh_status_t 692 command_cat(int argc, const char* const* argv) 693 { 694 size_t numBytes = 10; 695 int fileStart = 1; 696 if (argc < 2 || strcmp(argv[1], "--help") == 0) { 697 printf("Usage: %s [ -n ] [FILE]...\n" 698 "\t -n\tNumber of bytes to read\n", 699 argv[0]); 700 return FSSH_B_OK; 701 } 702 703 if (argc > 3 && strcmp(argv[1], "-n") == 0) { 704 fileStart += 2; 705 numBytes = strtol(argv[2], NULL, 10); 706 } 707 708 const char* const* files = argv + fileStart; 709 for (; *files; files++) { 710 const char* file = *files; 711 int fd = _kern_open(-1, file, FSSH_O_RDONLY, FSSH_O_RDONLY); 712 if (fd < 0) { 713 fprintf(stderr, "error: %s\n", fssh_strerror(fd)); 714 return FSSH_B_BAD_VALUE; 715 } 716 717 char buffer[numBytes + 1]; 718 if (buffer == NULL) { 719 fprintf(stderr, "error: No memory\n"); 720 _kern_close(fd); 721 return FSSH_B_NO_MEMORY; 722 } 723 724 if (_kern_read(fd, 0, buffer, numBytes) != (ssize_t)numBytes) { 725 fprintf(stderr, "error reading: %s\n", fssh_strerror(fd)); 726 _kern_close(fd); 727 return FSSH_B_BAD_VALUE; 728 } 729 730 _kern_close(fd); 731 buffer[numBytes] = '\0'; 732 printf("%s\n", buffer); 733 } 734 735 return FSSH_B_OK; 736 } 737 738 739 static fssh_status_t 740 command_help(int argc, const char* const* argv) 741 { 742 printf("supported commands:\n"); 743 CommandManager::Default()->ListCommands(); 744 return FSSH_B_OK; 745 } 746 747 748 static fssh_status_t 749 command_info(int argc, const char* const* argv) 750 { 751 fssh_dev_t volumeID = get_volume_id(); 752 if (volumeID < 0) 753 return volumeID; 754 755 fssh_fs_info info; 756 fssh_status_t status = _kern_read_fs_info(volumeID, &info); 757 if (status != FSSH_B_OK) 758 return status; 759 760 printf("root inode: %" FSSH_B_PRIdINO "\n", info.root); 761 printf("flags: "); 762 print_flag(info.flags, FSSH_B_FS_HAS_QUERY, "Q", "-"); 763 print_flag(info.flags, FSSH_B_FS_HAS_ATTR, "A", "-"); 764 print_flag(info.flags, FSSH_B_FS_HAS_MIME, "M", "-"); 765 print_flag(info.flags, FSSH_B_FS_IS_SHARED, "S", "-"); 766 print_flag(info.flags, FSSH_B_FS_IS_PERSISTENT, "P", "-"); 767 print_flag(info.flags, FSSH_B_FS_IS_REMOVABLE, "R", "-"); 768 print_flag(info.flags, FSSH_B_FS_IS_READONLY, "-", "W"); 769 770 printf("\nblock size: %" FSSH_B_PRIdOFF "\n", info.block_size); 771 printf("I/O size: %" FSSH_B_PRIdOFF "\n", info.io_size); 772 printf("total size: %s (%" FSSH_B_PRIdOFF " blocks)\n", 773 byte_string(info.total_blocks, info.block_size), info.total_blocks); 774 printf("free size: %s (%" FSSH_B_PRIdOFF " blocks)\n", 775 byte_string(info.free_blocks, info.block_size), info.free_blocks); 776 printf("total nodes: %" FSSH_B_PRIdOFF "\n", info.total_nodes); 777 printf("free nodes: %" FSSH_B_PRIdOFF "\n", info.free_nodes); 778 printf("volume name: %s\n", info.volume_name); 779 printf("fs name: %s\n", info.fsh_name); 780 781 return FSSH_B_OK; 782 } 783 784 785 static fssh_status_t 786 command_ln(int argc, const char* const* argv) 787 { 788 bool force = false; 789 bool symbolic = false; 790 bool dereference = true; 791 792 // parse parameters 793 int argi = 1; 794 for (argi = 1; argi < argc; argi++) { 795 const char *arg = argv[argi]; 796 if (arg[0] != '-') 797 break; 798 799 if (arg[1] == '\0') { 800 fprintf(stderr, "Error: Invalid option \"-\"\n"); 801 return FSSH_B_BAD_VALUE; 802 } 803 804 for (int i = 1; arg[i]; i++) { 805 switch (arg[i]) { 806 case 'f': 807 force = true; 808 break; 809 case 's': 810 symbolic = true; 811 break; 812 case 'n': 813 dereference = false; 814 break; 815 default: 816 fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); 817 return FSSH_B_BAD_VALUE; 818 } 819 } 820 } 821 822 if (argc - argi != 2) { 823 fprintf(stderr, "Usage: %s [Options] <source> <target>\n", argv[0]); 824 return FSSH_B_BAD_VALUE; 825 } 826 827 const char *source = argv[argi]; 828 const char *target = argv[argi + 1]; 829 830 // check, if the the target is an existing directory 831 struct fssh_stat st; 832 char targetBuffer[FSSH_B_PATH_NAME_LENGTH]; 833 fssh_status_t error = _kern_read_stat(-1, target, dereference, &st, 834 sizeof(st)); 835 if (error == FSSH_B_OK) { 836 if (FSSH_S_ISDIR(st.fssh_st_mode)) { 837 // get source leaf 838 char leaf[FSSH_B_FILE_NAME_LENGTH]; 839 error = get_last_path_component(source, leaf, sizeof(leaf)); 840 if (error != FSSH_B_OK) { 841 fprintf(stderr, "Error: Failed to get leaf name of source " 842 "path: %s\n", fssh_strerror(error)); 843 return error; 844 } 845 846 // compose a new path 847 int len = strlen(target) + 1 + strlen(leaf); 848 if (len > (int)sizeof(targetBuffer)) { 849 fprintf(stderr, "Error: Resulting target path is too long.\n"); 850 return FSSH_B_BAD_VALUE; 851 } 852 853 strcpy(targetBuffer, target); 854 strcat(targetBuffer, "/"); 855 strcat(targetBuffer, leaf); 856 target = targetBuffer; 857 } 858 } 859 860 // check, if the target exists 861 error = _kern_read_stat(-1, target, false, &st, sizeof(st)); 862 if (error == FSSH_B_OK) { 863 if (!force) { 864 fprintf(stderr, "Error: Can't create link. \"%s\" is in the way.\n", 865 target); 866 return FSSH_B_FILE_EXISTS; 867 } 868 869 // unlink the entry 870 error = _kern_unlink(-1, target); 871 if (error != FSSH_B_OK) { 872 fprintf(stderr, "Error: Failed to remove \"%s\" to make way for " 873 "link: %s\n", target, fssh_strerror(error)); 874 return error; 875 } 876 } 877 878 // finally create the link 879 if (symbolic) { 880 error = _kern_create_symlink(-1, target, source, 881 FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO); 882 } else 883 error = _kern_create_link(target, source); 884 885 if (error != FSSH_B_OK) { 886 fprintf(stderr, "Error: Failed to create link: %s\n", 887 fssh_strerror(error)); 888 } 889 890 return error; 891 } 892 893 894 static fssh_status_t 895 command_ls(int argc, const char* const* argv) 896 { 897 const char* const currentDirFiles[] = { ".", NULL }; 898 const char* const* files; 899 if (argc >= 2) 900 files = argv + 1; 901 else 902 files = currentDirFiles; 903 904 for (; *files; files++) { 905 const char* file = *files; 906 // stat file 907 struct fssh_stat st; 908 fssh_status_t error = _kern_read_stat(-1, file, false, &st, sizeof(st)); 909 if (error != FSSH_B_OK) { 910 fprintf(stderr, "Error: Failed to stat() \"%s\": %s\n", file, 911 fssh_strerror(error)); 912 continue; 913 } 914 915 // if it is a directory, print its entries 916 if (FSSH_S_ISDIR(st.fssh_st_mode)) { 917 printf("%s:\n", file); 918 919 // open dir 920 int fd = _kern_open_dir(-1, file); 921 if (fd < 0) { 922 fprintf(stderr, "Error: Failed to open dir \"%s\": %s\n", 923 file, fssh_strerror(fd)); 924 continue; 925 } 926 927 // iterate through the entries 928 char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH]; 929 fssh_dirent* entry = (fssh_dirent*)buffer; 930 fssh_ssize_t entriesRead = 0; 931 while ((entriesRead = _kern_read_dir(fd, entry, sizeof(buffer), 1)) 932 == 1) { 933 list_entry(file, entry->d_name); 934 } 935 936 if (entriesRead < 0) { 937 fprintf(stderr, "Error: reading dir \"%s\" failed: %s\n", 938 file, fssh_strerror(entriesRead)); 939 } 940 941 // close dir 942 error = _kern_close(fd); 943 if (error != FSSH_B_OK) { 944 fprintf(stderr, "Error: Closing dir \"%s\" (fd: %d) failed: " 945 "%s\n", file, fd, fssh_strerror(error)); 946 continue; 947 } 948 } else 949 list_entry(file); 950 } 951 952 return FSSH_B_OK; 953 } 954 955 956 static fssh_status_t 957 command_mkdir(int argc, const char* const* argv) 958 { 959 bool createParents = false; 960 961 // parse parameters 962 int argi = 1; 963 for (argi = 1; argi < argc; argi++) { 964 const char *arg = argv[argi]; 965 if (arg[0] != '-') 966 break; 967 968 if (arg[1] == '\0') { 969 fprintf(stderr, "Error: Invalid option \"-\"\n"); 970 return FSSH_B_BAD_VALUE; 971 } 972 973 for (int i = 1; arg[i]; i++) { 974 switch (arg[i]) { 975 case 'p': 976 createParents = true; 977 break; 978 default: 979 fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); 980 return FSSH_B_BAD_VALUE; 981 } 982 } 983 } 984 985 if (argi >= argc) { 986 printf("Usage: %s [ -p ] <dir>...\n", argv[0]); 987 return FSSH_B_BAD_VALUE; 988 } 989 990 // create loop 991 for (; argi < argc; argi++) { 992 const char *dir = argv[argi]; 993 if (strlen(dir) == 0) { 994 fprintf(stderr, "Error: An empty path is not a valid argument!\n"); 995 return FSSH_B_BAD_VALUE; 996 } 997 998 fssh_status_t error = create_dir(dir, createParents); 999 if (error != FSSH_B_OK) 1000 return error; 1001 } 1002 1003 return FSSH_B_OK; 1004 } 1005 1006 1007 static fssh_status_t 1008 command_mkindex(int argc, const char* const* argv) 1009 { 1010 if (argc != 2) { 1011 fprintf(stderr, "Usage: %s <index name>\n", argv[0]); 1012 return FSSH_B_BAD_VALUE; 1013 } 1014 1015 const char* indexName = argv[1]; 1016 1017 // get the volume ID 1018 fssh_dev_t volumeID = get_volume_id(); 1019 if (volumeID < 0) 1020 return volumeID; 1021 1022 // create the index 1023 fssh_status_t error =_kern_create_index(volumeID, indexName, 1024 FSSH_B_STRING_TYPE, 0); 1025 if (error != FSSH_B_OK) { 1026 fprintf(stderr, "Error: Failed to create index \"%s\": %s\n", 1027 indexName, fssh_strerror(error)); 1028 return error; 1029 } 1030 1031 return FSSH_B_OK; 1032 } 1033 1034 1035 static fssh_status_t 1036 command_mv(int argc, const char* const* argv) 1037 { 1038 bool force = false; 1039 1040 // parse parameters 1041 int argi = 1; 1042 for (argi = 1; argi < argc; argi++) { 1043 const char *arg = argv[argi]; 1044 if (arg[0] != '-') 1045 break; 1046 1047 if (arg[1] == '\0') { 1048 fprintf(stderr, "Error: Invalid option \"-\"\n"); 1049 return FSSH_B_BAD_VALUE; 1050 } 1051 1052 for (int i = 1; arg[i]; i++) { 1053 switch (arg[i]) { 1054 case 'f': 1055 force = true; 1056 break; 1057 default: 1058 fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); 1059 return FSSH_B_BAD_VALUE; 1060 } 1061 } 1062 } 1063 1064 // check params 1065 int count = argc - 1 - argi; 1066 if (count <= 0) { 1067 fprintf(stderr, "Usage: %s [-f] <file>... <target>\n", argv[0]); 1068 return FSSH_B_BAD_VALUE; 1069 } 1070 1071 const char* target = argv[argc - 1]; 1072 1073 // stat the target 1074 struct fssh_stat st; 1075 fssh_status_t status = _kern_read_stat(-1, target, true, &st, sizeof(st)); 1076 if (status != FSSH_B_OK && count != 1) { 1077 fprintf(stderr, "Error: Failed to stat target \"%s\": %s\n", target, 1078 fssh_strerror(status)); 1079 return status; 1080 } 1081 1082 if (status == FSSH_B_OK && FSSH_S_ISDIR(st.fssh_st_mode)) { 1083 // move several entries 1084 int targetDir = _kern_open_dir(-1, target); 1085 if (targetDir < 0) { 1086 fprintf(stderr, "Error: Failed to open dir \"%s\": %s\n", target, 1087 fssh_strerror(targetDir)); 1088 return targetDir; 1089 } 1090 1091 // move loop 1092 for (; argi < argc - 1; argi++) { 1093 status = move_entry(-1, argv[argi], targetDir, argv[argi], force); 1094 if (status != FSSH_B_OK) { 1095 _kern_close(targetDir); 1096 return status; 1097 } 1098 } 1099 1100 _kern_close(targetDir); 1101 return FSSH_B_OK; 1102 } 1103 1104 // rename single entry 1105 return move_entry(-1, argv[argi], -1, target, force); 1106 } 1107 1108 1109 static fssh_status_t 1110 command_query(int argc, const char* const* argv) 1111 { 1112 if (argc != 2) { 1113 fprintf(stderr, "Usage: %s <query string>\n", argv[0]); 1114 return FSSH_B_BAD_VALUE; 1115 } 1116 1117 const char* query = argv[1]; 1118 1119 // get the volume ID 1120 fssh_dev_t volumeID = get_volume_id(); 1121 if (volumeID < 0) 1122 return volumeID; 1123 1124 // open query 1125 int fd = _kern_open_query(volumeID, query, strlen(query), 0, -1, -1); 1126 if (fd < 0) { 1127 fprintf(stderr, "Error: Failed to open query: %s\n", fssh_strerror(fd)); 1128 return fd; 1129 } 1130 1131 // iterate through the entries 1132 fssh_status_t error = FSSH_B_OK; 1133 char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH]; 1134 fssh_dirent* entry = (fssh_dirent*)buffer; 1135 fssh_ssize_t entriesRead = 0; 1136 while ((entriesRead = _kern_read_dir(fd, entry, sizeof(buffer), 1)) == 1) { 1137 char path[FSSH_B_PATH_NAME_LENGTH]; 1138 error = _kern_entry_ref_to_path(volumeID, entry->d_pino, entry->d_name, 1139 path, sizeof(path)); 1140 if (error == FSSH_B_OK) { 1141 printf(" %s\n", path); 1142 } else { 1143 fprintf(stderr, " failed to resolve entry (%8" FSSH_B_PRIdINO 1144 ", \"%s\")\n", entry->d_pino, entry->d_name); 1145 } 1146 } 1147 1148 if (entriesRead < 0) { 1149 fprintf(stderr, "Error: reading query failed: %s\n", 1150 fssh_strerror(entriesRead)); 1151 } 1152 1153 // close query 1154 error = _kern_close(fd); 1155 if (error != FSSH_B_OK) { 1156 fprintf(stderr, "Error: Closing query (fd: %d) failed: %s\n", 1157 fd, fssh_strerror(error)); 1158 } 1159 1160 return error; 1161 } 1162 1163 1164 static fssh_status_t 1165 command_quit(int argc, const char* const* argv) 1166 { 1167 return COMMAND_RESULT_EXIT; 1168 } 1169 1170 1171 static fssh_status_t 1172 command_rm(int argc, const char* const* argv) 1173 { 1174 bool recursive = false; 1175 bool force = false; 1176 1177 // parse parameters 1178 int argi = 1; 1179 for (argi = 1; argi < argc; argi++) { 1180 const char *arg = argv[argi]; 1181 if (arg[0] != '-') 1182 break; 1183 1184 if (arg[1] == '\0') { 1185 fprintf(stderr, "Error: Invalid option \"-\"\n"); 1186 return FSSH_B_BAD_VALUE; 1187 } 1188 1189 for (int i = 1; arg[i]; i++) { 1190 switch (arg[i]) { 1191 case 'f': 1192 force = true; 1193 break; 1194 case 'r': 1195 recursive = true; 1196 break; 1197 default: 1198 fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); 1199 return FSSH_B_BAD_VALUE; 1200 } 1201 } 1202 } 1203 1204 // check params 1205 if (argi >= argc) { 1206 fprintf(stderr, "Usage: %s [ -r ] <file>...\n", argv[0]); 1207 return FSSH_B_BAD_VALUE; 1208 } 1209 1210 // remove loop 1211 for (; argi < argc; argi++) { 1212 fssh_status_t error = remove_entry(-1, argv[argi], recursive, force); 1213 if (error != FSSH_B_OK) 1214 return error; 1215 } 1216 1217 return FSSH_B_OK; 1218 } 1219 1220 1221 static fssh_status_t 1222 command_sync(int argc, const char* const* argv) 1223 { 1224 fssh_status_t error = _kern_sync(); 1225 if (error != FSSH_B_OK) { 1226 fprintf(stderr, "Error: syncing: %s\n", fssh_strerror(error)); 1227 return error; 1228 } 1229 1230 return FSSH_B_OK; 1231 } 1232 1233 1234 static fssh_status_t 1235 command_ioctl(int argc, const char* const* argv) 1236 { 1237 if (argc != 2) { 1238 fprintf(stderr, "Usage: %s <opcode>\n", argv[0]); 1239 return FSSH_B_BAD_VALUE; 1240 } 1241 1242 int rootDir = _kern_open_dir(-1, "/myfs"); 1243 if (rootDir < 0) 1244 return rootDir; 1245 1246 fssh_status_t status = _kern_ioctl(rootDir, atoi(argv[1]), NULL, 0); 1247 1248 _kern_close(rootDir); 1249 1250 if (status != FSSH_B_OK) { 1251 fprintf(stderr, "Error: ioctl failed: %s\n", fssh_strerror(status)); 1252 return status; 1253 } 1254 1255 return FSSH_B_OK; 1256 } 1257 1258 1259 static void 1260 register_commands() 1261 { 1262 CommandManager::Default()->AddCommands( 1263 command_cd, "cd", "change current directory", 1264 command_chmod, "chmod", "change file permissions", 1265 command_cp, "cp", "copy files and directories", 1266 command_cat, "cat", "concatenate file(s) to stdout", 1267 command_help, "help", "list supported commands", 1268 command_info, "info", "prints volume informations", 1269 command_ioctl, "ioctl", "ioctl() on root, for FS debugging only", 1270 command_ln, "ln", "create a hard or symbolic link", 1271 command_ls, "ls", "list files or directories", 1272 command_mkdir, "mkdir", "create directories", 1273 command_mkindex, "mkindex", "create an index", 1274 command_mv, "mv", "move/rename files and directories", 1275 command_query, "query", "query for files", 1276 command_quit, "quit/exit", "quit the shell", 1277 command_rm, "rm", "remove files and directories", 1278 command_sync, "sync", "syncs the file system", 1279 NULL 1280 ); 1281 } 1282 1283 1284 // #pragma mark - ArgVector 1285 1286 1287 class ArgVector { 1288 public: 1289 ArgVector() 1290 : fArgc(0), 1291 fArgv(NULL) 1292 { 1293 } 1294 1295 ~ArgVector() 1296 { 1297 _Cleanup(); 1298 } 1299 1300 int Argc() const 1301 { 1302 return fArgc; 1303 } 1304 1305 const char* const* Argv() const 1306 { 1307 return fArgv; 1308 } 1309 1310 bool Parse(const char* commandLine) 1311 { 1312 _Cleanup(); 1313 1314 // init temporary arg/argv storage 1315 std::string currentArg; 1316 std::vector<std::string> argVector; 1317 1318 fCurrentArg = ¤tArg; 1319 fCurrentArgStarted = false; 1320 fArgVector = &argVector; 1321 1322 for (; *commandLine; commandLine++) { 1323 char c = *commandLine; 1324 1325 // whitespace delimits args and is otherwise ignored 1326 if (isspace(c)) { 1327 _PushCurrentArg(); 1328 continue; 1329 } 1330 1331 switch (c) { 1332 case '\'': 1333 // quoted string -- no quoting 1334 while (*++commandLine != '\'') { 1335 c = *commandLine; 1336 if (c == '\0') { 1337 fprintf(stderr, "Error: Unterminated quoted " 1338 "string.\n"); 1339 return false; 1340 } 1341 _PushCharacter(c); 1342 } 1343 break; 1344 1345 case '"': 1346 // quoted string -- some quoting 1347 while (*++commandLine != '"') { 1348 c = *commandLine; 1349 if (c == '\0') { 1350 fprintf(stderr, "Error: Unterminated quoted " 1351 "string.\n"); 1352 return false; 1353 } 1354 1355 if (c == '\\') { 1356 c = *++commandLine; 1357 if (c == '\0') { 1358 fprintf(stderr, "Error: Unterminated quoted " 1359 "string.\n"); 1360 return false; 1361 } 1362 1363 // only '\' and '"' can be quoted, otherwise the 1364 // the '\' is treated as a normal char 1365 if (c != '\\' && c != '"') 1366 _PushCharacter('\\'); 1367 } 1368 1369 _PushCharacter(c); 1370 } 1371 break; 1372 1373 case '\\': 1374 // quoted char 1375 c = *++commandLine; 1376 if (c == '\0') { 1377 fprintf(stderr, "Error: Command line ends with " 1378 "'\\'.\n"); 1379 return false; 1380 } 1381 _PushCharacter(c); 1382 break; 1383 1384 default: 1385 // normal char 1386 _PushCharacter(c); 1387 break; 1388 } 1389 } 1390 1391 // commit last arg 1392 _PushCurrentArg(); 1393 1394 // build arg vector 1395 fArgc = argVector.size(); 1396 fArgv = new char*[fArgc + 1]; 1397 for (int i = 0; i < fArgc; i++) { 1398 int len = argVector[i].length(); 1399 fArgv[i] = new char[len + 1]; 1400 memcpy(fArgv[i], argVector[i].c_str(), len + 1); 1401 } 1402 fArgv[fArgc] = NULL; 1403 1404 return true; 1405 } 1406 1407 private: 1408 void _Cleanup() 1409 { 1410 if (fArgv) { 1411 for (int i = 0; i < fArgc; i++) 1412 delete[] fArgv[i]; 1413 delete[] fArgv; 1414 } 1415 } 1416 1417 void _PushCurrentArg() 1418 { 1419 if (fCurrentArgStarted) { 1420 fArgVector->push_back(*fCurrentArg); 1421 fCurrentArgStarted = false; 1422 } 1423 } 1424 1425 void _PushCharacter(char c) 1426 { 1427 if (!fCurrentArgStarted) { 1428 *fCurrentArg = ""; 1429 fCurrentArgStarted = true; 1430 } 1431 1432 *fCurrentArg += c; 1433 } 1434 1435 private: 1436 // temporaries 1437 std::string* fCurrentArg; 1438 bool fCurrentArgStarted; 1439 std::vector<std::string>* fArgVector; 1440 1441 int fArgc; 1442 char** fArgv; 1443 }; 1444 1445 1446 // #pragma mark - input loop 1447 1448 1449 static char* 1450 read_command_line(char* buffer, int bufferSize) 1451 { 1452 // print prompt (including cwd, if available) 1453 char directory[FSSH_B_PATH_NAME_LENGTH]; 1454 if (_kern_getcwd(directory, sizeof(directory)) == FSSH_B_OK) 1455 printf("fssh:%s> ", directory); 1456 else 1457 printf("fssh> "); 1458 fflush(stdout); 1459 1460 // read input line 1461 return fgets(buffer, bufferSize, stdin); 1462 } 1463 1464 1465 static void 1466 input_loop(bool interactive) 1467 { 1468 static const int kInputBufferSize = 100 * 1024; 1469 char* inputBuffer = new char[kInputBufferSize]; 1470 1471 for (;;) { 1472 // read command line 1473 if (interactive) { 1474 if (!read_command_line(inputBuffer, kInputBufferSize)) 1475 break; 1476 } else { 1477 if (!get_external_command(inputBuffer, kInputBufferSize)) 1478 break; 1479 } 1480 1481 // construct argv vector 1482 int result = FSSH_B_BAD_VALUE; 1483 ArgVector argVector; 1484 if (argVector.Parse(inputBuffer) && argVector.Argc() > 0) { 1485 int argc = argVector.Argc(); 1486 const char* const* argv = argVector.Argv(); 1487 1488 // find command 1489 Command* command = CommandManager::Default()->FindCommand(argv[0]); 1490 if (command) { 1491 // execute it 1492 result = command->Do(argc, argv); 1493 if (result == COMMAND_RESULT_EXIT) { 1494 if (!interactive) 1495 reply_to_external_command(0); 1496 break; 1497 } 1498 } else { 1499 fprintf(stderr, "Error: Invalid command \"%s\". Type \"help\" " 1500 "for a list of supported commands\n", argv[0]); 1501 } 1502 } 1503 1504 if (!interactive) 1505 reply_to_external_command(fssh_to_host_error(result)); 1506 } 1507 1508 if (!interactive) 1509 external_command_cleanup(); 1510 1511 delete[] inputBuffer; 1512 } 1513 1514 1515 static int 1516 standard_session(const char* device, const char* fsName, bool interactive) 1517 { 1518 // mount FS 1519 fssh_dev_t fsDev = _kern_mount(kMountPoint, device, fsName, 0, NULL, 0); 1520 if (fsDev < 0) { 1521 fprintf(stderr, "Error: Mounting FS failed: %s\n", 1522 fssh_strerror(fsDev)); 1523 return 1; 1524 } 1525 1526 // register commands 1527 register_commands(); 1528 register_additional_commands(); 1529 1530 // process commands 1531 input_loop(interactive); 1532 1533 // unmount FS 1534 _kern_setcwd(-1, "/"); // avoid a "busy" vnode 1535 fssh_status_t error = _kern_unmount(kMountPoint, 0); 1536 if (error != FSSH_B_OK) { 1537 fprintf(stderr, "Error: Unmounting FS failed: %s\n", 1538 fssh_strerror(error)); 1539 return 1; 1540 } 1541 1542 return 0; 1543 } 1544 1545 1546 static int 1547 initialization_session(const char* device, const char* fsName, 1548 const char* volumeName, const char* initParameters) 1549 { 1550 fssh_status_t error = _kern_initialize_volume(fsName, device, 1551 volumeName, initParameters); 1552 if (error != FSSH_B_OK) { 1553 fprintf(stderr, "Error: Initializing volume failed: %s\n", 1554 fssh_strerror(error)); 1555 return 1; 1556 } 1557 1558 return 0; 1559 } 1560 1561 1562 static void 1563 print_usage(bool error) 1564 { 1565 fprintf((error ? stderr : stdout), 1566 "Usage: %s [ --start-offset <startOffset>]\n" 1567 " [ --end-offset <endOffset>] [-n] <device>\n" 1568 " %s [ --start-offset <startOffset>]\n" 1569 " [ --end-offset <endOffset>]\n" 1570 " --initialize [-n] <device> <volume name> " 1571 "[ <init parameters> ]\n", 1572 sArgv[0], sArgv[0] 1573 ); 1574 } 1575 1576 1577 static void 1578 print_usage_and_exit(bool error) 1579 { 1580 print_usage(error); 1581 exit(error ? 1 : 0); 1582 } 1583 1584 1585 } // namespace FSShell 1586 1587 1588 using namespace FSShell; 1589 1590 1591 int 1592 main(int argc, const char* const* argv) 1593 { 1594 sArgc = argc; 1595 sArgv = argv; 1596 1597 // process arguments 1598 bool interactive = true; 1599 bool initialize = false; 1600 const char* device = NULL; 1601 const char* volumeName = NULL; 1602 const char* initParameters = NULL; 1603 fssh_off_t startOffset = 0; 1604 fssh_off_t endOffset = -1; 1605 1606 // eat options 1607 int argi = 1; 1608 while (argi < argc && argv[argi][0] == '-') { 1609 const char* arg = argv[argi++]; 1610 if (strcmp(arg, "--help") == 0) { 1611 print_usage_and_exit(false); 1612 } else if (strcmp(arg, "--initialize") == 0) { 1613 initialize = true; 1614 } else if (strcmp(arg, "-n") == 0) { 1615 interactive = false; 1616 } else if (strcmp(arg, "--start-offset") == 0) { 1617 if (argi >= argc) 1618 print_usage_and_exit(true); 1619 startOffset = atoll(argv[argi++]); 1620 } else if (strcmp(arg, "--end-offset") == 0) { 1621 if (argi >= argc) 1622 print_usage_and_exit(true); 1623 endOffset = atoll(argv[argi++]); 1624 } else { 1625 print_usage_and_exit(true); 1626 } 1627 } 1628 1629 // get device 1630 if (argi >= argc) 1631 print_usage_and_exit(true); 1632 device = argv[argi++]; 1633 1634 // get volume name and init parameters 1635 if (initialize) { 1636 // volume name 1637 if (argi >= argc) 1638 print_usage_and_exit(true); 1639 volumeName = argv[argi++]; 1640 1641 // (optional) init paramaters 1642 if (argi < argc) 1643 initParameters = argv[argi++]; 1644 } 1645 1646 // more parameters are excess 1647 if (argi < argc) 1648 print_usage_and_exit(true); 1649 1650 // get FS module 1651 if (!modules[0]) { 1652 fprintf(stderr, "Error: Couldn't find FS module!\n"); 1653 return 1; 1654 } 1655 const char* fsName = modules[0]->name; 1656 1657 fssh_status_t error; 1658 1659 // init kernel 1660 error = init_kernel(); 1661 if (error != FSSH_B_OK) { 1662 fprintf(stderr, "Error: Initializing kernel failed: %s\n", 1663 fssh_strerror(error)); 1664 return error; 1665 } 1666 1667 // restrict access if requested 1668 if (startOffset != 0 || endOffset != -1) 1669 add_file_restriction(device, startOffset, endOffset); 1670 1671 // start the action 1672 int result; 1673 if (initialize) { 1674 result = initialization_session(device, fsName, volumeName, 1675 initParameters); 1676 } else 1677 result = standard_session(device, fsName, interactive); 1678 1679 return result; 1680 } 1681