VirtualBox

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

Last change on this file since 96572 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.6 KB
Line 
1/* $Id: SUPSvc.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VirtualBox Support Service - Common Code.
4 */
5
6/*
7 * Copyright (C) 2008-2022 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 * @returns VBox status code, log entry is written on failure.
91 * @param pvInstance The instance handle.
92 */
93 DECLCALLBACKMEMBER(void, pfnStart,(void *pvInstance));
94
95 /**
96 * Attempt to stop a running service.
97 *
98 * This should fail if there are active clients. A stopped service
99 * can be restarted by calling pfnStart.
100 *
101 * @returns VBox status code, log entry is written on failure.
102 * @param pvInstance The instance handle.
103 */
104 DECLCALLBACKMEMBER(int, pfnTryStop,(void *pvInstance));
105
106 /**
107 * Destroy the service, stopping first it if necessary.
108 *
109 * @param pvInstance The instance handle.
110 * @param fRunning Whether the service is running or not.
111 */
112 DECLCALLBACKMEMBER(void, pfnStopAndDestroy,(void *pvInstance, bool fRunning));
113} SUPSVCSERVICE;
114/** Pointer to a service descriptor. */
115typedef SUPSVCSERVICE *PSUPSVCSERVICE;
116/** Pointer to a const service descriptor. */
117typedef SUPSVCSERVICE const *PCSUPSVCSERVICE;
118
119
120
121/*********************************************************************************************************************************
122* Global Variables *
123*********************************************************************************************************************************/
124static SUPSVCSERVICE g_aServices[] =
125{
126 {
127 "Global",
128 kSupSvcServiceState_NotCreated,
129 NULL,
130 supSvcGlobalCreate,
131 supSvcGlobalStart,
132 supSvcGlobalTryStop,
133 supSvcGlobalStopAndDestroy,
134 }
135#ifdef RT_OS_WINDOWS
136 ,
137 {
138 "Grant",
139 kSupSvcServiceState_NotCreated,
140 NULL,
141 supSvcGrantCreate,
142 supSvcGrantStart,
143 supSvcGrantTryStop,
144 supSvcGrantStopAndDestroy,
145 }
146#endif
147};
148
149
150
151/**
152 * Instantiates and starts the services.
153 *
154 * @returns VBox status code. Done bitching on failure.
155 */
156int supSvcCreateAndStartServices(void)
157{
158 LogFlowFuncEnter();
159
160 /*
161 * Validate that all services are in the NotCreated state.
162 */
163 unsigned i;
164 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
165 if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
166 {
167 supSvcLogError("service %s in state %d, expected state %d (NotCreated)",
168 g_aServices[i].pszName, g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
169 return VERR_WRONG_ORDER;
170 }
171
172 /*
173 * Create all the services, then start them.
174 */
175 int rc = VINF_SUCCESS;
176 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
177 {
178 void *pvInstance = NULL;
179 int rc = g_aServices[i].pfnCreate(&pvInstance);
180 if (RT_FAILURE(rc))
181 {
182 Log(("supSvcCreateAndStartServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
183 break;
184 }
185 g_aServices[i].pvInstance = pvInstance;
186 g_aServices[i].enmState = kSupSvcServiceState_Paused;
187 }
188 if (RT_SUCCESS(rc))
189 {
190 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
191 {
192 g_aServices[i].pfnStart(g_aServices[i].pvInstance);
193 g_aServices[i].enmState = kSupSvcServiceState_Running;
194 }
195 }
196 else
197 {
198 /*
199 * Destroy any services we managed to instantiate.
200 */
201 while (i-- > 0)
202 {
203 g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance, false /* fRunning */);
204 g_aServices[i].pvInstance = NULL;
205 g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
206 }
207 }
208
209 LogFlow(("supSvcCreateAndStartServices: returns %Rrc\n", rc));
210 return rc;
211}
212
213
214/**
215 * Checks if it's possible to stop the services.
216 *
217 * @returns VBox status code, done bitching on failure.
218 */
219int supSvcTryStopServices(void)
220{
221 LogFlowFuncEnter();
222
223 /*
224 * Check that the services are all created and count the running ones.
225 */
226 unsigned i;
227 unsigned cRunning = 0;
228 for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
229 if (g_aServices[i].enmState == kSupSvcServiceState_Running)
230 cRunning++;
231 else if (g_aServices[i].enmState == kSupSvcServiceState_NotCreated)
232 {
233 supSvcLogError("service %s in state %d (NotCreated), expected pause or running",
234 g_aServices[i].pszName, g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
235 return VERR_WRONG_ORDER;
236 }
237 if (!cRunning)
238 return VINF_SUCCESS; /* all stopped, nothing to do. */
239 Assert(cRunning == RT_ELEMENTS(g_aServices)); /* all or nothing */
240
241 /*
242 * Try stop them in reverse of start order.
243 */
244 int rc = VINF_SUCCESS;
245 i = RT_ELEMENTS(g_aServices);
246 while (i-- > 0)
247 {
248 rc = g_aServices[i].pfnTryStop(g_aServices[i].pvInstance);
249 if (RT_FAILURE(rc))
250 {
251 Log(("supSvcTryStopServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
252 break;
253 }
254 g_aServices[i].enmState = kSupSvcServiceState_Paused;
255 }
256 if (RT_FAILURE(rc))
257 {
258 /* Failed, restart the ones we succeeded in stopping. */
259 while (++i < RT_ELEMENTS(g_aServices))
260 {
261 g_aServices[i].pfnStart(g_aServices[i].pvInstance);
262 g_aServices[i].enmState = kSupSvcServiceState_Running;
263 }
264 }
265 LogFlow(("supSvcTryStopServices: returns %Rrc\n", rc));
266 return rc;
267}
268
269
270/**
271 * Stops and destroys the services.
272 */
273void supSvcStopAndDestroyServices(void)
274{
275 LogFlowFuncEnter();
276
277 /*
278 * Stop and destroy the service in reverse of start order.
279 */
280 unsigned i = RT_ELEMENTS(g_aServices);
281 while (i-- > 0)
282 if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
283 {
284 g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance,
285 g_aServices[i].enmState == kSupSvcServiceState_Running);
286 g_aServices[i].pvInstance = NULL;
287 g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
288 }
289
290 LogFlowFuncLeave();
291}
292
293
294
295/**
296 * Logs the message to the appropriate system log.
297 *
298 * In debug builds this will also put it in the debug log.
299 *
300 * @param pszMsg The log string.
301 *
302 * @remarks This may later be replaced by the release logger and callback destination(s).
303 */
304void supSvcLogErrorStr(const char *pszMsg)
305{
306 supSvcOsLogErrorStr(pszMsg);
307 LogRel(("%s\n", pszMsg));
308}
309
310
311/**
312 * Logs the message to the appropriate system log.
313 *
314 * In debug builds this will also put it in the debug log.
315 *
316 * @param pszFormat The log string. No trailing newline.
317 * @param va Format arguments.
318 *
319 * @todo This should later be replaced by the release logger and callback destination(s).
320 */
321void supSvcLogErrorV(const char *pszFormat, va_list va)
322{
323 if (*pszFormat)
324 {
325 char *pszMsg = NULL;
326 if (RTStrAPrintfV(&pszMsg, pszFormat, va) != -1)
327 {
328 supSvcLogErrorStr(pszMsg);
329 RTStrFree(pszMsg);
330 }
331 else
332 supSvcLogErrorStr(pszFormat);
333 }
334}
335
336
337/**
338 * Logs the error message to the appropriate system log.
339 *
340 * In debug builds this will also put it in the debug log.
341 *
342 * @param pszFormat The log string. No trailing newline.
343 * @param ... Format arguments.
344 *
345 * @todo This should later be replaced by the release logger and callback destination(s).
346 */
347void supSvcLogError(const char *pszFormat, ...)
348{
349 va_list va;
350 va_start(va, pszFormat);
351 supSvcLogErrorV(pszFormat, va);
352 va_end(va);
353}
354
355
356/**
357 * Deals with RTGetOpt failure, bitching in the system log.
358 *
359 * @returns 1
360 * @param pszAction The action name.
361 * @param rc The RTGetOpt return value.
362 * @param argc The argument count.
363 * @param argv The argument vector.
364 * @param iArg The argument index.
365 * @param pValue The value returned by RTGetOpt.
366 */
367int supSvcLogGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue)
368{
369 supSvcLogError("%s - RTGetOpt failure, %Rrc (%d): %s",
370 pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
371 return 1;
372}
373
374
375/**
376 * Bitch about too many arguments (after RTGetOpt stops) in the system log.
377 *
378 * @returns 1
379 * @param pszAction The action name.
380 * @param argc The argument count.
381 * @param argv The argument vector.
382 * @param iArg The argument index.
383 */
384int supSvcLogTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
385{
386 Assert(iArg < argc);
387 supSvcLogError("%s - Too many arguments: %s", pszAction, argv[iArg]);
388 for ( ; iArg < argc; iArg++)
389 LogRel(("arg#%i: %s\n", iArg, argv[iArg]));
390 return 1;
391}
392
393
394/**
395 * Prints an error message to the screen.
396 *
397 * @param pszFormat The message format string.
398 * @param va Format arguments.
399 */
400void supSvcDisplayErrorV(const char *pszFormat, va_list va)
401{
402 RTStrmPrintf(g_pStdErr, "VBoxSupSvc error: ");
403 RTStrmPrintfV(g_pStdErr, pszFormat, va);
404 Log(("supSvcDisplayErrorV: %s", pszFormat)); /** @todo format it! */
405}
406
407
408/**
409 * Prints an error message to the screen.
410 *
411 * @param pszFormat The message format string.
412 * @param ... Format arguments.
413 */
414void supSvcDisplayError(const char *pszFormat, ...)
415{
416 va_list va;
417 va_start(va, pszFormat);
418 supSvcDisplayErrorV(pszFormat, va);
419 va_end(va);
420}
421
422
423/**
424 * Deals with RTGetOpt failure.
425 *
426 * @returns 1
427 * @param pszAction The action name.
428 * @param rc The RTGetOpt return value.
429 * @param argc The argument count.
430 * @param argv The argument vector.
431 * @param iArg The argument index.
432 * @param pValue The value returned by RTGetOpt.
433 */
434int supSvcDisplayGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue)
435{
436 supSvcDisplayError("%s - RTGetOpt failure, %Rrc (%d): %s\n",
437 pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
438 return 1;
439}
440
441
442/**
443 * Bitch about too many arguments (after RTGetOpt stops).
444 *
445 * @returns 1
446 * @param pszAction The action name.
447 * @param argc The argument count.
448 * @param argv The argument vector.
449 * @param iArg The argument index.
450 */
451int supSvcDisplayTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
452{
453 Assert(iArg < argc);
454 supSvcDisplayError("%s - Too many arguments: %s\n", pszAction, argv[iArg]);
455 return 1;
456}
457
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