Changeset 33672 in vbox
- Timestamp:
- Nov 2, 2010 9:11:46 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r33597 r33672 302 302 "No user name specified!"); 303 303 304 /* lookup VM. */304 /* Lookup VM. */ 305 305 ComPtr<IMachine> machine; 306 /* Assume it's an UUID. */ 306 307 HRESULT rc; 307 308 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(), 308 309 machine.asOutParam())); 309 if (machine) 310 { 311 do 312 { 313 /* open an existing session for VM */ 314 CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Shared)); 315 // @todo r=dj assert that it's an existing session 316 317 /* get the mutable session machine */ 318 a->session->COMGETTER(Machine)(machine.asOutParam()); 319 320 /* get the associated console */ 321 ComPtr<IConsole> console; 322 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam())); 323 324 ComPtr<IGuest> guest; 325 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam())); 326 327 ComPtr<IProgress> progress; 328 ULONG uPID = 0; 329 330 if (fVerbose) 331 { 332 if (u32TimeoutMS == 0) 333 RTPrintf("Waiting for guest to start process ...\n"); 310 if (FAILED(rc)) 311 return 1; 312 313 /* Machine is running? */ 314 MachineState_T machineState; 315 CHECK_ERROR_RET(machine, COMGETTER(State)(&machineState), 1); 316 if (machineState != MachineState_Running) 317 { 318 RTMsgError("Machine \"%s\" is not running!\n", a->argv[0]); 319 return 1; 320 } 321 322 /* Open a session for the VM. */ 323 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1); 324 325 do 326 { 327 /* Get the associated console. */ 328 ComPtr<IConsole> console; 329 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam())); 330 /* ... and session machine */ 331 ComPtr<IMachine> sessionMachine; 332 CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam())); 333 334 ComPtr<IGuest> guest; 335 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam())); 336 337 ComPtr<IProgress> progress; 338 ULONG uPID = 0; 339 340 if (fVerbose) 341 { 342 if (u32TimeoutMS == 0) 343 RTPrintf("Waiting for guest to start process ...\n"); 344 else 345 RTPrintf("Waiting for guest to start process (within %ums)\n", u32TimeoutMS); 346 } 347 348 /* Get current time stamp to later calculate rest of timeout left. */ 349 uint64_t u64StartMS = RTTimeMilliTS(); 350 351 /* Execute the process. */ 352 rc = guest->ExecuteProcess(Bstr(Utf8Cmd).raw(), uFlags, 353 ComSafeArrayAsInParam(args), 354 ComSafeArrayAsInParam(env), 355 Bstr(Utf8UserName).raw(), 356 Bstr(Utf8Password).raw(), u32TimeoutMS, 357 &uPID, progress.asOutParam()); 358 if (FAILED(rc)) 359 { 360 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 361 * because it contains more accurate info about what went wrong. */ 362 ErrorInfo info(guest, COM_IIDOF(IGuest)); 363 if (info.isFullAvailable()) 364 { 365 if (rc == VBOX_E_IPRT_ERROR) 366 RTMsgError("%ls.", info.getText().raw()); 334 367 else 335 RTPrintf("Waiting for guest to start process (within %ums)\n", u32TimeoutMS); 336 } 337 338 /* Get current time stamp to later calculate rest of timeout left. */ 339 uint64_t u64StartMS = RTTimeMilliTS(); 340 341 /* Execute the process. */ 342 rc = guest->ExecuteProcess(Bstr(Utf8Cmd).raw(), uFlags, 343 ComSafeArrayAsInParam(args), 344 ComSafeArrayAsInParam(env), 345 Bstr(Utf8UserName).raw(), 346 Bstr(Utf8Password).raw(), u32TimeoutMS, 347 &uPID, progress.asOutParam()); 348 if (FAILED(rc)) 349 { 350 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 351 * because it contains more accurate info about what went wrong. */ 352 ErrorInfo info(guest, COM_IIDOF(IGuest)); 353 if (info.isFullAvailable()) 354 { 355 if (rc == VBOX_E_IPRT_ERROR) 356 RTMsgError("%ls.", info.getText().raw()); 357 else 358 RTMsgError("%ls (%Rhrc).", info.getText().raw(), info.getResultCode()); 359 } 360 break; 361 } 362 if (fVerbose) 363 RTPrintf("Process '%s' (PID: %u) started\n", Utf8Cmd.c_str(), uPID); 364 if (fWaitForExit) 365 { 366 if (fTimeout) 367 { 368 /* Calculate timeout value left after process has been started. */ 369 uint64_t u64Elapsed = RTTimeMilliTS() - u64StartMS; 370 /* Is timeout still bigger than current difference? */ 371 if (u32TimeoutMS > u64Elapsed) 368 RTMsgError("%ls (%Rhrc).", info.getText().raw(), info.getResultCode()); 369 } 370 break; 371 } 372 if (fVerbose) 373 RTPrintf("Process '%s' (PID: %u) started\n", Utf8Cmd.c_str(), uPID); 374 if (fWaitForExit) 375 { 376 if (fTimeout) 377 { 378 /* Calculate timeout value left after process has been started. */ 379 uint64_t u64Elapsed = RTTimeMilliTS() - u64StartMS; 380 /* Is timeout still bigger than current difference? */ 381 if (u32TimeoutMS > u64Elapsed) 382 { 383 u32TimeoutMS -= (uint32_t)u64Elapsed; 384 if (fVerbose) 385 RTPrintf("Waiting for process to exit (%ums left) ...\n", u32TimeoutMS); 386 } 387 else 388 { 389 if (fVerbose) 390 RTPrintf("No time left to wait for process!\n"); 391 } 392 } 393 else if (fVerbose) 394 RTPrintf("Waiting for process to exit ...\n"); 395 396 /* Setup signal handling if cancelable. */ 397 ASSERT(progress); 398 bool fCanceledAlready = false; 399 BOOL fCancelable; 400 HRESULT hrc = progress->COMGETTER(Cancelable)(&fCancelable); 401 if (FAILED(hrc)) 402 fCancelable = FALSE; 403 if (fCancelable) 404 { 405 signal(SIGINT, ctrlExecProcessSignalHandler); 406 #ifdef SIGBREAK 407 signal(SIGBREAK, ctrlExecProcessSignalHandler); 408 #endif 409 } 410 411 /* Wait for process to exit ... */ 412 BOOL fCompleted = FALSE; 413 BOOL fCanceled = FALSE; 414 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted)))) 415 { 416 SafeArray<BYTE> aOutputData; 417 ULONG cbOutputData = 0; 418 419 /* 420 * Some data left to output? 421 */ 422 if ( fWaitForStdOut 423 || fWaitForStdErr) 424 { 425 rc = guest->GetProcessOutput(uPID, 0 /* aFlags */, 426 u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)); 427 if (FAILED(rc)) 372 428 { 373 u32TimeoutMS -= (uint32_t)u64Elapsed; 374 if (fVerbose) 375 RTPrintf("Waiting for process to exit (%ums left) ...\n", u32TimeoutMS); 429 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 430 * because it contains more accurate info about what went wrong. */ 431 ErrorInfo info(guest, COM_IIDOF(IGuest)); 432 if (info.isFullAvailable()) 433 { 434 if (rc == VBOX_E_IPRT_ERROR) 435 RTMsgError("%ls.", info.getText().raw()); 436 else 437 RTMsgError("%ls (%Rhrc).", info.getText().raw(), info.getResultCode()); 438 } 439 cbOutputData = 0; 440 fCompleted = true; /* rc contains a failure, so we'll go into aborted state down below. */ 376 441 } 377 442 else 378 443 { 379 if (fVerbose) 380 RTPrintf("No time left to wait for process!\n"); 444 cbOutputData = aOutputData.size(); 445 if (cbOutputData > 0) 446 { 447 /* aOutputData has a platform dependent line ending, standardize on 448 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on 449 * Windows. Otherwise we end up with CR/CR/LF on Windows. */ 450 ULONG cbOutputDataPrint = cbOutputData; 451 for (BYTE *s = aOutputData.raw(), *d = s; 452 s - aOutputData.raw() < (ssize_t)cbOutputData; 453 s++, d++) 454 { 455 if (*s == '\r') 456 { 457 /* skip over CR, adjust destination */ 458 d--; 459 cbOutputDataPrint--; 460 } 461 else if (s != d) 462 *d = *s; 463 } 464 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint); 465 } 381 466 } 382 467 } 383 else if (fVerbose) 384 RTPrintf("Waiting for process to exit ...\n"); 385 386 /* Setup signal handling if cancelable. */ 387 ASSERT(progress); 388 bool fCanceledAlready = false; 389 BOOL fCancelable; 390 HRESULT hrc = progress->COMGETTER(Cancelable)(&fCancelable); 391 if (FAILED(hrc)) 392 fCancelable = FALSE; 393 if (fCancelable) 394 { 395 signal(SIGINT, ctrlExecProcessSignalHandler); 396 #ifdef SIGBREAK 397 signal(SIGBREAK, ctrlExecProcessSignalHandler); 398 #endif 399 } 400 401 /* Wait for process to exit ... */ 402 BOOL fCompleted = FALSE; 403 BOOL fCanceled = FALSE; 404 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted)))) 405 { 406 SafeArray<BYTE> aOutputData; 407 ULONG cbOutputData = 0; 408 409 /* 410 * Some data left to output? 411 */ 412 if ( fWaitForStdOut 413 || fWaitForStdErr) 468 if (cbOutputData <= 0) /* No more output data left? */ 469 { 470 if (fCompleted) 471 break; 472 473 if ( fTimeout 474 && RTTimeMilliTS() - u64StartMS > u32TimeoutMS + 5000) 414 475 { 415 rc = guest->GetProcessOutput(uPID, 0 /* aFlags */, 416 u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)); 417 if (FAILED(rc)) 418 { 419 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 420 * because it contains more accurate info about what went wrong. */ 421 ErrorInfo info(guest, COM_IIDOF(IGuest)); 422 if (info.isFullAvailable()) 423 { 424 if (rc == VBOX_E_IPRT_ERROR) 425 RTMsgError("%ls.", info.getText().raw()); 426 else 427 RTMsgError("%ls (%Rhrc).", info.getText().raw(), info.getResultCode()); 428 } 429 cbOutputData = 0; 430 fCompleted = true; /* rc contains a failure, so we'll go into aborted state down below. */ 431 } 476 progress->Cancel(); 477 break; 478 } 479 } 480 481 /* Process async cancelation */ 482 if (g_fExecCanceled && !fCanceledAlready) 483 { 484 hrc = progress->Cancel(); 485 if (SUCCEEDED(hrc)) 486 fCanceledAlready = TRUE; 487 else 488 g_fExecCanceled = false; 489 } 490 491 /* Progress canceled by Main API? */ 492 if ( SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled))) 493 && fCanceled) 494 { 495 break; 496 } 497 } 498 499 /* Undo signal handling */ 500 if (fCancelable) 501 { 502 signal(SIGINT, SIG_DFL); 503 #ifdef SIGBREAK 504 signal(SIGBREAK, SIG_DFL); 505 #endif 506 } 507 508 if (fCanceled) 509 { 510 if (fVerbose) 511 RTPrintf("Process execution canceled!\n"); 512 } 513 else if ( fCompleted 514 && SUCCEEDED(rc)) 515 { 516 LONG iRc = false; 517 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc); 518 if (FAILED(iRc)) 519 { 520 com::ProgressErrorInfo info(progress); 521 if ( info.isFullAvailable() 522 || info.isBasicAvailable()) 523 { 524 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 525 * because it contains more accurate info about what went wrong. */ 526 if (info.getResultCode() == VBOX_E_IPRT_ERROR) 527 RTMsgError("%ls.", info.getText().raw()); 432 528 else 433 529 { 434 cbOutputData = aOutputData.size(); 435 if (cbOutputData > 0) 436 { 437 /* aOutputData has a platform dependent line ending, standardize on 438 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on 439 * Windows. Otherwise we end up with CR/CR/LF on Windows. */ 440 ULONG cbOutputDataPrint = cbOutputData; 441 for (BYTE *s = aOutputData.raw(), *d = s; 442 s - aOutputData.raw() < (ssize_t)cbOutputData; 443 s++, d++) 444 { 445 if (*s == '\r') 446 { 447 /* skip over CR, adjust destination */ 448 d--; 449 cbOutputDataPrint--; 450 } 451 else if (s != d) 452 *d = *s; 453 } 454 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint); 455 } 530 RTMsgError("Process error details:"); 531 GluePrintErrorInfo(info); 456 532 } 457 533 } 458 if (cbOutputData <= 0) /* No more output data left? */ 459 { 460 if (fCompleted) 461 break; 462 463 if ( fTimeout 464 && RTTimeMilliTS() - u64StartMS > u32TimeoutMS + 5000) 465 { 466 progress->Cancel(); 467 break; 468 } 469 } 470 471 /* Process async cancelation */ 472 if (g_fExecCanceled && !fCanceledAlready) 473 { 474 hrc = progress->Cancel(); 475 if (SUCCEEDED(hrc)) 476 fCanceledAlready = TRUE; 477 else 478 g_fExecCanceled = false; 479 } 480 481 /* Progress canceled by Main API? */ 482 if ( SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled))) 483 && fCanceled) 484 { 485 break; 486 } 487 } 488 489 /* Undo signal handling */ 490 if (fCancelable) 491 { 492 signal(SIGINT, SIG_DFL); 493 #ifdef SIGBREAK 494 signal(SIGBREAK, SIG_DFL); 495 #endif 496 } 497 498 if (fCanceled) 499 { 500 if (fVerbose) 501 RTPrintf("Process execution canceled!\n"); 502 } 503 else if ( fCompleted 504 && SUCCEEDED(rc)) 505 { 506 LONG iRc = false; 507 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc); 508 if (FAILED(iRc)) 509 { 510 com::ProgressErrorInfo info(progress); 511 if ( info.isFullAvailable() 512 || info.isBasicAvailable()) 513 { 514 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 515 * because it contains more accurate info about what went wrong. */ 516 if (info.getResultCode() == VBOX_E_IPRT_ERROR) 517 RTMsgError("%ls.", info.getText().raw()); 518 else 519 { 520 RTMsgError("Process error details:"); 521 GluePrintErrorInfo(info); 522 } 523 } 524 else 525 com::GluePrintRCMessage(iRc); 526 } 527 else if (fVerbose) 528 { 529 ULONG uRetStatus, uRetExitCode, uRetFlags; 530 rc = guest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus); 531 if (SUCCEEDED(rc)) 532 RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, ctrlExecGetStatus(uRetStatus), uRetFlags); 533 } 534 } 535 else 536 { 537 if (fVerbose) 538 RTPrintf("Process execution aborted!\n"); 539 } 540 } 541 a->session->UnlockMachine(); 542 } while (0); 543 } 534 else 535 com::GluePrintRCMessage(iRc); 536 } 537 else if (fVerbose) 538 { 539 ULONG uRetStatus, uRetExitCode, uRetFlags; 540 rc = guest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus); 541 if (SUCCEEDED(rc)) 542 RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, ctrlExecGetStatus(uRetStatus), uRetFlags); 543 } 544 } 545 else 546 { 547 if (fVerbose) 548 RTPrintf("Process execution aborted!\n"); 549 } 550 } 551 a->session->UnlockMachine(); 552 } while (0); 544 553 return SUCCEEDED(rc) ? 0 : 1; 545 554 }
Note:
See TracChangeset
for help on using the changeset viewer.

