Changeset 35916 in vbox for trunk/src/VBox
- Timestamp:
- Feb 9, 2011 3:04:44 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r35907 r35916 228 228 229 229 /** 230 * Initializes the VM, that is checks whether it's up and 231 * running, if it can be locked (shared only) and returns a 232 * valid IGuest pointer on success. 230 * Initializes the VM for IGuest operations. 231 * 232 * That is, checks whether it's up and running, if it can be locked (shared 233 * only) and returns a valid IGuest pointer on success. 233 234 * 234 235 * @return IPRT status code. 235 236 * @param pArg Our command line argument structure. 236 * @param pszNameOrId The VM's name or UUID to use.237 * @param pGuest Pointer where to store the IGuest interface.237 * @param pszNameOrId The VM's name or UUID. 238 * @param pGuest Where to return the IGuest interface pointer. 238 239 */ 239 240 static int ctrlInitVM(HandlerArg *pArg, const char *pszNameOrId, ComPtr<IGuest> *pGuest) … … 280 281 } 281 282 283 /* <Missing docuemntation> */ 282 284 static int handleCtrlExecProgram(HandlerArg *a) 283 285 { 284 286 /* 285 * Check the syntax. We can deduce the correct syntax from the number of 286 * arguments. 287 * Parse arguments. 287 288 */ 288 289 if (a->argc < 2) /* At least the command we want to execute in the guest should be present :-). */ … … 301 302 }; 302 303 303 int ch;304 RTGETOPTUNION ValueUnion;305 RTGETOPTSTATE GetState;304 int ch; 305 RTGETOPTUNION ValueUnion; 306 RTGETOPTSTATE GetState; 306 307 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); 307 308 308 Utf8Str Utf8Cmd; 309 uint32_t uFlags = 0; 310 /* Note: this uses IN_BSTR as it must be BSTR on COM and CBSTR on XPCOM */ 309 Utf8Str Utf8Cmd; 310 uint32_t fFlags = 0; 311 311 com::SafeArray<IN_BSTR> args; 312 312 com::SafeArray<IN_BSTR> env; 313 Utf8Str Utf8UserName;314 Utf8Str Utf8Password;315 uint32_t u32TimeoutMS= 0;316 bool fWaitForExit= false;317 bool fWaitForStdOut= false;318 bool fWaitForStdErr= false;319 bool fVerbose= false;320 321 int vrc= VINF_SUCCESS;322 bool fUsageOK= true;313 Utf8Str Utf8UserName; 314 Utf8Str Utf8Password; 315 uint32_t u32TimeoutMS = 0; 316 bool fWaitForExit = false; 317 bool fWaitForStdOut = false; 318 bool fWaitForStdErr = false; 319 bool fVerbose = false; 320 321 int vrc = VINF_SUCCESS; 322 bool fUsageOK = true; 323 323 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 324 324 && RT_SUCCESS(vrc)) … … 360 360 361 361 case 'f': /* Flags */ 362 /** @todo r=bird: As stated before, this generic flags stuff 363 * does NOT make sense! The IgnoreOprphanedProcesses 364 * features should have been added as: 365 * { "--ignore-operhaned-processes", DEFINE, RTGETOPT_REQ_NOTHING } 366 * 367 * Please, remove -f in 4.1, replace it with above. */ 362 368 /** @todo Needs a bit better processing as soon as we have more flags. */ 363 369 /** @todo Add a hidden flag. */ 364 370 if (!RTStrICmp(ValueUnion.psz, "ignoreorphanedprocesses")) 365 uFlags |= ExecuteProcessFlag_IgnoreOrphanedProcesses;371 fFlags |= ExecuteProcessFlag_IgnoreOrphanedProcesses; 366 372 else 367 373 fUsageOK = false; … … 386 392 case 'w': /* Wait for ... */ 387 393 { 394 /** @todo r=bird: Same as for -f: Use individual options for 395 * indicating what to wait for. This is unix tradition and 396 * much simpler to write code for. It also avoids people 397 * finding out that the following sequence does not work 398 * (contrary to what one would expect): 399 * -w stdout,stderr 400 * */ 388 401 if (!RTStrICmp(ValueUnion.psz, "exit")) 389 402 fWaitForExit = true; … … 405 418 case VINF_GETOPT_NOT_OPTION: 406 419 { 420 /** @todo r=bird: Guess what the following does: 421 * VBoxManage guestcontrol exec myvm /bin/ls 1 2 3 4; 422 * 423 * In 4.1 this SHALL be changed to treat 1 2 3 4 as arguments 424 * to /bin/ls. Drop --arguments and replace it with --image 425 * <guest-file>. The --image defaults to the first argument if 426 * not specified. Users should be encouraged to use '--' to 427 * separate 'exec' options from options to the guest 428 * program: 429 * VBoxManage guestcontrol myvm exec --image /bin/busybox -- ln -s /foo /bar 430 */ 407 431 /* The actual command we want to execute on the guest. */ 408 432 Utf8Cmd = ValueUnion.psz; … … 415 439 } 416 440 417 if (!fUsageOK) 441 if (!fUsageOK) /** @todo r=bird: there is no clean up, so just return directly on failure with a specific message. */ 418 442 return errorSyntax(USAGE_GUESTCONTROL, "Incorrect parameters"); 419 443 420 444 if (Utf8Cmd.isEmpty()) 421 return errorSyntax(USAGE_GUESTCONTROL, 422 "No command to execute specified!"); 445 return errorSyntax(USAGE_GUESTCONTROL, "No command to execute specified!"); 423 446 424 447 if (Utf8UserName.isEmpty()) 425 return errorSyntax(USAGE_GUESTCONTROL, 426 "No user name specified!"); 427 448 return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!"); 449 450 /** @todo r=bird: You don't check vrc here, so if RTGetOptArgvFromString 451 * or RTGetOptArgvFromString failed above, you'll ignore it. 452 * 453 * Just simplify the argument parsing to not use unnecessary state 454 * variables and instead return directly on error with a specific error 455 * message. (See fUsageOk comment above.) */ 456 457 /* 458 * <comment missing> 459 */ 428 460 HRESULT rc = S_OK; 429 461 ComPtr<IGuest> guest; … … 431 463 if (RT_SUCCESS(vrc)) 432 464 { 433 ComPtr<IProgress> progress;434 ULONG uPID = 0;435 436 465 if (fVerbose) 437 466 { … … 446 475 447 476 /* Execute the process. */ 448 rc = guest->ExecuteProcess(Bstr(Utf8Cmd).raw(), uFlags, 477 ComPtr<IProgress> progress; 478 ULONG uPID = 0; 479 rc = guest->ExecuteProcess(Bstr(Utf8Cmd).raw(), 480 fFlags, 449 481 ComSafeArrayAsInParam(args), 450 482 ComSafeArrayAsInParam(env), 451 483 Bstr(Utf8UserName).raw(), 452 Bstr(Utf8Password).raw(), u32TimeoutMS, 453 &uPID, progress.asOutParam()); 484 Bstr(Utf8Password).raw(), 485 u32TimeoutMS, 486 &uPID, 487 progress.asOutParam()); 454 488 if (FAILED(rc)) 455 489 vrc = ctrlPrintError(guest, COM_IIDOF(IGuest)); … … 490 524 491 525 /* Wait for process to exit ... */ 492 BOOL fCompleted = FALSE;493 BOOL fCanceled = FALSE;494 int cMilliesSleep = 0;526 BOOL fCompleted = FALSE; 527 BOOL fCanceled = FALSE; 528 int cMilliesSleep = 0; 495 529 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted)))) 496 530 { … … 517 551 if (cbOutputData > 0) 518 552 { 553 /** @todo r=bird: cat'ing binary data from the guest is not going to work 554 * reliably if we do conversions like this. Should probably just 555 * write the output as it is by default, but bypassing RTStrWrite and 556 * it's automatic translation. Adding exec options to convert unix2dos 557 * and dos2unix. Use a VFS I/O stream filter for doing this, it's a 558 * generic problem and the new VFS APIs will handle it more 559 * transparently. (requires writing dos2unix/unix2dos filters ofc) */ 519 560 /* aOutputData has a platform dependent line ending, standardize on 520 561 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on … … 565 606 if ( SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled))) 566 607 && fCanceled) 567 {568 608 break; 569 }570 609 571 610 /* Did we run out of time? */ … … 578 617 579 618 /* Don't hog the CPU in a busy loop! */ 619 /** @todo r=bird: I believe I already mentioned that this problem is better 620 * solved by using WaitForCompletion and GetProcessOutput with timeouts. The 621 * 1ms hack above is not what I had in mind. This quick fix must go away. */ 580 622 if (cbOutputData <= 0) 581 623 { … … 586 628 else 587 629 cMilliesSleep = 0; 588 } 630 } /* while */ 589 631 590 632 /* Undo signal handling */ … … 592 634 ctrlSignalHandlerUninstall(); 593 635 636 /* Report status back to the user. */ 594 637 if (fCanceled) 595 638 { … … 603 646 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc); 604 647 if (FAILED(iRc)) 605 {606 648 vrc = ctrlPrintProgressError(progress); 607 }608 649 else if (fVerbose) 609 650 { … … 612 653 if (SUCCEEDED(rc)) 613 654 RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, ctrlExecGetStatus(uRetStatus), uRetFlags); 655 /** @todo r=bird: The guest application exit code 656 * should by default be returned by the command. 657 * Non-normal exits and exit codes outside 658 * the portable range (0..127) should be 659 * translated to more portable values. 660 * 661 * Alternatively, we could return say exit code 16 if 662 * the guest command failed, 17 if it terminated on a 663 * signal, 18 if it abended and exit code 19 if it 664 * timed out. This is possibly a better solution. 665 * 666 * Think about people using VBoxManage for scripting. */ 614 667 } 615 668 } … … 624 677 } 625 678 626 if (RT_FAILURE(vrc) )627 r c = VBOX_E_IPRT_ERROR;628 return SUCCEEDED(rc) ? 0 : 1;679 if (RT_FAILURE(vrc) || FAILED(rc)) 680 return RTEXITCODE_FAILURE; 681 return RTEXITCODE_SUCCESS; 629 682 } 630 683 … … 709 762 * @param pszFilter Search filter (e.g. *.pdf). 710 763 * @param pszDest Destination directory. 711 * @param uFlags Copy flags.764 * @param fFlags Copy flags. 712 765 * @param pcObjects Where to store the overall objects to 713 766 * copy found. … … 716 769 static int ctrlCopyDirectoryRead(const char *pszRootDir, const char *pszSubDir, 717 770 const char *pszFilter, const char *pszDest, 718 uint32_t uFlags, uint32_t *pcObjects, PRTLISTNODE pList)771 uint32_t fFlags, uint32_t *pcObjects, PRTLISTNODE pList) 719 772 { 720 773 AssertPtrReturn(pszRootDir, VERR_INVALID_POINTER); … … 762 815 break; 763 816 } 764 if ( uFlags & CopyFileFlag_Recursive)817 if (fFlags & CopyFileFlag_Recursive) 765 818 { 766 819 char *pszNewSub = NULL; … … 774 827 rc = ctrlCopyDirectoryRead(pszRootDir, pszNewSub, 775 828 pszFilter, pszDest, 776 uFlags, pcObjects, pList);829 fFlags, pcObjects, pList); 777 830 RTStrFree(pszNewSub); 778 831 } … … 783 836 784 837 case RTDIRENTRYTYPE_SYMLINK: 785 if ( ( uFlags & CopyFileFlag_Recursive)786 && ( uFlags & CopyFileFlag_FollowLinks))838 if ( (fFlags & CopyFileFlag_Recursive) 839 && (fFlags & CopyFileFlag_FollowLinks)) 787 840 { 788 841 /* Fall through to next case is intentional. */ … … 852 905 * @param pszSource Source path on host to use. 853 906 * @param pszDest Destination path on guest to use. 854 * @param uFlags Copy flags.907 * @param fFlags Copy flags. 855 908 * @param pcObjects Where to store the count of objects to be copied. 856 909 * @param pList Where to store the object list. 857 910 */ 858 static int ctrlCopyInit(const char *pszSource, const char *pszDest, uint32_t uFlags,911 static int ctrlCopyInit(const char *pszSource, const char *pszDest, uint32_t fFlags, 859 912 uint32_t *pcObjects, PRTLISTNODE pList) 860 913 { … … 958 1011 rc = ctrlCopyDirectoryRead(pszSourceAbsRoot, NULL /* Sub directory */, 959 1012 pszFilter, pszDestAbs, 960 uFlags, pcObjects, pList);1013 fFlags, pcObjects, pList); 961 1014 if (RT_SUCCESS(rc) && *pcObjects == 0) 962 1015 rc = VERR_NOT_FOUND; … … 988 1041 * @param pszUserName User name on guest to use for the copy operation. 989 1042 * @param pszPassword Password of user account. 990 * @param uFlags Copy flags.1043 * @param fFlags Copy flags. 991 1044 */ 992 1045 static int ctrlCopyFileToGuest(IGuest *pGuest, bool fVerbose, const char *pszSource, const char *pszDest, 993 1046 const char *pszUserName, const char *pszPassword, 994 uint32_t uFlags)1047 uint32_t fFlags) 995 1048 { 996 1049 AssertPtrReturn(pszSource, VERR_INVALID_PARAMETER); … … 1003 1056 HRESULT rc = pGuest->CopyToGuest(Bstr(pszSource).raw(), Bstr(pszDest).raw(), 1004 1057 Bstr(pszUserName).raw(), Bstr(pszPassword).raw(), 1005 uFlags, progress.asOutParam());1058 fFlags, progress.asOutParam()); 1006 1059 if (FAILED(rc)) 1007 1060 vrc = ctrlPrintError(pGuest, COM_IIDOF(IGuest)); … … 1043 1096 Utf8Str Utf8UserName; 1044 1097 Utf8Str Utf8Password; 1045 uint32_t uFlags = CopyFileFlag_None;1098 uint32_t fFlags = CopyFileFlag_None; 1046 1099 bool fVerbose = false; 1047 1100 bool fCopyRecursive = false; … … 1062 1115 1063 1116 case 'F': /* Follow symlinks */ 1064 uFlags |= CopyFileFlag_FollowLinks;1117 fFlags |= CopyFileFlag_FollowLinks; 1065 1118 break; 1066 1119 … … 1070 1123 1071 1124 case 'R': /* Recursive processing */ 1072 uFlags |= CopyFileFlag_Recursive;1125 fFlags |= CopyFileFlag_Recursive; 1073 1126 break; 1074 1127 … … 1139 1192 RTLISTNODE listToCopy; 1140 1193 uint32_t cObjects = 0; 1141 vrc = ctrlCopyInit(Utf8Source.c_str(), Utf8Dest.c_str(), uFlags,1194 vrc = ctrlCopyInit(Utf8Source.c_str(), Utf8Dest.c_str(), fFlags, 1142 1195 &cObjects, &listToCopy); 1143 1196 if (RT_FAILURE(vrc)) … … 1184 1237 if (!fDryRun) 1185 1238 vrc = ctrlCopyFileToGuest(guest, fVerbose, pNode->pszSourcePath, pNode->pszDestPath, 1186 Utf8UserName.c_str(), Utf8Password.c_str(), uFlags);1239 Utf8UserName.c_str(), Utf8Password.c_str(), fFlags); 1187 1240 } 1188 1241 if (RT_FAILURE(vrc)) … … 1228 1281 Utf8Str Utf8UserName; 1229 1282 Utf8Str Utf8Password; 1230 uint32_t uFlags = CreateDirectoryFlag_None;1283 uint32_t fFlags = CreateDirectoryFlag_None; 1231 1284 uint32_t uMode = 0; 1232 1285 bool fVerbose = false; … … 1249 1302 1250 1303 case 'P': /* Create parents */ 1251 uFlags |= CreateDirectoryFlag_Parents;1304 fFlags |= CreateDirectoryFlag_Parents; 1252 1305 break; 1253 1306 … … 1314 1367 rc = guest->CreateDirectory(Bstr(pNode->pszDestPath).raw(), 1315 1368 Bstr(Utf8UserName).raw(), Bstr(Utf8Password).raw(), 1316 uMode, uFlags, progress.asOutParam());1369 uMode, fFlags, progress.asOutParam()); 1317 1370 if (FAILED(rc)) 1318 1371 { … … 1445 1498 int handleGuestControl(HandlerArg *a) 1446 1499 { 1500 /** @todo This command does not follow the syntax where the <uuid|vmname> 1501 * comes between the command and subcommand. The commands controlvm, 1502 * snapshot and debugvm puts it between. The commands guestproperty, 1503 * guestcontrol and sharedfolder puts it after (the latter is 1504 * questionable). 1505 * 1506 * I would propose changing guestcontrol and guestproperty to the controlvm 1507 * syntax in 4.1. Whether sharedfolder should be changed as well is a bit 1508 * more open. 1509 */ 1510 1447 1511 HandlerArg arg = *a; 1448 1512 arg.argc = a->argc - 1; … … 1453 1517 1454 1518 /* switch (cmd) */ 1519 /** @todo r=bird: Subcommands are not case insensitive for other commands 1520 * like controlvm. Drop it. */ 1455 1521 if ( !RTStrICmp(a->argv[0], "exec") 1456 1522 || !RTStrICmp(a->argv[0], "execute")) 1457 {1458 1523 return handleCtrlExecProgram(&arg); 1459 } 1460 else if ( !RTStrICmp(a->argv[0], "copyto") 1461 || !RTStrICmp(a->argv[0], "cp")) 1462 { 1524 1525 if ( !RTStrICmp(a->argv[0], "copyto") 1526 || !RTStrICmp(a->argv[0], "cp")) 1463 1527 return handleCtrlCopyTo(&arg); 1464 } 1465 else if ( !RTStrICmp(a->argv[0], "createdirectory") 1466 || !RTStrICmp(a->argv[0], "createdir") 1467 || !RTStrICmp(a->argv[0], "mkdir") 1468 || !RTStrICmp(a->argv[0], "md")) 1469 { 1528 1529 if ( !RTStrICmp(a->argv[0], "createdirectory") 1530 || !RTStrICmp(a->argv[0], "createdir") 1531 || !RTStrICmp(a->argv[0], "mkdir") 1532 || !RTStrICmp(a->argv[0], "md")) 1470 1533 return handleCtrlCreateDirectory(&arg); 1471 } 1472 else if ( !RTStrICmp(a->argv[0], "updateadditions") 1473 || !RTStrICmp(a->argv[0], "updateadds")) 1474 { 1534 1535 if ( !RTStrICmp(a->argv[0], "updateadditions") 1536 || !RTStrICmp(a->argv[0], "updateadds")) 1475 1537 return handleCtrlUpdateAdditions(&arg); 1476 }1477 1538 1478 1539 /* default: */
Note:
See TracChangeset
for help on using the changeset viewer.