2 /* XXX: (value && value->string) is probably bogus because value is probably never null */
5 #define NSSM_AFFINITY_ALL _T("All")
7 extern const TCHAR *exit_action_strings[];
8 extern const TCHAR *startup_strings[];
9 extern const TCHAR *priority_strings[];
11 /* Does the parameter refer to the default value of the setting? */
12 static inline int is_default(const TCHAR *value) {
13 return (str_equiv(value, _T("default")) || str_equiv(value, _T("*")) || ! value[0]);
16 static int value_from_string(const TCHAR *name, value_t *value, const TCHAR *string) {
17 size_t len = _tcslen(string);
23 value->string = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));
24 if (! value->string) {
25 print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, name, _T("value_from_string()"));
29 if (_sntprintf_s(value->string, len, _TRUNCATE, _T("%s"), string) < 0) {
30 HeapFree(GetProcessHeap(), 0, value->string);
31 print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, name, _T("value_from_string()"));
38 /* Functions to manage NSSM-specific settings in the registry. */
39 static int setting_set_number(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
40 HKEY key = (HKEY) param;
46 /* Resetting to default? */
47 if (! value || ! value->string) {
48 error = RegDeleteValue(key, name);
49 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
50 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
53 if (str_number(value->string, &number)) return -1;
55 if (default_value && number == (unsigned long) default_value) {
56 error = RegDeleteValue(key, name);
57 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
58 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
62 if (set_number(key, (TCHAR *) name, number)) return -1;
67 static int setting_get_number(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
68 HKEY key = (HKEY) param;
69 return get_number(key, (TCHAR *) name, &value->numeric, false);
72 static int setting_set_string(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
73 HKEY key = (HKEY) param;
78 /* Resetting to default? */
79 if (! value || ! value->string) {
80 if (default_value) value->string = (TCHAR *) default_value;
82 error = RegDeleteValue(key, name);
83 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
84 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
88 if (default_value && _tcslen((TCHAR *) default_value) && str_equiv(value->string, (TCHAR *) default_value)) {
89 error = RegDeleteValue(key, name);
90 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
91 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
95 if (set_expand_string(key, (TCHAR *) name, value->string)) return -1;
100 static int setting_get_string(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
101 HKEY key = (HKEY) param;
102 TCHAR buffer[VALUE_LENGTH];
104 if (get_string(key, (TCHAR *) name, (TCHAR *) buffer, (unsigned long) sizeof(buffer), false, false, false)) return -1;
106 return value_from_string(name, value, buffer);
109 static int setting_set_exit_action(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
110 unsigned long exitcode;
112 TCHAR action_string[ACTION_LEN];
115 /* Default action? */
116 if (is_default(additional)) code = 0;
118 if (str_number(additional, &exitcode)) return -1;
119 code = (TCHAR *) additional;
123 HKEY key = open_registry(service_name, name, KEY_WRITE);
124 if (! key) return -1;
129 /* Resetting to default? */
130 if (value && value->string) _sntprintf_s(action_string, _countof(action_string), _TRUNCATE, _T("%s"), value->string);
133 /* Delete explicit action. */
134 error = RegDeleteValue(key, code);
136 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
137 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, code, service_name, error_string(error));
141 /* Explicitly keep the default action. */
142 if (default_value) _sntprintf_s(action_string, _countof(action_string), _TRUNCATE, _T("%s"), (TCHAR *) default_value);
147 /* Validate the string. */
148 for (int i = 0; exit_action_strings[i]; i++) {
149 if (! _tcsnicmp((const TCHAR *) action_string, exit_action_strings[i], ACTION_LEN)) {
150 if (default_value && str_equiv(action_string, (TCHAR *) default_value)) ret = 0;
151 if (RegSetValueEx(key, code, 0, REG_SZ, (const unsigned char *) exit_action_strings[i], (unsigned long) (_tcslen(action_string) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS) {
152 print_message(stderr, NSSM_MESSAGE_SETVALUE_FAILED, code, service_name, error_string(GetLastError()));
162 print_message(stderr, NSSM_MESSAGE_INVALID_EXIT_ACTION, action_string);
163 for (int i = 0; exit_action_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), exit_action_strings[i]);
168 static int setting_get_exit_action(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
169 unsigned long exitcode = 0;
170 unsigned long *code = 0;
173 if (! is_default(additional)) {
174 if (str_number(additional, &exitcode)) return -1;
179 TCHAR action_string[ACTION_LEN];
181 if (get_exit_action(service_name, code, action_string, &default_action)) return -1;
183 value_from_string(name, value, action_string);
185 if (default_action && ! _tcsnicmp((const TCHAR *) action_string, (TCHAR *) default_value, ACTION_LEN)) return 0;
189 static int setting_set_affinity(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
190 HKEY key = (HKEY) param;
191 if (! key) return -1;
195 __int64 system_affinity = 0LL;
197 if (value && value->string) {
199 if (! GetProcessAffinityMask(GetCurrentProcess(), &affinity, (DWORD_PTR *) &system_affinity)) system_affinity = ~0;
201 if (is_default(value->string) || str_equiv(value->string, NSSM_AFFINITY_ALL)) mask = 0LL;
202 else if (affinity_string_to_mask(value->string, &mask)) {
203 print_message(stderr, NSSM_MESSAGE_BOGUS_AFFINITY_MASK, value->string, num_cpus() - 1);
210 error = RegDeleteValue(key, name);
211 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
212 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
218 if (affinity_mask_to_string(mask, &canon)) canon = value->string;
220 __int64 effective_affinity = mask & system_affinity;
221 if (effective_affinity != mask) {
222 /* Requested CPUs did not intersect with available CPUs? */
223 if (! effective_affinity) mask = effective_affinity = system_affinity;
226 if (! affinity_mask_to_string(system_affinity, &system)) {
227 TCHAR *effective = 0;
228 if (! affinity_mask_to_string(effective_affinity, &effective)) {
229 print_message(stderr, NSSM_MESSAGE_EFFECTIVE_AFFINITY_MASK, value->string, system, effective);
230 HeapFree(GetProcessHeap(), 0, effective);
232 HeapFree(GetProcessHeap(), 0, system);
236 if (RegSetValueEx(key, name, 0, REG_SZ, (const unsigned char *) canon, (unsigned long) (_tcslen(canon) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS) {
237 if (canon != value->string) HeapFree(GetProcessHeap(), 0, canon);
238 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, name, error_string(GetLastError()), 0);
242 if (canon != value->string) HeapFree(GetProcessHeap(), 0, canon);
246 static int setting_get_affinity(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
247 HKEY key = (HKEY) param;
248 if (! key) return -1;
252 unsigned long buflen = 0;
254 int ret = RegQueryValueEx(key, name, 0, &type, 0, &buflen);
255 if (ret == ERROR_FILE_NOT_FOUND) {
256 if (value_from_string(name, value, NSSM_AFFINITY_ALL) == 1) return 0;
259 if (ret != ERROR_SUCCESS) return -1;
261 if (type != REG_SZ) return -1;
263 buffer = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, buflen);
265 print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("affinity"), _T("setting_get_affinity"));
269 if (get_string(key, (TCHAR *) name, buffer, buflen, false, false, true)) {
270 HeapFree(GetProcessHeap(), 0, buffer);
275 if (affinity_string_to_mask(buffer, &affinity)) {
276 print_message(stderr, NSSM_MESSAGE_BOGUS_AFFINITY_MASK, buffer, num_cpus() - 1);
277 HeapFree(GetProcessHeap(), 0, buffer);
281 HeapFree(GetProcessHeap(), 0, buffer);
284 if (affinity_mask_to_string(affinity, &buffer)) {
285 if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
289 ret = value_from_string(name, value, buffer);
290 HeapFree(GetProcessHeap(), 0, buffer);
294 static int setting_set_environment(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
295 HKEY key = (HKEY) param;
296 if (! param) return -1;
298 if (! value || ! value->string || ! value->string[0]) {
299 long error = RegDeleteValue(key, name);
300 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
301 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
305 unsigned long envlen = (unsigned long) _tcslen(value->string) + 1;
306 TCHAR *unformatted = 0;
307 unsigned long newlen;
308 if (unformat_environment(value->string, envlen, &unformatted, &newlen)) return -1;
310 if (test_environment(unformatted)) {
311 HeapFree(GetProcessHeap(), 0, unformatted);
312 print_message(stderr, NSSM_GUI_INVALID_ENVIRONMENT);
316 if (RegSetValueEx(key, name, 0, REG_MULTI_SZ, (const unsigned char *) unformatted, (unsigned long) newlen * sizeof(TCHAR)) != ERROR_SUCCESS) {
317 if (newlen) HeapFree(GetProcessHeap(), 0, unformatted);
318 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);
322 if (newlen) HeapFree(GetProcessHeap(), 0, unformatted);
326 static int setting_get_environment(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
327 HKEY key = (HKEY) param;
328 if (! param) return -1;
331 unsigned long envlen;
332 if (get_environment((TCHAR *) service_name, key, (TCHAR *) name, &env, &envlen)) return -1;
333 if (! envlen) return 0;
336 unsigned long newlen;
337 if (format_environment(env, envlen, &formatted, &newlen)) return -1;
341 /* Find named environment variable. */
343 size_t len = _tcslen(additional);
344 for (s = env; *s; s++) {
345 /* Look for <additional>=<string> NULL NULL */
346 if (! _tcsnicmp(s, additional, len) && s[len] == _T('=')) {
349 ret = value_from_string(name, value, s);
350 HeapFree(GetProcessHeap(), 0, env);
354 /* Skip this string. */
357 HeapFree(GetProcessHeap(), 0, env);
361 HeapFree(GetProcessHeap(), 0, env);
363 ret = value_from_string(name, value, formatted);
364 if (newlen) HeapFree(GetProcessHeap(), 0, formatted);
368 static int setting_set_priority(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
369 HKEY key = (HKEY) param;
370 if (! param) return -1;
372 TCHAR *priority_string;
376 if (value && value->string) priority_string = value->string;
377 else if (default_value) priority_string = (TCHAR *) default_value;
379 error = RegDeleteValue(key, name);
380 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
381 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
385 for (i = 0; priority_strings[i]; i++) {
386 if (! str_equiv(priority_strings[i], priority_string)) continue;
388 if (default_value && str_equiv(priority_string, (TCHAR *) default_value)) {
389 error = RegDeleteValue(key, name);
390 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
391 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
395 if (set_number(key, (TCHAR *) name, priority_index_to_constant(i))) return -1;
399 print_message(stderr, NSSM_MESSAGE_INVALID_PRIORITY, priority_string);
400 for (i = 0; priority_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), priority_strings[i]);
405 static int setting_get_priority(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
406 HKEY key = (HKEY) param;
407 if (! param) return -1;
409 unsigned long constant;
410 switch (get_number(key, (TCHAR *) name, &constant, false)) {
411 case 0: return value_from_string(name, value, (const TCHAR *) default_value);
415 return value_from_string(name, value, priority_strings[priority_constant_to_index(constant)]);
418 /* Functions to manage native service settings. */
419 int native_set_description(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
420 SC_HANDLE service_handle = (SC_HANDLE) param;
421 if (! service_handle) return -1;
423 TCHAR *description = 0;
424 if (value) description = value->string;
425 if (set_service_description(service_name, service_handle, description)) return -1;
427 if (description && description[0]) return 1;
432 int native_get_description(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
433 SC_HANDLE service_handle = (SC_HANDLE) param;
434 if (! service_handle) return -1;
436 TCHAR buffer[VALUE_LENGTH];
437 if (get_service_description(service_name, service_handle, _countof(buffer), buffer)) return -1;
439 if (buffer[0]) return value_from_string(name, value, buffer);
445 int native_set_displayname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
446 SC_HANDLE service_handle = (SC_HANDLE) param;
447 if (! service_handle) return -1;
449 TCHAR *displayname = 0;
450 if (value && value->string) displayname = value->string;
451 else displayname = (TCHAR *) service_name;
453 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, displayname)) {
454 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
459 If the display name and service name differ only in case,
460 ChangeServiceConfig() will return success but the display name will be
461 set to the service name, NOT the value passed to the function.
462 This appears to be a quirk of Windows rather than a bug here.
464 if (displayname != service_name && ! str_equiv(displayname, service_name)) return 1;
469 int native_get_displayname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
470 SC_HANDLE service_handle = (SC_HANDLE) param;
471 if (! service_handle) return -1;
473 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
474 if (! qsc) return -1;
476 int ret = value_from_string(name, value, qsc->lpDisplayName);
477 HeapFree(GetProcessHeap(), 0, qsc);
482 int native_set_imagepath(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
483 SC_HANDLE service_handle = (SC_HANDLE) param;
484 if (! service_handle) return -1;
486 /* It makes no sense to try to reset the image path. */
487 if (! value || ! value->string) {
488 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
492 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, value->string, 0, 0, 0, 0, 0, 0)) {
493 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
500 int native_get_imagepath(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
501 SC_HANDLE service_handle = (SC_HANDLE) param;
502 if (! service_handle) return -1;
504 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
505 if (! qsc) return -1;
507 int ret = value_from_string(name, value, qsc->lpBinaryPathName);
508 HeapFree(GetProcessHeap(), 0, qsc);
513 int native_set_name(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
514 print_message(stderr, NSSM_MESSAGE_CANNOT_RENAME_SERVICE);
518 int native_get_name(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
519 return value_from_string(name, value, service_name);
522 int native_set_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
523 SC_HANDLE service_handle = (SC_HANDLE) param;
524 if (! service_handle) return -1;
527 Logical syntax is: nssm set <service> ObjectName <username> <password>
528 That means the username is actually passed in the additional parameter.
530 bool localsystem = false;
531 TCHAR *username = NSSM_LOCALSYSTEM_ACCOUNT;
534 username = (TCHAR *) additional;
535 if (value && value->string) password = value->string;
537 else if (value && value->string) username = value->string;
539 const TCHAR *well_known = well_known_username(username);
540 size_t passwordsize = 0;
542 if (str_equiv(well_known, NSSM_LOCALSYSTEM_ACCOUNT)) localsystem = true;
543 username = (TCHAR *) well_known;
546 else if (! password) {
547 /* We need a password if the account requires it. */
548 print_message(stderr, NSSM_MESSAGE_MISSING_PASSWORD, name);
551 else passwordsize = _tcslen(password) * sizeof(TCHAR);
554 ChangeServiceConfig() will fail to set the username if the service is set
555 to interact with the desktop.
557 unsigned long type = SERVICE_NO_CHANGE;
559 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
561 if (passwordsize) SecureZeroMemory(password, passwordsize);
565 type = qsc->dwServiceType & ~SERVICE_INTERACTIVE_PROCESS;
566 HeapFree(GetProcessHeap(), 0, qsc);
570 if (grant_logon_as_service(username)) {
571 if (passwordsize) SecureZeroMemory(password, passwordsize);
572 print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);
577 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, username, password, 0)) {
578 if (passwordsize) SecureZeroMemory(password, passwordsize);
579 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
583 if (passwordsize) SecureZeroMemory(password, passwordsize);
585 if (localsystem) return 0;
590 int native_get_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
591 SC_HANDLE service_handle = (SC_HANDLE) param;
592 if (! service_handle) return -1;
594 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
595 if (! qsc) return -1;
597 int ret = value_from_string(name, value, qsc->lpServiceStartName);
598 HeapFree(GetProcessHeap(), 0, qsc);
603 int native_set_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
604 SC_HANDLE service_handle = (SC_HANDLE) param;
605 if (! service_handle) return -1;
607 /* It makes no sense to try to reset the startup type. */
608 if (! value || ! value->string) {
609 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
613 /* Map NSSM_STARTUP_* constant to Windows SERVICE_*_START constant. */
614 int service_startup = -1;
616 for (i = 0; startup_strings[i]; i++) {
617 if (str_equiv(value->string, startup_strings[i])) {
623 if (service_startup < 0) {
624 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_STARTUP, value->string);
625 for (i = 0; startup_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), startup_strings[i]);
629 unsigned long startup;
630 switch (service_startup) {
631 case NSSM_STARTUP_MANUAL: startup = SERVICE_DEMAND_START; break;
632 case NSSM_STARTUP_DISABLED: startup = SERVICE_DISABLED; break;
633 default: startup = SERVICE_AUTO_START;
636 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
637 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
641 SERVICE_DELAYED_AUTO_START_INFO delayed;
642 ZeroMemory(&delayed, sizeof(delayed));
643 if (service_startup == NSSM_STARTUP_DELAYED) delayed.fDelayedAutostart = 1;
644 else delayed.fDelayedAutostart = 0;
645 if (! ChangeServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) {
646 unsigned long error = GetLastError();
647 /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */
648 if (error != ERROR_INVALID_LEVEL) {
649 log_event(EVENTLOG_ERROR_TYPE, NSSM_MESSAGE_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service_name, error_string(error), 0);
656 int native_get_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
657 SC_HANDLE service_handle = (SC_HANDLE) param;
658 if (! service_handle) return -1;
660 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
661 if (! qsc) return -1;
663 unsigned long startup;
664 int ret = get_service_startup(service_name, service_handle, qsc, &startup);
665 HeapFree(GetProcessHeap(), 0, qsc);
670 for (i = 0; startup_strings[i]; i++);
671 if (startup >= i) return -1;
673 return value_from_string(name, value, startup_strings[startup]);
676 int native_set_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
677 SC_HANDLE service_handle = (SC_HANDLE) param;
678 if (! service_handle) return -1;
680 /* It makes no sense to try to reset the service type. */
681 if (! value || ! value->string) {
682 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
687 We can only manage services of type SERVICE_WIN32_OWN_PROCESS
688 and SERVICE_INTERACTIVE_PROCESS.
690 unsigned long type = SERVICE_WIN32_OWN_PROCESS;
691 if (str_equiv(value->string, NSSM_INTERACTIVE_PROCESS)) type |= SERVICE_INTERACTIVE_PROCESS;
692 else if (! str_equiv(value->string, NSSM_WIN32_OWN_PROCESS)) {
693 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_TYPE, value->string);
694 _ftprintf(stderr, _T("%s\n"), NSSM_WIN32_OWN_PROCESS);
695 _ftprintf(stderr, _T("%s\n"), NSSM_INTERACTIVE_PROCESS);
700 ChangeServiceConfig() will fail if the service runs under an account
701 other than LOCALSYSTEM and we try to make it interactive.
703 if (type & SERVICE_INTERACTIVE_PROCESS) {
704 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
705 if (! qsc) return -1;
707 if (! str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) {
708 HeapFree(GetProcessHeap(), 0, qsc);
709 print_message(stderr, NSSM_MESSAGE_INTERACTIVE_NOT_LOCALSYSTEM, value->string, service_name, NSSM_LOCALSYSTEM_ACCOUNT);
713 HeapFree(GetProcessHeap(), 0, qsc);
716 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
717 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
724 int native_get_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
725 SC_HANDLE service_handle = (SC_HANDLE) param;
726 if (! service_handle) return -1;
728 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
729 if (! qsc) return -1;
731 value->numeric = qsc->dwServiceType;
732 HeapFree(GetProcessHeap(), 0, qsc);
735 switch (value->numeric) {
736 case SERVICE_KERNEL_DRIVER: string = NSSM_KERNEL_DRIVER; break;
737 case SERVICE_FILE_SYSTEM_DRIVER: string = NSSM_FILE_SYSTEM_DRIVER; break;
738 case SERVICE_WIN32_OWN_PROCESS: string = NSSM_WIN32_OWN_PROCESS; break;
739 case SERVICE_WIN32_SHARE_PROCESS: string = NSSM_WIN32_SHARE_PROCESS; break;
740 case SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_INTERACTIVE_PROCESS; break;
741 case SERVICE_WIN32_SHARE_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_SHARE_INTERACTIVE_PROCESS; break;
742 default: string = NSSM_UNKNOWN;
745 return value_from_string(name, value, string);
748 int set_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
749 if (! key) return -1;
752 if (setting->set) ret = setting->set(service_name, (void *) key, setting->name, setting->default_value, value, additional);
755 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
756 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
757 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
762 int set_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
763 if (! service_handle) return -1;
766 if (setting->set) ret = setting->set(service_name, service_handle, setting->name, setting->default_value, value, additional);
769 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
770 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
771 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
777 Returns: 1 if the value was retrieved.
778 0 if the default value was retrieved.
781 int get_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
782 if (! key) return -1;
785 switch (setting->type) {
789 value->string = (TCHAR *) setting->default_value;
790 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
795 value->numeric = (unsigned long) setting->default_value;
796 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
805 if (ret < 0) print_message(stderr, NSSM_MESSAGE_GET_SETTING_FAILED, setting->name, service_name);
810 int get_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
811 if (! service_handle) return -1;
812 return setting->get(service_name, service_handle, setting->name, 0, value, additional);
815 settings_t settings[] = {
816 { NSSM_REG_EXE, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
817 { NSSM_REG_FLAGS, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
818 { NSSM_REG_DIR, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
819 { NSSM_REG_EXIT, REG_SZ, (void *) exit_action_strings[NSSM_EXIT_RESTART], false, ADDITIONAL_MANDATORY, setting_set_exit_action, setting_get_exit_action },
820 { NSSM_REG_AFFINITY, REG_SZ, 0, false, 0, setting_set_affinity, setting_get_affinity },
821 { NSSM_REG_ENV, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
822 { NSSM_REG_ENV_EXTRA, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
823 { NSSM_REG_NO_CONSOLE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
824 { NSSM_REG_PRIORITY, REG_SZ, (void *) priority_strings[NSSM_NORMAL_PRIORITY], false, 0, setting_set_priority, setting_get_priority },
825 { NSSM_REG_RESTART_DELAY, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
826 { NSSM_REG_STDIN, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
827 { NSSM_REG_STDIN NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDIN_SHARING, false, 0, setting_set_number, setting_get_number },
828 { NSSM_REG_STDIN NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDIN_DISPOSITION, false, 0, setting_set_number, setting_get_number },
829 { NSSM_REG_STDIN NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDIN_FLAGS, false, 0, setting_set_number, setting_get_number },
830 { NSSM_REG_STDOUT, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
831 { NSSM_REG_STDOUT NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDOUT_SHARING, false, 0, setting_set_number, setting_get_number },
832 { NSSM_REG_STDOUT NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDOUT_DISPOSITION, false, 0, setting_set_number, setting_get_number },
833 { NSSM_REG_STDOUT NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDOUT_FLAGS, false, 0, setting_set_number, setting_get_number },
834 { NSSM_REG_STDERR, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
835 { NSSM_REG_STDERR NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDERR_SHARING, false, 0, setting_set_number, setting_get_number },
836 { NSSM_REG_STDERR NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDERR_DISPOSITION, false, 0, setting_set_number, setting_get_number },
837 { NSSM_REG_STDERR NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDERR_FLAGS, false, 0, setting_set_number, setting_get_number },
838 { NSSM_REG_STOP_METHOD_SKIP, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
839 { NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_CONSOLE_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
840 { NSSM_REG_KILL_WINDOW_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_WINDOW_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
841 { NSSM_REG_KILL_THREADS_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_THREADS_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
842 { NSSM_REG_THROTTLE, REG_DWORD, (void *) NSSM_RESET_THROTTLE_RESTART, false, 0, setting_set_number, setting_get_number },
843 { NSSM_REG_ROTATE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
844 { NSSM_REG_ROTATE_ONLINE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
845 { NSSM_REG_ROTATE_SECONDS, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
846 { NSSM_REG_ROTATE_BYTES_LOW, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
847 { NSSM_REG_ROTATE_BYTES_HIGH, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
848 { NSSM_NATIVE_DESCRIPTION, REG_SZ, _T(""), true, 0, native_set_description, native_get_description },
849 { NSSM_NATIVE_DISPLAYNAME, REG_SZ, NULL, true, 0, native_set_displayname, native_get_displayname },
850 { NSSM_NATIVE_IMAGEPATH, REG_EXPAND_SZ, NULL, true, 0, native_set_imagepath, native_get_imagepath },
851 { NSSM_NATIVE_OBJECTNAME, REG_SZ, NSSM_LOCALSYSTEM_ACCOUNT, true, 0, native_set_objectname, native_get_objectname },
852 { NSSM_NATIVE_NAME, REG_SZ, NULL, true, 0, native_set_name, native_get_name },
853 { NSSM_NATIVE_STARTUP, REG_SZ, NULL, true, 0, native_set_startup, native_get_startup },
854 { NSSM_NATIVE_TYPE, REG_SZ, NULL, true, 0, native_set_type, native_get_type },
855 { NULL, NULL, NULL, NULL, NULL }