From 5b2f4afffe6972ecc61c506576f6e40787dc19ec Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 26 Jul 2004 01:48:00 +0000 Subject: [PATCH] Here is a patch that fixes the pipes used in find_other_exec() when running as a service on windows <= 2000. Required to make the pg_ctl service wrapper to work at all. Magnus Hagander --- doc/src/sgml/release.sgml | 4 +- src/port/exec.c | 142 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 128 insertions(+), 18 deletions(-) diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml index 10360fc1e5..b2c0be4eda 100644 --- a/doc/src/sgml/release.sgml +++ b/doc/src/sgml/release.sgml @@ -1,5 +1,5 @@ @@ -1271,7 +1271,7 @@ $PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.270 2004/07/26 00:26:42 momjian - New start/end of dump markers in pg_dump (Bruce) + New start/stop of dump markers in pg_dump (Bruce) diff --git a/src/port/exec.c b/src/port/exec.c index c8ba1227a1..d98da090c7 100644 --- a/src/port/exec.c +++ b/src/port/exec.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/port/exec.c,v 1.16 2004/06/10 22:26:24 momjian Exp $ + * $PostgreSQL: pgsql/src/port/exec.c,v 1.17 2004/07/26 01:48:00 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -279,6 +279,128 @@ find_my_exec(const char *argv0, char *retpath) #endif } +/* + * The runtime librarys popen() on win32 does not work when being + * called from a service when running on windows <= 2000, because + * there is no stdin/stdout/stderr. + * + * Executing a command in a pipe and reading the first line from it + * is all we need. + */ + +static char *pipe_read_line(char *cmd, char *line, int maxsize) +{ +#ifndef WIN32 + FILE *pgver; + + /* flush output buffers in case popen does not... */ + fflush(stdout); + fflush(stderr); + + if ((pgver = popen(cmd, "r")) == NULL) + return NULL; + + if (fgets(line, maxsize, pgver) == NULL) + { + perror("fgets failure"); + return NULL; + } + + if (pclose_check(pgver)) + return NULL; + + return line; +#else + /* Win32 */ + SECURITY_ATTRIBUTES sattr; + HANDLE childstdoutrd, childstdoutwr, childstdoutrddup; + PROCESS_INFORMATION pi; + STARTUPINFO si; + char *retval = NULL; + + sattr.nLength = sizeof(SECURITY_ATTRIBUTES); + sattr.bInheritHandle = TRUE; + sattr.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&childstdoutrd, &childstdoutwr, &sattr, 0)) + return NULL; + + if (!DuplicateHandle(GetCurrentProcess(), + childstdoutrd, + GetCurrentProcess(), + &childstdoutrddup, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + { + CloseHandle(childstdoutrd); + CloseHandle(childstdoutwr); + return NULL; + } + + CloseHandle(childstdoutrd); + + ZeroMemory(&pi,sizeof(pi)); + ZeroMemory(&si,sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdError = childstdoutwr; + si.hStdOutput = childstdoutwr; + si.hStdInput = INVALID_HANDLE_VALUE; + + if (CreateProcess(NULL, + cmd, + NULL, + NULL, + TRUE, + 0, + NULL, + NULL, + &si, + &pi)) + { + DWORD bytesread = 0; + /* Successfully started the process */ + + ZeroMemory(line,maxsize); + + /* Let's see if we can read */ + if (WaitForSingleObject(childstdoutrddup, 10000) != WAIT_OBJECT_0) + { + /* Got timeout */ + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + CloseHandle(childstdoutwr); + CloseHandle(childstdoutrddup); + return NULL; + } + + + /* We try just once */ + if (ReadFile(childstdoutrddup, line, maxsize, &bytesread, NULL) && + bytesread > 0) + { + /* So we read some data */ + retval = line; + + /* We emulate fgets() behaviour. So if there is no newline + * at the end, we add one... */ + if (line[strlen(line)-1] != '\n') + strcat(line,"\n"); + } + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + CloseHandle(childstdoutwr); + CloseHandle(childstdoutrddup); + + return retval; +#endif +} + + /* * Find our binary directory, then make sure the "target" executable @@ -290,14 +412,12 @@ find_other_exec(const char *argv0, const char *target, { char cmd[MAXPGPATH]; char line[100]; - FILE *pgver; - + if (find_my_exec(argv0, retpath) < 0) return -1; /* Trim off program name and keep just directory */ *last_dir_separator(retpath) = '\0'; - snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath), "/%s%s", target, EXE); @@ -306,19 +426,9 @@ find_other_exec(const char *argv0, const char *target, snprintf(cmd, sizeof(cmd), "\"%s\" -V 2>%s", retpath, DEVNULL); - /* flush output buffers in case popen does not... */ - fflush(stdout); - fflush(stderr); - - if ((pgver = popen(cmd, "r")) == NULL) - return -1; - - if (fgets(line, sizeof(line), pgver) == NULL) - perror("fgets failure"); - - if (pclose_check(pgver)) + if (!pipe_read_line(cmd, line, sizeof(line))) return -1; - + if (strcmp(line, versionstr) != 0) return -2; -- 2.11.0