/* Returns: NSSM_HOOK_STATUS_SUCCESS if the hook ran successfully. NSSM_HOOK_STATUS_NOTFOUND if no hook was found. NSSM_HOOK_STATUS_ABORT if the hook failed and we should cancel service start. NSSM_HOOK_STATUS_ERROR on error. NSSM_HOOK_STATUS_NOTRUN if the hook didn't run. NSSM_HOOK_STATUS_TIMEOUT if the hook timed out. NSSM_HOOK_STATUS_FAILED if the hook failed. */ int nssm_hook(hook_thread_t *hook_threads, nssm_service_t *service, TCHAR *hook_event, TCHAR *hook_action, unsigned long *hook_control, unsigned long deadline, bool async) { int ret = 0; hook_t *hook = (hook_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(hook_t)); if (! hook) { log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("hook"), _T("nssm_hook()"), 0); return NSSM_HOOK_STATUS_ERROR; } FILETIME now; GetSystemTimeAsFileTime(&now); EnterCriticalSection(&service->hook_section); /* Set the environment. */ if (service->env) duplicate_environment(service->env); if (service->env_extra) set_environment_block(service->env_extra); /* ABI version. */ TCHAR number[16]; _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), NSSM_HOOK_VERSION); SetEnvironmentVariable(NSSM_HOOK_ENV_VERSION, number); /* Event triggering this action. */ SetEnvironmentVariable(NSSM_HOOK_ENV_EVENT, hook_event); /* Hook action. */ SetEnvironmentVariable(NSSM_HOOK_ENV_ACTION, hook_action); /* Control triggering this action. May be empty. */ if (hook_control) SetEnvironmentVariable(NSSM_HOOK_ENV_TRIGGER, service_control_text(*hook_control)); else SetEnvironmentVariable(NSSM_HOOK_ENV_TRIGGER, _T("")); /* Last control handled. */ SetEnvironmentVariable(NSSM_HOOK_ENV_LAST_CONTROL, service_control_text(service->last_control)); /* Path to NSSM. */ TCHAR path[PATH_LENGTH]; GetModuleFileName(0, path, _countof(path)); SetEnvironmentVariable(NSSM_HOOK_ENV_IMAGE_PATH, path); /* NSSM version. */ SetEnvironmentVariable(NSSM_HOOK_ENV_NSSM_CONFIGURATION, NSSM_CONFIGURATION); SetEnvironmentVariable(NSSM_HOOK_ENV_NSSM_VERSION, NSSM_VERSION); SetEnvironmentVariable(NSSM_HOOK_ENV_BUILD_DATE, NSSM_DATE); /* NSSM PID. */ _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), GetCurrentProcessId()); SetEnvironmentVariable(NSSM_HOOK_ENV_PID, number); /* NSSM runtime. */ set_hook_runtime(NSSM_HOOK_ENV_RUNTIME, &service->nssm_creation_time, &now); /* Application PID. */ if (service->pid) { _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), service->pid); SetEnvironmentVariable(NSSM_HOOK_ENV_APPLICATION_PID, number); /* Application runtime. */ set_hook_runtime(NSSM_HOOK_ENV_APPLICATION_RUNTIME, &service->creation_time, &now); /* Exit code. */ SetEnvironmentVariable(NSSM_HOOK_ENV_EXITCODE, _T("")); } else { SetEnvironmentVariable(NSSM_HOOK_ENV_APPLICATION_PID, _T("")); if (str_equiv(hook_event, NSSM_HOOK_EVENT_START) && str_equiv(hook_action, NSSM_HOOK_ACTION_PRE)) { SetEnvironmentVariable(NSSM_HOOK_ENV_APPLICATION_RUNTIME, _T("")); SetEnvironmentVariable(NSSM_HOOK_ENV_EXITCODE, _T("")); } else { set_hook_runtime(NSSM_HOOK_ENV_APPLICATION_RUNTIME, &service->creation_time, &service->exit_time); /* Exit code. */ _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), service->exitcode); SetEnvironmentVariable(NSSM_HOOK_ENV_EXITCODE, number); } } /* Deadline for this script. */ _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), deadline); SetEnvironmentVariable(NSSM_HOOK_ENV_DEADLINE, number); /* Service name. */ SetEnvironmentVariable(NSSM_HOOK_ENV_SERVICE_NAME, service->name); SetEnvironmentVariable(NSSM_HOOK_ENV_SERVICE_DISPLAYNAME, service->displayname); /* Times the service was asked to start. */ _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), service->start_requested_count); SetEnvironmentVariable(NSSM_HOOK_ENV_START_REQUESTED_COUNT, number); /* Times the service actually did start. */ _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), service->start_count); SetEnvironmentVariable(NSSM_HOOK_ENV_START_COUNT, number); /* Times the service exited. */ _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), service->exit_count); SetEnvironmentVariable(NSSM_HOOK_ENV_EXIT_COUNT, number); /* Throttled count. */ _sntprintf_s(number, _countof(number), _TRUNCATE, _T("%lu"), service->throttle); SetEnvironmentVariable(NSSM_HOOK_ENV_THROTTLE_COUNT, number); /* Command line. */ TCHAR app[CMD_LENGTH]; _sntprintf_s(app, _countof(app), _TRUNCATE, _T("\"%s\" %s"), service->exe, service->flags); SetEnvironmentVariable(NSSM_HOOK_ENV_COMMAND_LINE, app); TCHAR cmd[CMD_LENGTH]; if (get_hook(service->name, hook_event, hook_action, cmd, sizeof(cmd))) { log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_HOOK_FAILED, hook_event, hook_action, service->name, 0); duplicate_environment_strings(service->initial_env); LeaveCriticalSection(&service->hook_section); HeapFree(GetProcessHeap(), 0, hook); return NSSM_HOOK_STATUS_ERROR; } /* No hook. */ if (! _tcslen(cmd)) { duplicate_environment_strings(service->initial_env); LeaveCriticalSection(&service->hook_section); HeapFree(GetProcessHeap(), 0, hook); return NSSM_HOOK_STATUS_NOTFOUND; } /* Run the command. */ STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); unsigned long flags = 0; #ifdef UNICODE flags |= CREATE_UNICODE_ENVIRONMENT; #endif ret = NSSM_HOOK_STATUS_NOTRUN; if (CreateProcess(0, cmd, 0, 0, false, flags, 0, service->dir, &si, &pi)) { hook->name = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, HOOK_NAME_LENGTH * sizeof(TCHAR)); if (hook->name) _sntprintf_s(hook->name, HOOK_NAME_LENGTH, _TRUNCATE, _T("%s (%s/%s)"), service->name, hook_event, hook_action); hook->process_handle = pi.hProcess; hook->pid = pi.dwProcessId; hook->deadline = deadline; if (get_process_creation_time(hook->process_handle, &hook->creation_time)) GetSystemTimeAsFileTime(&hook->creation_time); unsigned long tid; HANDLE thread_handle = CreateThread(NULL, 0, await_hook, (void *) hook, 0, &tid); if (thread_handle) { if (async) { ret = 0; await_hook_threads(hook_threads, service->status_handle, &service->status, 0); add_thread_handle(hook_threads, thread_handle, hook->name); } else { await_single_handle(service->status_handle, &service->status, thread_handle, hook->name, _T(__FUNCTION__), deadline + NSSM_SERVICE_STATUS_DEADLINE); unsigned long exitcode; GetExitCodeThread(thread_handle, &exitcode); ret = (int) exitcode; CloseHandle(thread_handle); } } else { log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0); await_hook(hook); if (hook->name) HeapFree(GetProcessHeap(), 0, hook->name); HeapFree(GetProcessHeap(), 0, hook); } } else { log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_HOOK_CREATEPROCESS_FAILED, hook_event, hook_action, service->name, cmd, error_string(GetLastError()), 0); HeapFree(GetProcessHeap(), 0, hook); } /* Restore our environment. */ duplicate_environment_strings(service->initial_env); LeaveCriticalSection(&service->hook_section); return ret; }
/* Callback function, called when a new device has been inserted. */ static void device_added(LibHalContext *context, const char *did) { const char *dudi, *fstype; char *dev, *mountp, *mountable, *label, *locked_reason; LibHalVolume *volume; LibHalDrive *drive; struct device_t *device; if (libhal_device_property_exists(context, did, "info.locked", (DBusError *)NULL) && libhal_device_get_property_bool(context, did, "info.locked", (DBusError *)NULL)) { if (debug_mode_flag) { locked_reason = libhal_device_get_property_string( context, did, "info.locked.reason", (DBusError *)NULL); if (locked_reason) { if (debug_mode_flag) printf("%s%d: %s\n", __FILE__, __LINE__, locked_reason); libhal_free_string(locked_reason); } } return; } if (!libhal_device_query_capability(context, did, "volume", (DBusError *)NULL)) return; label = libhal_device_get_property_string(context, did, "volume.label", (DBusError *)NULL); if (!(mountable = libhal_device_get_property_string( context, did, "volume.fsusage", (DBusError *)NULL)) || strcmp(mountable, "filesystem")) goto out; if (!(volume = libhal_volume_from_udi(context, did))) goto out; if (!(dudi = libhal_volume_get_storage_device_udi(volume))) goto out; if (!(drive = libhal_drive_from_udi(context, dudi))) goto out; if (!libhal_drive_is_hotpluggable(drive) && !libhal_drive_uses_removable_media(drive)) goto out; if (!(fstype = libhal_volume_get_fstype(volume))) goto out; if (!(dev = libhal_device_get_property_string(context, did, "block.device", (DBusError *)NULL))) goto out; mountp = get_mount_point(dev, label); if (!mountp) goto out; device = get_device(mountp, did, dev, label, fstype, volume, drive); if(!is_mounted(device)) { free_device(device); goto out; } if (!device) goto out; consider_fstab(device); device->hook = malloc(2*sizeof(char*)); if(!file_exists(HOOK_PATH)) { device->hook[0] = get_hook(device, "mount"); device->hook[1] = get_hook(device, "umount"); } else { device->hook[0] = NULL; device->hook[1] = NULL; } if (file_exists(device->mountp) < 0) mkdir(device->mountp, 0750); do_mount(device) < 0 ? free_device(device) : add_to_device_list(device); if (device) { if (!add_fstab_entry(device)) device->should_remove_entry = 1; if (debug_mode_flag) debug_dump_device(device); } if (device->hook[0]) run_hook(0, device); out: if (mountable) libhal_free_string(mountable); if (label) libhal_free_string(label); }