VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceExec.cpp@ 22586

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

Additions/Windows: export VBoxServiceExec

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1/* $Id: VBoxServiceExec.cpp 22586 2009-08-31 06:43:23Z vboxsync $ */
2/** @file
3 * VBoxServiceExec - In-VM Command Execution Service.
4 */
5/** @todo r=bird: Why is this called VMExec while the filename is VBoxServiceExec.cpp? See VMInfo... */
6/** @todo r=bird: Use svn-ps.[sh|cmd] -a when adding new files, please. Then the EOLs and $Id: VBoxServiceExec.cpp 22586 2009-08-31 06:43:23Z vboxsync $ won't be messed up all the time. */
7
8/*
9 * Copyright (C) 2009 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24
25/*******************************************************************************
26* Header Files *
27*******************************************************************************/
28#include <iprt/assert.h>
29#include <iprt/env.h>
30#include <iprt/file.h>
31#include <iprt/mem.h>
32#include <iprt/process.h>
33#include <iprt/string.h>
34#include <iprt/semaphore.h>
35#include <iprt/thread.h>
36#include <VBox/version.h>
37#include <VBox/VBoxGuestLib.h>
38#include "VBoxServiceInternal.h"
39#include "VBoxServiceUtils.h"
40
41
42/*******************************************************************************
43* Global Variables *
44*******************************************************************************/
45/** The vminfo interval (millseconds). */
46uint32_t g_VMExecInterval = 0;
47/** The semaphore we're blocking on. */
48static RTSEMEVENTMULTI g_VMExecEvent = NIL_RTSEMEVENTMULTI;
49/** The guest property service client ID. */
50static uint32_t g_VMExecGuestPropSvcClientID = 0;
51
52
53/** @copydoc VBOXSERVICE::pfnPreInit */
54static DECLCALLBACK(int) VBoxServiceExecPreInit(void)
55{
56 return VINF_SUCCESS;
57}
58
59
60/** @copydoc VBOXSERVICE::pfnOption */
61static DECLCALLBACK(int) VBoxServiceExecOption(const char **ppszShort, int argc, char **argv, int *pi)
62{
63 int rc = -1;
64 if (ppszShort)
65 /* no short options */;
66 else if (!strcmp(argv[*pi], "--vmexec-interval"))
67 rc = VBoxServiceArgUInt32(argc, argv, "", pi, &g_VMExecInterval, 1, UINT32_MAX - 1);
68 return rc;
69}
70
71
72/** @copydoc VBOXSERVICE::pfnInit */
73static DECLCALLBACK(int) VBoxServiceExecInit(void)
74{
75 /*
76 * If not specified, find the right interval default.
77 * Then create the event sem to block on.
78 */
79 if (!g_VMExecInterval)
80 g_VMExecInterval = g_DefaultInterval * 1000;
81 if (!g_VMExecInterval)
82 g_VMExecInterval = 10 * 1000;
83
84 int rc = RTSemEventMultiCreate(&g_VMExecEvent);
85 AssertRCReturn(rc, rc);
86
87 rc = VbglR3GuestPropConnect(&g_VMExecGuestPropSvcClientID);
88 if (RT_SUCCESS(rc))
89 VBoxServiceVerbose(3, "Property Service Client ID: %#x\n", g_VMExecGuestPropSvcClientID);
90 else
91 {
92 VBoxServiceError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
93 RTSemEventMultiDestroy(g_VMExecEvent);
94 g_VMExecEvent = NIL_RTSEMEVENTMULTI;
95 }
96
97 return rc;
98}
99
100
101/** @copydoc VBOXSERVICE::pfnWorker */
102DECLCALLBACK(int) VBoxServiceExecWorker(bool volatile *pfShutdown)
103{
104 int rc = VINF_SUCCESS;
105
106 /*
107 * Tell the control thread that it can continue
108 * spawning services.
109 */
110 RTThreadUserSignal(RTThreadSelf());
111
112 /*
113 * Execution loop.
114 */
115#ifdef FULL_FEATURED_EXEC
116 uint64_t u64TimestampPrev = UINT64_MAX;
117#endif
118 bool fSysprepDone = false;
119 for (;;)
120 {
121#ifndef TARGET_NT4 /** @todo r=bird: Add comment explaining why please. */
122 /*
123 * The thread at the moment does nothing but checking for one specific guest property
124 * for triggering a hard coded sysprep command with parameters given by the host. This
125 * feature was required by the VDI guys.
126 *
127 * Later this thread could become a general host->guest executor (remote shell?).
128 */
129 if (!fSysprepDone)
130 {
131 /* Get arguments. */
132 /** @todo r=bird: How exactly does this work wrt. enabled/disabled? In
133 * ConsoleImpl2.cpp it's now always set to "", which means it will
134 * always be executed. So, if someone adds a bogus
135 * c:\\sysprep\\sysprep.exe to their system and install the latest
136 * additions this will be executed everytime the system starts now - if
137 * I understand the code correctly. Is this intentional? */
138 char *pszArgs;
139 rc = VbglR3GuestPropReadValueAlloc(g_VMExecGuestPropSvcClientID, "/VirtualBox/HostGuest/SysprepArgs", &pszArgs);
140 if (RT_FAILURE(rc))
141 VBoxServiceVerbose(2, "Sysprep guest property not found or broken communication. Error: %Rrc\n", pszArgs, rc);
142
143 /** @todo r=bird: You must check that the flags, you should require it to the
144 * TRANSIENT and RDONLYGUEST. Otherwise, we'll have a potential priviledge
145 * escalation issue inside the guest if the variable is removed. */
146
147 static char *s_pszSysprepImage = "c:\\sysprep\\sysprep.exe";
148 if ( RT_SUCCESS(rc)
149 && !RTFileExists(s_pszSysprepImage))
150 {
151 VBoxServiceError("Sysprep executable not found! Search path=%s\n", s_pszSysprepImage);
152 rc = VERR_FILE_NOT_FOUND;
153 }
154
155 if (RT_SUCCESS(rc))
156 {
157 RTPROCESS pid;
158 const char *papszArgs[6] = { s_pszSysprepImage, "-quiet", "-reseal", "-mini", "-activated", NULL};
159
160 /** @todo append the arguments in SysprepArgs/pszArgs. */
161 VBoxServiceVerbose(3, "Executing sysprep ...\n");
162 rc = RTProcCreate(papszArgs[0], papszArgs, RTENV_DEFAULT, 0, &pid);
163 if (RT_SUCCESS(rc))
164 {
165 RTPROCSTATUS Status;
166 rc = RTProcWait(pid, RTPROCWAIT_FLAGS_BLOCK, &Status);
167
168 VBoxServiceVerbose(3, "Sysprep returned: %d\n", Status.iStatus);
169 if (RT_SUCCESS(rc))
170 {
171 if ( Status.iStatus == 0
172 && Status.enmReason == RTPROCEXITREASON_NORMAL)
173 {
174 rc = VINF_SUCCESS;
175 fSysprepDone = true; /** r=bird: So, if sysprep fails, the idea is to continue executing the code every 10 seconds? */
176 }
177 }
178
179 /* Set return value so the host knows what happend. */
180 rc = VbglR3GuestPropWriteValueF(g_VMExecGuestPropSvcClientID, "/VirtualBox/HostGuest/SysprepRet", "%d", Status.iStatus);
181 if (RT_FAILURE(rc))
182 VBoxServiceError("Failed to write SysprepRet: rc=%Rrc\n", rc);
183 }
184 }
185
186 VbglR3GuestPropReadValueFree(pszArgs);
187 }
188#endif /* !TARGET_NT4 */
189
190#ifdef FULL_FEATURED_EXEC
191 1. Read the command - value, timestamp and flags.
192 2. Check that the flags indicates that the guest cannot write to it and that it's transient.
193 3. Check if the timestamp changed.
194 4. Get the arguments and other stuff.
195 5. Execute it. This may involve grabbing the output (stderr and/or stdout) and pushing into
196 values afterwards. It may also entail redirecting input to a file containing text from a guest prop value.
197 6. Set the result values (there will be three, one IPRT style one for everything up to
198 and including RTProcWait and two that mirrors Status.iStatus and Status.enmReason (stringified)).
199#endif
200
201 /*
202 * Block for a while.
203 *
204 * The event semaphore takes care of ignoring interruptions and it
205 * allows us to implement service wakeup later.
206 */
207 if (*pfShutdown)
208 break;
209#ifdef FULL_FEATURED_EXEC
210 Wait for changes to the command value. If that fails for some reason other than timeout / interrupt, fall back on the semaphore.
211#else
212 int rc2 = RTSemEventMultiWait(g_VMExecEvent, g_VMExecInterval);
213#endif
214 if (*pfShutdown)
215 break;
216 if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
217 {
218 VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
219 rc = rc2;
220 break;
221 }
222 }
223
224 RTSemEventMultiDestroy(g_VMExecEvent);
225 g_VMExecEvent = NIL_RTSEMEVENTMULTI;
226 return rc;
227}
228
229
230/** @copydoc VBOXSERVICE::pfnStop */
231static DECLCALLBACK(void) VBoxServiceExecStop(void)
232{
233 /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
234 * annoying call since doesn't support timeouts in the posix world. */
235 RTSemEventMultiSignal(g_VMExecEvent);
236#ifdef FULL_FEATURED_EXEC
237 Interrupts waits.
238#endif
239}
240
241
242/** @copydoc VBOXSERVICE::pfnTerm */
243static DECLCALLBACK(void) VBoxServiceExecTerm(void)
244{
245 /* Nothing here yet. */
246 /** @todo r=bird: Shouldn't you do the following here:
247 * VbglR3GuestPropDisconnect(g_VMExecGuestPropSvcClientID);
248 * g_VMExecGuestPropSvcClientID = 0;
249 * And quite possibly:
250 * RTSemEventMultiDestroy(g_hVMExecEvent);
251 * g_hVMExecEvent = NIL_RTSEMEVENTMULTI;
252 */
253}
254
255
256/**
257 * The 'vminfo' service description.
258 */
259VBOXSERVICE g_VMExec =
260{
261 /* pszName. */
262 "vmexec",
263 /* pszDescription. */
264 "Virtual Machine Remote Execution",
265 /* pszUsage. */
266 "[--vmexec-interval <ms>]"
267 ,
268 /* pszOptions. */
269 " --vmexec-interval Specifies the interval at which to check for new\n"
270 " remote execution commands. The default is 10000 ms.\n"
271 ,
272 /* methods */
273 VBoxServiceExecPreInit,
274 VBoxServiceExecOption,
275 VBoxServiceExecInit,
276 VBoxServiceExecWorker,
277 VBoxServiceExecStop,
278 VBoxServiceExecTerm
279};
280
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