VirtualBox

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

Last change on this file was 99739, checked in by vboxsync, 12 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use