From: Marko Kreen Date: Sat, 10 Jan 2009 18:54:16 +0000 (+0000) Subject: win32: simpler service handling, cleanups X-Git-Tag: pgbouncer_1_3_rc1~12 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=576bfbb5850ec811d07f6f1234161a9593301d59;p=pgbouncer win32: simpler service handling, cleanups - one pgbouncer instance per service, in-process - read service name from config file cleanups: - use FormatMessage for strerror() - error out on wide-char build - tag stdout/err _IONBF, they seem fully buffered by default --- diff --git a/win32/win32support.c b/win32/win32support.c index 67e7408..61a2456 100644 --- a/win32/win32support.c +++ b/win32/win32support.c @@ -4,9 +4,10 @@ * Windows service integration and eventlog * * Copyright (c) 2005, PostgreSQL Global Development Group - * Author: Magnus Hagander and Hiroshi Saito + * Authors: Magnus Hagander, Hiroshi Saito, Marko Kreen *------------------------------------------------------------------------- */ + #define WIN32_LEAN_AND_MEAN #include #include @@ -15,46 +16,38 @@ #include "bouncer.h" -/* forward declarations */ -static void WINAPI win32_servicemain(DWORD argc, LPTSTR * argv); -static void WINAPI win32_servicehandler(DWORD request); -static void win32_setservicestatus(DWORD state); -static bool win32_load_child_list(void); -static HANDLE win32_start_engine(int num); - -static void RegisterService(char *servicename); -static void UnRegisterService(char *servicename); -static void ListEngines(char *servicename); -static void AddEngine(char *servicename, char *configfile); -static void DelEngine(char *servicename, char *configfile); - -/* Gobals for service control */ -static SERVICE_STATUS status; -static SERVICE_STATUS_HANDLE hStatus; -static HANDLE shutdownEvent; - -/* Not used in WIN32_OWN_PROCESS, but has to exist */ +#if defined(UNICODE) || defined(_UNICODE) +#error This code does not support wide characters. +#endif + +/* Globals for service control */ +static SERVICE_STATUS_HANDLE hStatus = 0; +static SERVICE_STATUS svcStatus = { + .dwServiceType = SERVICE_WIN32_OWN_PROCESS, + .dwControlsAccepted = 0, + .dwWin32ExitCode = NO_ERROR, + .dwCheckPoint = 0, + .dwWaitHint = 0, + .dwCurrentState = SERVICE_START_PENDING, +}; + +/* Event source name for ReportEvent. + * + * Also used as placeholder for service handling API's, but it is ignored + * because our service is defined as WIN32_OWN_PROCESS. + */ static char *servicename = "pgbouncer"; -/* Name of the service as the SCM sees it */ -static char running_servicename[256]; - -/* Child engines */ -static DWORD childcount; -static char **children_config_files; - +/* custom help string for win32 exe */ static const char *usage_str = "Usage: %s [OPTION]... config.ini\n" " -q No console messages\n" " -v Increase verbosity\n" " -V Show version\n" " -h Show this help screen and exit\n" -" \n" -" -regservice [servicename]\n" -" -unregservice [servicename]\n" -" -listengines [servicename]\n" -" -addengine [servicename] config.ini\n" -" -delengine [servicename] config.ini\n" +"Windows service registration:\n" +" -regservice config.ini\n" +" -unregservice config.ini\n" ""; static void usage(int err, char *exe) @@ -63,129 +56,52 @@ static void usage(int err, char *exe) exit(err); } -/* Start running as a service */ -static void win32_servicestart(void) +static int exec_real_main(int argc, char *argv[]) { - SERVICE_TABLE_ENTRY st[] = { {servicename, win32_servicemain}, {NULL, NULL} }; - - if (StartServiceCtrlDispatcher(st) == 0) { - fprintf(stderr, "could not start service control dispatcher: %lu\n", GetLastError()); - exit(1); - } -} - -/* - * Entrypoint for actual service work. - * - * Fork of a normal pgbouncer process with specified commandline. Wait - * on them to die (and restart) or the SCM to tell us to shut - * down (and stop all engines). - */ -static void WINAPI win32_servicemain(DWORD argc, LPTSTR * argv) -{ - DWORD ret; - HANDLE *waithandles = NULL; - DWORD i; - DWORD startcount; - - /* fetch our actual service name */ - safe_strcpy(running_servicename, argv[0], sizeof(running_servicename)); - - /* initialize the status structure with static stuff */ - status.dwWin32ExitCode = 0; - status.dwCheckPoint = 0; - status.dwWaitHint = 30000; - status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - status.dwServiceSpecificExitCode = 0; - status.dwCurrentState = SERVICE_START_PENDING; - - /* register control request handler */ - hStatus = RegisterServiceCtrlHandler(servicename, win32_servicehandler); - if (hStatus == 0) { - fatal("could not connect to service control handler: %lu", GetLastError()); - exit(1); - } - - /* Tell SCM we are running before we make any API calls */ - win32_setservicestatus(SERVICE_RUNNING); - - /* create event to handle shutdown */ - shutdownEvent = CreateEvent(NULL, true, false, NULL); - if (shutdownEvent == NULL) { - fatal("could not create shutdown event: %lu", GetLastError()); - exit(1); - } + int i, j; + WSADATA wsaData; - /* Report we're up and running */ - log_info("pgbouncer service controller version %s started", PACKAGE_VERSION); + /* win32 stdio seems to be fully buffered by default */ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); - /* Read our configuration from the registry to determine which - enginesto start. Will do it's own error logging. */ - if (!win32_load_child_list()) - exit(1); + /* initialize socket subsystem */ + if (WSAStartup(MAKEWORD(2,0), &wsaData)) + fatal("Cannot start the network subsystem"); - /* Set up our array of handles to wait on. First handle is the - shutdown handle, then one handle for each child */ - waithandles = malloc((childcount + 1) * sizeof(HANDLE)); - if (!waithandles) { - fatal("win32_servicemain: out of memory"); - exit(1); - } - waithandles[0] = shutdownEvent; - - /* Start the required pgbouncer processes */ - startcount = 0; - for (i = 0; i < childcount; i++) { - waithandles[i + 1] = win32_start_engine(i); - - /* If start failed, set to shutdown event to - prevent failure in wait code */ - if (waithandles[i + 1] == INVALID_HANDLE_VALUE) - waithandles[i + 1] = shutdownEvent; - else - startcount++; - } - log_info("started %i pgbouncer engine(s)", (int)startcount); - - /* Stay in a loop until SCM shuts us down */ - while (true) { - ret = WaitForMultipleObjectsEx(childcount + 1, waithandles, FALSE, INFINITE, FALSE); - if (ret == WAIT_FAILED) { - fatal("win32_servicemain: could not wait for child handles: %lu", GetLastError()); - exit(1); - } - if (ret == WAIT_OBJECT_0) { /* shutdown */ - win32_setservicestatus(SERVICE_STOP_PENDING); - /* Shut down all pgbouncer processes */ - log_info("received shutdown event, terminating all engines"); - for (i = 0; i < childcount; i++) { - if (waithandles[i + 1] != shutdownEvent && waithandles[i + 1] != INVALID_HANDLE_VALUE) { - TerminateProcess(waithandles[i + 1], 0); - CloseHandle(waithandles[i + 1]); - } - } - win32_setservicestatus(SERVICE_STOPPED); - break; - } else if (ret > WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + childcount) { - /* a child process died! */ - int ofs = ret - WAIT_OBJECT_0 - 1; - - log_warning("engine for '%s' terminated, restarting.", children_config_files[ofs]); - CloseHandle(waithandles[ofs + 1]); - waithandles[ofs + 1] = win32_start_engine(ofs); - if (waithandles[ofs + 1] == INVALID_HANDLE_VALUE) - waithandles[ofs + 1] = shutdownEvent; + /* check if regular arguments are in allowed list */ + for (i = 1; i < argc; i++) { + char *p = argv[i]; + if (p[0] != '-') + continue; + for (j = 1; p[j]; j++) { + if (!strchr("qvhV", p[j])) + usage(1, argv[0]); + if (p[j] == 'h') + usage(0, argv[0]); } - /* else just ignore what happened */ } + + /* call actual main() */ + return real_main(argc, argv); } /* Set the current service status */ static void win32_setservicestatus(DWORD state) { - status.dwCurrentState = state; - SetServiceStatus(hStatus, (LPSERVICE_STATUS) & status); + svcStatus.dwCurrentState = state; + switch (state) { + case SERVICE_START_PENDING: + case SERVICE_STOP_PENDING: + svcStatus.dwControlsAccepted = 0; + svcStatus.dwWaitHint = 5000; + break; + default: + svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + svcStatus.dwWaitHint = 0; + } + + SetServiceStatus(hStatus, &svcStatus); } /* @@ -200,205 +116,87 @@ static void WINAPI win32_servicehandler(DWORD request) case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: win32_setservicestatus(SERVICE_STOP_PENDING); - SetEvent(shutdownEvent); - return; - default: + cf_shutdown = 2; + break; + case SERVICE_CONTROL_INTERROGATE: + SetServiceStatus(hStatus, &svcStatus); break; } } -/* - * Open the \Parameters\Engines registry key, which holds the list - * of all the engines associated with this service. - */ -static HKEY OpenEnginesKey(DWORD access) +/* notify control thread about stop */ +static void win32_service_cleanup(void) { - char rootkey[1024]; - HKEY key; - int r; - - snprintf(rootkey, sizeof(rootkey), - "SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters\\Engines", - running_servicename); - - r = RegCreateKeyEx(HKEY_LOCAL_MACHINE, rootkey, 0, NULL, REG_OPTION_NON_VOLATILE, access, NULL, &key, NULL); - if (r != ERROR_SUCCESS) { - fatal("Failed to open registry key '%s': %d", rootkey, r); - return NULL; - } - return key; + if (hStatus) + win32_setservicestatus(SERVICE_STOPPED); + hStatus = 0; /* may get called twice from atexit */ } /* - * Load the list of pgbouncer engines to start + * Entrypoint for actual service work. + * + * Service is set-up and then actual main() is called. */ -static bool win32_load_child_list(void) +static void WINAPI win32_servicemain(DWORD argc, LPSTR *argv) { - char rootkey[1024]; - HKEY key; - char valname[256]; - char valval[256]; - DWORD valnamesize = sizeof(valname); - DWORD valvalsize = sizeof(valval); - DWORD regtype; - int r; - - key = OpenEnginesKey(KEY_READ); - if (!key) - return false; - - childcount = 0; - while ((r = RegEnumValue(key, childcount, valname, &valnamesize, NULL, ®type, NULL, NULL)) == ERROR_SUCCESS) { - if (regtype != REG_SZ) { - fatal("Bad data type in registry key '%s', value '%s': %i", rootkey, valname, (int)regtype); - RegCloseKey(key); - return false; - } + int new_argc = 2; + char *new_argv[] = { servicename, cf_config_file, NULL }; - valnamesize = sizeof(valname); - childcount++; - } - if (r != ERROR_NO_MORE_ITEMS) { - fatal("Failed to enumerate registry key '%s': %d", rootkey, r); - RegCloseKey(key); - return false; + /* register control request handler */ + hStatus = RegisterServiceCtrlHandler(servicename, win32_servicehandler); + if (hStatus == 0) { + fatal("could not connect to service control handler: %s", strerror(GetLastError())); + exit(1); } - children_config_files = malloc(childcount * sizeof(char *)); - if (!children_config_files) { - fatal("Out of memory."); - RegCloseKey(key); - return false; - } + /* Tell SCM we are running before we make any API calls */ + win32_setservicestatus(SERVICE_RUNNING); - childcount = 0; - valnamesize = sizeof(valname); - valvalsize = sizeof(valval); - while ((r = RegEnumValue(key, childcount, valname, &valnamesize, NULL, - ®type, (unsigned char *)valval, &valvalsize)) == ERROR_SUCCESS) { - children_config_files[childcount] = strdup(valval); - if (!children_config_files[childcount]) { - fatal("Out of memory."); - RegCloseKey(key); - return false; - } + /* register with system atexit(), in case somebody calls exit() */ + atexit(win32_service_cleanup); - childcount++; - valnamesize = sizeof(valname); - valvalsize = sizeof(valval); - } - if (r != ERROR_NO_MORE_ITEMS) { - fatal("Failed to enumerate registry key '%s' a second time: %d", rootkey, r); - RegCloseKey(key); - return false; - } - RegCloseKey(key); - return true; + /* Execute actual main() */ + exec_real_main(new_argc, new_argv); + win32_service_cleanup(); } -/* Start engine with config file at offset num in children_config_files */ -static HANDLE win32_start_engine(int num) +/* Start running as a service */ +static void win32_servicestart(void) { - STARTUPINFO si; - PROCESS_INFORMATION pi; - char cmdline[512]; - static char self_process[512] = { 0 }; - int r; - - ZeroMemory(&si, sizeof(si)); - ZeroMemory(&pi, sizeof(pi)); - si.cb = sizeof(si); - - if (!self_process[0]) { - if (!GetModuleFileName(NULL, self_process, sizeof(self_process))) { - fatal("Failed to determine own filename: %lu", GetLastError()); - return INVALID_HANDLE_VALUE; - } - } - wsprintf(cmdline, "\"%s\" -q \"%s\"", self_process, children_config_files[num]); + SERVICE_TABLE_ENTRY st[] = { {servicename, win32_servicemain}, {NULL, NULL} }; - if (!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { - log_error("Failed to spawn process for engine at '%s': %lu", - children_config_files[num], GetLastError()); - return INVALID_HANDLE_VALUE; - } - CloseHandle(pi.hThread); - - /* Give the process five seconds to start up, and see if - it's still around. If not, we call it dead on startup. */ - r = WaitForSingleObject(pi.hProcess, 5000); - if (r == WAIT_TIMEOUT) { - /* nothing happened, so things seem ok */ - return pi.hProcess; - } else if (r == WAIT_OBJECT_0) { - /* process died within one second */ - log_error("Process for engine at '%s' died on startup.", children_config_files[num]); - CloseHandle(pi.hProcess); - return INVALID_HANDLE_VALUE; - } else { - fatal("Failed to wait for newly started process: %lu", GetLastError()); - TerminateProcess(pi.hProcess, 250); - CloseHandle(pi.hProcess); - return INVALID_HANDLE_VALUE; + if (StartServiceCtrlDispatcher(st) == 0) { + fprintf(stderr, "could not start service control dispatcher: %s\n", + strerror(GetLastError())); + exit(1); } - log_info("Started pgbouncer engine for '%s' with pid %lu", children_config_files[num], pi.dwProcessId); } -/* Write a log entry to the eventlog */ -static void win32_eventlog(int level, const char *msg) +/* Open Service Control Manager */ +static SC_HANDLE openSCM(void) { - int elevel; - static HANDLE evtHandle = INVALID_HANDLE_VALUE; - - switch (level) { - case LOG_CRIT: - case LOG_ERR: - elevel = EVENTLOG_ERROR_TYPE; - break; - case LOG_WARNING: - elevel = EVENTLOG_WARNING_TYPE; - break; - default: - elevel = EVENTLOG_INFORMATION_TYPE; - } - - if (evtHandle == INVALID_HANDLE_VALUE) { - evtHandle = RegisterEventSource(NULL, "pgbouncer"); - if (evtHandle == NULL) { - evtHandle = INVALID_HANDLE_VALUE; - return; - } + SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!manager) { + fprintf(stderr, "Failed to open service control manager: %s\n", strerror(GetLastError())); + exit(1); } - ReportEvent(evtHandle, elevel, 0, 0, NULL, 1, 0, (const char **)&msg, NULL); + return manager; } -/* Deal with service and engine registration and unregistration */ -static void win32_serviceconfig(int argc, char *const argv[]) +/* Full path to current config file. */ +static const char *get_config_fullpath(void) { - if (!strcmp(argv[1], "-regservice")) { - if (argc != 2 && argc != 3) - usage(1, argv[0]); - RegisterService((argc == 3) ? argv[2] : "pgbouncer"); - } else if (!strcmp(argv[1], "-unregservice")) { - if (argc != 2 && argc != 3) - usage(1, argv[0]); - UnRegisterService((argc == 3) ? argv[2] : "pgbouncer"); - } else if (!strcmp(argv[1], "-listengines")) { - if (argc != 2 && argc != 3) - usage(1, argv[0]); - ListEngines((argc == 3) ? argv[2] : "pgbouncer"); - } else if (!strcmp(argv[1], "-addengine")) { - if (argc != 3 && argc != 4) - usage(1, argv[0]); - AddEngine((argc == 4) ? argv[2] : "pgbouncer", (argc == 4) ? argv[3] : argv[2]); - } else if (!strcmp(argv[1], "-delengine")) { - if (argc != 3 && argc != 4) - usage(1, argv[0]); - DelEngine((argc == 4) ? argv[2] : "pgbouncer", (argc == 4) ? argv[3] : argv[2]); - } else - usage(1, argv[0]); - exit(0); + DWORD r; + static char buf[PATH_MAX]; + + r = GetFullPathName(cf_config_file, sizeof(buf), buf, NULL); + if (r == 0 || r >= sizeof(buf)) { + fprintf(stderr, "Failed to get full pathname for '%s': %s\n", + cf_config_file, strerror(GetLastError())); + exit(1); + } + return buf; } /* Check windows version against Server 2003 to determine service functionality */ @@ -407,9 +205,8 @@ static bool is_windows2003ornewer(void) OSVERSIONINFO vi; vi.dwOSVersionInfoSize = sizeof(vi); - if (!GetVersionEx(&vi)) { - fprintf(stderr, "Failed to determine OS version: %lu\n", GetLastError()); + fprintf(stderr, "Failed to determine OS version: %s\n", strerror(GetLastError())); exit(1); } if (vi.dwMajorVersion > 5) @@ -419,71 +216,63 @@ static bool is_windows2003ornewer(void) return false; } -/* Open Service Control Manager */ -static SC_HANDLE openSCM(void) -{ - SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (!manager) { - fprintf(stderr, "Failed to open service control manager: %lu\n", GetLastError()); - exit(1); - } - return manager; -} - /* Register a service with the specified name with the local service control manager */ -static void RegisterService(char *servicename) +static void RegisterService(void) { char self[1024]; - char execpath[1200]; + char cmdline[2048]; + const char *config_fn = get_config_fullpath(); SC_HANDLE manager; SC_HANDLE service; + SERVICE_DESCRIPTION sd; + DWORD r; char *account = is_windows2003ornewer() ? "NT AUTHORITY\\Local Service" : NULL; - ZeroMemory(self, sizeof(self)); - - if (!GetModuleFileName(NULL, self, sizeof(self))) { - fprintf(stderr, "Failed to determine path name: %lu\n", GetLastError()); + r = GetModuleFileName(NULL, self, sizeof(self)); + if (!r || r >= sizeof(self)) { + fprintf(stderr, "Failed to determine path name: %s\n", strerror(GetLastError())); exit(1); } - wsprintf(execpath, "%s -service", self); + snprintf(cmdline, sizeof(cmdline), "%s -service %s", self, config_fn); manager = openSCM(); - - service = CreateService(manager, servicename, servicename, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, execpath, NULL, NULL, "RPCSS\0", account, ""); + service = CreateService(manager, cf_jobname, cf_jobname, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, cmdline, NULL, NULL, "RPCSS\0", account, ""); if (!service) { - fprintf(stderr, "Failed to create service: %lu\n", GetLastError()); + fprintf(stderr, "Failed to create service: %s\n", strerror(GetLastError())); exit(1); } + /* set cmdline as desc, makes details more visible */ + sd.lpDescription = cmdline; + ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sd); + CloseServiceHandle(service); CloseServiceHandle(manager); printf("Service registered.\n"); - printf("Before you can run pgbouncer, you must also register an engine!\n\n"); if (account == NULL) { - printf("WARNING! Service is registered to run as Local System. You are\n"); + printf("\nWARNING! Service is registered to run as Local System. You are\n"); printf("encouraged to change this to a low privilege account to increase\n"); printf("system security.\n"); } } /* Remove a service with the specified name from the local service control manager */ -static void UnRegisterService(char *servicename) +static void UnRegisterService(void) { SC_HANDLE manager; SC_HANDLE service; manager = openSCM(); - - service = OpenService(manager, servicename, SC_MANAGER_ALL_ACCESS); + service = OpenService(manager, cf_jobname, SC_MANAGER_ALL_ACCESS); if (!service) { - fprintf(stderr, "Failed to open service: %lu\n", GetLastError()); + fprintf(stderr, "Failed to open service: %s\n", strerror(GetLastError())); exit(1); } if (!DeleteService(service)) { - fprintf(stderr, "Failed to delete service: %lu\n", GetLastError()); + fprintf(stderr, "Failed to delete service: %s\n", strerror(GetLastError())); exit(1); } @@ -493,184 +282,95 @@ static void UnRegisterService(char *servicename) printf("Service removed.\n"); } -/* Print a list of all engines associated with the specified service */ -static void ListEngines(char *servicename) -{ - DWORD i; - - safe_strcpy(running_servicename, servicename, sizeof(running_servicename)); - if (!win32_load_child_list()) - exit(1); - - printf("\n%lu engine(s) registered for service '%s'\n", childcount, servicename); - for (i = 0; i < childcount; i++) { - printf("Engine %lu: %s\n", i + 1, children_config_files[i]); - } -} /* - * Verify that a file exists, and also expand the filename to - * an absolute path. + * syslog() interface to event log. */ -static char _vfe_buf[UNIX_PATH_MAX]; -static char *VerifyFileExists(char *filename) -{ - DWORD r; - - ZeroMemory(_vfe_buf, sizeof(_vfe_buf)); - r = GetFullPathName(filename, sizeof(_vfe_buf), _vfe_buf, NULL); - if (r == 0 || r > sizeof(_vfe_buf)) { - fprintf(stderr, "Failed to get full pathname for '%s': %lu\n", filename, GetLastError()); - exit(1); - } - - if (GetFileAttributes(_vfe_buf) == 0xFFFFFFFF) { - fprintf(stderr, "File '%s' could not be opened: %lu\n", _vfe_buf, GetLastError()); - exit(1); - } - - return _vfe_buf; -} - -/* Register a new engine with a specific config file with the specified service */ -static void AddEngine(char *servicename, char *configfile) -{ - HKEY key; - int r; - - char *full_configfile = VerifyFileExists(configfile); - - safe_strcpy(running_servicename, servicename, sizeof(running_servicename)); - key = OpenEnginesKey(KEY_ALL_ACCESS); - if (!key) - exit(1); - - r = RegQueryValueEx(key, full_configfile, 0, NULL, NULL, NULL); - if (r == 0) { - fprintf(stderr, "Engine '%s' already registered for service '%s'.\n", full_configfile, servicename); - exit(1); - } - - r = RegSetValueEx(key, full_configfile, 0, REG_SZ, - (unsigned char *)full_configfile, strlen(full_configfile) + 1); - RegCloseKey(key); - if (r == ERROR_SUCCESS) { - printf("Engine added.\n"); - printf("NOTE! You need to restart the pgbouncer service before this takes effect.\n"); - return; - } else - fprintf(stderr, "Failed to register engine: %d.\n", r); - exit(1); -} - -/* Remove an engine registration from the specified service */ -static void DelEngine(char *servicename, char *configfile) -{ - HKEY key; - int r; - - safe_strcpy(running_servicename, servicename, sizeof(running_servicename)); - key = OpenEnginesKey(KEY_ALL_ACCESS); - if (!key) - exit(1); - - r = RegDeleteValue(key, configfile); - RegCloseKey(key); - if (r == ERROR_SUCCESS) { - printf("Engine removed.\n"); - printf("NOTE! You need to restart the pgbouncer service before this takes effect.\n"); - return; - } else if (r == 2) { - fprintf(stderr, "Engine '%s' not registered for service '%s'.\n", configfile, servicename); - } else - fprintf(stderr, "Failed to unregister engine: %d\n", r); - exit(1); -} -void openlog(const char *ident, int option, int facility) -{ -} - -void syslog(int prio, const char *fmt, ...) +void win32_eventlog(int level, const char *fmt, ...) { + static HANDLE evtHandle = INVALID_HANDLE_VALUE; + int elevel; char buf[1024]; + const char *strlist[1] = { buf }; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - win32_eventlog(prio, buf); -} + switch (level) { + case LOG_CRIT: + case LOG_ERR: + elevel = EVENTLOG_ERROR_TYPE; + break; + case LOG_WARNING: + elevel = EVENTLOG_WARNING_TYPE; + break; + default: + elevel = EVENTLOG_INFORMATION_TYPE; + } -void closelog(void) -{ + if (evtHandle == INVALID_HANDLE_VALUE) { + evtHandle = RegisterEventSource(NULL, servicename); + if (evtHandle == NULL || evtHandle == INVALID_HANDLE_VALUE) { + evtHandle = INVALID_HANDLE_VALUE; + return; + } + } + ReportEvent(evtHandle, elevel, 0, 0, NULL, 1, 0, strlist, NULL); } -#define WCASE(x) case x: return #x -const char *wsa_strerror(int e) +/* + * Error strings for win32 errors. + */ + +const char *win32_strerror(int e) { - static char wsa_buf[256]; - switch (e) { - /* display few common ones by name */ - WCASE(WSAEWOULDBLOCK); - WCASE(WSAEINPROGRESS); - WCASE(WSAECONNABORTED); - WCASE(WSAEINTR); - default: - snprintf(wsa_buf, sizeof(wsa_buf), "wsa_error: %d", e); - return wsa_buf; - } + static char buf[1024]; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, e, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, sizeof(buf), NULL); + return buf; } -#define strerror(x) w_strerror(x) -static void manage_win32_service(int argc, char *argv[]) +/* config loader for service register/unregister */ +static void win32_load_config(char *conf) { - /* parse cmdline */ - if (argc >= 2 && !strcmp(argv[1], "-service")) - { - win32_servicestart(); - exit(0); - } - if (argc >= 2 && argc <= 4 && ( - !strcmp(argv[1], "-regservice") || - !strcmp(argv[1], "-unregservice") || - !strcmp(argv[1], "-addengine") || - !strcmp(argv[1], "-delengine") || - !strcmp(argv[1], "-listengines"))) - { - win32_serviceconfig(argc, argv); - exit(0); - } + cf_config_file = conf; + init_objects(); + load_config(false); } +/* + * Wrapper around actual main() that handles win32 hacks. + */ + #undef main int main(int argc, char *argv[]) { - int i, j; - WSADATA wsaData; + /* service cmdline */ + if (argc == 3) { + if (!strcmp(argv[1], "-service")) { + cf_quiet = 1; + cf_config_file = argv[2]; + win32_servicestart(); + return 0; + } - manage_win32_service(argc, argv); + if (!strcmp(argv[1], "-regservice")) { + win32_load_config(argv[2]); + RegisterService(); + return 0; + } - /* check if regular arguments are in allowed list */ - for (i = 1; i < argc; i++) { - char *p = argv[i]; - if (p[0] != '-') - continue; - for (j = 1; p[j]; j++) { - if (!strchr("qvhV", p[j])) - usage(1, argv[0]); - if (p[j] == 'h') - usage(0, argv[0]); + if (!strcmp(argv[1], "-unregservice")) { + win32_load_config(argv[2]); + UnRegisterService(); + return 0; } } - /* initialize socket subsystem */ - if (WSAStartup(MAKEWORD(2,0), &wsaData)) - fatal("Cannot start the network subsystem"); - - /* call actual main() */ - return real_main(argc, argv); + return exec_real_main(argc, argv); } - diff --git a/win32/win32support.h b/win32/win32support.h index 3140004..4a5f9b2 100644 --- a/win32/win32support.h +++ b/win32/win32support.h @@ -123,11 +123,11 @@ static inline struct hostent *w_gethostbyname(const char *n) { } #define gethostbyname(a) w_gethostbyname(a) -const char *wsa_strerror(int e); +const char *win32_strerror(int e); static inline const char *w_strerror(int e) { if (e > 900) - return wsa_strerror(e); + return win32_strerror(e); return strerror(e); } #define strerror(x) w_strerror(x) @@ -286,10 +286,6 @@ static inline int fcntl(int fd, int cmd, long arg) * syslog */ -#define openlog w_openlog -#define syslog w_syslog -#define closelog w_closelog - #define LOG_EMERG 0 #define LOG_ALERT 1 #define LOG_CRIT 2 @@ -322,10 +318,10 @@ static inline int fcntl(int fd, int cmd, long arg) #define LOG_LOCAL6 0 #define LOG_LOCAL7 0 - -void openlog(const char *ident, int option, int facility); -void syslog(int priority, const char *format, ...); -void closelog(void); +static inline void openlog(const char *ident, int option, int facility) {} +static inline void closelog(void) {} +void win32_eventlog(int priority, const char *format, ...); +#define syslog win32_eventlog /* redirect main() */ #define main(a,b) real_main(a,b)