From 236833dd6a0798c84bb98d42d5f307bc519d47c6 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 7 Aug 2013 23:32:05 +0200 Subject: [PATCH 1/2] Add windows service handler. --- cmake/bus/CMakeLists.txt | 14 -- cmake/tools/CMakeLists.txt | 8 + tools/dbus-service-win.c | 387 ++++++++++++++++++++++++++++++++++++++++++++ 3 Dateien geändert, 395 Zeilen hinzugefügt(+), 14 Zeilen entfernt(-) create mode 100644 tools/dbus-service-win.c diff --git a/cmake/bus/CMakeLists.txt b/cmake/bus/CMakeLists.txt index 9943584..700441d 100644 --- a/cmake/bus/CMakeLists.txt +++ b/cmake/bus/CMakeLists.txt @@ -93,20 +93,6 @@ install_targets(/bin dbus-daemon) install_files(/etc/dbus-1 FILES ${config_DATA}) install(DIRECTORY . DESTINATION etc/dbus-1/session.d FILES_MATCHING PATTERN "*.conf") -if (DBUS_SERVICE) - set (dbus_service_SOURCES - ${BUS_DIR}/bus-service-win.c - # TODO: add additional files - # ${BUS_DIR}/service-main.c - # ${BUS_SOURCES} - ) - - add_executable(dbus-service ${dbus_service_SOURCES} ) - target_link_libraries(dbus-service ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY}) - set_target_properties(dbus-service PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS}) - install_targets(/bin dbus-service ) -endif (DBUS_SERVICE) - if (DBUS_ENABLE_EMBEDDED_TESTS) add_executable(bus-test ${BUS_SOURCES} ${BUS_DIR}/test-main.c) target_link_libraries(bus-test ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY}) diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt index 101c7e6..d582187 100644 --- a/cmake/tools/CMakeLists.txt +++ b/cmake/tools/CMakeLists.txt @@ -47,3 +47,11 @@ install_targets(/bin dbus-launch ) add_executable(dbus-monitor ${dbus_monitor_SOURCES}) target_link_libraries(dbus-monitor ${DBUS_LIBRARIES}) install_targets(/bin dbus-monitor ) + +if (WIN32 AND DBUS_SERVICE) + set (dbus_service_SOURCES + ../../tools/dbus-service-win.c + ) + add_executable(dbus-service ${dbus_service_SOURCES}) + install_targets(/bin dbus-service) +endif () diff --git a/tools/dbus-service-win.c b/tools/dbus-service-win.c new file mode 100644 index 0000000..88cf403 --- /dev/null +++ b/tools/dbus-service-win.c @@ -0,0 +1,387 @@ +/* dbus-service-win.c dbus windows service handler + * + * Copyright (C) 2006,2013 Ralf Habacker + * + * Licensed under the Academic Free License version 2.1 + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +// based on http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/installing_a_service.asp +// you can view the debug output with http://www.sysinternals.com/Utilities/DebugView.html + +#include "config.h" + +#include +#include + +#define SERVICE_NAME "dbus-daemon" +#define SERVICE_DISPLAY_NAME "DBus-Daemon" + +SERVICE_STATUS DBusServiceStatus; +SERVICE_STATUS_HANDLE DBusServiceStatusHandle; + +SC_HANDLE schSCManager; +SC_HANDLE schService; + +void SvcDebugOut (const char *format, ...); +VOID WINAPI DBusServiceCtrlHandler (DWORD opcode); + +PROCESS_INFORMATION pi; + +int run_daemon (char *app, char *params) +{ + STARTUPINFO si; + + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + char buf[MAX_PATH]; + strcpy(buf, "\""); + strcat(buf, app); + strcat(buf, "\" "); + strcat(buf, params); + SvcDebugOut ("CreateProcess command line(%s).\n", buf); + + SetEnvironmentVariable ("DBUS_VERBOSE","1"); + + // Start the child process. + if( !CreateProcess (NULL, // No module name (use command line) + buf, // Command line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + FALSE, // Set handle inheritance to FALSE + 0, // No creation flags + NULL, // Use parent's environment block + NULL, // Use parent's starting directory + &si, // Pointer to STARTUPINFO structure + &pi ) // Pointer to PROCESS_INFORMATION structure + ) + { + SvcDebugOut("CreateProcess failed (%d).\n", GetLastError()); + return -1; + } + return 1; +} + +int pid = 0; + +int _dbus_main_init (int argc, char **argv) +{ + int result = run_daemon ("dbus-daemon.exe","--session"); + return result > 0; +} + +void _dbus_main_loop () +{ +} + +void _dbus_main_end () +{ + if (!TerminateProcess (pi.hProcess, -1)) + { + SvcDebugOut ("TerminateProcess failed (%d).\n", GetLastError()); + } + else + SvcDebugOut ("TerminateProcess\n", 0); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + +// Open a handle to the SC Manager database. +BOOL OpenDataBase() +{ + schSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + + if (schSCManager == NULL) + { + SvcDebugOut ("OpenSCManager failed (%d)\n", GetLastError()); + return FALSE; + } + else + { + return TRUE; + } +} + + +int installService() +{ + TCHAR szPath[MAX_PATH]; + + if(!GetModuleFileName (NULL, szPath, MAX_PATH)) + { + fprintf(stderr, "GetModuleFileName failed (%d)\n", GetLastError()); + return -1; + } + + strcat (szPath," --run"); + + if (OpenDataBase () == FALSE) + { + fprintf(stderr, "OpenDataBase failed (%d)\n", GetLastError()); + return -2; + } + + schService = CreateService ( + schSCManager, // SCManager database + TEXT(SERVICE_NAME), // name of service + TEXT(SERVICE_DISPLAY_NAME),// service name to display + SERVICE_ALL_ACCESS, // desired access + SERVICE_WIN32_OWN_PROCESS, // service type + SERVICE_DEMAND_START, // start type + SERVICE_ERROR_NORMAL, // error control type + szPath, // path to service's binary + NULL, // no load ordering group + NULL, // no tag identifier + NULL, // no dependencies + NULL, // LocalSystem account + NULL); // no password + + if (schService == NULL) + { + fprintf(stderr, "CreateService failed (%d)\n", GetLastError()); + return -3; + } + else + { + fprintf(stderr, "Service %s installed\n", SERVICE_NAME); + CloseServiceHandle (schService); + return -4; + } + return 0; +} + +int removeService() +{ + if (OpenDataBase () == FALSE) + { + fprintf (stderr, "OpenDataBase failed (%d)\n", GetLastError()); + return -5; + } + + schService = OpenService (schSCManager, TEXT(SERVICE_NAME), DELETE); + + if (schService == NULL) + { + fprintf (stderr, "OpenService failed (%d)\n", GetLastError()); + return -6; + } + + if (!DeleteService (schService) ) + { + fprintf (stderr, "DeleteService failed (%d)\n", GetLastError()); + return -7; + } + else + { + fprintf (stderr, "Service %s removed\n", SERVICE_NAME); + CloseServiceHandle (schService); + return -8; + } + return 0; +} + +// Stub initialization function. +DWORD DBusServiceInitialization (DWORD argc, LPTSTR *argv, + DWORD *specificError) +{ + _dbus_main_init(argc,argv); + + SvcDebugOut ("Init Service\n",0); + return 0; +} + +VOID WINAPI DBusServiceCtrlHandler (DWORD Opcode) +{ + DWORD status; + SvcDebugOut ("DBusServiceCtrlHandler opcode=%ld\n", Opcode); + + switch(Opcode) + { + case SERVICE_CONTROL_PAUSE: + // Do whatever it takes to pause here. + DBusServiceStatus.dwCurrentState = SERVICE_PAUSED; + SvcDebugOut ("Service paused\n",0); + break; + + case SERVICE_CONTROL_CONTINUE: + // Do whatever it takes to continue here. + DBusServiceStatus.dwCurrentState = SERVICE_RUNNING; + SvcDebugOut ("Service continued\n",0); + break; + + case SERVICE_CONTROL_STOP: + SvcDebugOut ("Service stopped\n",0); + // Do whatever it takes to stop here. + _dbus_main_end (); + + DBusServiceStatus.dwWin32ExitCode = 0; + DBusServiceStatus.dwCurrentState = SERVICE_STOPPED; + DBusServiceStatus.dwCheckPoint = 0; + DBusServiceStatus.dwWaitHint = 0; + + if (!SetServiceStatus (DBusServiceStatusHandle, + &DBusServiceStatus)) + { + status = GetLastError (); + SvcDebugOut ("SetServiceStatus error %ld\n", status); + } + + SvcDebugOut ("Leaving Service\n",0); + return; + + case SERVICE_CONTROL_INTERROGATE: + // Fall through to send current status. + break; + + default: + SvcDebugOut ("Unrecognized opcode %ld\n", + Opcode); + } + + // Send current status. + if (!SetServiceStatus (DBusServiceStatusHandle, &DBusServiceStatus)) + { + status = GetLastError (); + SvcDebugOut ("SetServiceStatus error %ld\n", status); + } + return; +} + +void WINAPI DBusServiceStart (DWORD argc, LPTSTR *argv) +{ + DWORD status; + DWORD specificError; + + DBusServiceStatus.dwServiceType = SERVICE_WIN32; + DBusServiceStatus.dwCurrentState = SERVICE_START_PENDING; + DBusServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + DBusServiceStatus.dwWin32ExitCode = 0; + DBusServiceStatus.dwServiceSpecificExitCode = 0; + DBusServiceStatus.dwCheckPoint = 0; + DBusServiceStatus.dwWaitHint = 0; + + DBusServiceStatusHandle = RegisterServiceCtrlHandler ( + "DBusService", + DBusServiceCtrlHandler); + + if (DBusServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) + { + SvcDebugOut ("RegisterServiceCtrlHandler failed %d\n", GetLastError()); + return; + } + + // Initialization code goes here. + status = DBusServiceInitialization(argc,argv, &specificError); + + // Handle error condition + if (status != NO_ERROR) + { + DBusServiceStatus.dwCurrentState = SERVICE_STOPPED; + DBusServiceStatus.dwCheckPoint = 0; + DBusServiceStatus.dwWaitHint = 0; + DBusServiceStatus.dwWin32ExitCode = status; + DBusServiceStatus.dwServiceSpecificExitCode = specificError; + + SetServiceStatus (DBusServiceStatusHandle, &DBusServiceStatus); + return; + } + + // Initialization complete - report running status. + DBusServiceStatus.dwCurrentState = SERVICE_RUNNING; + DBusServiceStatus.dwCheckPoint = 0; + DBusServiceStatus.dwWaitHint = 0; + + if (!SetServiceStatus (DBusServiceStatusHandle, &DBusServiceStatus)) + { + status = GetLastError(); + SvcDebugOut ("SetServiceStatus error %ld\n",status); + } + + // This is where the service does its work. + SvcDebugOut ("Returning the Main Thread \n",0); + + _dbus_main_loop (); + return; +} + +int runService() +{ + SERVICE_TABLE_ENTRY DispatchTable[] = + { + { "DBusService", DBusServiceStart }, + { NULL, NULL } + }; + + SvcDebugOut ("RunService\n", 0); + + if (!StartServiceCtrlDispatcher (DispatchTable)) + { + SvcDebugOut ("StartServiceCtrlDispatcher (%d)\n", GetLastError()); + } + return 0; +} + +void SvcDebugOut (const char *format, ...) +{ + va_list args; + char buf[1024]; + + va_start (args, format); + strcpy (buf, "dbus-service: "); + vsprintf (buf+strlen(buf), format, args); + va_end (args); + OutputDebugStringA (buf); +} + +int main(int argc, char **argv ) +{ + if (argc != 2) + { + printf("no parameter provided\n"); + } + + // internal switch for running service + if (argc == 2 && strcmp (argv[1], "--run") == 0) + { + return runService (); + } + else if(argc == 2 && strcmp (argv[1], "--install") == 0) + { + return installService (); + } + else if(argc == 2 && strcmp (argv[1], "--remove") == 0) + { + return removeService (); + } + else if(argc == 2 && strcmp (argv[1], "--version") == 0) + { + printf("D-Bus Windows Service Installer %s\n" + "Copyright (C) 2006, 2013 Ralf Habacker\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", + DBUS_VERSION_STRING); + } + else + { + printf("Usage: dbus-service [--install | --remove | --version | --help]\n"); + } + + return 1; +} -- 1.7.10.4