Changeset 37403 in vbox
- Timestamp:
- Jun 10, 2011 8:05:58 AM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 72200
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp
r37340 r37403 46 46 #define CAT_OPT_NO_CONTENT_INDEXED 1000 47 47 48 #define LS_OPT_MACHINE_READABLE 1000 49 48 50 /* Enable the following define to be able to debug/invoke the toolbox 49 51 * commandos directly from command line, e.g. VBoxService vbox_cat [args] */ … … 64 66 } VBOXSERVICETOOLBOXPATHENTRY, *PVBOXSERVICETOOLBOXPATHENTRY; 65 67 68 typedef struct VBOXSERVICETOOLBOXDIRENTRY 69 { 70 /** Our node. */ 71 RTLISTNODE Node; 72 /** The actual entry. */ 73 RTDIRENTRYEX dirEntry; 74 } VBOXSERVICETOOLBOXDIRENTRY, *PVBOXSERVICETOOLBOXDIRENTRY; 75 66 76 67 77 /** … … 72 82 RTPrintf("Toolbox Usage:\n" 73 83 "cat [FILE] - Concatenate FILE(s), or standard input, to standard output.\n" 84 "\n" 85 /** @todo Document options! */ 86 "ls [OPTION]... FILE... - List information about the FILEs (the current directory by default).\n" 74 87 "\n" 75 88 /** @todo Document options! */ … … 216 229 217 230 /** 231 * Main function for tool "vbox_cat". 232 * 233 * @return RTEXITCODE. 234 * @param argc Number of arguments. 235 * @param argv Pointer to argument array. 236 */ 237 static RTEXITCODE VBoxServiceToolboxCat(int argc, char **argv) 238 { 239 static const RTGETOPTDEF s_aOptions[] = 240 { 241 /* Sorted by short ops. */ 242 { "--show-all", 'a', RTGETOPT_REQ_NOTHING }, 243 { "--number-nonblank", 'b', RTGETOPT_REQ_NOTHING}, 244 { NULL, 'e', RTGETOPT_REQ_NOTHING}, 245 { NULL, 'E', RTGETOPT_REQ_NOTHING}, 246 { "--flags", 'f', RTGETOPT_REQ_STRING}, 247 { "--no-content-indexed", CAT_OPT_NO_CONTENT_INDEXED, RTGETOPT_REQ_NOTHING}, 248 { "--number", 'n', RTGETOPT_REQ_NOTHING}, 249 { "--output", 'o', RTGETOPT_REQ_STRING}, 250 { "--squeeze-blank", 's', RTGETOPT_REQ_NOTHING}, 251 { NULL, 't', RTGETOPT_REQ_NOTHING}, 252 { "--show-tabs", 'T', RTGETOPT_REQ_NOTHING}, 253 { NULL, 'u', RTGETOPT_REQ_NOTHING}, 254 { "--show-noneprinting", 'v', RTGETOPT_REQ_NOTHING} 255 }; 256 257 int ch; 258 RTGETOPTUNION ValueUnion; 259 RTGETOPTSTATE GetState; 260 261 RTGetOptInit(&GetState, argc, argv, 262 s_aOptions, RT_ELEMENTS(s_aOptions), 263 /* Index of argv to start with. */ 264 #ifdef VBOXSERVICE_TOOLBOX_DEBUG 265 2, 266 #else 267 1, 268 #endif 269 0); 270 271 int rc = VINF_SUCCESS; 272 bool fUsageOK = true; 273 274 char szOutput[RTPATH_MAX] = { 0 }; 275 RTFILE hOutput = NIL_RTFILE; 276 uint32_t fFlags = RTFILE_O_CREATE_REPLACE /* Output file flags. */ 277 | RTFILE_O_WRITE 278 | RTFILE_O_DENY_WRITE; 279 280 /* Init directory list. */ 281 RTLISTNODE inputList; 282 RTListInit(&inputList); 283 284 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 285 && RT_SUCCESS(rc)) 286 { 287 /* For options that require an argument, ValueUnion has received the value. */ 288 switch (ch) 289 { 290 case 'a': 291 case 'b': 292 case 'e': 293 case 'E': 294 case 'n': 295 case 's': 296 case 't': 297 case 'T': 298 case 'v': 299 RTMsgError("cat: Sorry, option '%s' is not implemented yet!\n", 300 ValueUnion.pDef->pszLong); 301 rc = VERR_INVALID_PARAMETER; 302 break; 303 304 case 'h': 305 VBoxServiceToolboxShowUsage(); 306 return RTEXITCODE_SUCCESS; 307 308 case 'o': 309 if (!RTStrPrintf(szOutput, sizeof(szOutput), ValueUnion.psz)) 310 rc = VERR_NO_MEMORY; 311 break; 312 313 case 'u': 314 /* Ignored. */ 315 break; 316 317 case 'V': 318 VBoxServiceToolboxShowVersion(); 319 return RTEXITCODE_SUCCESS; 320 321 case CAT_OPT_NO_CONTENT_INDEXED: 322 fFlags |= RTFILE_O_NOT_CONTENT_INDEXED; 323 break; 324 325 case VINF_GETOPT_NOT_OPTION: 326 { 327 /* Add file(s) to buffer. This enables processing multiple paths 328 * at once. 329 * 330 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when 331 * processing this loop it's safe to immediately exit on syntax errors 332 * or showing the help text (see above). */ 333 rc = VBoxServiceToolboxPathBufAddPathEntry(&inputList, ValueUnion.psz); 334 break; 335 } 336 337 default: 338 return RTGetOptPrintError(ch, &ValueUnion); 339 } 340 } 341 342 if (RT_SUCCESS(rc)) 343 { 344 if (strlen(szOutput)) 345 { 346 rc = RTFileOpen(&hOutput, szOutput, fFlags); 347 if (RT_FAILURE(rc)) 348 RTMsgError("cat: Could not create output file '%s', rc=%Rrc\n", 349 szOutput, rc); 350 } 351 352 if (RT_SUCCESS(rc)) 353 { 354 /* Process each input file. */ 355 PVBOXSERVICETOOLBOXPATHENTRY pNodeIt; 356 RTFILE hInput = NIL_RTFILE; 357 RTListForEach(&inputList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node) 358 { 359 rc = RTFileOpen(&hInput, pNodeIt->pszName, 360 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 361 if (RT_SUCCESS(rc)) 362 { 363 rc = VBoxServiceToolboxCatOutput(hInput, hOutput); 364 RTFileClose(hInput); 365 } 366 else 367 { 368 PCRTSTATUSMSG pMsg = RTErrGet(rc); 369 if (pMsg) 370 RTMsgError("cat: Could not open input file '%s': %s\n", 371 pNodeIt->pszName, pMsg->pszMsgFull); 372 else 373 RTMsgError("cat: Could not open input file '%s', rc=%Rrc\n", pNodeIt->pszName, rc); 374 } 375 376 if (RT_FAILURE(rc)) 377 break; 378 } 379 380 /* If not input files were defined, process stdin. */ 381 if (RTListNodeIsFirst(&inputList, &inputList)) 382 rc = VBoxServiceToolboxCatOutput(hInput, hOutput); 383 } 384 } 385 386 if (hOutput != NIL_RTFILE) 387 RTFileClose(hOutput); 388 VBoxServiceToolboxPathBufDestroy(&inputList); 389 390 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 391 } 392 393 /** 394 * Helper routine for ls tool doing the actual parsing and output of 395 * a specified directory. 396 * 397 * @return IPRT status code. 398 * @param pszDir Directory (path) to ouptut. 399 * @param fRecursive Flag indicating whether recursive directory handling 400 * is wanted or not. 401 * @param fLong Flag indicating whether long output is required or not. 402 * @param fParseable Flag indicating whether machine parseable output 403 * is required or not 404 */ 405 static int VBoxServiceToolboxLsOutput(const char *pszDir, 406 bool fRecursive, bool fLong, bool fParseable) 407 { 408 AssertPtrReturn(pszDir, VERR_INVALID_PARAMETER); 409 410 if (fParseable) 411 RTPrintf("dname=%s%c", pszDir, 0); 412 413 char szPathAbs[RTPATH_MAX + 1]; 414 int rc = RTPathAbs(pszDir, szPathAbs, sizeof(szPathAbs)); 415 if (RT_FAILURE(rc)) 416 { 417 RTMsgError("ls: Failed to retrieve absolute path of '%s', rc=%Rrc\n", pszDir, rc); 418 return rc; 419 } 420 421 PRTDIR pDir; 422 rc = RTDirOpen(&pDir, szPathAbs); 423 if (RT_FAILURE(rc)) 424 { 425 RTMsgError("ls: Failed to open '%s', rc=%Rrc\n", szPathAbs, rc); 426 return rc; 427 } 428 429 RTLISTNODE dirList; 430 RTListInit(&dirList); 431 432 /* To prevent races we need to read in the directory entries once 433 * and process them afterwards: First loop is displaying the current 434 * directory's content and second loop is diving deeper into 435 * sub directories (if wanted). */ 436 for (;RT_SUCCESS(rc);) 437 { 438 RTDIRENTRYEX DirEntry; 439 rc = RTDirReadEx(pDir, &DirEntry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); 440 if (RT_SUCCESS(rc)) 441 { 442 PVBOXSERVICETOOLBOXDIRENTRY pNode = (PVBOXSERVICETOOLBOXDIRENTRY)RTMemAlloc(sizeof(VBOXSERVICETOOLBOXDIRENTRY)); 443 if (pNode) 444 { 445 memcpy(&pNode->dirEntry, &DirEntry, sizeof(RTDIRENTRYEX)); 446 /*rc =*/ RTListAppend(&dirList, &pNode->Node); 447 } 448 else 449 rc = VERR_NO_MEMORY; 450 } 451 } 452 453 if (rc == VERR_NO_MORE_FILES) 454 rc = VINF_SUCCESS; 455 456 int rc2 = RTDirClose(pDir); 457 if (RT_FAILURE(rc2)) 458 { 459 RTMsgError("ls: Failed to close dir '%s', rc=%Rrc\n", 460 pszDir, rc2); 461 if (RT_SUCCESS(rc)) 462 rc = rc2; 463 } 464 465 if (RT_SUCCESS(rc)) 466 { 467 PVBOXSERVICETOOLBOXDIRENTRY pNodeIt; 468 RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXDIRENTRY, Node) 469 { 470 RTFMODE fMode = pNodeIt->dirEntry.Info.Attr.fMode; 471 char cFileType; 472 switch (fMode & RTFS_TYPE_MASK) 473 { 474 case RTFS_TYPE_FIFO: cFileType = 'f'; break; 475 case RTFS_TYPE_DEV_CHAR: cFileType = 'c'; break; 476 case RTFS_TYPE_DIRECTORY: cFileType = 'd'; break; 477 case RTFS_TYPE_DEV_BLOCK: cFileType = 'b'; break; 478 case RTFS_TYPE_FILE: cFileType = '-'; break; 479 case RTFS_TYPE_SYMLINK: cFileType = 'l'; break; 480 case RTFS_TYPE_SOCKET: cFileType = 's'; break; 481 case RTFS_TYPE_WHITEOUT: cFileType = 'w'; break; 482 default: 483 cFileType = '?'; 484 break; 485 } 486 /** @todo sticy bits++ */ 487 488 if (!fLong) 489 { 490 if (fParseable) 491 { 492 /** @todo Skip node_id if not present/available! */ 493 RTPrintf("ftype=%c%cnode_id=%RU64%cname_len=%RU16%cname=%s%c", 494 cFileType, 0, (uint64_t)pNodeIt->dirEntry.Info.Attr.u.Unix.INodeId, 0, 495 pNodeIt->dirEntry.cbName, 0, pNodeIt->dirEntry.szName, 0); 496 } 497 else 498 RTPrintf("%c %#18llx %3d %s\n", (uint64_t)pNodeIt->dirEntry.Info.Attr.u.Unix.INodeId, 499 cFileType, pNodeIt->dirEntry.cbName, pNodeIt->dirEntry.szName); 500 501 if (fParseable) /* End of data block. */ 502 RTPrintf("%c%c", 0, 0); 503 } 504 else 505 { 506 if (fParseable) 507 { 508 RTPrintf("ftype=%c%c", cFileType, 0); 509 RTPrintf("owner_mask=%c%c%c%c", 510 fMode & RTFS_UNIX_IRUSR ? 'r' : '-', 511 fMode & RTFS_UNIX_IWUSR ? 'w' : '-', 512 fMode & RTFS_UNIX_IXUSR ? 'x' : '-', 0); 513 RTPrintf("group_mask=%c%c%c%c", 514 fMode & RTFS_UNIX_IRGRP ? 'r' : '-', 515 fMode & RTFS_UNIX_IWGRP ? 'w' : '-', 516 fMode & RTFS_UNIX_IXGRP ? 'x' : '-', 0); 517 RTPrintf("other_mask=%c%c%c%c", 518 fMode & RTFS_UNIX_IROTH ? 'r' : '-', 519 fMode & RTFS_UNIX_IWOTH ? 'w' : '-', 520 fMode & RTFS_UNIX_IXOTH ? 'x' : '-', 0); 521 RTPrintf("dos_mask=%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", 522 fMode & RTFS_DOS_READONLY ? 'R' : '-', 523 fMode & RTFS_DOS_HIDDEN ? 'H' : '-', 524 fMode & RTFS_DOS_SYSTEM ? 'S' : '-', 525 fMode & RTFS_DOS_DIRECTORY ? 'D' : '-', 526 fMode & RTFS_DOS_ARCHIVED ? 'A' : '-', 527 fMode & RTFS_DOS_NT_DEVICE ? 'd' : '-', 528 fMode & RTFS_DOS_NT_NORMAL ? 'N' : '-', 529 fMode & RTFS_DOS_NT_TEMPORARY ? 'T' : '-', 530 fMode & RTFS_DOS_NT_SPARSE_FILE ? 'P' : '-', 531 fMode & RTFS_DOS_NT_REPARSE_POINT ? 'J' : '-', 532 fMode & RTFS_DOS_NT_COMPRESSED ? 'C' : '-', 533 fMode & RTFS_DOS_NT_OFFLINE ? 'O' : '-', 534 fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-', 535 fMode & RTFS_DOS_NT_ENCRYPTED ? 'E' : '-', 0); 536 537 char szTimeBirth[256]; 538 RTTimeSpecToString(&pNodeIt->dirEntry.Info.BirthTime, szTimeBirth, sizeof(szTimeBirth)); 539 char szTimeChange[256]; 540 RTTimeSpecToString(&pNodeIt->dirEntry.Info.ChangeTime, szTimeChange, sizeof(szTimeChange)); 541 char szTimeModification[256]; 542 RTTimeSpecToString(&pNodeIt->dirEntry.Info.ModificationTime, szTimeModification, sizeof(szTimeModification)); 543 char szTimeAccess[256]; 544 RTTimeSpecToString(&pNodeIt->dirEntry.Info.AccessTime, szTimeAccess, sizeof(szTimeAccess)); 545 546 RTPrintf("hlinks=%RU32%cuid=%RU32%cgid=%RU32%cst_size=%RI64%calloc=%RI64%c" 547 "st_birthtime=%s%cst_ctime=%s%cst_mtime=%s%cst_atime=%s%c", 548 pNodeIt->dirEntry.Info.Attr.u.Unix.cHardlinks, 0, 549 pNodeIt->dirEntry.Info.Attr.u.Unix.uid, 0, 550 pNodeIt->dirEntry.Info.Attr.u.Unix.gid, 0, 551 pNodeIt->dirEntry.Info.cbObject, 0, 552 pNodeIt->dirEntry.Info.cbAllocated, 0, 553 szTimeBirth, 0, 554 szTimeChange, 0, 555 szTimeModification, 0, 556 szTimeAccess, 0); 557 RTPrintf("cname_len=%RU16%cname=%s%c", 558 pNodeIt->dirEntry.cbName, 0, pNodeIt->dirEntry.szName, 0); 559 560 /* End of data block. */ 561 RTPrintf("%c%c", 0, 0); 562 } 563 else 564 { 565 RTPrintf("%c", cFileType); 566 RTPrintf("%c%c%c", 567 fMode & RTFS_UNIX_IRUSR ? 'r' : '-', 568 fMode & RTFS_UNIX_IWUSR ? 'w' : '-', 569 fMode & RTFS_UNIX_IXUSR ? 'x' : '-'); 570 RTPrintf("%c%c%c", 571 fMode & RTFS_UNIX_IRGRP ? 'r' : '-', 572 fMode & RTFS_UNIX_IWGRP ? 'w' : '-', 573 fMode & RTFS_UNIX_IXGRP ? 'x' : '-'); 574 RTPrintf("%c%c%c", 575 fMode & RTFS_UNIX_IROTH ? 'r' : '-', 576 fMode & RTFS_UNIX_IWOTH ? 'w' : '-', 577 fMode & RTFS_UNIX_IXOTH ? 'x' : '-'); 578 RTPrintf(" %c%c%c%c%c%c%c%c%c%c%c%c%c%c", 579 fMode & RTFS_DOS_READONLY ? 'R' : '-', 580 fMode & RTFS_DOS_HIDDEN ? 'H' : '-', 581 fMode & RTFS_DOS_SYSTEM ? 'S' : '-', 582 fMode & RTFS_DOS_DIRECTORY ? 'D' : '-', 583 fMode & RTFS_DOS_ARCHIVED ? 'A' : '-', 584 fMode & RTFS_DOS_NT_DEVICE ? 'd' : '-', 585 fMode & RTFS_DOS_NT_NORMAL ? 'N' : '-', 586 fMode & RTFS_DOS_NT_TEMPORARY ? 'T' : '-', 587 fMode & RTFS_DOS_NT_SPARSE_FILE ? 'P' : '-', 588 fMode & RTFS_DOS_NT_REPARSE_POINT ? 'J' : '-', 589 fMode & RTFS_DOS_NT_COMPRESSED ? 'C' : '-', 590 fMode & RTFS_DOS_NT_OFFLINE ? 'O' : '-', 591 fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-', 592 fMode & RTFS_DOS_NT_ENCRYPTED ? 'E' : '-'); 593 RTPrintf(" %d %4d %4d %10lld %10lld %#llx %#llx %#llx %#llx", 594 pNodeIt->dirEntry.Info.Attr.u.Unix.cHardlinks, 595 pNodeIt->dirEntry.Info.Attr.u.Unix.uid, 596 pNodeIt->dirEntry.Info.Attr.u.Unix.gid, 597 pNodeIt->dirEntry.Info.cbObject, 598 pNodeIt->dirEntry.Info.cbAllocated, 599 pNodeIt->dirEntry.Info.BirthTime, 600 pNodeIt->dirEntry.Info.ChangeTime, 601 pNodeIt->dirEntry.Info.ModificationTime, 602 pNodeIt->dirEntry.Info.AccessTime); 603 RTPrintf(" %2d %s\n", pNodeIt->dirEntry.cbName, pNodeIt->dirEntry.szName); 604 } 605 } 606 if (RT_FAILURE(rc)) 607 break; 608 } 609 610 /* If everything went fine we do the second run (if needed) ... */ 611 if (RT_SUCCESS(rc) && fRecursive) 612 { 613 /* Process all sub-directories. */ 614 PVBOXSERVICETOOLBOXDIRENTRY pNodeIt; 615 RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXDIRENTRY, Node) 616 { 617 RTFMODE fMode = pNodeIt->dirEntry.Info.Attr.fMode; 618 switch (fMode & RTFS_TYPE_MASK) 619 { 620 //case RTFS_TYPE_SYMLINK: 621 case RTFS_TYPE_DIRECTORY: 622 { 623 const char *pszName = pNodeIt->dirEntry.szName; 624 if ( !RTStrICmp(pszName, ".") 625 || !RTStrICmp(pszName, "..")) 626 { 627 /* Skip dot directories. */ 628 continue; 629 } 630 rc = VBoxServiceToolboxLsOutput(pNodeIt->dirEntry.szName, fRecursive, 631 fLong, fParseable); 632 } 633 break; 634 635 default: /* Ignore the rest. */ 636 break; 637 } 638 if (RT_FAILURE(rc)) 639 break; 640 } 641 } 642 } 643 644 /* Clean up the mess. */ 645 PVBOXSERVICETOOLBOXDIRENTRY pNode, pSafe; 646 RTListForEachSafe(&dirList, pNode, pSafe, VBOXSERVICETOOLBOXDIRENTRY, Node) 647 { 648 RTListNodeRemove(&pNode->Node); 649 RTMemFree(pNode); 650 } 651 return rc; 652 } 653 654 655 /** 656 * Main function for tool "vbox_ls". 657 * 658 * @return RTEXITCODE. 659 * @param argc Number of arguments. 660 * @param argv Pointer to argument array. 661 */ 662 static RTEXITCODE VBoxServiceToolboxLs(int argc, char **argv) 663 { 664 static const RTGETOPTDEF s_aOptions[] = 665 { 666 { "--machinereadable", LS_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING }, 667 { NULL, 'l', RTGETOPT_REQ_NOTHING }, 668 { NULL, 'R', RTGETOPT_REQ_NOTHING }, 669 { "--verbose", 'v', RTGETOPT_REQ_NOTHING} 670 }; 671 672 int ch; 673 RTGETOPTUNION ValueUnion; 674 RTGETOPTSTATE GetState; 675 RTGetOptInit(&GetState, argc, argv, 676 s_aOptions, RT_ELEMENTS(s_aOptions), 677 /* Index of argv to start with. */ 678 #ifdef VBOXSERVICE_TOOLBOX_DEBUG 679 2, 680 #else 681 1, 682 #endif 683 RTGETOPTINIT_FLAGS_OPTS_FIRST); 684 685 int rc = VINF_SUCCESS; 686 bool fVerbose = false; 687 bool fLong = false; 688 bool fMachineReadable = false; 689 bool fRecursive = false; 690 691 /* Init file list. */ 692 RTLISTNODE fileList; 693 RTListInit(&fileList); 694 695 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 696 && RT_SUCCESS(rc)) 697 { 698 /* For options that require an argument, ValueUnion has received the value. */ 699 switch (ch) 700 { 701 case 'h': 702 VBoxServiceToolboxShowUsage(); 703 return RTEXITCODE_SUCCESS; 704 705 case 'l': /* Print long format. */ 706 fLong = true; 707 break; 708 709 case LS_OPT_MACHINE_READABLE: 710 fMachineReadable = true; 711 break; 712 713 case 'R': /* Recursive processing. */ 714 fRecursive = true; 715 break; 716 717 case 'v': 718 fVerbose = true; 719 break; 720 721 case 'V': 722 VBoxServiceToolboxShowVersion(); 723 return RTEXITCODE_SUCCESS; 724 725 case VINF_GETOPT_NOT_OPTION: 726 { 727 /* Add file(s) to buffer. This enables processing multiple files 728 * at once. 729 * 730 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when 731 * processing this loop it's safe to immediately exit on syntax errors 732 * or showing the help text (see above). */ 733 rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, ValueUnion.psz); 734 break; 735 } 736 737 default: 738 return RTGetOptPrintError(ch, &ValueUnion); 739 } 740 } 741 742 if (RT_SUCCESS(rc)) 743 { 744 /* If not files given add current directory to list. */ 745 if (RTListIsEmpty(&fileList)) 746 { 747 char szDirCur[RTPATH_MAX + 1]; 748 rc = RTPathGetCurrent(szDirCur, sizeof(szDirCur)); 749 if (RT_SUCCESS(rc)) 750 { 751 rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, szDirCur); 752 if (RT_FAILURE(rc)) 753 RTMsgError("ls: Adding current directory failed, rc=%Rrc\n", rc); 754 } 755 else 756 RTMsgError("ls: Getting current directory failed, rc=%Rrc\n", rc); 757 } 758 759 /* Print magic/version. */ 760 if (fMachineReadable) 761 RTPrintf("hdr_id=vbt_ls%chdr_ver=%u%c", 0, 1 /* Version 1 */, 0); 762 763 PVBOXSERVICETOOLBOXPATHENTRY pNodeIt; 764 RTListForEach(&fileList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node) 765 { 766 rc = VBoxServiceToolboxLsOutput(pNodeIt->pszName, 767 fRecursive, fLong, fMachineReadable); 768 if (RT_FAILURE(rc)) 769 RTMsgError("ls: Failed while enumerating directory '%s', rc=%Rrc\n", 770 pNodeIt->pszName, rc); 771 } 772 773 if (fMachineReadable) /* Output termination. */ 774 RTPrintf("%c%c%c%c", 0, 0, 0, 0); 775 } 776 else if (fVerbose) 777 RTMsgError("ls: Failed with rc=%Rrc\n", rc); 778 779 VBoxServiceToolboxPathBufDestroy(&fileList); 780 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 781 } 782 783 784 /** 218 785 * Main function for tool "vbox_mkdir". 219 786 * … … 224 791 static RTEXITCODE VBoxServiceToolboxMkDir(int argc, char **argv) 225 792 { 226 227 228 229 { "--parents", 'p', RTGETOPT_REQ_NOTHING},230 { "--verbose", 'v', RTGETOPT_REQ_NOTHING}231 232 233 234 235 236 237 238 793 static const RTGETOPTDEF s_aOptions[] = 794 { 795 { "--mode", 'm', RTGETOPT_REQ_STRING }, 796 { "--parents", 'p', RTGETOPT_REQ_NOTHING}, 797 { "--verbose", 'v', RTGETOPT_REQ_NOTHING} 798 }; 799 800 int ch; 801 RTGETOPTUNION ValueUnion; 802 RTGETOPTSTATE GetState; 803 RTGetOptInit(&GetState, argc, argv, 804 s_aOptions, RT_ELEMENTS(s_aOptions), 805 /* Index of argv to start with. */ 239 806 #ifdef VBOXSERVICE_TOOLBOX_DEBUG 240 807 2, 241 808 #else 242 809 1, 243 810 #endif 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 && RT_SUCCESS(rc))259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 {290 /* Add path(s) to buffer. This enables processing multiple paths291 * at once.292 *293 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when294 * processing this loop it's safe to immediately exit on syntax errors295 * or showing the help text (see above). */296 rc = VBoxServiceToolboxPathBufAddPathEntry(&dirList, ValueUnion.psz);297 break;298 }299 300 301 302 303 304 305 306 307 308 811 RTGETOPTINIT_FLAGS_OPTS_FIRST); 812 813 int rc = VINF_SUCCESS; 814 bool fMakeParentDirs = false; 815 bool fVerbose = false; 816 817 RTFMODE newMode = 0; 818 RTFMODE dirMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO; 819 820 /* Init directory list. */ 821 RTLISTNODE dirList; 822 RTListInit(&dirList); 823 824 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 825 && RT_SUCCESS(rc)) 826 { 827 /* For options that require an argument, ValueUnion has received the value. */ 828 switch (ch) 829 { 830 case 'h': 831 VBoxServiceToolboxShowUsage(); 832 return RTEXITCODE_SUCCESS; 833 834 case 'p': 835 fMakeParentDirs = true; 836 break; 837 838 case 'm': 839 rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 8 /* Base */, &newMode); 840 if (RT_FAILURE(rc)) /* Only octet based values supported right now! */ 841 { 842 RTMsgError("mkdir: Mode flag strings not implemented yet! Use octal numbers instead.\n"); 843 return RTEXITCODE_SYNTAX; 844 } 845 break; 846 847 case 'v': 848 fVerbose = true; 849 break; 850 851 case 'V': 852 VBoxServiceToolboxShowVersion(); 853 return RTEXITCODE_SUCCESS; 854 855 case VINF_GETOPT_NOT_OPTION: 856 { 857 /* Add path(s) to buffer. This enables processing multiple paths 858 * at once. 859 * 860 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when 861 * processing this loop it's safe to immediately exit on syntax errors 862 * or showing the help text (see above). */ 863 rc = VBoxServiceToolboxPathBufAddPathEntry(&dirList, ValueUnion.psz); 864 break; 865 } 866 867 default: 868 return RTGetOptPrintError(ch, &ValueUnion); 869 } 870 } 871 872 if (RT_SUCCESS(rc)) 873 { 874 if (fMakeParentDirs || newMode) 875 { 309 876 #ifndef RT_OS_WINDOWS 310 311 877 mode_t umaskMode = umask(0); /* Get current umask. */ 878 if (newMode) 312 879 dirMode = newMode; 313 880 #endif 314 } 315 316 PVBOXSERVICETOOLBOXPATHENTRY pNodeIt; 317 RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node) 318 { 319 rc = fMakeParentDirs ? 320 RTDirCreateFullPath(pNodeIt->pszName, dirMode) 321 : RTDirCreate(pNodeIt->pszName, dirMode); 322 323 if (RT_SUCCESS(rc) && fVerbose) 324 RTMsgError("mkdir: Created directory 's', mode %#RTfmode\n", pNodeIt->pszName, dirMode); 325 else if (RT_FAILURE(rc)) /** @todo Add a switch with more helpful error texts! */ 326 { 327 PCRTSTATUSMSG pMsg = RTErrGet(rc); 328 if (pMsg) 329 RTMsgError("mkdir: Could not create directory '%s': %s\n", 330 pNodeIt->pszName, pMsg->pszMsgFull); 331 else 332 RTMsgError("mkdir: Could not create directory '%s', rc=%Rrc\n", pNodeIt->pszName, rc); 333 break; 334 } 335 } 336 } 337 else if (fVerbose) 338 RTMsgError("mkdir: Failed with rc=%Rrc\n", rc); 339 340 VBoxServiceToolboxPathBufDestroy(&dirList); 341 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 342 } 343 344 345 /** 346 * Main function for tool "vbox_cat". 347 * 348 * @return RTEXITCODE. 349 * @param argc Number of arguments. 350 * @param argv Pointer to argument array. 351 */ 352 static RTEXITCODE VBoxServiceToolboxCat(int argc, char **argv) 353 { 354 static const RTGETOPTDEF s_aOptions[] = 355 { 356 /* Sorted by short ops. */ 357 { "--show-all", 'a', RTGETOPT_REQ_NOTHING }, 358 { "--number-nonblank", 'b', RTGETOPT_REQ_NOTHING }, 359 { NULL, 'e', RTGETOPT_REQ_NOTHING }, 360 { NULL, 'E', RTGETOPT_REQ_NOTHING }, 361 { "--flags", 'f', RTGETOPT_REQ_STRING }, 362 { "--no-content-indexed", CAT_OPT_NO_CONTENT_INDEXED, RTGETOPT_REQ_NOTHING }, 363 { "--number", 'n', RTGETOPT_REQ_NOTHING }, 364 { "--output", 'o', RTGETOPT_REQ_STRING }, 365 { "--squeeze-blank", 's', RTGETOPT_REQ_NOTHING }, 366 { NULL, 't', RTGETOPT_REQ_NOTHING }, 367 { "--show-tabs", 'T', RTGETOPT_REQ_NOTHING }, 368 { NULL, 'u', RTGETOPT_REQ_NOTHING }, 369 { "--show-noneprinting", 'v', RTGETOPT_REQ_NOTHING } 370 }; 371 372 int ch; 373 RTGETOPTUNION ValueUnion; 374 RTGETOPTSTATE GetState; 375 376 RTGetOptInit(&GetState, argc, argv, 377 s_aOptions, RT_ELEMENTS(s_aOptions), 378 /* Index of argv to start with. */ 379 #ifdef VBOXSERVICE_TOOLBOX_DEBUG 380 2, 381 #else 382 1, 383 #endif 384 0); 385 386 int rc = VINF_SUCCESS; 387 bool fUsageOK = true; 388 389 char szOutput[RTPATH_MAX] = { 0 }; 390 RTFILE hOutput = NIL_RTFILE; 391 uint32_t fFlags = RTFILE_O_CREATE_REPLACE /* Output file flags. */ 392 | RTFILE_O_WRITE 393 | RTFILE_O_DENY_WRITE; 394 395 /* Init directory list. */ 396 RTLISTNODE inputList; 397 RTListInit(&inputList); 398 399 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 400 && RT_SUCCESS(rc)) 401 { 402 /* For options that require an argument, ValueUnion has received the value. */ 403 switch (ch) 404 { 405 case 'a': 406 case 'b': 407 case 'e': 408 case 'E': 409 case 'n': 410 case 's': 411 case 't': 412 case 'T': 413 case 'v': 414 RTMsgError("cat: Sorry, option '%s' is not implemented yet!\n", 415 ValueUnion.pDef->pszLong); 416 rc = VERR_INVALID_PARAMETER; 417 break; 418 419 case 'h': 420 VBoxServiceToolboxShowUsage(); 421 return RTEXITCODE_SUCCESS; 422 423 case 'o': 424 if (!RTStrPrintf(szOutput, sizeof(szOutput), ValueUnion.psz)) 425 rc = VERR_NO_MEMORY; 426 break; 427 428 case 'u': 429 /* Ignored. */ 430 break; 431 432 case 'V': 433 VBoxServiceToolboxShowVersion(); 434 return RTEXITCODE_SUCCESS; 435 436 case CAT_OPT_NO_CONTENT_INDEXED: 437 fFlags |= RTFILE_O_NOT_CONTENT_INDEXED; 438 break; 439 440 case VINF_GETOPT_NOT_OPTION: 441 { 442 /* Add file(s) to buffer. This enables processing multiple paths 443 * at once. 444 * 445 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when 446 * processing this loop it's safe to immediately exit on syntax errors 447 * or showing the help text (see above). */ 448 rc = VBoxServiceToolboxPathBufAddPathEntry(&inputList, ValueUnion.psz); 449 break; 450 } 451 452 default: 453 return RTGetOptPrintError(ch, &ValueUnion); 454 } 455 } 456 457 if (RT_SUCCESS(rc)) 458 { 459 if (strlen(szOutput)) 460 { 461 rc = RTFileOpen(&hOutput, szOutput, fFlags); 462 if (RT_FAILURE(rc)) 463 RTMsgError("cat: Could not create output file '%s'! rc=%Rrc\n", 464 szOutput, rc); 465 } 466 467 if (RT_SUCCESS(rc)) 468 { 469 /* Process each input file. */ 470 PVBOXSERVICETOOLBOXPATHENTRY pNodeIt; 471 RTFILE hInput = NIL_RTFILE; 472 RTListForEach(&inputList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node) 473 { 474 rc = RTFileOpen(&hInput, pNodeIt->pszName, 475 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 476 if (RT_SUCCESS(rc)) 477 { 478 rc = VBoxServiceToolboxCatOutput(hInput, hOutput); 479 RTFileClose(hInput); 480 } 481 else 482 { 483 PCRTSTATUSMSG pMsg = RTErrGet(rc); 484 if (pMsg) 485 RTMsgError("cat: Could not open input file '%s': %s\n", 486 pNodeIt->pszName, pMsg->pszMsgFull); 487 else 488 RTMsgError("cat: Could not open input file '%s', rc=%Rrc\n", pNodeIt->pszName, rc); 489 } 490 491 if (RT_FAILURE(rc)) 492 break; 493 } 494 495 /* If not input files were defined, process stdin. */ 496 if (RTListNodeIsFirst(&inputList, &inputList)) 497 rc = VBoxServiceToolboxCatOutput(hInput, hOutput); 498 } 499 } 500 501 if (hOutput != NIL_RTFILE) 502 RTFileClose(hOutput); 503 VBoxServiceToolboxPathBufDestroy(&inputList); 504 505 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 881 } 882 883 PVBOXSERVICETOOLBOXPATHENTRY pNodeIt; 884 RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node) 885 { 886 rc = fMakeParentDirs ? 887 RTDirCreateFullPath(pNodeIt->pszName, dirMode) 888 : RTDirCreate(pNodeIt->pszName, dirMode); 889 890 if (RT_SUCCESS(rc) && fVerbose) 891 RTMsgError("mkdir: Created directory 's', mode %#RTfmode\n", pNodeIt->pszName, dirMode); 892 else if (RT_FAILURE(rc)) /** @todo Add a switch with more helpful error texts! */ 893 { 894 PCRTSTATUSMSG pMsg = RTErrGet(rc); 895 if (pMsg) 896 RTMsgError("mkdir: Could not create directory '%s': %s\n", 897 pNodeIt->pszName, pMsg->pszMsgFull); 898 else 899 RTMsgError("mkdir: Could not create directory '%s', rc=%Rrc\n", pNodeIt->pszName, rc); 900 break; 901 } 902 } 903 } 904 else if (fVerbose) 905 RTMsgError("mkdir: Failed with rc=%Rrc\n", rc); 906 907 VBoxServiceToolboxPathBufDestroy(&dirList); 908 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 506 909 } 507 910 … … 516 919 static RTEXITCODE VBoxServiceToolboxStat(int argc, char **argv) 517 920 { 518 519 520 521 { "--dereference", 'L', RTGETOPT_REQ_NOTHING},522 { "--terse", 't', RTGETOPT_REQ_NOTHING},523 { "--verbose", 'v', RTGETOPT_REQ_NOTHING}524 525 526 527 528 529 530 531 921 static const RTGETOPTDEF s_aOptions[] = 922 { 923 { "--file-system", 'f', RTGETOPT_REQ_NOTHING }, 924 { "--dereference", 'L', RTGETOPT_REQ_NOTHING}, 925 { "--terse", 't', RTGETOPT_REQ_NOTHING}, 926 { "--verbose", 'v', RTGETOPT_REQ_NOTHING} 927 }; 928 929 int ch; 930 RTGETOPTUNION ValueUnion; 931 RTGETOPTSTATE GetState; 932 RTGetOptInit(&GetState, argc, argv, 933 s_aOptions, RT_ELEMENTS(s_aOptions), 934 /* Index of argv to start with. */ 532 935 #ifdef VBOXSERVICE_TOOLBOX_DEBUG 533 936 2, 534 937 #else 535 938 1, 536 939 #endif 537 538 539 540 541 542 543 544 545 546 547 && RT_SUCCESS(rc))548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 {573 /* Add file(s) to buffer. This enables processing multiple files574 * at once.575 *576 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when577 * processing this loop it's safe to immediately exit on syntax errors578 * or showing the help text (see above). */579 rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, ValueUnion.psz);580 break;581 }582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 940 RTGETOPTINIT_FLAGS_OPTS_FIRST); 941 942 int rc = VINF_SUCCESS; 943 bool fVerbose = false; 944 945 /* Init file list. */ 946 RTLISTNODE fileList; 947 RTListInit(&fileList); 948 949 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 950 && RT_SUCCESS(rc)) 951 { 952 /* For options that require an argument, ValueUnion has received the value. */ 953 switch (ch) 954 { 955 case 'h': 956 VBoxServiceToolboxShowUsage(); 957 return RTEXITCODE_SUCCESS; 958 959 case 'f': 960 case 'L': 961 RTMsgError("stat: Sorry, option '%s' is not implemented yet!\n", 962 ValueUnion.pDef->pszLong); 963 rc = VERR_INVALID_PARAMETER; 964 break; 965 966 case 'v': 967 fVerbose = true; 968 break; 969 970 case 'V': 971 VBoxServiceToolboxShowVersion(); 972 return RTEXITCODE_SUCCESS; 973 974 case VINF_GETOPT_NOT_OPTION: 975 { 976 /* Add file(s) to buffer. This enables processing multiple files 977 * at once. 978 * 979 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when 980 * processing this loop it's safe to immediately exit on syntax errors 981 * or showing the help text (see above). */ 982 rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, ValueUnion.psz); 983 break; 984 } 985 986 default: 987 return RTGetOptPrintError(ch, &ValueUnion); 988 } 989 } 990 991 if (RT_SUCCESS(rc)) 992 { 993 PVBOXSERVICETOOLBOXPATHENTRY pNodeIt; 994 RTListForEach(&fileList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node) 995 { 996 /* Only check for file existence for now. */ 997 if (RTFileExists(pNodeIt->pszName)) 998 { 999 /** @todo Do some more work (query size etc.) here later. 1000 * Not needed for now. */ 1001 } 1002 else 1003 { 1004 RTMsgError("stat: Cannot stat for '%s': No such file or directory\n", 1005 pNodeIt->pszName); 1006 rc = VERR_FILE_NOT_FOUND; 1007 /* Do not break here -- process every file in the list 1008 * and keep failing rc. */ 1009 } 1010 } 1011 1012 if (RTListIsEmpty(&fileList)) 1013 RTMsgError("stat: Missing operand\n"); 1014 } 1015 else if (fVerbose) 1016 RTMsgError("stat: Failed with rc=%Rrc\n", rc); 1017 1018 VBoxServiceToolboxPathBufDestroy(&fileList); 1019 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 617 1020 } 618 1021 … … 642 1045 } 643 1046 1047 if ( !strcmp(argv[iCmdIdx], "ls") 1048 || !strcmp(argv[iCmdIdx], "vbox_ls")) 1049 { 1050 *prcExit = VBoxServiceToolboxLs(argc, argv); 1051 return true; 1052 } 1053 644 1054 if ( !strcmp(argv[iCmdIdx], "mkdir") 645 1055 || !strcmp(argv[iCmdIdx], "vbox_mkdir"))
Note:
See TracChangeset
for help on using the changeset viewer.