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 (set_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 = true;
531 TCHAR *username = NSSM_LOCALSYSTEM_ACCOUNT;
534 if (! str_equiv(additional, NSSM_LOCALSYSTEM_ACCOUNT)) {
536 username = (TCHAR *) additional;
537 if (value && value->string) password = value->string;
539 /* We need a password if the account is not LOCALSYSTEM. */
540 print_message(stderr, NSSM_MESSAGE_MISSING_PASSWORD, name);
547 ChangeServiceConfig() will fail to set the username if the service is set
548 to interact with the desktop.
550 unsigned long type = SERVICE_NO_CHANGE;
552 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
554 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
558 type = qsc->dwServiceType & ~SERVICE_INTERACTIVE_PROCESS;
559 HeapFree(GetProcessHeap(), 0, qsc);
562 if (grant_logon_as_service(username)) {
563 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
564 print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);
568 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, username, password, 0)) {
569 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
570 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
573 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
575 if (localsystem) return 0;
580 int native_get_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
581 SC_HANDLE service_handle = (SC_HANDLE) param;
582 if (! service_handle) return -1;
584 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
585 if (! qsc) return -1;
587 int ret = value_from_string(name, value, qsc->lpServiceStartName);
588 HeapFree(GetProcessHeap(), 0, qsc);
593 int native_set_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
594 SC_HANDLE service_handle = (SC_HANDLE) param;
595 if (! service_handle) return -1;
597 /* It makes no sense to try to reset the startup type. */
598 if (! value || ! value->string) {
599 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
603 /* Map NSSM_STARTUP_* constant to Windows SERVICE_*_START constant. */
604 int service_startup = -1;
606 for (i = 0; startup_strings[i]; i++) {
607 if (str_equiv(value->string, startup_strings[i])) {
613 if (service_startup < 0) {
614 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_STARTUP, value->string);
615 for (i = 0; startup_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), startup_strings[i]);
619 unsigned long startup;
620 switch (service_startup) {
621 case NSSM_STARTUP_MANUAL: startup = SERVICE_DEMAND_START; break;
622 case NSSM_STARTUP_DISABLED: startup = SERVICE_DISABLED; break;
623 default: startup = SERVICE_AUTO_START;
626 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
627 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
631 SERVICE_DELAYED_AUTO_START_INFO delayed;
632 ZeroMemory(&delayed, sizeof(delayed));
633 if (service_startup == NSSM_STARTUP_DELAYED) delayed.fDelayedAutostart = 1;
634 else delayed.fDelayedAutostart = 0;
635 if (! ChangeServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) {
636 unsigned long error = GetLastError();
637 /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */
638 if (error != ERROR_INVALID_LEVEL) {
639 log_event(EVENTLOG_ERROR_TYPE, NSSM_MESSAGE_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service_name, error_string(error), 0);
646 int native_get_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
647 SC_HANDLE service_handle = (SC_HANDLE) param;
648 if (! service_handle) return -1;
650 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
651 if (! qsc) return -1;
653 unsigned long startup;
654 int ret = get_service_startup(service_name, service_handle, qsc, &startup);
655 HeapFree(GetProcessHeap(), 0, qsc);
660 for (i = 0; startup_strings[i]; i++);
661 if (startup >= i) return -1;
663 return value_from_string(name, value, startup_strings[startup]);
666 int native_set_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
667 SC_HANDLE service_handle = (SC_HANDLE) param;
668 if (! service_handle) return -1;
670 /* It makes no sense to try to reset the service type. */
671 if (! value || ! value->string) {
672 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
677 We can only manage services of type SERVICE_WIN32_OWN_PROCESS
678 and SERVICE_INTERACTIVE_PROCESS.
680 unsigned long type = SERVICE_WIN32_OWN_PROCESS;
681 if (str_equiv(value->string, NSSM_INTERACTIVE_PROCESS)) type |= SERVICE_INTERACTIVE_PROCESS;
682 else if (! str_equiv(value->string, NSSM_WIN32_OWN_PROCESS)) {
683 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_TYPE, value->string);
684 _ftprintf(stderr, _T("%s\n"), NSSM_WIN32_OWN_PROCESS);
685 _ftprintf(stderr, _T("%s\n"), NSSM_INTERACTIVE_PROCESS);
690 ChangeServiceConfig() will fail if the service runs under an account
691 other than LOCALSYSTEM and we try to make it interactive.
693 if (type & SERVICE_INTERACTIVE_PROCESS) {
694 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
695 if (! qsc) return -1;
697 if (! str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) {
698 HeapFree(GetProcessHeap(), 0, qsc);
699 print_message(stderr, NSSM_MESSAGE_INTERACTIVE_NOT_LOCALSYSTEM, value->string, service_name, NSSM_LOCALSYSTEM_ACCOUNT);
703 HeapFree(GetProcessHeap(), 0, qsc);
706 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
707 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
714 int native_get_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
715 SC_HANDLE service_handle = (SC_HANDLE) param;
716 if (! service_handle) return -1;
718 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
719 if (! qsc) return -1;
721 value->numeric = qsc->dwServiceType;
722 HeapFree(GetProcessHeap(), 0, qsc);
725 switch (value->numeric) {
726 case SERVICE_KERNEL_DRIVER: string = NSSM_KERNEL_DRIVER; break;
727 case SERVICE_FILE_SYSTEM_DRIVER: string = NSSM_FILE_SYSTEM_DRIVER; break;
728 case SERVICE_WIN32_OWN_PROCESS: string = NSSM_WIN32_OWN_PROCESS; break;
729 case SERVICE_WIN32_SHARE_PROCESS: string = NSSM_WIN32_SHARE_PROCESS; break;
730 case SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_INTERACTIVE_PROCESS; break;
731 case SERVICE_WIN32_SHARE_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_SHARE_INTERACTIVE_PROCESS; break;
732 default: string = NSSM_UNKNOWN;
735 return value_from_string(name, value, string);
738 int set_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
739 if (! key) return -1;
742 if (setting->set) ret = setting->set(service_name, (void *) key, setting->name, setting->default_value, value, additional);
745 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
746 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
747 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
752 int set_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
753 if (! service_handle) return -1;
756 if (setting->set) ret = setting->set(service_name, service_handle, setting->name, setting->default_value, value, additional);
759 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
760 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
761 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
767 Returns: 1 if the value was retrieved.
768 0 if the default value was retrieved.
771 int get_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
772 if (! key) return -1;
775 switch (setting->type) {
779 value->string = (TCHAR *) setting->default_value;
780 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
785 value->numeric = (unsigned long) setting->default_value;
786 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
795 if (ret < 0) print_message(stderr, NSSM_MESSAGE_GET_SETTING_FAILED, setting->name, service_name);
800 int get_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
801 if (! service_handle) return -1;
802 return setting->get(service_name, service_handle, setting->name, 0, value, additional);
805 settings_t settings[] = {
806 { NSSM_REG_EXE, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
807 { NSSM_REG_FLAGS, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
808 { NSSM_REG_DIR, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
809 { NSSM_REG_EXIT, REG_SZ, (void *) exit_action_strings[NSSM_EXIT_RESTART], false, ADDITIONAL_MANDATORY, setting_set_exit_action, setting_get_exit_action },
810 { NSSM_REG_AFFINITY, REG_SZ, 0, false, 0, setting_set_affinity, setting_get_affinity },
811 { NSSM_REG_ENV, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
812 { NSSM_REG_ENV_EXTRA, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
813 { NSSM_REG_PRIORITY, REG_SZ, (void *) priority_strings[NSSM_NORMAL_PRIORITY], false, 0, setting_set_priority, setting_get_priority },
814 { NSSM_REG_RESTART_DELAY, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
815 { NSSM_REG_STDIN, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
816 { NSSM_REG_STDIN NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDIN_SHARING, false, 0, setting_set_number, setting_get_number },
817 { NSSM_REG_STDIN NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDIN_DISPOSITION, false, 0, setting_set_number, setting_get_number },
818 { NSSM_REG_STDIN NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDIN_FLAGS, false, 0, setting_set_number, setting_get_number },
819 { NSSM_REG_STDOUT, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
820 { NSSM_REG_STDOUT NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDOUT_SHARING, false, 0, setting_set_number, setting_get_number },
821 { NSSM_REG_STDOUT NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDOUT_DISPOSITION, false, 0, setting_set_number, setting_get_number },
822 { NSSM_REG_STDOUT NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDOUT_FLAGS, false, 0, setting_set_number, setting_get_number },
823 { NSSM_REG_STDERR, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
824 { NSSM_REG_STDERR NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDERR_SHARING, false, 0, setting_set_number, setting_get_number },
825 { NSSM_REG_STDERR NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDERR_DISPOSITION, false, 0, setting_set_number, setting_get_number },
826 { NSSM_REG_STDERR NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDERR_FLAGS, false, 0, setting_set_number, setting_get_number },
827 { NSSM_REG_STOP_METHOD_SKIP, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
828 { NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_CONSOLE_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
829 { NSSM_REG_KILL_WINDOW_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_WINDOW_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
830 { NSSM_REG_KILL_THREADS_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_THREADS_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
831 { NSSM_REG_THROTTLE, REG_DWORD, (void *) NSSM_RESET_THROTTLE_RESTART, false, 0, setting_set_number, setting_get_number },
832 { NSSM_REG_ROTATE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
833 { NSSM_REG_ROTATE_ONLINE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
834 { NSSM_REG_ROTATE_SECONDS, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
835 { NSSM_REG_ROTATE_BYTES_LOW, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
836 { NSSM_REG_ROTATE_BYTES_HIGH, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
837 { NSSM_NATIVE_DESCRIPTION, REG_SZ, _T(""), true, 0, native_set_description, native_get_description },
838 { NSSM_NATIVE_DISPLAYNAME, REG_SZ, NULL, true, 0, native_set_displayname, native_get_displayname },
839 { NSSM_NATIVE_IMAGEPATH, REG_EXPAND_SZ, NULL, true, 0, native_set_imagepath, native_get_imagepath },
840 { NSSM_NATIVE_OBJECTNAME, REG_SZ, NSSM_LOCALSYSTEM_ACCOUNT, true, ADDITIONAL_SETTING, native_set_objectname, native_get_objectname },
841 { NSSM_NATIVE_NAME, REG_SZ, NULL, true, 0, native_set_name, native_get_name },
842 { NSSM_NATIVE_STARTUP, REG_SZ, NULL, true, 0, native_set_startup, native_get_startup },
843 { NSSM_NATIVE_TYPE, REG_SZ, NULL, true, 0, native_set_type, native_get_type },
844 { NULL, NULL, NULL, NULL, NULL }