* 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 <windows.h>
#include <winsock2.h>
#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"
-" <windows service registration>\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)
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);
}
/*
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 <servicename>\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 */
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)
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);
}
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);
}
-