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;
535 username = (TCHAR *) additional;
536 if (value && value->string) password = value->string;
538 else if (value && value->string) username = value->string;
540 if (requires_password(username)) {
542 /* We need a password if the account requires it. */
543 print_message(stderr, NSSM_MESSAGE_MISSING_PASSWORD, name);
549 if (is_localsystem(username)) {
551 username = NSSM_LOCALSYSTEM_ACCOUNT;
554 canon = canonical_username(username);
555 if (canon) username = canon;
560 ChangeServiceConfig() will fail to set the username if the service is set
561 to interact with the desktop.
563 unsigned long type = SERVICE_NO_CHANGE;
565 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
567 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
568 if (canon) LocalFree(canon);
572 type = qsc->dwServiceType & ~SERVICE_INTERACTIVE_PROCESS;
573 HeapFree(GetProcessHeap(), 0, qsc);
577 if (grant_logon_as_service(username)) {
578 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
579 if (canon) LocalFree(canon);
580 print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);
585 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, username, password, 0)) {
586 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
587 if (canon) LocalFree(canon);
588 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
591 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
593 if (canon) LocalFree(canon);
594 if (localsystem) return 0;
599 int native_get_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
600 SC_HANDLE service_handle = (SC_HANDLE) param;
601 if (! service_handle) return -1;
603 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
604 if (! qsc) return -1;
606 int ret = value_from_string(name, value, qsc->lpServiceStartName);
607 HeapFree(GetProcessHeap(), 0, qsc);
612 int native_set_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
613 SC_HANDLE service_handle = (SC_HANDLE) param;
614 if (! service_handle) return -1;
616 /* It makes no sense to try to reset the startup type. */
617 if (! value || ! value->string) {
618 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
622 /* Map NSSM_STARTUP_* constant to Windows SERVICE_*_START constant. */
623 int service_startup = -1;
625 for (i = 0; startup_strings[i]; i++) {
626 if (str_equiv(value->string, startup_strings[i])) {
632 if (service_startup < 0) {
633 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_STARTUP, value->string);
634 for (i = 0; startup_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), startup_strings[i]);
638 unsigned long startup;
639 switch (service_startup) {
640 case NSSM_STARTUP_MANUAL: startup = SERVICE_DEMAND_START; break;
641 case NSSM_STARTUP_DISABLED: startup = SERVICE_DISABLED; break;
642 default: startup = SERVICE_AUTO_START;
645 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
646 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
650 SERVICE_DELAYED_AUTO_START_INFO delayed;
651 ZeroMemory(&delayed, sizeof(delayed));
652 if (service_startup == NSSM_STARTUP_DELAYED) delayed.fDelayedAutostart = 1;
653 else delayed.fDelayedAutostart = 0;
654 if (! ChangeServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) {
655 unsigned long error = GetLastError();
656 /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */
657 if (error != ERROR_INVALID_LEVEL) {
658 log_event(EVENTLOG_ERROR_TYPE, NSSM_MESSAGE_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service_name, error_string(error), 0);
665 int native_get_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
666 SC_HANDLE service_handle = (SC_HANDLE) param;
667 if (! service_handle) return -1;
669 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
670 if (! qsc) return -1;
672 unsigned long startup;
673 int ret = get_service_startup(service_name, service_handle, qsc, &startup);
674 HeapFree(GetProcessHeap(), 0, qsc);
679 for (i = 0; startup_strings[i]; i++);
680 if (startup >= i) return -1;
682 return value_from_string(name, value, startup_strings[startup]);
685 int native_set_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
686 SC_HANDLE service_handle = (SC_HANDLE) param;
687 if (! service_handle) return -1;
689 /* It makes no sense to try to reset the service type. */
690 if (! value || ! value->string) {
691 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
696 We can only manage services of type SERVICE_WIN32_OWN_PROCESS
697 and SERVICE_INTERACTIVE_PROCESS.
699 unsigned long type = SERVICE_WIN32_OWN_PROCESS;
700 if (str_equiv(value->string, NSSM_INTERACTIVE_PROCESS)) type |= SERVICE_INTERACTIVE_PROCESS;
701 else if (! str_equiv(value->string, NSSM_WIN32_OWN_PROCESS)) {
702 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_TYPE, value->string);
703 _ftprintf(stderr, _T("%s\n"), NSSM_WIN32_OWN_PROCESS);
704 _ftprintf(stderr, _T("%s\n"), NSSM_INTERACTIVE_PROCESS);
709 ChangeServiceConfig() will fail if the service runs under an account
710 other than LOCALSYSTEM and we try to make it interactive.
712 if (type & SERVICE_INTERACTIVE_PROCESS) {
713 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
714 if (! qsc) return -1;
716 if (! str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) {
717 HeapFree(GetProcessHeap(), 0, qsc);
718 print_message(stderr, NSSM_MESSAGE_INTERACTIVE_NOT_LOCALSYSTEM, value->string, service_name, NSSM_LOCALSYSTEM_ACCOUNT);
722 HeapFree(GetProcessHeap(), 0, qsc);
725 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
726 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
733 int native_get_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
734 SC_HANDLE service_handle = (SC_HANDLE) param;
735 if (! service_handle) return -1;
737 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
738 if (! qsc) return -1;
740 value->numeric = qsc->dwServiceType;
741 HeapFree(GetProcessHeap(), 0, qsc);
744 switch (value->numeric) {
745 case SERVICE_KERNEL_DRIVER: string = NSSM_KERNEL_DRIVER; break;
746 case SERVICE_FILE_SYSTEM_DRIVER: string = NSSM_FILE_SYSTEM_DRIVER; break;
747 case SERVICE_WIN32_OWN_PROCESS: string = NSSM_WIN32_OWN_PROCESS; break;
748 case SERVICE_WIN32_SHARE_PROCESS: string = NSSM_WIN32_SHARE_PROCESS; break;
749 case SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_INTERACTIVE_PROCESS; break;
750 case SERVICE_WIN32_SHARE_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_SHARE_INTERACTIVE_PROCESS; break;
751 default: string = NSSM_UNKNOWN;
754 return value_from_string(name, value, string);
757 int set_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
758 if (! key) return -1;
761 if (setting->set) ret = setting->set(service_name, (void *) key, setting->name, setting->default_value, value, additional);
764 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
765 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
766 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
771 int set_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
772 if (! service_handle) return -1;
775 if (setting->set) ret = setting->set(service_name, service_handle, setting->name, setting->default_value, value, additional);
778 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
779 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
780 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
786 Returns: 1 if the value was retrieved.
787 0 if the default value was retrieved.
790 int get_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
791 if (! key) return -1;
794 switch (setting->type) {
798 value->string = (TCHAR *) setting->default_value;
799 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
804 value->numeric = (unsigned long) setting->default_value;
805 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
814 if (ret < 0) print_message(stderr, NSSM_MESSAGE_GET_SETTING_FAILED, setting->name, service_name);
819 int get_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
820 if (! service_handle) return -1;
821 return setting->get(service_name, service_handle, setting->name, 0, value, additional);
824 settings_t settings[] = {
825 { NSSM_REG_EXE, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
826 { NSSM_REG_FLAGS, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
827 { NSSM_REG_DIR, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
828 { NSSM_REG_EXIT, REG_SZ, (void *) exit_action_strings[NSSM_EXIT_RESTART], false, ADDITIONAL_MANDATORY, setting_set_exit_action, setting_get_exit_action },
829 { NSSM_REG_AFFINITY, REG_SZ, 0, false, 0, setting_set_affinity, setting_get_affinity },
830 { NSSM_REG_ENV, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
831 { NSSM_REG_ENV_EXTRA, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
832 { NSSM_REG_NO_CONSOLE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
833 { NSSM_REG_PRIORITY, REG_SZ, (void *) priority_strings[NSSM_NORMAL_PRIORITY], false, 0, setting_set_priority, setting_get_priority },
834 { NSSM_REG_RESTART_DELAY, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
835 { NSSM_REG_STDIN, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
836 { NSSM_REG_STDIN NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDIN_SHARING, false, 0, setting_set_number, setting_get_number },
837 { NSSM_REG_STDIN NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDIN_DISPOSITION, false, 0, setting_set_number, setting_get_number },
838 { NSSM_REG_STDIN NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDIN_FLAGS, false, 0, setting_set_number, setting_get_number },
839 { NSSM_REG_STDOUT, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
840 { NSSM_REG_STDOUT NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDOUT_SHARING, false, 0, setting_set_number, setting_get_number },
841 { NSSM_REG_STDOUT NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDOUT_DISPOSITION, false, 0, setting_set_number, setting_get_number },
842 { NSSM_REG_STDOUT NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDOUT_FLAGS, false, 0, setting_set_number, setting_get_number },
843 { NSSM_REG_STDERR, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
844 { NSSM_REG_STDERR NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDERR_SHARING, false, 0, setting_set_number, setting_get_number },
845 { NSSM_REG_STDERR NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDERR_DISPOSITION, false, 0, setting_set_number, setting_get_number },
846 { NSSM_REG_STDERR NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDERR_FLAGS, false, 0, setting_set_number, setting_get_number },
847 { NSSM_REG_STOP_METHOD_SKIP, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
848 { NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_CONSOLE_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
849 { NSSM_REG_KILL_WINDOW_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_WINDOW_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
850 { NSSM_REG_KILL_THREADS_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_THREADS_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
851 { NSSM_REG_THROTTLE, REG_DWORD, (void *) NSSM_RESET_THROTTLE_RESTART, false, 0, setting_set_number, setting_get_number },
852 { NSSM_REG_ROTATE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
853 { NSSM_REG_ROTATE_ONLINE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
854 { NSSM_REG_ROTATE_SECONDS, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
855 { NSSM_REG_ROTATE_BYTES_LOW, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
856 { NSSM_REG_ROTATE_BYTES_HIGH, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
857 { NSSM_NATIVE_DESCRIPTION, REG_SZ, _T(""), true, 0, native_set_description, native_get_description },
858 { NSSM_NATIVE_DISPLAYNAME, REG_SZ, NULL, true, 0, native_set_displayname, native_get_displayname },
859 { NSSM_NATIVE_IMAGEPATH, REG_EXPAND_SZ, NULL, true, 0, native_set_imagepath, native_get_imagepath },
860 { NSSM_NATIVE_OBJECTNAME, REG_SZ, NSSM_LOCALSYSTEM_ACCOUNT, true, 0, native_set_objectname, native_get_objectname },
861 { NSSM_NATIVE_NAME, REG_SZ, NULL, true, 0, native_set_name, native_get_name },
862 { NSSM_NATIVE_STARTUP, REG_SZ, NULL, true, 0, native_set_startup, native_get_startup },
863 { NSSM_NATIVE_TYPE, REG_SZ, NULL, true, 0, native_set_type, native_get_type },
864 { NULL, NULL, NULL, NULL, NULL }