In ntmain, call set_main_thread() before running the loop.
[tor/appveyor.git] / src / or / ntmain.c
blobddbe7a3e442d1ead28ee940f5dc003cbe0e6b6b8
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2013, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #include "or.h"
7 #include "config.h"
8 #include "main.h"
9 #include "ntmain.h"
11 #ifdef HAVE_EVENT2_EVENT_H
12 #include <event2/event.h>
13 #else
14 #include <event.h>
15 #endif
17 #include <windows.h>
18 #define GENSRV_SERVICENAME "tor"
19 #define GENSRV_DISPLAYNAME "Tor Win32 Service"
20 #define GENSRV_DESCRIPTION \
21 "Provides an anonymous Internet communication system"
22 #define GENSRV_USERACCT "NT AUTHORITY\\LocalService"
24 // Cheating: using the pre-defined error codes, tricks Windows into displaying
25 // a semi-related human-readable error message if startup fails as
26 // opposed to simply scaring people with Error: 0xffffffff
27 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
29 static SERVICE_STATUS service_status;
30 static SERVICE_STATUS_HANDLE hStatus;
32 /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
33 * is a job for arguments, not globals. Alas, some of the functions that
34 * use them use them need to have fixed signatures, so they can be passed
35 * to the NT service functions. */
36 static char **backup_argv;
37 static int backup_argc;
39 static void nt_service_control(DWORD request);
40 static void nt_service_body(int argc, char **argv);
41 static void nt_service_main(void);
42 static SC_HANDLE nt_service_open_scm(void);
43 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
44 static int nt_service_start(SC_HANDLE hService);
45 static int nt_service_stop(SC_HANDLE hService);
46 static int nt_service_install(int argc, char **argv);
47 static int nt_service_remove(void);
48 static int nt_service_cmd_start(void);
49 static int nt_service_cmd_stop(void);
51 /** Struct to hold dynamically loaded NT-service related function pointers.
53 struct service_fns {
54 int loaded;
56 /** @{ */
57 /** Function pointers for Windows API functions related to service
58 * management. These are NULL, or they point to the . They're set by
59 * calling the LOAD macro below. */
61 BOOL (WINAPI *ChangeServiceConfig2A_fn)(
62 SC_HANDLE hService,
63 DWORD dwInfoLevel,
64 LPVOID lpInfo);
66 BOOL (WINAPI *CloseServiceHandle_fn)(
67 SC_HANDLE hSCObject);
69 BOOL (WINAPI *ControlService_fn)(
70 SC_HANDLE hService,
71 DWORD dwControl,
72 LPSERVICE_STATUS lpServiceStatus);
74 SC_HANDLE (WINAPI *CreateServiceA_fn)(
75 SC_HANDLE hSCManager,
76 LPCSTR lpServiceName,
77 LPCSTR lpDisplayName,
78 DWORD dwDesiredAccess,
79 DWORD dwServiceType,
80 DWORD dwStartType,
81 DWORD dwErrorControl,
82 LPCSTR lpBinaryPathName,
83 LPCSTR lpLoadOrderGroup,
84 LPDWORD lpdwTagId,
85 LPCSTR lpDependencies,
86 LPCSTR lpServiceStartName,
87 LPCSTR lpPassword);
89 BOOL (WINAPI *DeleteService_fn)(
90 SC_HANDLE hService);
92 SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
93 LPCSTR lpMachineName,
94 LPCSTR lpDatabaseName,
95 DWORD dwDesiredAccess);
97 SC_HANDLE (WINAPI *OpenServiceA_fn)(
98 SC_HANDLE hSCManager,
99 LPCSTR lpServiceName,
100 DWORD dwDesiredAccess);
102 BOOL (WINAPI *QueryServiceStatus_fn)(
103 SC_HANDLE hService,
104 LPSERVICE_STATUS lpServiceStatus);
106 SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
107 LPCSTR lpServiceName,
108 LPHANDLER_FUNCTION lpHandlerProc);
110 BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
111 LPSERVICE_STATUS);
113 BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
114 const SERVICE_TABLE_ENTRYA* lpServiceTable);
116 BOOL (WINAPI *StartServiceA_fn)(
117 SC_HANDLE hService,
118 DWORD dwNumServiceArgs,
119 LPCSTR* lpServiceArgVectors);
121 BOOL (WINAPI *LookupAccountNameA_fn)(
122 LPCSTR lpSystemName,
123 LPCSTR lpAccountName,
124 PSID Sid,
125 LPDWORD cbSid,
126 LPTSTR ReferencedDomainName,
127 LPDWORD cchReferencedDomainName,
128 PSID_NAME_USE peUse);
129 /** @} */
130 } service_fns = { 0,
131 NULL, NULL, NULL, NULL, NULL, NULL,
132 NULL, NULL, NULL, NULL, NULL, NULL,
133 NULL};
135 /** Loads functions used by NT services. Returns on success, or prints a
136 * complaint to stdout and exits on error. */
137 static void
138 nt_service_loadlibrary(void)
140 HMODULE library = 0;
141 void *fn;
143 if (service_fns.loaded)
144 return;
146 if (!(library = load_windows_system_library(TEXT("advapi32.dll")))) {
147 log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use "
148 "NT services on Windows 98? That doesn't work.");
149 goto err;
152 /* Helper macro: try to load a function named <b>f</b> from "library" into
153 * service_functions.<b>f</b>_fn. On failure, log an error message, and goto
154 * err.
156 #define LOAD(f) STMT_BEGIN \
157 if (!(fn = GetProcAddress(library, #f))) { \
158 log_err(LD_BUG, \
159 "Couldn't find %s in advapi32.dll! We probably got the " \
160 "name wrong.", #f); \
161 goto err; \
162 } else { \
163 service_fns.f ## _fn = fn; \
165 STMT_END
167 LOAD(ChangeServiceConfig2A);
168 LOAD(CloseServiceHandle);
169 LOAD(ControlService);
170 LOAD(CreateServiceA);
171 LOAD(DeleteService);
172 LOAD(OpenSCManagerA);
173 LOAD(OpenServiceA);
174 LOAD(QueryServiceStatus);
175 LOAD(RegisterServiceCtrlHandlerA);
176 LOAD(SetServiceStatus);
177 LOAD(StartServiceCtrlDispatcherA);
178 LOAD(StartServiceA);
179 LOAD(LookupAccountNameA);
181 service_fns.loaded = 1;
183 return;
184 err:
185 printf("Unable to load library support for NT services: exiting.\n");
186 exit(1);
189 /** If we're compiled to run as an NT service, and the service wants to
190 * shut down, then change our current status and return 1. Else
191 * return 0.
194 nt_service_is_stopping(void)
196 /* If we haven't loaded the function pointers, we can't possibly be an NT
197 * service trying to shut down. */
198 if (!service_fns.loaded)
199 return 0;
201 if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
202 service_status.dwWin32ExitCode = 0;
203 service_status.dwCurrentState = SERVICE_STOPPED;
204 service_fns.SetServiceStatus_fn(hStatus, &service_status);
205 return 1;
206 } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
207 return 1;
209 return 0;
212 /** Set the dwCurrentState field for our service to <b>state</b>. */
213 void
214 nt_service_set_state(DWORD state)
216 service_status.dwCurrentState = state;
219 /** Handles service control requests, such as stopping or starting the
220 * Tor service. */
221 static void
222 nt_service_control(DWORD request)
224 static struct timeval exit_now;
225 exit_now.tv_sec = 0;
226 exit_now.tv_usec = 0;
228 nt_service_loadlibrary();
230 switch (request) {
231 case SERVICE_CONTROL_STOP:
232 case SERVICE_CONTROL_SHUTDOWN:
233 log_notice(LD_GENERAL,
234 "Got stop/shutdown request; shutting down cleanly.");
235 service_status.dwCurrentState = SERVICE_STOP_PENDING;
236 event_base_loopexit(tor_libevent_get_base(), &exit_now);
237 return;
239 service_fns.SetServiceStatus_fn(hStatus, &service_status);
242 /** Called when the service is started via the system's service control
243 * manager. This calls tor_init() and starts the main event loop. If
244 * tor_init() fails, the service will be stopped and exit code set to
245 * NT_SERVICE_ERROR_TORINIT_FAILED. */
246 static void
247 nt_service_body(int argc, char **argv)
249 int r;
250 (void) argc; /* unused */
251 (void) argv; /* unused */
252 nt_service_loadlibrary();
253 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
254 service_status.dwCurrentState = SERVICE_START_PENDING;
255 service_status.dwControlsAccepted =
256 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
257 service_status.dwWin32ExitCode = 0;
258 service_status.dwServiceSpecificExitCode = 0;
259 service_status.dwCheckPoint = 0;
260 service_status.dwWaitHint = 1000;
261 hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
262 (LPHANDLER_FUNCTION) nt_service_control);
264 if (hStatus == 0) {
265 /* Failed to register the service control handler function */
266 return;
269 r = tor_init(backup_argc, backup_argv);
270 if (r) {
271 /* Failed to start the Tor service */
272 r = NT_SERVICE_ERROR_TORINIT_FAILED;
273 service_status.dwCurrentState = SERVICE_STOPPED;
274 service_status.dwWin32ExitCode = r;
275 service_status.dwServiceSpecificExitCode = r;
276 service_fns.SetServiceStatus_fn(hStatus, &service_status);
277 return;
280 /* Set the service's status to SERVICE_RUNNING and start the main
281 * event loop */
282 service_status.dwCurrentState = SERVICE_RUNNING;
283 service_fns.SetServiceStatus_fn(hStatus, &service_status);
284 set_main_thread();
285 do_main_loop();
286 tor_cleanup();
289 /** Main service entry point. Starts the service control dispatcher and waits
290 * until the service status is set to SERVICE_STOPPED. */
291 static void
292 nt_service_main(void)
294 SERVICE_TABLE_ENTRYA table[2];
295 DWORD result = 0;
296 char *errmsg;
297 nt_service_loadlibrary();
298 table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
299 table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body;
300 table[1].lpServiceName = NULL;
301 table[1].lpServiceProc = NULL;
303 if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
304 result = GetLastError();
305 errmsg = format_win32_error(result);
306 printf("Service error %d : %s\n", (int) result, errmsg);
307 tor_free(errmsg);
308 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
309 if (tor_init(backup_argc, backup_argv) < 0)
310 return;
311 switch (get_options()->command) {
312 case CMD_RUN_TOR:
313 do_main_loop();
314 break;
315 case CMD_LIST_FINGERPRINT:
316 case CMD_HASH_PASSWORD:
317 case CMD_VERIFY_CONFIG:
318 case CMD_DUMP_CONFIG:
319 log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
320 "--hash-password, or --verify-config) in NT service.");
321 break;
322 case CMD_RUN_UNITTESTS:
323 default:
324 log_err(LD_CONFIG, "Illegal command number %d: internal error.",
325 get_options()->command);
327 tor_cleanup();
332 /** Return a handle to the service control manager on success, or NULL on
333 * failure. */
334 static SC_HANDLE
335 nt_service_open_scm(void)
337 SC_HANDLE hSCManager;
338 char *errmsg = NULL;
340 nt_service_loadlibrary();
341 if ((hSCManager = service_fns.OpenSCManagerA_fn(
342 NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
343 errmsg = format_win32_error(GetLastError());
344 printf("OpenSCManager() failed : %s\n", errmsg);
345 tor_free(errmsg);
347 return hSCManager;
350 /** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
351 * on failure. */
352 static SC_HANDLE
353 nt_service_open(SC_HANDLE hSCManager)
355 SC_HANDLE hService;
356 char *errmsg = NULL;
357 nt_service_loadlibrary();
358 if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
359 SERVICE_ALL_ACCESS)) == NULL) {
360 errmsg = format_win32_error(GetLastError());
361 printf("OpenService() failed : %s\n", errmsg);
362 tor_free(errmsg);
364 return hService;
367 /** Start the Tor service. Return 0 if the service is started or was
368 * previously running. Return -1 on error. */
369 static int
370 nt_service_start(SC_HANDLE hService)
372 char *errmsg = NULL;
374 nt_service_loadlibrary();
376 service_fns.QueryServiceStatus_fn(hService, &service_status);
377 if (service_status.dwCurrentState == SERVICE_RUNNING) {
378 printf("Service is already running\n");
379 return 0;
382 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
383 /* Loop until the service has finished attempting to start */
384 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
385 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
386 Sleep(500);
389 /* Check if it started successfully or not */
390 if (service_status.dwCurrentState == SERVICE_RUNNING) {
391 printf("Service started successfully\n");
392 return 0;
393 } else {
394 errmsg = format_win32_error(service_status.dwWin32ExitCode);
395 printf("Service failed to start : %s\n", errmsg);
396 tor_free(errmsg);
398 } else {
399 errmsg = format_win32_error(GetLastError());
400 printf("StartService() failed : %s\n", errmsg);
401 tor_free(errmsg);
403 return -1;
406 /** Stop the Tor service. Return 0 if the service is stopped or was not
407 * previously running. Return -1 on error. */
408 static int
409 nt_service_stop(SC_HANDLE hService)
411 /** Wait at most 10 seconds for the service to stop. */
412 #define MAX_SERVICE_WAIT_TIME 10
413 int wait_time;
414 char *errmsg = NULL;
415 nt_service_loadlibrary();
417 service_fns.QueryServiceStatus_fn(hService, &service_status);
418 if (service_status.dwCurrentState == SERVICE_STOPPED) {
419 printf("Service is already stopped\n");
420 return 0;
423 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
424 &service_status)) {
425 wait_time = 0;
426 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
427 (service_status.dwCurrentState != SERVICE_STOPPED) &&
428 (wait_time < MAX_SERVICE_WAIT_TIME)) {
429 Sleep(1000);
430 wait_time++;
432 if (service_status.dwCurrentState == SERVICE_STOPPED) {
433 printf("Service stopped successfully\n");
434 return 0;
435 } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
436 printf("Service did not stop within %d seconds.\n", wait_time);
437 } else {
438 errmsg = format_win32_error(GetLastError());
439 printf("QueryServiceStatus() failed : %s\n",errmsg);
440 tor_free(errmsg);
442 } else {
443 errmsg = format_win32_error(GetLastError());
444 printf("ControlService() failed : %s\n", errmsg);
445 tor_free(errmsg);
447 return -1;
450 /** Build a formatted command line used for the NT service. Return a
451 * pointer to the formatted string on success, or NULL on failure. Set
452 * *<b>using_default_torrc</b> to true if we're going to use the default
453 * location to torrc, or 1 if an option was specified on the command line.
455 static char *
456 nt_service_command_line(int *using_default_torrc)
458 TCHAR tor_exe[MAX_PATH+1];
459 char tor_exe_ascii[MAX_PATH*2+1];
460 char *command=NULL, *options=NULL;
461 smartlist_t *sl;
462 int i;
463 *using_default_torrc = 1;
465 /* Get the location of tor.exe */
466 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
467 return NULL;
469 /* Get the service arguments */
470 sl = smartlist_new();
471 for (i = 1; i < backup_argc; ++i) {
472 if (!strcmp(backup_argv[i], "--options") ||
473 !strcmp(backup_argv[i], "-options")) {
474 while (++i < backup_argc) {
475 if (!strcmp(backup_argv[i], "-f"))
476 *using_default_torrc = 0;
477 smartlist_add(sl, backup_argv[i]);
481 if (smartlist_len(sl))
482 options = smartlist_join_strings(sl,"\" \"",0,NULL);
483 smartlist_free(sl);
485 #ifdef UNICODE
486 wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
487 tor_exe_ascii[sizeof(tor_exe_ascii)-1] = '\0';
488 #else
489 strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
490 #endif
492 /* Allocate a string for the NT service command line and */
493 /* Format the service command */
494 if (options) {
495 tor_asprintf(&command, "\"%s\" --nt-service \"%s\"",
496 tor_exe_ascii, options);
497 } else { /* ! options */
498 tor_asprintf(&command, "\"%s\" --nt-service", tor_exe_ascii);
501 tor_free(options);
502 return command;
505 /** Creates a Tor NT service, set to start on boot. The service will be
506 * started if installation succeeds. Returns 0 on success, or -1 on
507 * failure. */
508 static int
509 nt_service_install(int argc, char **argv)
511 /* Notes about developing NT services:
513 * 1. Don't count on your CWD. If an absolute path is not given, the
514 * fopen() function goes wrong.
515 * 2. The parameters given to the nt_service_body() function differ
516 * from those given to main() function.
519 SC_HANDLE hSCManager = NULL;
520 SC_HANDLE hService = NULL;
521 SERVICE_DESCRIPTIONA sdBuff;
522 char *command;
523 char *errmsg;
524 const char *user_acct = NULL;
525 const char *password = "";
526 int i;
527 OSVERSIONINFOEX info;
528 SID_NAME_USE sidUse;
529 DWORD sidLen = 0, domainLen = 0;
530 int is_win2k_or_worse = 0;
531 int using_default_torrc = 0;
533 nt_service_loadlibrary();
535 /* Open the service control manager so we can create a new service */
536 if ((hSCManager = nt_service_open_scm()) == NULL)
537 return -1;
538 /* Build the command line used for the service */
539 if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
540 printf("Unable to build service command line.\n");
541 service_fns.CloseServiceHandle_fn(hSCManager);
542 return -1;
545 for (i=1; i < argc; ++i) {
546 if (!strcmp(argv[i], "--user") && i+1<argc) {
547 user_acct = argv[i+1];
548 ++i;
550 if (!strcmp(argv[i], "--password") && i+1<argc) {
551 password = argv[i+1];
552 ++i;
556 /* Compute our version and see whether we're running win2k or earlier. */
557 memset(&info, 0, sizeof(info));
558 info.dwOSVersionInfoSize = sizeof(info);
559 if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
560 printf("Call to GetVersionEx failed.\n");
561 is_win2k_or_worse = 1;
562 } else {
563 if (info.dwMajorVersion < 5 ||
564 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
565 is_win2k_or_worse = 1;
568 if (!user_acct) {
569 if (is_win2k_or_worse) {
570 /* On Win2k, there is no LocalService account, so we actually need to
571 * fall back on NULL (the system account). */
572 printf("Running on Win2K or earlier, so the LocalService account "
573 "doesn't exist. Falling back to SYSTEM account.\n");
574 } else {
575 /* Genericity is apparently _so_ last year in Redmond, where some
576 * accounts are accounts that you can look up, and some accounts
577 * are magic and undetectable via the security subsystem. See
578 * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
580 printf("Running on a Post-Win2K OS, so we'll assume that the "
581 "LocalService account exists.\n");
582 user_acct = GENSRV_USERACCT;
584 } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
585 user_acct,
586 NULL, &sidLen, // Don't care about the SID
587 NULL, &domainLen, // Don't care about the domain
588 &sidUse) == 0) {
589 /* XXXX For some reason, the above test segfaults. Fix that. */
590 printf("User \"%s\" doesn't seem to exist.\n", user_acct);
591 return -1;
592 } else {
593 printf("Will try to install service as user \"%s\".\n", user_acct);
595 /* XXXX This warning could be better about explaining how to resolve the
596 * situation. */
597 if (using_default_torrc)
598 printf("IMPORTANT NOTE:\n"
599 " The Tor service will run under the account \"%s\". This means\n"
600 " that Tor will look for its configuration file under that\n"
601 " account's Application Data directory, which is probably not\n"
602 " the same as yours.\n", user_acct?user_acct:"<local system>");
604 /* Create the Tor service, set to auto-start on boot */
605 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
606 GENSRV_DISPLAYNAME,
607 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
608 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
609 command, NULL, NULL, NULL,
610 user_acct, password)) == NULL) {
611 errmsg = format_win32_error(GetLastError());
612 printf("CreateService() failed : %s\n", errmsg);
613 service_fns.CloseServiceHandle_fn(hSCManager);
614 tor_free(errmsg);
615 tor_free(command);
616 return -1;
618 printf("Done with CreateService.\n");
620 /* Set the service's description */
621 sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
622 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
623 &sdBuff);
624 printf("Service installed successfully\n");
626 /* Start the service initially */
627 nt_service_start(hService);
629 service_fns.CloseServiceHandle_fn(hService);
630 service_fns.CloseServiceHandle_fn(hSCManager);
631 tor_free(command);
633 return 0;
636 /** Removes the Tor NT service. Returns 0 if the service was successfully
637 * removed, or -1 on error. */
638 static int
639 nt_service_remove(void)
641 SC_HANDLE hSCManager = NULL;
642 SC_HANDLE hService = NULL;
643 char *errmsg;
645 nt_service_loadlibrary();
646 if ((hSCManager = nt_service_open_scm()) == NULL)
647 return -1;
648 if ((hService = nt_service_open(hSCManager)) == NULL) {
649 service_fns.CloseServiceHandle_fn(hSCManager);
650 return -1;
653 nt_service_stop(hService);
654 if (service_fns.DeleteService_fn(hService) == FALSE) {
655 errmsg = format_win32_error(GetLastError());
656 printf("DeleteService() failed : %s\n", errmsg);
657 tor_free(errmsg);
658 service_fns.CloseServiceHandle_fn(hService);
659 service_fns.CloseServiceHandle_fn(hSCManager);
660 return -1;
663 service_fns.CloseServiceHandle_fn(hService);
664 service_fns.CloseServiceHandle_fn(hSCManager);
665 printf("Service removed successfully\n");
667 return 0;
670 /** Starts the Tor service. Returns 0 on success, or -1 on error. */
671 static int
672 nt_service_cmd_start(void)
674 SC_HANDLE hSCManager;
675 SC_HANDLE hService;
676 int start;
678 if ((hSCManager = nt_service_open_scm()) == NULL)
679 return -1;
680 if ((hService = nt_service_open(hSCManager)) == NULL) {
681 service_fns.CloseServiceHandle_fn(hSCManager);
682 return -1;
685 start = nt_service_start(hService);
686 service_fns.CloseServiceHandle_fn(hService);
687 service_fns.CloseServiceHandle_fn(hSCManager);
689 return start;
692 /** Stops the Tor service. Returns 0 on success, or -1 on error. */
693 static int
694 nt_service_cmd_stop(void)
696 SC_HANDLE hSCManager;
697 SC_HANDLE hService;
698 int stop;
700 if ((hSCManager = nt_service_open_scm()) == NULL)
701 return -1;
702 if ((hService = nt_service_open(hSCManager)) == NULL) {
703 service_fns.CloseServiceHandle_fn(hSCManager);
704 return -1;
707 stop = nt_service_stop(hService);
708 service_fns.CloseServiceHandle_fn(hService);
709 service_fns.CloseServiceHandle_fn(hSCManager);
711 return stop;
715 nt_service_parse_options(int argc, char **argv, int *should_exit)
717 backup_argv = argv;
718 backup_argc = argc;
719 *should_exit = 0;
721 if ((argc >= 3) &&
722 (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
723 nt_service_loadlibrary();
724 *should_exit = 1;
725 if (!strcmp(argv[2], "install"))
726 return nt_service_install(argc, argv);
727 if (!strcmp(argv[2], "remove"))
728 return nt_service_remove();
729 if (!strcmp(argv[2], "start"))
730 return nt_service_cmd_start();
731 if (!strcmp(argv[2], "stop"))
732 return nt_service_cmd_stop();
733 printf("Unrecognized service command '%s'\n", argv[2]);
734 return 1;
736 if (argc >= 2) {
737 if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
738 nt_service_loadlibrary();
739 nt_service_main();
740 *should_exit = 1;
741 return 0;
743 // These values have been deprecated since 0.1.1.2-alpha; we've warned
744 // about them since 0.1.2.7-alpha.
745 if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
746 nt_service_loadlibrary();
747 fprintf(stderr,
748 "The %s option is deprecated; use \"--service install\" instead.",
749 argv[1]);
750 *should_exit = 1;
751 return nt_service_install(argc, argv);
753 if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
754 nt_service_loadlibrary();
755 fprintf(stderr,
756 "The %s option is deprecated; use \"--service remove\" instead.",
757 argv[1]);
758 *should_exit = 1;
759 return nt_service_remove();
762 *should_exit = 0;
763 return 0;