VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart-win.cpp@ 43911

最後變更 在這個檔案從43911是 43911,由 vboxsync 提交於 12 年 前

fix OSE

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette