VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPSvc-win.cpp@ 37070

Last change on this file since 37070 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.7 KB
Line 
1/* $Id: SUPSvc-win.cpp 33540 2010-10-28 09:27:05Z vboxsync $ */
2/** @file
3 * VirtualBox Support Service - Windows Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008 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* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_SUP
31#include <Windows.h>
32
33#include <VBox/log.h>
34#include <VBox/version.h>
35#include <iprt/string.h>
36#include <iprt/mem.h>
37#include <iprt/initterm.h>
38#include <iprt/stream.h>
39#include <iprt/getopt.h>
40#include <iprt/semaphore.h>
41#ifdef DEBUG_bird
42# include <iprt/env.h>
43#endif
44
45#include "../SUPSvcInternal.h"
46
47
48/*******************************************************************************
49* Defined Constants And Macros *
50*******************************************************************************/
51/** The service name. */
52#define SUPSVC_SERVICE_NAME "VBoxSupSvc"
53/** The service display name. */
54#define SUPSVC_SERVICE_DISPLAY_NAME "VirtualBox Support Service"
55
56
57/*******************************************************************************
58* Global Variables *
59*******************************************************************************/
60/** The service control handler handle. */
61static SERVICE_STATUS_HANDLE g_hSupSvcWinCtrlHandler = NULL;
62/** The service status. */
63static uint32_t volatile g_u32SupSvcWinStatus = SERVICE_STOPPED;
64/** The semaphore the main service thread is waiting on in supSvcWinServiceMain. */
65static RTSEMEVENTMULTI g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
66
67
68/*******************************************************************************
69* Internal Functions *
70*******************************************************************************/
71static SC_HANDLE supSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess);
72
73
74/**
75 * Opens the service control manager.
76 *
77 * When this fails, an error message will be displayed.
78 *
79 * @returns Valid handle on success.
80 * NULL on failure, will display an error message.
81 *
82 * @param pszAction The action which is requesting access to SCM.
83 * @param dwAccess The desired access.
84 */
85static SC_HANDLE supSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess)
86{
87 SC_HANDLE hSCM = OpenSCManager(NULL /* lpMachineName*/, NULL /* lpDatabaseName */, dwAccess);
88 if (hSCM == NULL)
89 {
90 DWORD err = GetLastError();
91 switch (err)
92 {
93 case ERROR_ACCESS_DENIED:
94 supSvcDisplayError("%s - OpenSCManager failure: access denied\n", pszAction);
95 break;
96 default:
97 supSvcDisplayError("%s - OpenSCManager failure: %d\n", pszAction, err);
98 break;
99 }
100 }
101 return hSCM;
102}
103
104
105/**
106 * Opens the service.
107 *
108 * Last error is preserved on failure and set to 0 on success.
109 *
110 * @returns Valid service handle on success.
111 * NULL on failure, will display an error message unless it's ignored.
112 *
113 * @param pszAction The action which is requesting access to the service.
114 * @param dwSCMAccess The service control manager access.
115 * @param dwSVCAccess The desired service access.
116 * @param cIgnoredErrors The number of ignored errors.
117 * @param ... Errors codes that should not cause a message to be displayed.
118 */
119static SC_HANDLE supSvcWinOpenService(const char *pszAction, DWORD dwSCMAccess, DWORD dwSVCAccess,
120 unsigned cIgnoredErrors, ...)
121{
122 SC_HANDLE hSCM = supSvcWinOpenSCManager(pszAction, dwSCMAccess);
123 if (!hSCM)
124 return NULL;
125
126 SC_HANDLE hSvc = OpenService(hSCM, SUPSVC_SERVICE_NAME, dwSVCAccess);
127 if (hSvc)
128 {
129 CloseServiceHandle(hSCM);
130 SetLastError(0);
131 }
132 else
133 {
134 DWORD err = GetLastError();
135 bool fIgnored = false;
136 va_list va;
137 va_start(va, cIgnoredErrors);
138 while (!fIgnored && cIgnoredErrors-- > 0)
139 fIgnored = va_arg(va, long) == err;
140 va_end(va);
141 if (!fIgnored)
142 {
143 switch (err)
144 {
145 case ERROR_ACCESS_DENIED:
146 supSvcDisplayError("%s - OpenService failure: access denied\n", pszAction);
147 break;
148 case ERROR_SERVICE_DOES_NOT_EXIST:
149 supSvcDisplayError("%s - OpenService failure: The service does not exist. Reinstall it.\n", pszAction);
150 break;
151 default:
152 supSvcDisplayError("%s - OpenService failure: %d\n", pszAction, err);
153 break;
154 }
155 }
156
157 CloseServiceHandle(hSCM);
158 SetLastError(err);
159 }
160 return hSvc;
161}
162
163
164
165void supSvcOsLogErrorStr(const char *pszMsg)
166{
167 HANDLE hEventLog = RegisterEventSource(NULL /* local computer */, "VBoxSupSvc");
168 AssertReturnVoid(hEventLog != NULL);
169 const char *apsz[2];
170 apsz[0] = "VBoxSupSvc";
171 apsz[1] = pszMsg;
172 BOOL fRc = ReportEvent(hEventLog, /* hEventLog */
173 EVENTLOG_ERROR_TYPE, /* wType */
174 0, /* wCategory */
175 0 /** @todo mc */, /* dwEventID */
176 NULL, /* lpUserSid */
177 RT_ELEMENTS(apsz), /* wNumStrings */
178 0, /* dwDataSize */
179 apsz, /* lpStrings */
180 NULL); /* lpRawData */
181 AssertMsg(fRc, ("%d\n", GetLastError()));
182 DeregisterEventSource(hEventLog);
183}
184
185
186static int supSvcWinInterrogate(int argc, char **argv)
187{
188 RTPrintf("VBoxSupSvc: The \"interrogate\" action is not implemented.\n");
189 return 1;
190}
191
192
193static int supSvcWinStop(int argc, char **argv)
194{
195 RTPrintf("VBoxSupSvc: The \"stop\" action is not implemented.\n");
196 return 1;
197}
198
199
200static int supSvcWinContinue(int argc, char **argv)
201{
202 RTPrintf("VBoxSupSvc: The \"continue\" action is not implemented.\n");
203 return 1;
204}
205
206
207static int supSvcWinPause(int argc, char **argv)
208{
209 RTPrintf("VBoxSupSvc: The \"pause\" action is not implemented.\n");
210 return 1;
211}
212
213
214static int supSvcWinStart(int argc, char **argv)
215{
216 RTPrintf("VBoxSupSvc: The \"start\" action is not implemented.\n");
217 return 1;
218}
219
220
221static int supSvcWinQueryDescription(int argc, char **argv)
222{
223 RTPrintf("VBoxSupSvc: The \"qdescription\" action is not implemented.\n");
224 return 1;
225}
226
227
228static int supSvcWinQueryConfig(int argc, char **argv)
229{
230 RTPrintf("VBoxSupSvc: The \"qconfig\" action is not implemented.\n");
231 return 1;
232}
233
234
235static int supSvcWinDisable(int argc, char **argv)
236{
237 RTPrintf("VBoxSupSvc: The \"disable\" action is not implemented.\n");
238 return 1;
239}
240
241static int supSvcWinEnable(int argc, char **argv)
242{
243 RTPrintf("VBoxSupSvc: The \"enable\" action is not implemented.\n");
244 return 1;
245}
246
247
248/**
249 * Handle the 'delete' action.
250 *
251 * @returns 0 or 1.
252 * @param argc The action argument count.
253 * @param argv The action argument vector.
254 */
255static int supSvcWinDelete(int argc, char **argv)
256{
257 /*
258 * Parse the arguments.
259 */
260 bool fVerbose = false;
261 static const RTGETOPTDEF s_aOptions[] =
262 {
263 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
264 };
265 int ch;
266 RTGETOPTUNION Value;
267 RTGETOPTSTATE GetState;
268 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
269 while ((ch = RTGetOpt(&GetState, &Value)))
270 switch (ch)
271 {
272 case 'v':
273 fVerbose = true;
274 break;
275 case VINF_GETOPT_NOT_OPTION:
276 return supSvcDisplayTooManyArgsError("delete", argc, argv, iArg);
277 default:
278 return supSvcDisplayGetOptError("delete", ch, argc, argv, iArg, &Value);
279 }
280
281 /*
282 * Create the service.
283 */
284 int rc = 1;
285 SC_HANDLE hSvc = supSvcWinOpenService("delete", SERVICE_CHANGE_CONFIG, DELETE,
286 1, ERROR_SERVICE_DOES_NOT_EXIST);
287 if (hSvc)
288 {
289 if (DeleteService(hSvc))
290 {
291 RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME);
292 rc = 0;
293 }
294 else
295 supSvcDisplayError("delete - DeleteService failed, err=%d.\n", GetLastError());
296 CloseServiceHandle(hSvc);
297 }
298 else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
299 {
300
301 if (fVerbose)
302 RTPrintf("The service %s was not installed, nothing to be done.", SUPSVC_SERVICE_NAME);
303 else
304 RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME);
305 rc = 0;
306 }
307 return rc;
308}
309
310
311/**
312 * Handle the 'create' action.
313 *
314 * @returns 0 or 1.
315 * @param argc The action argument count.
316 * @param argv The action argument vector.
317 */
318static int supSvcWinCreate(int argc, char **argv)
319{
320 /*
321 * Parse the arguments.
322 */
323 bool fVerbose = false;
324 static const RTOPTIONDEF s_aOptions[] =
325 {
326 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
327 };
328 int iArg = 0;
329 int ch;
330 RTGETOPTUNION Value;
331 while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
332 switch (ch)
333 {
334 case 'v': fVerbose = true; break;
335 default: return supSvcDisplayGetOptError("create", ch, argc, argv, iArg, &Value);
336 }
337 if (iArg != argc)
338 return supSvcDisplayTooManyArgsError("create", argc, argv, iArg);
339
340 /*
341 * Create the service.
342 */
343 int rc = 1;
344 SC_HANDLE hSCM = supSvcWinOpenSCManager("create", SC_MANAGER_CREATE_SERVICE); /*SC_MANAGER_ALL_ACCESS*/
345 if (hSCM)
346 {
347 char szExecPath[MAX_PATH];
348 if (GetModuleFileName(NULL /* the executable */, szExecPath, sizeof(szExecPath)))
349 {
350 if (fVerbose)
351 RTPrintf("Creating the %s service, binary \"%s\"...\n",
352 SUPSVC_SERVICE_NAME, szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */
353
354 SC_HANDLE hSvc = CreateService(hSCM, /* hSCManager */
355 SUPSVC_SERVICE_NAME, /* lpServiceName */
356 SUPSVC_SERVICE_DISPLAY_NAME, /* lpDisplayName */
357 SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG, /* dwDesiredAccess */
358 SERVICE_WIN32_OWN_PROCESS, /* dwServiceType ( | SERVICE_INTERACTIVE_PROCESS? ) */
359 SERVICE_DEMAND_START/*_AUTO*/, /* dwStartType */
360 SERVICE_ERROR_NORMAL, /* dwErrorControl */
361 szExecPath, /* lpBinaryPathName */
362 NULL, /* lpLoadOrderGroup */
363 NULL, /* lpdwTagId */
364 NULL, /* lpDependencies */
365 NULL, /* lpServiceStartName (=> LocalSystem) */
366 NULL); /* lpPassword */
367 if (hSvc)
368 {
369 RTPrintf("Successfully created the %s service.\n", SUPSVC_SERVICE_NAME);
370 /** @todo Set the service description or it'll look weird in the vista service manager.
371 * Anything else that should be configured? Start access or something? */
372 rc = 0;
373 CloseServiceHandle(hSvc);
374 }
375 else
376 {
377 DWORD err = GetLastError();
378 switch (err)
379 {
380 case ERROR_SERVICE_EXISTS:
381 supSvcDisplayError("create - The service already exists.\n");
382 break;
383 default:
384 supSvcDisplayError("create - CreateService failed, err=%d.\n", GetLastError());
385 break;
386 }
387 }
388 CloseServiceHandle(hSvc);
389 }
390 else
391 supSvcDisplayError("create - Failed to obtain the executable path: %d\n", GetLastError());
392 }
393 return rc;
394}
395
396
397/**
398 * Sets the service status, just a SetServiceStatus Wrapper.
399 *
400 * @returns See SetServiceStatus.
401 * @param dwStatus The current status.
402 * @param iWaitHint The wait hint, if < 0 then supply a default.
403 * @param dwExitCode The service exit code.
404 */
405static bool supSvcWinSetServiceStatus(DWORD dwStatus, int iWaitHint, DWORD dwExitCode)
406{
407 SERVICE_STATUS SvcStatus;
408 SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
409 SvcStatus.dwWin32ExitCode = dwExitCode;
410 SvcStatus.dwServiceSpecificExitCode = 0;
411 SvcStatus.dwWaitHint = iWaitHint >= 0 ? iWaitHint : 3000;
412 SvcStatus.dwCurrentState = dwStatus;
413 LogFlow(("supSvcWinSetServiceStatus: %d -> %d\n", g_u32SupSvcWinStatus, dwStatus));
414 g_u32SupSvcWinStatus = dwStatus;
415 switch (dwStatus)
416 {
417 case SERVICE_START_PENDING:
418 SvcStatus.dwControlsAccepted = 0;
419 break;
420 default:
421 SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
422 break;
423 }
424
425 static DWORD dwCheckPoint = 0;
426 switch (dwStatus)
427 {
428 case SERVICE_RUNNING:
429 case SERVICE_STOPPED:
430 SvcStatus.dwCheckPoint = 0;
431 default:
432 SvcStatus.dwCheckPoint = ++dwCheckPoint;
433 break;
434 }
435 return SetServiceStatus(g_hSupSvcWinCtrlHandler, &SvcStatus) != FALSE;
436}
437
438
439/**
440 * Service control handler (extended).
441 *
442 * @returns Windows status (see HandlerEx).
443 * @retval NO_ERROR if handled.
444 * @retval ERROR_CALL_NOT_IMPLEMENTED if not handled.
445 *
446 * @param dwControl The control code.
447 * @param dwEventType Event type. (specific to the control?)
448 * @param pvEventData Event data, specific to the event.
449 * @param pvContext The context pointer registered with the handler.
450 * Currently not used.
451 */
452static DWORD WINAPI supSvcWinServiceCtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pvEventData, LPVOID pvContext)
453{
454 LogFlow(("supSvcWinServiceCtrlHandlerEx: dwControl=%#x dwEventType=%#x pvEventData=%p\n",
455 dwControl, dwEventType, pvEventData));
456
457 switch (dwControl)
458 {
459 /*
460 * Interrogate the service about it's current status.
461 * MSDN says that this should just return NO_ERROR and does
462 * not need to set the status again.
463 */
464 case SERVICE_CONTROL_INTERROGATE:
465 return NO_ERROR;
466
467 /*
468 * Request to stop the service.
469 */
470 case SERVICE_CONTROL_STOP:
471 {
472 /*
473 * Check if the real services can be stopped and then tell them to stop.
474 */
475 supSvcWinSetServiceStatus(SERVICE_STOP_PENDING, 3000, NO_ERROR);
476 int rc = supSvcTryStopServices();
477 if (RT_SUCCESS(rc))
478 {
479 /*
480 * Notify the main thread that we're done, it will wait for the
481 * real services to stop, destroy them, and finally set the windows
482 * service status to SERVICE_STOPPED and return.
483 */
484 rc = RTSemEventMultiSignal(g_hSupSvcWinEvent);
485 if (RT_FAILURE(rc))
486 supSvcLogError("SERVICE_CONTROL_STOP: RTSemEventMultiSignal failed, %Rrc\n", rc);
487 }
488 return NO_ERROR;
489 }
490
491 case SERVICE_CONTROL_PAUSE:
492 case SERVICE_CONTROL_CONTINUE:
493 case SERVICE_CONTROL_SHUTDOWN:
494 case SERVICE_CONTROL_PARAMCHANGE:
495 case SERVICE_CONTROL_NETBINDADD:
496 case SERVICE_CONTROL_NETBINDREMOVE:
497 case SERVICE_CONTROL_NETBINDENABLE:
498 case SERVICE_CONTROL_NETBINDDISABLE:
499 case SERVICE_CONTROL_DEVICEEVENT:
500 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
501 case SERVICE_CONTROL_POWEREVENT:
502 case SERVICE_CONTROL_SESSIONCHANGE:
503#ifdef SERVICE_CONTROL_PRESHUTDOWN /* vista */
504 case SERVICE_CONTROL_PRESHUTDOWN:
505#endif
506 default:
507 return ERROR_CALL_NOT_IMPLEMENTED;
508 }
509
510 NOREF(dwEventType);
511 NOREF(pvEventData);
512 NOREF(pvContext);
513 return NO_ERROR;
514}
515
516
517/**
518 * Windows Service Main.
519 *
520 * This is invoked when the service is started and should not return until
521 * the service has been stopped.
522 *
523 * @param cArgs Argument count.
524 * @param papszArgs Argument vector.
525 */
526static VOID WINAPI supSvcWinServiceMain(DWORD cArgs, LPSTR *papszArgs)
527{
528 LogFlowFuncEnter();
529
530 /*
531 * Register the control handler function for the service and report to SCM.
532 */
533 Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
534 g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerEx(SUPSVC_SERVICE_NAME, supSvcWinServiceCtrlHandlerEx, NULL);
535 if (g_hSupSvcWinCtrlHandler)
536 {
537 DWORD err = ERROR_GEN_FAILURE;
538 if (supSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
539 {
540 /*
541 * Parse arguments.
542 */
543 static const RTOPTIONDEF s_aOptions[] =
544 {
545 { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
546 };
547 int iArg = 1; /* the first arg is the service name */
548 int ch;
549 int rc = 0;
550 RTGETOPTUNION Value;
551 while ( !rc
552 && (ch = RTGetOpt(cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
553 switch (ch)
554 {
555 default: rc = supSvcLogGetOptError("main", ch, cArgs, papszArgs, iArg, &Value); break;
556 }
557 if (iArg != cArgs)
558 rc = supSvcLogTooManyArgsError("main", cArgs, papszArgs, iArg);
559 if (!rc)
560 {
561 /*
562 * Create the event semaphore we'll be waiting on and
563 * then instantiate the actual services.
564 */
565 int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
566 if (RT_SUCCESS(rc))
567 {
568 rc = supSvcCreateAndStartServices();
569 if (RT_SUCCESS(rc))
570 {
571 /*
572 * Update the status and enter the work loop.
573 *
574 * The work loop is just a dummy wait here as the services run
575 * in independent threads.
576 */
577 if (supSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
578 {
579 LogFlow(("supSvcWinServiceMain: calling RTSemEventMultiWait\n"));
580 rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
581 if (RT_SUCCESS(rc))
582 {
583 LogFlow(("supSvcWinServiceMain: woke up\n"));
584 err = NO_ERROR;
585 }
586 else
587 supSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
588 }
589 else
590 {
591 err = GetLastError();
592 supSvcLogError("SetServiceStatus failed, err=%d", err);
593 }
594
595 /*
596 * Destroy the service instances, stopping them if
597 * they're still running (weird failure cause).
598 */
599 supSvcStopAndDestroyServices();
600 }
601
602 RTSemEventMultiDestroy(g_hSupSvcWinEvent);
603 g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
604 }
605 else
606 supSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
607 }
608 /* else: bad args */
609 }
610 else
611 {
612 err = GetLastError();
613 supSvcLogError("SetServiceStatus failed, err=%d", err);
614 }
615 supSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
616 }
617 else
618 supSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
619 LogFlowFuncLeave();
620}
621
622
623/**
624 * Handle the 'create' action.
625 *
626 * @returns 0 or 1.
627 * @param argc The action argument count.
628 * @param argv The action argument vector.
629 */
630static int supSvcWinRunIt(int argc, char **argv)
631{
632 LogFlowFuncEnter();
633
634 /*
635 * Initialize release logging.
636 */
637 /** @todo release logging of the system-wide service. */
638
639 /*
640 * Parse the arguments.
641 */
642 static const RTOPTIONDEF s_aOptions[] =
643 {
644 { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
645 };
646 int iArg = 0;
647 int ch;
648 RTGETOPTUNION Value;
649 while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
650 switch (ch)
651 {
652 default: return supSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
653 }
654 if (iArg != argc)
655 return supSvcDisplayTooManyArgsError("runit", argc, argv, iArg);
656
657 /*
658 * Register the service with the service control manager
659 * and start dispatching requests from it (all done by the API).
660 */
661 static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
662 {
663 { SUPSVC_SERVICE_NAME, supSvcWinServiceMain },
664 { NULL, NULL}
665 };
666 if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
667 {
668 LogFlowFuncLeave();
669 return 0; /* told to quit, so quit. */
670 }
671
672 DWORD err = GetLastError();
673 switch (err)
674 {
675 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
676 supSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
677 break;
678 default:
679 supSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
680 break;
681 }
682 return 1;
683}
684
685
686/**
687 * Show the version info.
688 *
689 * @returns 0.
690 */
691static int supSvcWinShowVersion(int argc, char **argv)
692{
693 /*
694 * Parse the arguments.
695 */
696 bool fBrief = false;
697 static const RTOPTIONDEF s_aOptions[] =
698 {
699 { "--brief", 'b', RTGETOPT_REQ_NOTHING }
700 };
701 int iArg = 0;
702 int ch;
703 RTGETOPTUNION Value;
704 while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
705 switch (ch)
706 {
707 case 'b': fBrief = true; break;
708 default: return supSvcDisplayGetOptError("version", ch, argc, argv, iArg, &Value);
709
710 }
711 if (iArg != argc)
712 return supSvcDisplayTooManyArgsError("version", argc, argv, iArg);
713
714 /*
715 * Do the printing.
716 */
717 if (fBrief)
718 RTPrintf("%s\n", VBOX_VERSION_STRING);
719 else
720 RTPrintf("VirtualBox System Service Version %s\n"
721 "(C) 2008-2010 Oracle Corporation\n"
722 "All rights reserved.\n",
723 VBOX_VERSION_STRING);
724 return 0;
725}
726
727
728/**
729 * Show the usage help screen.
730 *
731 * @returns 0.
732 */
733static int supSvcWinShowHelp(void)
734{
735 RTPrintf("VirtualBox System Service Version %s\n"
736 "(C) 2008-2010 Oracle Corporation\n"
737 "All rights reserved.\n"
738 "\n",
739 VBOX_VERSION_STRING);
740 RTPrintf("Usage:\n"
741 "\n"
742 "VBoxSupSvc\n"
743 " Runs the service.\n"
744 "VBoxSupSvc <version|-v|--version> [-brief]\n"
745 " Displays the version.\n"
746 "VBoxSupSvc <help|-?|-h|--help> [...]\n"
747 " Displays this help screen.\n"
748 "\n"
749 "VBoxSupSvc <install|/RegServer|/i>\n"
750 " Installs the service.\n"
751 "VBoxSupSvc <install|delete|/UnregServer|/u>\n"
752 " Uninstalls the service.\n"
753 );
754 return 0;
755}
756
757
758/**
759 * VBoxSUPSvc main(), Windows edition.
760 *
761 *
762 * @returns 0 on success.
763 *
764 * @param argc Number of arguments in argv.
765 * @param argv Argument vector.
766 */
767int main(int argc, char **argv)
768{
769 /*
770 * Initialize the IPRT first of all.
771 */
772#ifdef DEBUG_bird
773 RTEnvSet("VBOX_LOG", "sup=~0");
774 RTEnvSet("VBOX_LOG_DEST", "file=E:\\temp\\VBoxSupSvc.log");
775 RTEnvSet("VBOX_LOG_FLAGS", "unbuffered thread msprog");
776#endif
777 int rc = RTR3Init();
778 if (RT_FAILURE(rc))
779 {
780 supSvcLogError("RTR3Init failed with rc=%Rrc", rc);
781 return 1;
782 }
783
784 /*
785 * Parse the initial arguments to determine the desired action.
786 */
787 enum
788 {
789 kSupSvcAction_RunIt,
790
791 kSupSvcAction_Create,
792 kSupSvcAction_Delete,
793
794 kSupSvcAction_Enable,
795 kSupSvcAction_Disable,
796 kSupSvcAction_QueryConfig,
797 kSupSvcAction_QueryDescription,
798
799 kSupSvcAction_Start,
800 kSupSvcAction_Pause,
801 kSupSvcAction_Continue,
802 kSupSvcAction_Stop,
803 kSupSvcAction_Interrogate,
804
805 kSupSvcAction_End
806 } enmAction = kSupSvcAction_RunIt;
807 int iArg = 1;
808 if (argc > 1)
809 {
810 if ( !stricmp(argv[iArg], "/RegServer")
811 || !stricmp(argv[iArg], "install")
812 || !stricmp(argv[iArg], "/i"))
813 enmAction = kSupSvcAction_Create;
814 else if ( !stricmp(argv[iArg], "/UnregServer")
815 || !stricmp(argv[iArg], "/u")
816 || !stricmp(argv[iArg], "uninstall")
817 || !stricmp(argv[iArg], "delete"))
818 enmAction = kSupSvcAction_Delete;
819
820 else if (!stricmp(argv[iArg], "enable"))
821 enmAction = kSupSvcAction_Enable;
822 else if (!stricmp(argv[iArg], "disable"))
823 enmAction = kSupSvcAction_Disable;
824 else if (!stricmp(argv[iArg], "qconfig"))
825 enmAction = kSupSvcAction_QueryConfig;
826 else if (!stricmp(argv[iArg], "qdescription"))
827 enmAction = kSupSvcAction_QueryDescription;
828
829 else if ( !stricmp(argv[iArg], "start")
830 || !stricmp(argv[iArg], "/t"))
831 enmAction = kSupSvcAction_Start;
832 else if (!stricmp(argv[iArg], "pause"))
833 enmAction = kSupSvcAction_Start;
834 else if (!stricmp(argv[iArg], "continue"))
835 enmAction = kSupSvcAction_Continue;
836 else if (!stricmp(argv[iArg], "stop"))
837 enmAction = kSupSvcAction_Stop;
838 else if (!stricmp(argv[iArg], "interrogate"))
839 enmAction = kSupSvcAction_Interrogate;
840 else if ( !stricmp(argv[iArg], "help")
841 || !stricmp(argv[iArg], "?")
842 || !stricmp(argv[iArg], "/?")
843 || !stricmp(argv[iArg], "-?")
844 || !stricmp(argv[iArg], "/h")
845 || !stricmp(argv[iArg], "-h")
846 || !stricmp(argv[iArg], "/help")
847 || !stricmp(argv[iArg], "-help")
848 || !stricmp(argv[iArg], "--help"))
849 return supSvcWinShowHelp();
850 else if ( !stricmp(argv[iArg], "version")
851 || !stricmp(argv[iArg], "/v")
852 || !stricmp(argv[iArg], "-v")
853 || !stricmp(argv[iArg], "/version")
854 || !stricmp(argv[iArg], "-version")
855 || !stricmp(argv[iArg], "--version"))
856 return supSvcWinShowVersion(argc - iArg - 1, argv + iArg + 1);
857 else
858 iArg--;
859 iArg++;
860 }
861
862 /*
863 * Dispatch it.
864 */
865 switch (enmAction)
866 {
867 case kSupSvcAction_RunIt:
868 return supSvcWinRunIt(argc - iArg, argv + iArg);
869
870 case kSupSvcAction_Create:
871 return supSvcWinCreate(argc - iArg, argv + iArg);
872 case kSupSvcAction_Delete:
873 return supSvcWinDelete(argc - iArg, argv + iArg);
874
875 case kSupSvcAction_Enable:
876 return supSvcWinEnable(argc - iArg, argv + iArg);
877 case kSupSvcAction_Disable:
878 return supSvcWinDisable(argc - iArg, argv + iArg);
879 case kSupSvcAction_QueryConfig:
880 return supSvcWinQueryConfig(argc - iArg, argv + iArg);
881 case kSupSvcAction_QueryDescription:
882 return supSvcWinQueryDescription(argc - iArg, argv + iArg);
883
884 case kSupSvcAction_Start:
885 return supSvcWinStart(argc - iArg, argv + iArg);
886 case kSupSvcAction_Pause:
887 return supSvcWinPause(argc - iArg, argv + iArg);
888 case kSupSvcAction_Continue:
889 return supSvcWinContinue(argc - iArg, argv + iArg);
890 case kSupSvcAction_Stop:
891 return supSvcWinStop(argc - iArg, argv + iArg);
892 case kSupSvcAction_Interrogate:
893 return supSvcWinInterrogate(argc - iArg, argv + iArg);
894
895 default:
896 AssertMsgFailed(("enmAction=%d\n", enmAction));
897 return 1;
898 }
899}
900
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