VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPSvc.cpp@ 85526

Last change on this file since 85526 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* $Id: SUPSvc.cpp 85121 2020-07-08 19:33:26Z vboxsync $ */
2/** @file
3 * VirtualBox Support Service - Common Code.
4 */
5
6/*
7 * Copyright (C) 2008-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP
32#include <VBox/log.h>
33#include <iprt/string.h>
34#include <iprt/mem.h>
35#include <iprt/stream.h>
36#include <iprt/getopt.h>
37
38#include "SUPSvcInternal.h"
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Service state.
46 */
47typedef enum SUPSVCSERVICESTATE
48{
49 kSupSvcServiceState_Invalid = 0,
50 kSupSvcServiceState_NotCreated,
51 kSupSvcServiceState_Paused,
52 kSupSvcServiceState_Running,
53 kSupSvcServiceState_End
54} SUPSVCSERVICESTATE;
55
56
57/**
58 * Service descriptor.
59 */
60typedef struct SUPSVCSERVICE
61{
62 /** The service name. */
63 const char *pszName;
64 /** The service state. */
65 SUPSVCSERVICESTATE enmState;
66 /** The instance handle returned by pfnCreate. */
67 void *pvInstance;
68
69 /**
70 * Create the service (don't start it).
71 *
72 * @returns VBox status code, log entry is written on failure.
73 * @param ppvInstance Where to store the instance handle.
74 */
75 DECLCALLBACKMEMBER(int, pfnCreate,(void **ppvInstance));
76
77 /**
78 * Start the service.
79 *
80 * @returns VBox status code, log entry is written on failure.
81 * @param pvInstance The instance handle.
82 */
83 DECLCALLBACKMEMBER(void, pfnStart,(void *pvInstance));
84
85 /**
86 * Attempt to stop a running service.
87 *
88 * This should fail if there are active clients. A stopped service
89 * can be restarted by calling pfnStart.
90 *
91 * @returns VBox status code, log entry is written on failure.
92 * @param pvInstance The instance handle.
93 */
94 DECLCALLBACKMEMBER(int, pfnTryStop,(void *pvInstance));
95
96 /**
97 * Destroy the service, stopping first it if necessary.
98 *
99 * @param pvInstance The instance handle.
100 * @param fRunning Whether the service is running or not.
101 */
102 DECLCALLBACKMEMBER(void, pfnStopAndDestroy,(void *pvInstance, bool fRunning));
103} SUPSVCSERVICE;
104/** Pointer to a service descriptor. */
105typedef SUPSVCSERVICE *PSUPSVCSERVICE;
106/** Pointer to a const service descriptor. */
107typedef SUPSVCSERVICE const *PCSUPSVCSERVICE;
108
109
110
111/*********************************************************************************************************************************
112* Global Variables *
113*********************************************************************************************************************************/
114static SUPSVCSERVICE g_aServices[] =
115{
116 {
117 "Global",
118 kSupSvcServiceState_NotCreated,
119 NULL,
120 supSvcGlobalCreate,
121 supSvcGlobalStart,
122 supSvcGlobalTryStop,
123 supSvcGlobalStopAndDestroy,
124 }
125#ifdef RT_OS_WINDOWS
126 ,
127 {
128 "Grant",
129 kSupSvcServiceState_NotCreated,
130 NULL,
131 supSvcGrantCreate,
132 supSvcGrantStart,
133 supSvcGrantTryStop,
134 supSvcGrantStopAndDestroy,
135 }
136#endif
137};
138
139
140
141/**
142 * Instantiates and starts the services.
143 *
144 * @returns VBox status code. Done bitching on failure.
145 */
146int supSvcCreateAndStartServices(void)
147{
148 LogFlowFuncEnter();
149
150 /*
151 * Validate that all services are in the NotCreated state.
152 */
153 unsigned i;
154 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
155 if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
156 {
157 supSvcLogError("service %s in state %d, expected state %d (NotCreated)",
158 g_aServices[i].pszName, g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
159 return VERR_WRONG_ORDER;
160 }
161
162 /*
163 * Create all the services, then start them.
164 */
165 int rc = VINF_SUCCESS;
166 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
167 {
168 void *pvInstance = NULL;
169 int rc = g_aServices[i].pfnCreate(&pvInstance);
170 if (RT_FAILURE(rc))
171 {
172 Log(("supSvcCreateAndStartServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
173 break;
174 }
175 g_aServices[i].pvInstance = pvInstance;
176 g_aServices[i].enmState = kSupSvcServiceState_Paused;
177 }
178 if (RT_SUCCESS(rc))
179 {
180 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
181 {
182 g_aServices[i].pfnStart(g_aServices[i].pvInstance);
183 g_aServices[i].enmState = kSupSvcServiceState_Running;
184 }
185 }
186 else
187 {
188 /*
189 * Destroy any services we managed to instantiate.
190 */
191 while (i-- > 0)
192 {
193 g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance, false /* fRunning */);
194 g_aServices[i].pvInstance = NULL;
195 g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
196 }
197 }
198
199 LogFlow(("supSvcCreateAndStartServices: returns %Rrc\n", rc));
200 return rc;
201}
202
203
204/**
205 * Checks if it's possible to stop the services.
206 *
207 * @returns VBox status code, done bitching on failure.
208 */
209int supSvcTryStopServices(void)
210{
211 LogFlowFuncEnter();
212
213 /*
214 * Check that the services are all created and count the running ones.
215 */
216 unsigned i;
217 unsigned cRunning = 0;
218 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
219 if (g_aServices[i].enmState == kSupSvcServiceState_Running)
220 cRunning++;
221 else if (g_aServices[i].enmState == kSupSvcServiceState_NotCreated)
222 {
223 supSvcLogError("service %s in state %d (NotCreated), expected pause or running",
224 g_aServices[i].pszName, g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
225 return VERR_WRONG_ORDER;
226 }
227 if (!cRunning)
228 return VINF_SUCCESS; /* all stopped, nothing to do. */
229 Assert(cRunning == RT_ELEMENTS(g_aServices)); /* all or nothing */
230
231 /*
232 * Try stop them in reverse of start order.
233 */
234 int rc = VINF_SUCCESS;
235 i = RT_ELEMENTS(g_aServices);
236 while (i-- > 0)
237 {
238 rc = g_aServices[i].pfnTryStop(g_aServices[i].pvInstance);
239 if (RT_FAILURE(rc))
240 {
241 Log(("supSvcTryStopServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
242 break;
243 }
244 g_aServices[i].enmState = kSupSvcServiceState_Paused;
245 }
246 if (RT_FAILURE(rc))
247 {
248 /* Failed, restart the ones we succeeded in stopping. */
249 while (++i < RT_ELEMENTS(g_aServices))
250 {
251 g_aServices[i].pfnStart(g_aServices[i].pvInstance);
252 g_aServices[i].enmState = kSupSvcServiceState_Running;
253 }
254 }
255 LogFlow(("supSvcTryStopServices: returns %Rrc\n", rc));
256 return rc;
257}
258
259
260/**
261 * Stops and destroys the services.
262 */
263void supSvcStopAndDestroyServices(void)
264{
265 LogFlowFuncEnter();
266
267 /*
268 * Stop and destroy the service in reverse of start order.
269 */
270 unsigned i = RT_ELEMENTS(g_aServices);
271 while (i-- > 0)
272 if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
273 {
274 g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance,
275 g_aServices[i].enmState == kSupSvcServiceState_Running);
276 g_aServices[i].pvInstance = NULL;
277 g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
278 }
279
280 LogFlowFuncLeave();
281}
282
283
284
285/**
286 * Logs the message to the appropriate system log.
287 *
288 * In debug builds this will also put it in the debug log.
289 *
290 * @param pszMsg The log string.
291 *
292 * @remarks This may later be replaced by the release logger and callback destination(s).
293 */
294void supSvcLogErrorStr(const char *pszMsg)
295{
296 supSvcOsLogErrorStr(pszMsg);
297 LogRel(("%s\n", pszMsg));
298}
299
300
301/**
302 * Logs the message to the appropriate system log.
303 *
304 * In debug builds this will also put it in the debug log.
305 *
306 * @param pszFormat The log string. No trailing newline.
307 * @param va Format arguments.
308 *
309 * @todo This should later be replaced by the release logger and callback destination(s).
310 */
311void supSvcLogErrorV(const char *pszFormat, va_list va)
312{
313 if (*pszFormat)
314 {
315 char *pszMsg = NULL;
316 if (RTStrAPrintfV(&pszMsg, pszFormat, va) != -1)
317 {
318 supSvcLogErrorStr(pszMsg);
319 RTStrFree(pszMsg);
320 }
321 else
322 supSvcLogErrorStr(pszFormat);
323 }
324}
325
326
327/**
328 * Logs the error message to the appropriate system log.
329 *
330 * In debug builds this will also put it in the debug log.
331 *
332 * @param pszFormat The log string. No trailing newline.
333 * @param ... Format arguments.
334 *
335 * @todo This should later be replaced by the release logger and callback destination(s).
336 */
337void supSvcLogError(const char *pszFormat, ...)
338{
339 va_list va;
340 va_start(va, pszFormat);
341 supSvcLogErrorV(pszFormat, va);
342 va_end(va);
343}
344
345
346/**
347 * Deals with RTGetOpt failure, bitching in the system log.
348 *
349 * @returns 1
350 * @param pszAction The action name.
351 * @param rc The RTGetOpt return value.
352 * @param argc The argument count.
353 * @param argv The argument vector.
354 * @param iArg The argument index.
355 * @param pValue The value returned by RTGetOpt.
356 */
357int supSvcLogGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue)
358{
359 supSvcLogError("%s - RTGetOpt failure, %Rrc (%d): %s",
360 pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
361 return 1;
362}
363
364
365/**
366 * Bitch about too many arguments (after RTGetOpt stops) in the system log.
367 *
368 * @returns 1
369 * @param pszAction The action name.
370 * @param argc The argument count.
371 * @param argv The argument vector.
372 * @param iArg The argument index.
373 */
374int supSvcLogTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
375{
376 Assert(iArg < argc);
377 supSvcLogError("%s - Too many arguments: %s", pszAction, argv[iArg]);
378 for ( ; iArg < argc; iArg++)
379 LogRel(("arg#%i: %s\n", iArg, argv[iArg]));
380 return 1;
381}
382
383
384/**
385 * Prints an error message to the screen.
386 *
387 * @param pszFormat The message format string.
388 * @param va Format arguments.
389 */
390void supSvcDisplayErrorV(const char *pszFormat, va_list va)
391{
392 RTStrmPrintf(g_pStdErr, "VBoxSupSvc error: ");
393 RTStrmPrintfV(g_pStdErr, pszFormat, va);
394 Log(("supSvcDisplayErrorV: %s", pszFormat)); /** @todo format it! */
395}
396
397
398/**
399 * Prints an error message to the screen.
400 *
401 * @param pszFormat The message format string.
402 * @param ... Format arguments.
403 */
404void supSvcDisplayError(const char *pszFormat, ...)
405{
406 va_list va;
407 va_start(va, pszFormat);
408 supSvcDisplayErrorV(pszFormat, va);
409 va_end(va);
410}
411
412
413/**
414 * Deals with RTGetOpt failure.
415 *
416 * @returns 1
417 * @param pszAction The action name.
418 * @param rc The RTGetOpt return value.
419 * @param argc The argument count.
420 * @param argv The argument vector.
421 * @param iArg The argument index.
422 * @param pValue The value returned by RTGetOpt.
423 */
424int supSvcDisplayGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue)
425{
426 supSvcDisplayError("%s - RTGetOpt failure, %Rrc (%d): %s\n",
427 pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
428 return 1;
429}
430
431
432/**
433 * Bitch about too many arguments (after RTGetOpt stops).
434 *
435 * @returns 1
436 * @param pszAction The action name.
437 * @param argc The argument count.
438 * @param argv The argument vector.
439 * @param iArg The argument index.
440 */
441int supSvcDisplayTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
442{
443 Assert(iArg < argc);
444 supSvcDisplayError("%s - Too many arguments: %s\n", pszAction, argv[iArg]);
445 return 1;
446}
447
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