VirtualBox

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

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

Guest Control/VBoxService+Main: Bugfix for multiple environment blocks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.0 KB
Line 
1
2/* $Id: VBoxServiceControl.cpp 28029 2010-04-07 07:31:23Z 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 VBoxServiceVerbose(3, "VBoxServiceControlHandleCmdExec: Called uNumParms=%ld\n", uNumParms);
99
100 VBOXSERVICECTRLPROCDATA execData;
101 execData.cbEnv = sizeof(execData.szEnv);
102
103 int rc = VbglR3GuestCtrlGetHostCmdExec(u32ClientId, uNumParms,
104 execData.szCmd, sizeof(execData.szCmd),
105 &execData.uFlags,
106 execData.szArgs, sizeof(execData.szArgs), &execData.uNumArgs,
107 execData.szEnv, &execData.cbEnv, &execData.uNumEnvVars,
108 execData.szStdIn, sizeof(execData.szStdIn),
109 execData.szStdOut, sizeof(execData.szStdOut),
110 execData.szStdErr, sizeof(execData.szStdErr),
111 execData.szUser, sizeof(execData.szUser),
112 execData.szPassword, sizeof(execData.szPassword),
113 &execData.uTimeLimitMS);
114 if (RT_FAILURE(rc))
115 {
116 VBoxServiceError("Control: Failed to retrieve execution command! Error: %Rrc\n", rc);
117 }
118 else
119 {
120 /* Adjust time limit value. */
121 execData.uTimeLimitMS = UINT32_MAX ?
122 RT_INDEFINITE_WAIT : execData.uTimeLimitMS;
123
124 /* Prepare argument list. */
125 char **ppaArg;
126 int iArgs;
127 rc = RTGetOptArgvFromString(&ppaArg, &iArgs,
128 execData.uNumArgs ? execData.szArgs : "", NULL);
129 Assert(execData.uNumArgs == iArgs);
130 if (RT_SUCCESS(rc))
131 {
132 /* Prepare environment list. */
133 char **ppaEnv;
134 if (execData.uNumEnvVars)
135 {
136 ppaEnv = (char**)RTMemAlloc(execData.uNumEnvVars * sizeof(char*));
137 AssertPtr(ppaEnv);
138
139 char *pcCur = execData.szEnv;
140 uint32_t i = 0;
141 uint32_t cbLen = 0;
142 while (cbLen < execData.cbEnv)
143 {
144 if (RTStrAPrintf(&ppaEnv[i++], "%s", pcCur) < 0)
145 {
146 rc = VERR_NO_MEMORY;
147 break;
148 }
149 cbLen += strlen(pcCur) + 1; /* Skip terminating zero. */
150 pcCur += cbLen;
151 }
152 }
153
154 if (RT_SUCCESS(rc))
155 {
156 /* Do the actual execution. */
157 rc = VBoxServiceControlExecProcess(&execData, ppaArg, ppaEnv);
158 /* Cleanup. */
159 if (execData.uNumEnvVars)
160 {
161 for (uint32_t i = 0; i < execData.uNumEnvVars; i++)
162 RTStrFree(ppaEnv[i]);
163 RTMemFree(ppaEnv);
164 }
165 }
166 RTGetOptArgvFree(ppaArg);
167 }
168 }
169 return rc;
170}
171
172
173/** @copydoc VBOXSERVICE::pfnWorker */
174DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
175{
176 /*
177 * Tell the control thread that it can continue
178 * spawning services.
179 */
180 RTThreadUserSignal(RTThreadSelf());
181 Assert(g_GuestControlSvcClientID > 0);
182
183 int rc = VINF_SUCCESS;
184
185 /*
186 * Execution loop.
187 *
188 * @todo
189 */
190 for (;;)
191 {
192 uint32_t uMsg;
193 uint32_t uNumParms;
194 rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms);
195 if (RT_SUCCESS(rc))
196 {
197 switch(uMsg)
198 {
199 case GETHOSTMSG_EXEC_CMD:
200 rc = VBoxServiceControlHandleCmdExec(g_GuestControlSvcClientID, uNumParms);
201 break;
202
203 default:
204 VBoxServiceVerbose(3, "VBoxServiceControlWorker: Unsupported message from host! Msg=%ld\n", uMsg);
205 /* Don't terminate here; just wait for the next message. */
206 break;
207 }
208 }
209
210 /*
211 * Block for a while.
212 *
213 * The event semaphore takes care of ignoring interruptions and it
214 * allows us to implement service wakeup later.
215 */
216 if (*pfShutdown)
217 break;
218 int rc2 = RTSemEventMultiWait(g_hControlEvent, g_ControlInterval);
219 if (*pfShutdown)
220 break;
221 if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
222 {
223 VBoxServiceError("VBoxServiceControlWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
224 rc = rc2;
225 break;
226 }
227 }
228
229 RTSemEventMultiDestroy(g_hControlEvent);
230 g_hControlEvent = NIL_RTSEMEVENTMULTI;
231 return rc;
232}
233
234
235/** @copydoc VBOXSERVICE::pfnStop */
236static DECLCALLBACK(void) VBoxServiceControlStop(void)
237{
238 /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
239 * annoying call since doesn't support timeouts in the posix world. */
240 RTSemEventMultiSignal(g_hControlEvent);
241}
242
243
244/** @copydoc VBOXSERVICE::pfnTerm */
245static DECLCALLBACK(void) VBoxServiceControlTerm(void)
246{
247 /* Nothing here yet. */
248 VbglR3GuestCtrlDisconnect(g_GuestControlSvcClientID);
249 g_GuestControlSvcClientID = 0;
250
251 if (g_hControlEvent != NIL_RTSEMEVENTMULTI)
252 {
253 RTSemEventMultiDestroy(g_hControlEvent);
254 g_hControlEvent = NIL_RTSEMEVENTMULTI;
255 }
256}
257
258
259/**
260 * The 'vminfo' service description.
261 */
262VBOXSERVICE g_Control =
263{
264 /* pszName. */
265 "control",
266 /* pszDescription. */
267 "Host-driven Guest Control",
268 /* pszUsage. */
269 "[--control-interval <ms>]"
270 ,
271 /* pszOptions. */
272 " --control-interval Specifies the interval at which to check for\n"
273 " new ocntrol commands. The default is 1000 ms.\n"
274 ,
275 /* methods */
276 VBoxServiceControlPreInit,
277 VBoxServiceControlOption,
278 VBoxServiceControlInit,
279 VBoxServiceControlWorker,
280 VBoxServiceControlStop,
281 VBoxServiceControlTerm
282};
283
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