/* * Copyright (c) Likewise Software. All rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General * Public License along with this program. If not, see * . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Module Name: * * main.c * * Abstract: * * Client utility program * * Authors: Brian Koropoff (bkoropoff@likewise.com) * */ #include "includes.h" static struct { BOOLEAN bQuiet; } gState = { .bQuiet = FALSE }; static PCSTR LwSmStateToString( LW_SERVICE_STATE state ) { switch (state) { case LW_SERVICE_STATE_STOPPED: return "stopped"; case LW_SERVICE_STATE_STARTING: return "starting"; case LW_SERVICE_STATE_RUNNING: return "running"; case LW_SERVICE_STATE_STOPPING: return "stopping"; case LW_SERVICE_STATE_PAUSED: return "paused"; case LW_SERVICE_STATE_DEAD: return "dead"; default: return "unknown"; } } static PCSTR LwSmHomeToString( LW_SERVICE_HOME home ) { switch (home) { case LW_SERVICE_HOME_STANDALONE: return "standalone"; case LW_SERVICE_HOME_CONTAINER: return "container"; case LW_SERVICE_HOME_IO_MANAGER: return "io"; case LW_SERVICE_HOME_SERVICE_MANAGER: return "sm"; default: return "unknown"; } } static PCSTR LwSmTypeToString( LW_SERVICE_TYPE type ) { switch (type) { case LW_SERVICE_TYPE_LEGACY_EXECUTABLE: return "legacy executable"; case LW_SERVICE_TYPE_EXECUTABLE: return "executable"; case LW_SERVICE_TYPE_MODULE: return "module"; case LW_SERVICE_TYPE_DRIVER: return "driver"; case LW_SERVICE_TYPE_STUB: return "stub"; default: return "unknown"; } } static PCSTR LwSmLogLevelToString( LW_SM_LOG_LEVEL level ) { switch (level) { case LW_SM_LOG_LEVEL_ALWAYS: return "ALWAYS"; case LW_SM_LOG_LEVEL_ERROR: return "ERROR"; case LW_SM_LOG_LEVEL_WARNING: return "WARNING"; case LW_SM_LOG_LEVEL_INFO: return "INFO"; case LW_SM_LOG_LEVEL_VERBOSE: return "VERBOSE"; case LW_SM_LOG_LEVEL_DEBUG: return "DEBUG"; case LW_SM_LOG_LEVEL_TRACE: return "TRACE"; default: return "UNKNOWN"; } } static DWORD LwSmLogLevelNameToLogLevel( PCSTR pszName, PLW_SM_LOG_LEVEL pLevel ) { DWORD dwError = 0; if (!strcasecmp(pszName, "always")) { *pLevel = LW_SM_LOG_LEVEL_ALWAYS; } else if (!strcasecmp(pszName, "error")) { *pLevel = LW_SM_LOG_LEVEL_ERROR; } else if (!strcasecmp(pszName, "warning")) { *pLevel = LW_SM_LOG_LEVEL_WARNING; } else if (!strcasecmp(pszName, "info")) { *pLevel = LW_SM_LOG_LEVEL_INFO; } else if (!strcasecmp(pszName, "verbose")) { *pLevel = LW_SM_LOG_LEVEL_VERBOSE; } else if (!strcasecmp(pszName, "debug")) { *pLevel = LW_SM_LOG_LEVEL_DEBUG; } else if (!strcasecmp(pszName, "trace")) { *pLevel = LW_SM_LOG_LEVEL_TRACE; } else { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } error: return dwError; } static VOID LwSmHandleSigint( int sig ) { raise(SIGTERM); } static DWORD LwSmConfigureSignals( VOID ) { DWORD dwError = 0; sigset_t set; static int blockSignals[] = { SIGTERM, SIGCHLD, SIGHUP, -1 }; int i = 0; struct sigaction intAction; memset(&intAction, 0, sizeof(intAction)); if (sigemptyset(&set) < 0) { dwError = LwMapErrnoToLwError(errno); BAIL_ON_ERROR(dwError); } for (i = 0; blockSignals[i] != -1; i++) { if (sigaddset(&set, blockSignals[i]) < 0) { dwError = LwMapErrnoToLwError(errno); BAIL_ON_ERROR(dwError); } } dwError = LwMapErrnoToLwError(pthread_sigmask(SIG_SETMASK, &set, NULL)); BAIL_ON_ERROR(dwError); intAction.sa_handler = LwSmHandleSigint; intAction.sa_flags = 0; if (sigaction(SIGINT, &intAction, NULL) < 0) { dwError = LwMapErrnoToLwError(errno); BAIL_ON_ERROR(dwError); } cleanup: return dwError; error: goto cleanup; } static DWORD LwSmWaitSignals( int* pSig ) { DWORD dwError = 0; sigset_t set; static int waitSignals[] = { SIGTERM, SIGHUP, -1 }; int sig = -1; int i = 0; if (sigemptyset(&set) < 0) { dwError = LwMapErrnoToLwError(errno); BAIL_ON_ERROR(dwError); } for (i = 0; waitSignals[i] != -1; i++) { if (sigaddset(&set, waitSignals[i]) < 0) { dwError = LwMapErrnoToLwError(errno); BAIL_ON_ERROR(dwError); } } for (;;) { if (sigwait(&set, &sig) < 0) { dwError = LwMapErrnoToLwError(errno); BAIL_ON_ERROR(dwError); } switch (sig) { case SIGTERM: case SIGHUP: *pSig = sig; goto cleanup; default: break; } } cleanup: return dwError; error: goto cleanup; }; static DWORD LwSmWaitForLwsmd( void ) { DWORD dwError = 0; int try = 0; static const int maxTries = 4; static const int interval = 5; PWSTR* ppwszServices = NULL; do { dwError = LwSmEnumerateServices(&ppwszServices); if (dwError) { sleep(interval); } try++; } while (dwError != LW_ERROR_SUCCESS && try < maxTries); BAIL_ON_ERROR(dwError); cleanup: if (ppwszServices) { LwSmFreeServiceNameList(ppwszServices); } return dwError; error: goto cleanup; } static DWORD LwSmList( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR* ppwszServiceNames = NULL; PSTR pszServiceName = NULL; LW_SERVICE_STATUS status; LW_SERVICE_HANDLE hHandle = NULL; size_t i = 0; size_t len = 0; size_t maxLen = 0; dwError = LwSmEnumerateServices(&ppwszServiceNames); BAIL_ON_ERROR(dwError); for (i = 0; ppwszServiceNames[i]; i++) { dwError = LwWc16sLen(ppwszServiceNames[i], &len); BAIL_ON_ERROR(dwError); if (len > maxLen) { maxLen = len; } } for (i = 0; ppwszServiceNames[i]; i++) { dwError = LwSmAcquireServiceHandle(ppwszServiceNames[i], &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceStatus(hHandle, &status); BAIL_ON_ERROR(dwError); dwError = LwWc16sToMbs(ppwszServiceNames[i], &pszServiceName); BAIL_ON_ERROR(dwError); if (!gState.bQuiet) { printf("%s", pszServiceName); dwError = LwWc16sLen(ppwszServiceNames[i], &len); BAIL_ON_ERROR(dwError); for (; len < maxLen; len++) { printf(" "); } printf(" "); switch (status.state) { case LW_SERVICE_STATE_RUNNING: BAIL_ON_ERROR(dwError); printf("%s (%s: %li)\n", LwSmStateToString(status.state), LwSmHomeToString(status.home), (long) status.pid); break; default: printf("%s\n", LwSmStateToString(status.state)); break; } } dwError = LwSmReleaseServiceHandle(hHandle); hHandle = NULL; BAIL_ON_ERROR(dwError); LW_SAFE_FREE_MEMORY(pszServiceName); } cleanup: LW_SAFE_FREE_MEMORY(pszServiceName); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } if (ppwszServiceNames) { LwSmFreeServiceNameList(ppwszServiceNames); } return dwError; error: goto cleanup; } static DWORD LwSmStartOnly( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); if (!gState.bQuiet) { printf("Starting service: %s\n", pArgv[1]); } dwError = LwSmStartService(hHandle); BAIL_ON_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } return dwError; error: goto cleanup; } static DWORD LwSmStart( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; LW_SERVICE_HANDLE hDepHandle = NULL; LW_SERVICE_STATUS status = {0}; PWSTR* ppwszDependencies = NULL; PSTR pszTemp = NULL; size_t i = 0; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceDependencyClosure(hHandle, &ppwszDependencies); BAIL_ON_ERROR(dwError); for (i = 0; ppwszDependencies[i]; i++) { dwError = LwSmAcquireServiceHandle(ppwszDependencies[i], &hDepHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceStatus(hDepHandle, &status); BAIL_ON_ERROR(dwError); if (status.state != LW_SERVICE_STATE_RUNNING) { if (!gState.bQuiet) { dwError = LwWc16sToMbs(ppwszDependencies[i], &pszTemp); BAIL_ON_ERROR(dwError); printf("Starting service dependency: %s\n", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); } dwError = LwSmStartService(hDepHandle); BAIL_ON_ERROR(dwError); } dwError = LwSmReleaseServiceHandle(hDepHandle); hDepHandle = NULL; BAIL_ON_ERROR(dwError); } if (!gState.bQuiet) { printf("Starting service: %s\n", pArgv[1]); } dwError = LwSmStartService(hHandle); BAIL_ON_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); LW_SAFE_FREE_MEMORY(pszTemp); if (ppwszDependencies) { LwSmFreeServiceNameList(ppwszDependencies); } if (hHandle) { LwSmReleaseServiceHandle(hHandle); } if (hDepHandle) { LwSmReleaseServiceHandle(hDepHandle); } return dwError; error: goto cleanup; } static DWORD LwSmStopOnly( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); if (!gState.bQuiet) { printf("Stopping service: %s\n", pArgv[1]); } dwError = LwSmStopService(hHandle); BAIL_ON_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } return dwError; error: goto cleanup; } static DWORD LwSmStop( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; LW_SERVICE_HANDLE hDepHandle = NULL; LW_SERVICE_STATUS status = {0}; PWSTR* ppwszDependencies = NULL; PSTR pszTemp = NULL; size_t i = 0; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceReverseDependencyClosure(hHandle, &ppwszDependencies); BAIL_ON_ERROR(dwError); for (i = 0; ppwszDependencies[i]; i++) { dwError = LwSmAcquireServiceHandle(ppwszDependencies[i], &hDepHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceStatus(hDepHandle, &status); BAIL_ON_ERROR(dwError); if (status.state != LW_SERVICE_STATE_STOPPED) { if (!gState.bQuiet) { dwError = LwWc16sToMbs(ppwszDependencies[i], &pszTemp); BAIL_ON_ERROR(dwError); printf("Stopping service reverse dependency: %s\n", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); } dwError = LwSmStopService(hDepHandle); BAIL_ON_ERROR(dwError); } dwError = LwSmReleaseServiceHandle(hDepHandle); hDepHandle = NULL; BAIL_ON_ERROR(dwError); } if (!gState.bQuiet) { printf("Stopping service: %s\n", pArgv[1]); } dwError = LwSmStopService(hHandle); BAIL_ON_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); LW_SAFE_FREE_MEMORY(pszTemp); if (ppwszDependencies) { LwSmFreeServiceNameList(ppwszDependencies); } if (hHandle) { LwSmReleaseServiceHandle(hHandle); } if (hDepHandle) { LwSmReleaseServiceHandle(hDepHandle); } return dwError; error: goto cleanup; } static DWORD LwSmRestart( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; PWSTR* ppwszReverseDeps = NULL; PLW_SERVICE_STATUS pStatus = NULL; PLW_SERVICE_HANDLE phDepHandles = NULL; PSTR pszTemp = NULL; size_t count = 0; size_t i = 0; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceReverseDependencyClosure(hHandle, &ppwszReverseDeps); BAIL_ON_ERROR(dwError); count = LwSmStringListLength(ppwszReverseDeps); dwError = LwAllocateMemory(sizeof(*pStatus) * count, OUT_PPVOID(&pStatus)); BAIL_ON_ERROR(dwError); dwError = LwAllocateMemory(sizeof(*phDepHandles) * count, OUT_PPVOID(&phDepHandles)); BAIL_ON_ERROR(dwError); for (i = 0; i < count; i++) { dwError = LwSmAcquireServiceHandle(ppwszReverseDeps[i], &phDepHandles[i]); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceStatus(phDepHandles[i], &pStatus[i]); BAIL_ON_ERROR(dwError); if (pStatus[i].state != LW_SERVICE_STATE_STOPPED) { if (!gState.bQuiet) { dwError = LwWc16sToMbs(ppwszReverseDeps[i], &pszTemp); BAIL_ON_ERROR(dwError); printf("Stopping service reverse dependency: %s\n", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); } dwError = LwSmStopService(phDepHandles[i]); BAIL_ON_ERROR(dwError); } } if (!gState.bQuiet) { printf("Stopping service: %s\n", pArgv[1]); } dwError = LwSmStopService(hHandle); BAIL_ON_ERROR(dwError); if (!gState.bQuiet) { printf("Starting service: %s\n", pArgv[1]); } dwError = LwSmStartService(hHandle); BAIL_ON_ERROR(dwError); for (i = 0; i < count; i++) { if (pStatus[count - 1 - i].state == LW_SERVICE_STATE_RUNNING) { if (!gState.bQuiet) { dwError = LwWc16sToMbs(ppwszReverseDeps[count - 1 - i], &pszTemp); BAIL_ON_ERROR(dwError); printf("Starting service reverse dependency: %s\n", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); } dwError = LwSmStartService(phDepHandles[count - 1 - i]); BAIL_ON_ERROR(dwError); } } cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); LW_SAFE_FREE_MEMORY(pStatus); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } if (phDepHandles) { for (i = 0; i < count; i++) { if (phDepHandles[i]) { LwSmReleaseServiceHandle(phDepHandles[i]); } } LW_SAFE_FREE_MEMORY(phDepHandles); } return dwError; error: goto cleanup; } static DWORD LwSmRefresh( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); if (!gState.bQuiet) { printf("Refreshing service: %s\n", pArgv[1]); } dwError = LwSmRefreshService(hHandle); BAIL_ON_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } return dwError; error: goto cleanup; } static DWORD LwSmInfo( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; PLW_SERVICE_INFO pInfo = NULL; PSTR pszTemp = NULL; size_t i = 0; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceInfo(hHandle, &pInfo); BAIL_ON_ERROR(dwError); printf("Service: %s\n", pArgv[1]); dwError = LwWc16sToMbs(pInfo->pwszDescription, &pszTemp); BAIL_ON_ERROR(dwError); printf("Description: %s\n", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); printf("Type: %s\n", LwSmTypeToString(pInfo->type)); printf("Autostart: %s\n", pInfo->bAutostart ? "yes" : "no"); dwError = LwWc16sToMbs(pInfo->pwszPath, &pszTemp); BAIL_ON_ERROR(dwError); printf("Path: %s\n", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); printf("Arguments:"); for (i = 0; pInfo->ppwszArgs[i]; i++) { dwError = LwWc16sToMbs(pInfo->ppwszArgs[i], &pszTemp); BAIL_ON_ERROR(dwError); printf(" '%s'", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); } printf("\n"); printf("Dependencies:"); for (i = 0; pInfo->ppwszDependencies[i]; i++) { dwError = LwWc16sToMbs(pInfo->ppwszDependencies[i], &pszTemp); BAIL_ON_ERROR(dwError); printf(" %s", pszTemp); LW_SAFE_FREE_MEMORY(pszTemp); } printf("\n"); cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); LW_SAFE_FREE_MEMORY(pszTemp); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } return dwError; error: goto cleanup; } static DWORD LwSmStatus( int argc, char** pArgv, int* pRet ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; LW_SERVICE_STATUS status = {0}; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceStatus(hHandle, &status); BAIL_ON_ERROR(dwError); if (!gState.bQuiet) { switch (status.state) { case LW_SERVICE_STATE_RUNNING: printf("%s (%s: %li)\n", LwSmStateToString(status.state), LwSmHomeToString(status.home), (long) status.pid); break; default: printf("%s\n", LwSmStateToString(status.state)); break; } } *pRet = status.state; cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } return dwError; error: goto cleanup; } static PVOID LwSmWaitThread( PVOID pData ) { DWORD dwError = 0; LW_SERVICE_HANDLE hHandle = pData; LW_SERVICE_STATUS status = {0}; while (status.state != LW_SERVICE_STATE_STOPPED && status.state != LW_SERVICE_STATE_DEAD) { dwError = LwSmWaitService(hHandle, status.state, &status.state); BAIL_ON_ERROR(dwError); } cleanup: kill(getpid(), SIGHUP); return NULL; error: goto cleanup; } static DWORD LwSmProxy( int argc, char** pArgv ) { DWORD dwError = 0; LW_SERVICE_HANDLE hHandle = NULL; PWSTR pwszServiceName = NULL; pthread_t waitThread; int sig = 0; dwError = LwSmWaitForLwsmd(); BAIL_ON_ERROR(dwError); dwError = LwSmConfigureSignals(); BAIL_ON_ERROR(dwError); dwError = LwSmStart(argc, pArgv); BAIL_ON_ERROR(dwError); dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwMapErrnoToLwError(pthread_create( &waitThread, NULL, LwSmWaitThread, hHandle)); BAIL_ON_ERROR(dwError); dwError = LwMapErrnoToLwError(pthread_detach(waitThread)); BAIL_ON_ERROR(dwError); if (!gState.bQuiet) { printf("Proxying for service: %s\n", pArgv[1]); } dwError = LwSmWaitSignals(&sig); BAIL_ON_ERROR(dwError); switch (sig) { case SIGTERM: dwError = LwSmStop(argc, pArgv); BAIL_ON_ERROR(dwError); break; default: break; } cleanup: LW_SAFE_FREE_MEMORY(pwszServiceName); if (hHandle) { LwSmReleaseServiceHandle(hHandle); } return dwError; error: goto cleanup; } static DWORD LwSmFindServiceWithPid( pid_t pid, PLW_SERVICE_HANDLE phHandle ) { DWORD dwError = 0; PWSTR* ppwszServiceNames = NULL; DWORD i = 0; PLW_SERVICE_INFO pInfo = NULL; LW_SERVICE_HANDLE hHandle = NULL; LW_SERVICE_STATUS status = {0}; dwError = LwSmEnumerateServices(&ppwszServiceNames); BAIL_ON_ERROR(dwError); for (i = 0; ppwszServiceNames[i]; i++) { dwError = LwSmAcquireServiceHandle(ppwszServiceNames[i], &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceStatus(hHandle, &status); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceInfo(hHandle, &pInfo); BAIL_ON_ERROR(dwError); if (status.pid == pid && (pInfo->type == LW_SERVICE_TYPE_EXECUTABLE || pInfo->type == LW_SERVICE_TYPE_LEGACY_EXECUTABLE)) { *phHandle = hHandle; hHandle = NULL; goto cleanup; } LwSmReleaseServiceHandle(hHandle); LwSmFreeServiceInfo(pInfo); } dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); cleanup: if (hHandle) { LwSmReleaseServiceHandle(hHandle); } if (ppwszServiceNames) { LwSmFreeServiceNameList(ppwszServiceNames); } if (pInfo) { LwSmFreeServiceInfo(pInfo); } return dwError; error: goto cleanup; } static DWORD LwSmGdb( int argc, char** pArgv ) { DWORD dwError = 0; PWSTR pwszServiceName = NULL; LW_SERVICE_HANDLE hHandle = NULL; LW_SERVICE_STATUS status = {0}; PLW_SERVICE_INFO pInfo = NULL; PSTR pszExecutablePath = NULL; PSTR pszPid = NULL; dwError = LwMbsToWc16s(pArgv[1], &pwszServiceName); BAIL_ON_ERROR(dwError); dwError = LwSmAcquireServiceHandle(pwszServiceName, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceStatus(hHandle, &status); BAIL_ON_ERROR(dwError); if (status.state != LW_SERVICE_STATE_RUNNING) { printf("Service is not running\n"); dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } dwError = LwSmQueryServiceInfo(hHandle, &pInfo); BAIL_ON_ERROR(dwError); if (pInfo->type != LW_SERVICE_TYPE_EXECUTABLE && pInfo->type != LW_SERVICE_TYPE_LEGACY_EXECUTABLE) { LwSmReleaseServiceHandle(hHandle); LwSmFreeServiceInfo(pInfo); dwError = LwSmFindServiceWithPid(status.pid, &hHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceInfo(hHandle, &pInfo); if (dwError == LW_ERROR_INVALID_PARAMETER) { printf("Service type is not supported\n"); } BAIL_ON_ERROR(dwError); } dwError = LwWc16sToMbs(pInfo->pwszPath, &pszExecutablePath); BAIL_ON_ERROR(dwError); dwError = LwAllocateStringPrintf(&pszPid, "%lu", (unsigned long) status.pid); BAIL_ON_ERROR(dwError); if (execlp("gdb", "gdb", pszExecutablePath, pszPid, NULL) < 0) { dwError = LwMapErrnoToLwError(errno); BAIL_ON_ERROR(dwError); } error: LW_SAFE_FREE_MEMORY(pszPid); LW_SAFE_FREE_MEMORY(pszExecutablePath); if (pInfo) { LwSmFreeServiceInfo(pInfo); } if (hHandle) { LwSmReleaseServiceHandle(hHandle); } return dwError; } static DWORD LwSmSetLog( int argc, char** pArgv ) { DWORD dwError = 0; LW_SM_LOGGER_TYPE type = 0; PSTR pszTarget = NULL; if (argc < 2) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } if (!strcasecmp(pArgv[1], "none")) { type = LW_SM_LOGGER_NONE; } else if (!strcasecmp(pArgv[1], "file")) { if (argc < 3) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } type = LW_SM_LOGGER_FILE; pszTarget = pArgv[2]; } else if (!strcasecmp(pArgv[1], "syslog")) { type = LW_SM_LOGGER_SYSLOG; pszTarget = NULL; } else { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } dwError = LwSmSetLogInfo(type, pszTarget); BAIL_ON_ERROR(dwError); error: return dwError; } static DWORD LwSmGetLog( int argc, char** pArgv ) { DWORD dwError = 0; LW_SM_LOGGER_TYPE type; PSTR pszTarget = NULL; PCSTR pszLoggerName = NULL; dwError = LwSmGetLogInfo(&type, &pszTarget); BAIL_ON_ERROR(dwError); switch (type) { case LW_SM_LOGGER_NONE: pszLoggerName = "none"; break; case LW_SM_LOGGER_FILE: pszLoggerName = "file"; break; case LW_SM_LOGGER_SYSLOG: pszLoggerName = "syslog"; break; } if (pszTarget) { printf("%s: %s\n", pszLoggerName, pszTarget); } else { printf("%s\n", pszLoggerName); } error: if (pszTarget) { LwSmFreeLogTarget(pszTarget); } return dwError; } static DWORD LwSmCmdSetLogLevel( int argc, char** pArgv ) { DWORD dwError = 0; LW_SM_LOG_LEVEL level; if (argc < 2) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } dwError = LwSmLogLevelNameToLogLevel(pArgv[1], &level); BAIL_ON_ERROR(dwError); dwError = LwSmSetLogLevel(level); BAIL_ON_ERROR(dwError); error: return dwError; } static DWORD LwSmCmdGetLogLevel( int argc, char** pArgv ) { DWORD dwError = 0; LW_SM_LOG_LEVEL level; dwError = LwSmGetLogLevel(&level); BAIL_ON_ERROR(dwError); printf("%s\n", LwSmLogLevelToString(level)); error: return dwError; } static DWORD LwSmUsage( int argc, char** pArgv ) { DWORD dwError = 0; printf("Usage: %s [ options ... ] ...\n\n", pArgv[0]); printf("Service commands:\n" " list List all known services and their status\n" " start-only Start a service\n" " start Start a service and all dependencies\n" " stop-only Stop a service\n" " stop Stop a service and all running dependents\n" " restart Restart a service and all running dependents\n" " refresh Refresh service's configuration\n" " proxy Act as a proxy process for a service\n" " info Get information about a service\n" " status Get the status of a service\n" " gdb Attach gdb to the specified running service\n\n"); printf("Maintenance commands:\n" " set-log [] Set logging destination\n" " Valid types:\n" " file (target is filename)\n" " syslog\n" " get-log Show current logging destination\n" " set-log-level Sets log level\n" " Valid levels:\n" " always\n" " error\n" " warning\n" " info\n" " verbose\n" " debug\n" " trace\n" " get-log-level Show current log level\n\n"); printf("Options:\n" " -q, --quiet Suppress console output\n" " -h, --help Show usage information\n\n"); return dwError; } int main( int argc, char** pArgv ) { DWORD dwError = 0; CHAR szErrorMessage[2048]; int ret = 0; int i = 0; PCSTR pszErrorName = NULL; for (i = 1; i < argc; i++) { if (!strcmp(pArgv[i], "-h") || !strcmp(pArgv[i], "--help")) { dwError = LwSmUsage(argc, pArgv); goto error; } if (!strcmp(pArgv[i], "-q") || !strcmp(pArgv[i], "--quiet")) { gState.bQuiet = TRUE; } else if (!strcmp(pArgv[i], "list")) { dwError = LwSmList(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "start-only")) { dwError = LwSmStartOnly(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "start")) { dwError = LwSmStart(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "stop-only")) { dwError = LwSmStopOnly(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "stop")) { dwError = LwSmStop(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "info")) { dwError = LwSmInfo(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "status")) { dwError = LwSmStatus(argc-i, pArgv+i, &ret); goto error; } else if (!strcmp(pArgv[i], "refresh")) { dwError = LwSmRefresh(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "restart")) { dwError = LwSmRestart(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "proxy")) { dwError = LwSmProxy(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "gdb")) { dwError = LwSmGdb(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "set-log")) { dwError = LwSmSetLog(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "get-log")) { dwError = LwSmGetLog(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "set-log-level")) { dwError = LwSmCmdSetLogLevel(argc-i, pArgv+i); goto error; } else if (!strcmp(pArgv[i], "get-log-level")) { dwError = LwSmCmdGetLogLevel(argc-i, pArgv+i); goto error; } else { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } } dwError = LwSmUsage(argc, pArgv); BAIL_ON_ERROR(dwError); error: if (dwError) { memset(szErrorMessage, 0, sizeof(szErrorMessage)); LwGetErrorString(dwError, szErrorMessage, sizeof(szErrorMessage) - 1); pszErrorName = LwWin32ExtErrorToName(dwError); if (!gState.bQuiet) { printf("Error: %s (%lu)\n", pszErrorName ? pszErrorName : "UNKNOWN", (unsigned long) dwError); printf("%s\n", szErrorMessage); } return 1; } else { return ret; } }