- Timestamp:
- May 25, 2020 5:29:52 PM (5 years ago)
- Location:
- trunk/src/VBox/Frontends/VBoxManage
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h
r84032 r84519 144 144 # define HELP_SCOPE_GSTCTRL_UPDATEGA RT_BIT(13) 145 145 # define HELP_SCOPE_GSTCTRL_WATCH RT_BIT(14) 146 # define HELP_SCOPE_GSTCTRL_WAITRUNLEVEL RT_BIT(15) 146 147 #endif 147 148 -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r83874 r84519 44 44 #include <iprt/path.h> 45 45 #include <iprt/process.h> /* For RTProcSelf(). */ 46 #include <iprt/semaphore.h> 46 47 #include <iprt/thread.h> 47 48 #include <iprt/vfs.h> … … 104 105 * action shall be aborted. */ 105 106 static volatile bool g_fGuestCtrlCanceled = false; 107 /** Event semaphore used for wait notifications. 108 * Also being used for the listener implementations in VBoxManageGuestCtrlListener.cpp. */ 109 RTSEMEVENT g_SemEventGuestCtrlCanceled = NIL_RTSEMEVENT; 106 110 107 111 … … 116 120 VBOX_LISTENER_DECLARE(GuestSessionEventListenerImpl) 117 121 VBOX_LISTENER_DECLARE(GuestEventListenerImpl) 118 122 VBOX_LISTENER_DECLARE(GuestAdditionsRunlevelListener) 119 123 120 124 /** … … 237 241 | HELP_SCOPE_GSTCTRL_CLOSESESSION 238 242 | HELP_SCOPE_GSTCTRL_UPDATEGA 239 | HELP_SCOPE_GSTCTRL_WATCH; 243 | HELP_SCOPE_GSTCTRL_WATCH 244 | HELP_SCOPE_GSTCTRL_WAITRUNLEVEL; 240 245 241 246 /* 0 1 2 3 4 5 6 7 8XXXXXXXXXX */ … … 358 363 if (fSubcommandScope & HELP_SCOPE_GSTCTRL_WATCH) 359 364 RTStrmPrintf(pStrm, 360 " watch [common-options]\n" 365 " watch [--timeout <msec>] [common-options]\n" 366 "\n"); 367 if (fSubcommandScope & HELP_SCOPE_GSTCTRL_WAITRUNLEVEL) 368 RTStrmPrintf(pStrm, 369 " waitrunlevel [--timeout <msec>] [common-options]\n" 370 " <system|userland|desktop>\n" 361 371 "\n"); 362 372 } … … 427 437 # endif 428 438 #endif 439 440 if (RT_SUCCESS(rc)) 441 rc = RTSemEventCreate(&g_SemEventGuestCtrlCanceled); 442 429 443 return rc; 430 444 } … … 450 464 # endif 451 465 #endif 466 467 if (g_SemEventGuestCtrlCanceled != NIL_RTSEMEVENT) 468 { 469 RTSemEventDestroy(g_SemEventGuestCtrlCanceled); 470 g_SemEventGuestCtrlCanceled = NIL_RTSEMEVENT; 471 } 452 472 return rc; 453 473 } … … 2653 2673 } 2654 2674 2675 /** 2676 * Waits for a Guest Additions run level being reached. 2677 * 2678 * @returns VBox status code. 2679 * Returns VERR_CANCELLED if waiting for cancelled due to signal handling, e.g. when CTRL+C or some sort was pressed. 2680 * @param pCtx The guest control command context. 2681 * @param enmRunLevel Run level to wait for. 2682 * @param cMsTimeout Timeout (in ms) for waiting. 2683 */ 2684 static int gctlWaitForRunLevel(PGCTLCMDCTX pCtx, AdditionsRunLevelType_T enmRunLevel, RTMSINTERVAL cMsTimeout) 2685 { 2686 int vrc; 2687 2688 try 2689 { 2690 HRESULT rc = S_OK; 2691 /** Whether we need to actually wait for the run level or if we already reached it. */ 2692 bool fWait; 2693 2694 /* Install an event handler first to catch any runlevel changes. */ 2695 ComObjPtr<GuestAdditionsRunlevelListenerImpl> pGuestListener; 2696 do 2697 { 2698 /* Listener creation. */ 2699 pGuestListener.createObject(); 2700 pGuestListener->init(new GuestAdditionsRunlevelListener(enmRunLevel)); 2701 2702 /* Register for IGuest events. */ 2703 ComPtr<IEventSource> es; 2704 CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(EventSource)(es.asOutParam())); 2705 com::SafeArray<VBoxEventType_T> eventTypes; 2706 eventTypes.push_back(VBoxEventType_OnGuestAdditionsStatusChanged); 2707 CHECK_ERROR_BREAK(es, RegisterListener(pGuestListener, ComSafeArrayAsInParam(eventTypes), 2708 true /* Active listener */)); 2709 2710 AdditionsRunLevelType_T enmRunLevelCur = AdditionsRunLevelType_None; 2711 CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(AdditionsRunLevel)(&enmRunLevelCur)); 2712 fWait = enmRunLevelCur != enmRunLevel; 2713 2714 if (pCtx->cVerbose) 2715 RTPrintf("Current run level is %RU32\n", enmRunLevelCur); 2716 2717 } while (0); 2718 2719 if (fWait) 2720 { 2721 if (pCtx->cVerbose) 2722 RTPrintf("Waiting for run level %RU32 ...\n", enmRunLevel); 2723 2724 RTMSINTERVAL tsStart = RTTimeMilliTS(); 2725 while (RTTimeMilliTS() - tsStart < cMsTimeout) 2726 { 2727 /* Wait for the global signal semaphore getting signalled. */ 2728 vrc = RTSemEventWait(g_SemEventGuestCtrlCanceled, 100 /* ms */); 2729 if (RT_FAILURE(vrc)) 2730 { 2731 if (vrc == VERR_TIMEOUT) 2732 continue; 2733 else 2734 { 2735 RTPrintf("Waiting failed with %Rrc\n", vrc); 2736 break; 2737 } 2738 } 2739 else if (pCtx->cVerbose) 2740 { 2741 RTPrintf("Run level %RU32 reached\n", enmRunLevel); 2742 break; 2743 } 2744 2745 NativeEventQueue::getMainEventQueue()->processEventQueue(0); 2746 } 2747 2748 if ( vrc == VERR_TIMEOUT 2749 && pCtx->cVerbose) 2750 RTPrintf("Run level %RU32 not reached within time\n", enmRunLevel); 2751 } 2752 2753 if (!pGuestListener.isNull()) 2754 { 2755 /* Guest callback unregistration. */ 2756 ComPtr<IEventSource> pES; 2757 CHECK_ERROR(pCtx->pGuest, COMGETTER(EventSource)(pES.asOutParam())); 2758 if (!pES.isNull()) 2759 CHECK_ERROR(pES, UnregisterListener(pGuestListener)); 2760 pGuestListener.setNull(); 2761 } 2762 2763 if (g_fGuestCtrlCanceled) 2764 vrc = VERR_CANCELLED; 2765 } 2766 catch (std::bad_alloc &) 2767 { 2768 vrc = VERR_NO_MEMORY; 2769 } 2770 2771 return vrc; 2772 } 2773 2655 2774 static DECLCALLBACK(RTEXITCODE) gctlHandleUpdateAdditions(PGCTLCMDCTX pCtx, int argc, char **argv) 2656 2775 { 2657 2776 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 2658 2777 2778 /** Timeout to wait for the whole updating procedure to complete. */ 2779 uint32_t cMsTimeout = RT_INDEFINITE_WAIT; 2780 /** Source path to .ISO Guest Additions file to use. */ 2781 Utf8Str strSource; 2782 com::SafeArray<IN_BSTR> aArgs; 2783 /* Whether to reboot the guest automatically when the update process has finished successfully. */ 2784 bool fRebootOnFinish = false; 2785 /* Whether to only wait for getting the update process started instead of waiting until it finishes. */ 2786 bool fWaitStartOnly = false; 2787 /* Whether to wait for the VM being ready to start the update. Needs Guest Additions facility reporting. */ 2788 bool fWaitReady = false; 2789 /* Whether to verify if the Guest Additions were successfully updated on the guest. */ 2790 bool fVerify = false; 2791 2659 2792 /* 2660 * Check the syntax. We can deduce the correct syntax from the number of 2661 * arguments. 2793 * Parse arguments. 2662 2794 */ 2663 Utf8Str strSource; 2664 com::SafeArray<IN_BSTR> aArgs; 2665 bool fWaitStartOnly = false; 2795 enum KGSTCTRLUPDATEADDITIONSOPT 2796 { 2797 KGSTCTRLUPDATEADDITIONSOPT_REBOOT = 1000, 2798 KGSTCTRLUPDATEADDITIONSOPT_SOURCE, 2799 KGSTCTRLUPDATEADDITIONSOPT_TIMEOUT, 2800 KGSTCTRLUPDATEADDITIONSOPT_VERIFY, 2801 KGSTCTRLUPDATEADDITIONSOPT_WAITREADY, 2802 KGSTCTRLUPDATEADDITIONSOPT_WAITSTART 2803 }; 2666 2804 2667 2805 static const RTGETOPTDEF s_aOptions[] = 2668 2806 { 2669 2807 GCTLCMD_COMMON_OPTION_DEFS() 2670 { "--source", 's', RTGETOPT_REQ_STRING }, 2671 { "--wait-start", 'w', RTGETOPT_REQ_NOTHING } 2808 { "--reboot", KGSTCTRLUPDATEADDITIONSOPT_REBOOT, RTGETOPT_REQ_NOTHING }, 2809 { "--source", KGSTCTRLUPDATEADDITIONSOPT_SOURCE, RTGETOPT_REQ_STRING }, 2810 { "--timeout", KGSTCTRLUPDATEADDITIONSOPT_TIMEOUT, RTGETOPT_REQ_UINT32 }, 2811 { "--verify", KGSTCTRLUPDATEADDITIONSOPT_VERIFY, RTGETOPT_REQ_NOTHING }, 2812 { "--wait-ready", KGSTCTRLUPDATEADDITIONSOPT_WAITREADY, RTGETOPT_REQ_NOTHING }, 2813 { "--wait-start", KGSTCTRLUPDATEADDITIONSOPT_WAITSTART, RTGETOPT_REQ_NOTHING } 2672 2814 }; 2673 2815 … … 2685 2827 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 2686 2828 2687 case 's': 2829 case KGSTCTRLUPDATEADDITIONSOPT_REBOOT: 2830 fRebootOnFinish = true; 2831 break; 2832 2833 case KGSTCTRLUPDATEADDITIONSOPT_SOURCE: 2688 2834 vrc = RTPathAbsCxx(strSource, ValueUnion.psz); 2689 2835 if (RT_FAILURE(vrc)) … … 2691 2837 break; 2692 2838 2693 case 'w':2839 case KGSTCTRLUPDATEADDITIONSOPT_WAITSTART: 2694 2840 fWaitStartOnly = true; 2841 break; 2842 2843 case KGSTCTRLUPDATEADDITIONSOPT_WAITREADY: 2844 fWaitReady = true; 2845 break; 2846 2847 case KGSTCTRLUPDATEADDITIONSOPT_VERIFY: 2848 fVerify = true; 2695 2849 break; 2696 2850 … … 2733 2887 } 2734 2888 2889 2890 2891 #if 0 2892 ComPtr<IGuest> guest; 2893 rc = pConsole->COMGETTER(Guest)(guest.asOutParam()); 2894 if (SUCCEEDED(rc) && !guest.isNull()) 2895 { 2896 SHOW_STRING_PROP_NOT_EMPTY(guest, OSTypeId, "GuestOSType", "OS type:"); 2897 2898 AdditionsRunLevelType_T guestRunLevel; /** @todo Add a runlevel-to-string (e.g. 0 = "None") method? */ 2899 rc = guest->COMGETTER(AdditionsRunLevel)(&guestRunLevel); 2900 if (SUCCEEDED(rc)) 2901 SHOW_ULONG_VALUE("GuestAdditionsRunLevel", "Additions run level:", (ULONG)guestRunLevel, ""); 2902 2903 Bstr guestString; 2904 rc = guest->COMGETTER(AdditionsVersion)(guestString.asOutParam()); 2905 if ( SUCCEEDED(rc) 2906 && !guestString.isEmpty()) 2907 { 2908 ULONG uRevision; 2909 rc = guest->COMGETTER(AdditionsRevision)(&uRevision); 2910 if (FAILED(rc)) 2911 uRevision = 0; 2912 RTStrPrintf(szValue, sizeof(szValue), "%ls r%u", guestString.raw(), uRevision); 2913 SHOW_UTF8_STRING("GuestAdditionsVersion", "Additions version:", szValue); 2914 } 2915 #endif 2916 2735 2917 if (RT_SUCCESS(vrc)) 2736 2918 { 2737 2919 if (pCtx->cVerbose) 2738 2920 RTPrintf("Using source: %s\n", strSource.c_str()); 2739 2740 2921 2741 2922 RTEXITCODE rcExit = gctlCtxPostOptionParsingInit(pCtx); … … 2743 2924 return rcExit; 2744 2925 2745 2746 com::SafeArray<AdditionsUpdateFlag_T> aUpdateFlags; 2747 if (fWaitStartOnly) 2748 { 2749 aUpdateFlags.push_back(AdditionsUpdateFlag_WaitForUpdateStartOnly); 2926 if (fWaitReady) 2927 { 2750 2928 if (pCtx->cVerbose) 2751 RTPrintf("Preparing and waiting for Guest Additions installer to start ...\n"); 2752 } 2753 2754 ComPtr<IProgress> pProgress; 2755 CHECK_ERROR(pCtx->pGuest, UpdateGuestAdditions(Bstr(strSource).raw(), 2756 ComSafeArrayAsInParam(aArgs), 2757 /* Wait for whole update process to complete. */ 2758 ComSafeArrayAsInParam(aUpdateFlags), 2759 pProgress.asOutParam())); 2760 if (FAILED(rc)) 2761 vrc = gctlPrintError(pCtx->pGuest, COM_IIDOF(IGuest)); 2762 else 2763 { 2764 if (pCtx->cVerbose) 2765 rc = showProgress(pProgress); 2929 RTPrintf("Waiting for current Guest Additions inside VM getting ready for updating ...\n"); 2930 2931 const uint64_t uTsStart = RTTimeMilliTS(); 2932 vrc = gctlWaitForRunLevel(pCtx, AdditionsRunLevelType_Userland, cMsTimeout); 2933 if (RT_SUCCESS(vrc)) 2934 cMsTimeout = cMsTimeout != RT_INDEFINITE_WAIT ? cMsTimeout - (RTTimeMilliTS() - uTsStart) : cMsTimeout; 2935 } 2936 2937 if (RT_SUCCESS(vrc)) 2938 { 2939 /* Get current Guest Additions version / revision. */ 2940 Bstr strGstVerCur; 2941 ULONG uGstRevCur = 0; 2942 rc = pCtx->pGuest->COMGETTER(AdditionsVersion)(strGstVerCur.asOutParam()); 2943 if ( SUCCEEDED(rc) 2944 && !strGstVerCur.isEmpty()) 2945 { 2946 rc = pCtx->pGuest->COMGETTER(AdditionsRevision)(&uGstRevCur); 2947 if (SUCCEEDED(rc)) 2948 { 2949 if (pCtx->cVerbose) 2950 RTPrintf("Guest Additions %lsr%RU64 currently installed, waiting for Guest Additions installer to start ...\n", 2951 strGstVerCur.raw(), uGstRevCur); 2952 } 2953 } 2954 2955 com::SafeArray<AdditionsUpdateFlag_T> aUpdateFlags; 2956 if (fWaitStartOnly) 2957 aUpdateFlags.push_back(AdditionsUpdateFlag_WaitForUpdateStartOnly); 2958 2959 ComPtr<IProgress> pProgress; 2960 CHECK_ERROR(pCtx->pGuest, UpdateGuestAdditions(Bstr(strSource).raw(), 2961 ComSafeArrayAsInParam(aArgs), 2962 ComSafeArrayAsInParam(aUpdateFlags), 2963 pProgress.asOutParam())); 2964 if (FAILED(rc)) 2965 vrc = gctlPrintError(pCtx->pGuest, COM_IIDOF(IGuest)); 2766 2966 else 2767 rc = pProgress->WaitForCompletion(-1 /* No timeout */);2768 2769 if (SUCCEEDED(rc))2770 CHECK_PROGRESS_ERROR(pProgress, ("Guest additions update failed"));2771 vrc = gctlPrintProgressError(pProgress);2772 if (RT_SUCCESS(vrc))2773 2967 { 2774 RTPrintf("Guest Additions update successful.\n"); 2775 RTPrintf("The guest needs to be restarted in order to make use of the updated Guest Additions.\n"); 2968 if (pCtx->cVerbose) 2969 rc = showProgress(pProgress); 2970 else 2971 rc = pProgress->WaitForCompletion((int32_t)cMsTimeout); 2972 2973 if (SUCCEEDED(rc)) 2974 CHECK_PROGRESS_ERROR(pProgress, ("Guest Additions update failed")); 2975 vrc = gctlPrintProgressError(pProgress); 2976 if (RT_SUCCESS(vrc)) 2977 { 2978 if (pCtx->cVerbose) 2979 RTPrintf("Guest Additions update successful.\n"); 2980 2981 if (fRebootOnFinish) 2982 { 2983 /** @todo Implement this. */ 2984 vrc = VERR_NOT_IMPLEMENTED; 2985 2986 if (RT_SUCCESS(vrc)) 2987 { 2988 if (pCtx->cVerbose) 2989 RTPrintf("Rebooting guest ...\n"); 2990 } 2991 2992 if (RT_SUCCESS(vrc)) 2993 { 2994 if (fWaitReady) 2995 { 2996 if (pCtx->cVerbose) 2997 RTPrintf("Waiting for new Guest Additions inside VM getting ready ...\n"); 2998 2999 vrc = gctlWaitForRunLevel(pCtx, AdditionsRunLevelType_Userland, cMsTimeout); 3000 if (RT_SUCCESS(vrc)) 3001 { 3002 if (fVerify) 3003 { 3004 if (pCtx->cVerbose) 3005 RTPrintf("Verifying Guest Additions update ...\n"); 3006 3007 /* Get new Guest Additions version / revision. */ 3008 Bstr strGstVerNew; 3009 ULONG uGstRevNew = 0; 3010 rc = pCtx->pGuest->COMGETTER(AdditionsVersion)(strGstVerNew.asOutParam()); 3011 if ( SUCCEEDED(rc) 3012 && !strGstVerNew.isEmpty()) 3013 { 3014 rc = pCtx->pGuest->COMGETTER(AdditionsRevision)(&uGstRevNew); 3015 if (FAILED(rc)) 3016 uGstRevNew = 0; 3017 } 3018 3019 /** @todo Do more verification here. */ 3020 vrc = uGstRevNew > uGstRevCur ? VINF_SUCCESS : VERR_NO_CHANGE; 3021 3022 if (pCtx->cVerbose) 3023 { 3024 RTPrintf("Old Guest Additions: %ls%RU64\n", strGstVerCur.raw(), uGstRevCur); 3025 RTPrintf("New Guest Additions: %ls%RU64\n", strGstVerNew.raw(), uGstRevNew); 3026 3027 if (RT_FAILURE(vrc)) 3028 { 3029 RTPrintf("\nError updating Guest Additions, please check guest installer log\n"); 3030 } 3031 else 3032 { 3033 if (uGstRevNew < uGstRevCur) 3034 RTPrintf("\nWARNING: Guest Additions were downgraded\n"); 3035 } 3036 } 3037 } 3038 } 3039 } 3040 else if (pCtx->cVerbose) 3041 RTPrintf("The guest needs to be restarted in order to make use of the updated Guest Additions.\n"); 3042 } 3043 } 3044 } 2776 3045 } 2777 3046 } 2778 3047 } 3048 3049 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 3050 } 3051 3052 /** 3053 * Returns a Guest Additions run level from a string. 3054 * 3055 * @returns Run level if found, or AdditionsRunLevelType_None if not found / invalid. 3056 * @param pcszStr String to return run level for. 3057 */ 3058 static AdditionsRunLevelType_T gctlGetRunLevelFromStr(const char *pcszStr) 3059 { 3060 AssertPtrReturn(pcszStr, AdditionsRunLevelType_None); 3061 3062 if (RTStrICmp(pcszStr, "system") == 0) return AdditionsRunLevelType_System; 3063 else if (RTStrICmp(pcszStr, "userland") == 0) return AdditionsRunLevelType_Userland; 3064 else if (RTStrICmp(pcszStr, "desktop") == 0) return AdditionsRunLevelType_Desktop; 3065 3066 return AdditionsRunLevelType_None; 3067 } 3068 3069 static DECLCALLBACK(RTEXITCODE) gctlHandleWaitRunLevel(PGCTLCMDCTX pCtx, int argc, char **argv) 3070 { 3071 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3072 3073 /** Timeout to wait for run level being reached. 3074 * By default we wait until it's reached. */ 3075 uint32_t cMsTimeout = RT_INDEFINITE_WAIT; 3076 3077 /* 3078 * Parse arguments. 3079 */ 3080 enum KGSTCTRLWAITRUNLEVELOPT 3081 { 3082 KGSTCTRLWAITRUNLEVELOPT_TIMEOUT = 1000 3083 }; 3084 3085 static const RTGETOPTDEF s_aOptions[] = 3086 { 3087 GCTLCMD_COMMON_OPTION_DEFS() 3088 { "--timeout", KGSTCTRLWAITRUNLEVELOPT_TIMEOUT, RTGETOPT_REQ_UINT32 } 3089 }; 3090 3091 int ch; 3092 RTGETOPTUNION ValueUnion; 3093 RTGETOPTSTATE GetState; 3094 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3095 3096 AdditionsRunLevelType_T enmRunLevel = AdditionsRunLevelType_None; 3097 3098 int vrc = VINF_SUCCESS; 3099 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 3100 && RT_SUCCESS(vrc)) 3101 { 3102 switch (ch) 3103 { 3104 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3105 3106 case KGSTCTRLWAITRUNLEVELOPT_TIMEOUT: 3107 cMsTimeout = ValueUnion.u32; 3108 break; 3109 3110 case VINF_GETOPT_NOT_OPTION: 3111 { 3112 enmRunLevel = gctlGetRunLevelFromStr(ValueUnion.psz); 3113 if (enmRunLevel == AdditionsRunLevelType_None) 3114 return errorSyntaxEx(USAGE_GUESTCONTROL, HELP_SCOPE_GSTCTRL_WAITRUNLEVEL, 3115 "Invalid run level specified. Valid values are: system, userland, desktop"); 3116 break; 3117 } 3118 3119 default: 3120 return errorGetOptEx(USAGE_GUESTCONTROL, HELP_SCOPE_GSTCTRL_WAITRUNLEVEL, ch, &ValueUnion); 3121 } 3122 } 3123 3124 RTEXITCODE rcExit = gctlCtxPostOptionParsingInit(pCtx); 3125 if (rcExit != RTEXITCODE_SUCCESS) 3126 return rcExit; 3127 3128 if (enmRunLevel == AdditionsRunLevelType_None) 3129 return errorSyntaxEx(USAGE_GUESTCONTROL, HELP_SCOPE_GSTCTRL_WAITRUNLEVEL, "Missing run level to wait for"); 3130 3131 vrc = gctlWaitForRunLevel(pCtx, enmRunLevel, cMsTimeout); 2779 3132 2780 3133 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; … … 3257 3610 { 3258 3611 GCTLCMD_COMMON_OPTION_DEFS() 3612 { "--timeout", 't', RTGETOPT_REQ_UINT32 } 3259 3613 }; 3614 3615 uint32_t cMsTimeout = RT_INDEFINITE_WAIT; 3260 3616 3261 3617 int ch; … … 3270 3626 { 3271 3627 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3628 3629 case 't': /* Timeout */ 3630 cMsTimeout = ValueUnion.u32; 3631 break; 3272 3632 3273 3633 case VINF_GETOPT_NOT_OPTION: … … 3311 3671 RTPrintf("Waiting for events ...\n"); 3312 3672 3313 /** @todo r=bird: This are-we-there-yet approach to things could easily be 3314 * replaced by a global event semaphore that gets signalled from the 3315 * signal handler and the callback event. Please fix! */ 3316 while (!g_fGuestCtrlCanceled) 3317 { 3318 /** @todo Timeout handling (see above)? */ 3319 RTThreadSleep(10); 3320 } 3321 3322 if (pCtx->cVerbose) 3323 RTPrintf("Signal caught, exiting ...\n"); 3673 /* Wait for the global signal semaphore getting signalled. */ 3674 int vrc = RTSemEventWait(g_SemEventGuestCtrlCanceled, cMsTimeout); 3675 if (vrc == VERR_TIMEOUT) 3676 { 3677 if (pCtx->cVerbose) 3678 RTPrintf("Waiting done\n"); 3679 } 3680 else if (RT_FAILURE(vrc)) 3681 RTPrintf("Waiting failed with %Rrc\n", vrc); 3324 3682 3325 3683 if (!pGuestListener.isNull()) … … 3361 3719 static const GCTLCMDDEF s_aCmdDefs[] = 3362 3720 { 3363 { "run", gctlHandleRun, HELP_SCOPE_GSTCTRL_RUN, 0, }, 3364 { "start", gctlHandleStart, HELP_SCOPE_GSTCTRL_START, 0, }, 3365 { "copyfrom", gctlHandleCopyFrom, HELP_SCOPE_GSTCTRL_COPYFROM, 0, }, 3366 { "copyto", gctlHandleCopyTo, HELP_SCOPE_GSTCTRL_COPYTO, 0, }, 3367 3368 { "mkdir", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0, }, 3369 { "md", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0, }, 3370 { "createdirectory", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0, }, 3371 { "createdir", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0, }, 3372 3373 { "rmdir", gctlHandleRmDir, HELP_SCOPE_GSTCTRL_RMDIR, 0, }, 3374 { "removedir", gctlHandleRmDir, HELP_SCOPE_GSTCTRL_RMDIR, 0, }, 3375 { "removedirectory", gctlHandleRmDir, HELP_SCOPE_GSTCTRL_RMDIR, 0, }, 3376 3377 { "rm", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0, }, 3378 { "removefile", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0, }, 3379 { "erase", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0, }, 3380 { "del", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0, }, 3381 { "delete", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0, }, 3382 3383 { "mv", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0, }, 3384 { "move", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0, }, 3385 { "ren", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0, }, 3386 { "rename", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0, }, 3387 3388 { "mktemp", gctlHandleMkTemp, HELP_SCOPE_GSTCTRL_MKTEMP, 0, }, 3389 { "createtemp", gctlHandleMkTemp, HELP_SCOPE_GSTCTRL_MKTEMP, 0, }, 3390 { "createtemporary", gctlHandleMkTemp, HELP_SCOPE_GSTCTRL_MKTEMP, 0, }, 3391 3392 { "stat", gctlHandleStat, HELP_SCOPE_GSTCTRL_STAT, 0, }, 3393 3394 { "closeprocess", gctlHandleCloseProcess, HELP_SCOPE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 3395 { "closesession", gctlHandleCloseSession, HELP_SCOPE_GSTCTRL_CLOSESESSION, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 3396 { "list", gctlHandleList, HELP_SCOPE_GSTCTRL_LIST, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 3397 { "watch", gctlHandleWatch, HELP_SCOPE_GSTCTRL_WATCH, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 3398 3399 {"updateguestadditions",gctlHandleUpdateAdditions, HELP_SCOPE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 3400 { "updateadditions", gctlHandleUpdateAdditions, HELP_SCOPE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 3401 { "updatega", gctlHandleUpdateAdditions, HELP_SCOPE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 3721 { "run", gctlHandleRun, HELP_SCOPE_GSTCTRL_RUN, 0 }, 3722 { "start", gctlHandleStart, HELP_SCOPE_GSTCTRL_START, 0 }, 3723 { "copyfrom", gctlHandleCopyFrom, HELP_SCOPE_GSTCTRL_COPYFROM, 0 }, 3724 { "copyto", gctlHandleCopyTo, HELP_SCOPE_GSTCTRL_COPYTO, 0 }, 3725 3726 { "mkdir", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0 }, 3727 { "md", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0 }, 3728 { "createdirectory", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0 }, 3729 { "createdir", gctrlHandleMkDir, HELP_SCOPE_GSTCTRL_MKDIR, 0 }, 3730 3731 { "rmdir", gctlHandleRmDir, HELP_SCOPE_GSTCTRL_RMDIR, 0 }, 3732 { "removedir", gctlHandleRmDir, HELP_SCOPE_GSTCTRL_RMDIR, 0 }, 3733 { "removedirectory", gctlHandleRmDir, HELP_SCOPE_GSTCTRL_RMDIR, 0 }, 3734 3735 { "rm", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0 }, 3736 { "removefile", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0 }, 3737 { "erase", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0 }, 3738 { "del", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0 }, 3739 { "delete", gctlHandleRm, HELP_SCOPE_GSTCTRL_RM, 0 }, 3740 3741 { "mv", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0 }, 3742 { "move", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0 }, 3743 { "ren", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0 }, 3744 { "rename", gctlHandleMv, HELP_SCOPE_GSTCTRL_MV, 0 }, 3745 3746 { "mktemp", gctlHandleMkTemp, HELP_SCOPE_GSTCTRL_MKTEMP, 0 }, 3747 { "createtemp", gctlHandleMkTemp, HELP_SCOPE_GSTCTRL_MKTEMP, 0 }, 3748 { "createtemporary", gctlHandleMkTemp, HELP_SCOPE_GSTCTRL_MKTEMP, 0 }, 3749 3750 { "stat", gctlHandleStat, HELP_SCOPE_GSTCTRL_STAT, 0 }, 3751 3752 { "closeprocess", gctlHandleCloseProcess, HELP_SCOPE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER }, 3753 { "closesession", gctlHandleCloseSession, HELP_SCOPE_GSTCTRL_CLOSESESSION, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER }, 3754 { "list", gctlHandleList, HELP_SCOPE_GSTCTRL_LIST, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER }, 3755 { "watch", gctlHandleWatch, HELP_SCOPE_GSTCTRL_WATCH, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER }, 3756 3757 {"updateguestadditions",gctlHandleUpdateAdditions, HELP_SCOPE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS }, 3758 { "updateadditions", gctlHandleUpdateAdditions, HELP_SCOPE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS }, 3759 { "updatega", gctlHandleUpdateAdditions, HELP_SCOPE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS }, 3760 3761 { "waitrunlevel", gctlHandleWaitRunLevel, HELP_SCOPE_GSTCTRL_WAITRUNLEVEL, GCTLCMDCTX_F_SESSION_ANONYMOUS }, 3762 { "waitforrunlevel", gctlHandleWaitRunLevel, HELP_SCOPE_GSTCTRL_WAITRUNLEVEL, GCTLCMDCTX_F_SESSION_ANONYMOUS }, 3402 3763 }; 3403 3764 -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h
r82968 r84519 28 28 #include <VBox/com/VirtualBox.h> 29 29 30 #include <iprt/semaphore.h> 30 31 #include <iprt/time.h> 31 32 … … 49 50 class GuestEventListener; 50 51 typedef ListenerImpl<GuestEventListener> GuestEventListenerImpl; 52 53 class GuestAdditionsRunlevelListener; 54 typedef ListenerImpl<GuestAdditionsRunlevelListener> GuestAdditionsRunlevelListenerImpl; 51 55 52 56 /** Simple statistics class for binding locally … … 231 235 GuestEventSessions mSessions; 232 236 }; 237 238 /** 239 * Handler for Guest Additions runlevel change events. 240 */ 241 class GuestAdditionsRunlevelListener : public GuestListenerBase 242 { 243 244 public: 245 246 GuestAdditionsRunlevelListener(AdditionsRunLevelType_T enmRunLevel); 247 248 virtual ~GuestAdditionsRunlevelListener(void); 249 250 public: 251 252 void uninit(void); 253 254 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent); 255 256 protected: 257 258 /** The run level target we're waiting for. */ 259 AdditionsRunLevelType_T mRunLevelTarget; 260 }; 233 261 #endif /* !VBOX_ONLY_DOCS */ 234 262 -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp
r82968 r84519 29 29 #include <VBox/com/errorprint.h> 30 30 31 #include <iprt/semaphore.h> 31 32 #include <iprt/time.h> 32 33 … … 34 35 #include <vector> 35 36 37 38 /** Event semaphore we're using for notification. */ 39 extern RTSEMEVENT g_SemEventGuestCtrlCanceled; 36 40 37 41 … … 515 519 } 516 520 521 /* 522 * GuestAdditionsRunlevelListener 523 * GuestAdditionsRunlevelListener 524 * GuestAdditionsRunlevelListener 525 */ 526 527 GuestAdditionsRunlevelListener::GuestAdditionsRunlevelListener(AdditionsRunLevelType_T enmRunLevel) 528 : mRunLevelTarget(enmRunLevel) 529 { 530 } 531 532 GuestAdditionsRunlevelListener::~GuestAdditionsRunlevelListener(void) 533 { 534 } 535 536 void GuestAdditionsRunlevelListener::uninit(void) 537 { 538 } 539 540 STDMETHODIMP GuestAdditionsRunlevelListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent) 541 { 542 Assert(mRunLevelTarget != AdditionsRunLevelType_None); 543 544 HRESULT rc; 545 546 switch (aType) 547 { 548 case VBoxEventType_OnGuestAdditionsStatusChanged: 549 { 550 ComPtr<IGuestAdditionsStatusChangedEvent> pEvent = aEvent; 551 Assert(!pEvent.isNull()); 552 553 AdditionsRunLevelType_T RunLevelCur = AdditionsRunLevelType_None; 554 CHECK_ERROR_BREAK(pEvent, COMGETTER(RunLevel)(&RunLevelCur)); 555 556 if (mfVerbose) 557 RTPrintf("Reached run level %RU32\n", RunLevelCur); 558 559 if (RunLevelCur == mRunLevelTarget) 560 { 561 int vrc = RTSemEventSignal(g_SemEventGuestCtrlCanceled); 562 AssertRC(vrc); 563 } 564 565 break; 566 } 567 568 default: 569 AssertFailed(); 570 } 571 572 return S_OK; 573 } 574 517 575 #endif /* !VBOX_ONLY_DOCS */ 518 576
Note:
See TracChangeset
for help on using the changeset viewer.