VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp@ 28112

Last change on this file since 28112 was 28086, checked in by vboxsync, 15 years ago

Guest Control: Update; now buffered and deferred commands work.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.3 KB
Line 
1
2/* $Id: VBoxServiceControl.cpp 28086 2010-04-08 12:32:07Z vboxsync $ */
3/** @file
4 * VBoxServiceControl - Host-driven Guest Control.
5 */
6
7/*
8 * Copyright (C) 2010 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <iprt/assert.h>
28#include <iprt/getopt.h>
29#include <iprt/mem.h>
30#include <iprt/semaphore.h>
31#include <iprt/thread.h>
32#include <VBox/VBoxGuestLib.h>
33#include <VBox/HostServices/GuestControlSvc.h>
34#include "VBoxServiceInternal.h"
35#include "VBoxServiceUtils.h"
36
37using namespace guestControl;
38
39/*******************************************************************************
40* Global Variables *
41*******************************************************************************/
42/** The control interval (millseconds). */
43uint32_t g_ControlInterval = 0;
44/** The semaphore we're blocking on. */
45static RTSEMEVENTMULTI g_hControlEvent = NIL_RTSEMEVENTMULTI;
46/** The guest property service client ID. */
47static uint32_t g_GuestControlSvcClientID = 0;
48
49/** @copydoc VBOXSERVICE::pfnPreInit */
50static DECLCALLBACK(int) VBoxServiceControlPreInit(void)
51{
52 return VINF_SUCCESS;
53}
54
55
56/** @copydoc VBOXSERVICE::pfnOption */
57static DECLCALLBACK(int) VBoxServiceControlOption(const char **ppszShort, int argc, char **argv, int *pi)
58{
59 int rc = -1;
60 if (ppszShort)
61 /* no short options */;
62 else if (!strcmp(argv[*pi], "--control-interval"))
63 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
64 &g_ControlInterval, 1, UINT32_MAX - 1);
65 return rc;
66}
67
68
69/** @copydoc VBOXSERVICE::pfnInit */
70static DECLCALLBACK(int) VBoxServiceControlInit(void)
71{
72 /*
73 * If not specified, find the right interval default.
74 * Then create the event sem to block on.
75 */
76 if (!g_ControlInterval)
77 g_ControlInterval = 1000;
78
79 int rc = RTSemEventMultiCreate(&g_hControlEvent);
80 AssertRCReturn(rc, rc);
81
82 rc = VbglR3GuestCtrlConnect(&g_GuestControlSvcClientID);
83 if (RT_SUCCESS(rc))
84 VBoxServiceVerbose(3, "Control: Service Client ID: %#x\n", g_GuestControlSvcClientID);
85 else
86 {
87 VBoxServiceError("Control: Failed to connect to the guest control service! Error: %Rrc\n", rc);
88 RTSemEventMultiDestroy(g_hControlEvent);
89 g_hControlEvent = NIL_RTSEMEVENTMULTI;
90 }
91
92 return rc;
93}
94
95
96static int VBoxServiceControlHandleCmdExec(uint32_t u32ClientId, uint32_t uNumParms)
97{
98 VBOXSERVICECTRLPROCDATA execData;
99 execData.cbEnv = sizeof(execData.szEnv);
100
101 int rc = VbglR3GuestCtrlGetHostCmdExec(u32ClientId, uNumParms,
102 execData.szCmd, sizeof(execData.szCmd),
103 &execData.uFlags,
104 execData.szArgs, sizeof(execData.szArgs), &execData.uNumArgs,
105 execData.szEnv, &execData.cbEnv, &execData.uNumEnvVars,
106 execData.szStdIn, sizeof(execData.szStdIn),
107 execData.szStdOut, sizeof(execData.szStdOut),
108 execData.szStdErr, sizeof(execData.szStdErr),
109 execData.szUser, sizeof(execData.szUser),
110 execData.szPassword, sizeof(execData.szPassword),
111 &execData.uTimeLimitMS);
112 if (RT_FAILURE(rc))
113 {
114 VBoxServiceError("Control: Failed to retrieve execution command! Error: %Rrc\n", rc);
115 }
116 else
117 {
118 /* Adjust time limit value. */
119 execData.uTimeLimitMS = UINT32_MAX ?
120 RT_INDEFINITE_WAIT : execData.uTimeLimitMS;
121
122 /* Prepare argument list. */
123 char **ppaArg;
124 int iArgs;
125 rc = RTGetOptArgvFromString(&ppaArg, &iArgs,
126 execData.uNumArgs ? execData.szArgs : "", NULL);
127 Assert(execData.uNumArgs == iArgs);
128 if (RT_SUCCESS(rc))
129 {
130 /* Prepare environment list. */
131 char **ppaEnv;
132 if (execData.uNumEnvVars)
133 {
134 ppaEnv = (char**)RTMemAlloc(execData.uNumEnvVars * sizeof(char*));
135 AssertPtr(ppaEnv);
136
137 char *pcCur = execData.szEnv;
138 uint32_t i = 0;
139 uint32_t cbLen = 0;
140 while (cbLen < execData.cbEnv)
141 {
142 if (RTStrAPrintf(&ppaEnv[i++], "%s", pcCur) < 0)
143 {
144 rc = VERR_NO_MEMORY;
145 break;
146 }
147 cbLen += strlen(pcCur) + 1; /* Skip terminating zero. */
148 pcCur += cbLen;
149 }
150 }
151
152 if (RT_SUCCESS(rc))
153 {
154 /* Do the actual execution. */
155 rc = VBoxServiceControlExecProcess(&execData, ppaArg, ppaEnv);
156 if (RT_FAILURE(rc))
157 VBoxServiceVerbose(3, "Control: Could not execute process \"%s\"! Error: %Rrc\n",
158 execData.szCmd, rc);
159 /* Cleanup. */
160 if (execData.uNumEnvVars)
161 {
162 for (uint32_t i = 0; i < execData.uNumEnvVars; i++)
163 RTStrFree(ppaEnv[i]);
164 RTMemFree(ppaEnv);
165 }
166 }
167 RTGetOptArgvFree(ppaArg);
168 }
169 }
170 return rc;
171}
172
173
174/** @copydoc VBOXSERVICE::pfnWorker */
175DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
176{
177 /*
178 * Tell the control thread that it can continue
179 * spawning services.
180 */
181 RTThreadUserSignal(RTThreadSelf());
182 Assert(g_GuestControlSvcClientID > 0);
183
184 int rc = VINF_SUCCESS;
185
186 /*
187 * Execution loop.
188 *
189 * @todo
190 */
191 for (;;)
192 {
193 uint32_t uMsg;
194 uint32_t uNumParms;
195 rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms);
196 if (rc == VERR_TOO_MUCH_DATA)
197 {
198 VBoxServiceVerbose(3, "Control: Message requires %ld parameters, but only 2 supplied.\n", uNumParms);
199 rc = VINF_SUCCESS;
200 }
201 if (RT_SUCCESS(rc))
202 {
203 switch(uMsg)
204 {
205 case GETHOSTMSG_EXEC_CMD:
206 rc = VBoxServiceControlHandleCmdExec(g_GuestControlSvcClientID, uNumParms);
207 break;
208
209 default:
210 VBoxServiceVerbose(3, "Control: Unsupported message from host! Msg=%ld\n", uMsg);
211 /* Don't terminate here; just wait for the next message. */
212 break;
213 }
214 }
215
216 /*
217 * Block for a while.
218 *
219 * The event semaphore takes care of ignoring interruptions and it
220 * allows us to implement service wakeup later.
221 */
222 if (*pfShutdown)
223 break;
224 int rc2 = RTSemEventMultiWait(g_hControlEvent, g_ControlInterval);
225 if (*pfShutdown)
226 break;
227 if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
228 {
229 VBoxServiceError("Control: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
230 rc = rc2;
231 break;
232 }
233 }
234
235 RTSemEventMultiDestroy(g_hControlEvent);
236 g_hControlEvent = NIL_RTSEMEVENTMULTI;
237 return rc;
238}
239
240
241/** @copydoc VBOXSERVICE::pfnStop */
242static DECLCALLBACK(void) VBoxServiceControlStop(void)
243{
244 /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
245 * annoying call since doesn't support timeouts in the posix world. */
246 RTSemEventMultiSignal(g_hControlEvent);
247}
248
249
250/** @copydoc VBOXSERVICE::pfnTerm */
251static DECLCALLBACK(void) VBoxServiceControlTerm(void)
252{
253 /* Nothing here yet. */
254 VbglR3GuestCtrlDisconnect(g_GuestControlSvcClientID);
255 g_GuestControlSvcClientID = 0;
256
257 if (g_hControlEvent != NIL_RTSEMEVENTMULTI)
258 {
259 RTSemEventMultiDestroy(g_hControlEvent);
260 g_hControlEvent = NIL_RTSEMEVENTMULTI;
261 }
262}
263
264
265/**
266 * The 'vminfo' service description.
267 */
268VBOXSERVICE g_Control =
269{
270 /* pszName. */
271 "control",
272 /* pszDescription. */
273 "Host-driven Guest Control",
274 /* pszUsage. */
275 "[--control-interval <ms>]"
276 ,
277 /* pszOptions. */
278 " --control-interval Specifies the interval at which to check for\n"
279 " new ocntrol commands. The default is 1000 ms.\n"
280 ,
281 /* methods */
282 VBoxServiceControlPreInit,
283 VBoxServiceControlOption,
284 VBoxServiceControlInit,
285 VBoxServiceControlWorker,
286 VBoxServiceControlStop,
287 VBoxServiceControlTerm
288};
289
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette