VirtualBox

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

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

RTGetOpt interface changes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use