On Tuesday, September 11, 2012 7:07 PM Amit Kapila wrote:
On Monday, September 10, 2012 8:20 PM Amit Kapila wrote:
On Sunday, September 09, 2012 1:37 PM Amit Kapila wrote:
On Friday, September 07, 2012 11:19 PM Tom Lane wrote:
Heikki Linnakangas <hlinn...@iki.fi> writes:
>>>> Would socketpair(2) be simpler?
>>>>I've not done anything yet about the potential security issues
>>>>associated with untrusted libpq connection strings. I think this
>>>is still at the proof-of-concept stage; in particular, it's probably
>>> time to see if we can make it work on Windows before we worry more
>>>about that.
>> I have started working on this patch to make it work on Windows. The 3
main things to make it work are:
>The patch which contains Windows implementation as well is attached with this
>mail. It contains changes related to following
>1. waitpid
>2. socketpair
>3. fork-exec
>The following is still left:
> 1. Error handling in all paths
The modified version 2 contains error handling in all paths.
With Regards,
Amit Kapila
*** a/src/backend/main/main.c
--- b/src/backend/main/main.c
***************
*** 191,196 **** main(int argc, char *argv[])
--- 191,198 ----
AuxiliaryProcessMain(argc, argv); /* does not
return */
else if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
GucInfoMain(); /* does not return */
+ else if (argc > 1 && strncmp(argv[1], "--child=", 8) == 0)
+ ChildPostgresMain(argc, argv, get_current_username(progname));
/* does not return */
else if (argc > 1 && strcmp(argv[1], "--single") == 0)
PostgresMain(argc, argv, get_current_username(progname)); /*
does not return */
else
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 463,468 **** typedef struct
--- 463,469 ----
static void read_backend_variables(char *id, Port *port);
static void restore_backend_variables(BackendParameters *param, Port *port);
+ static void read_standalone_child_variables(char *id, int *psock);
#ifndef WIN32
static bool save_backend_variables(BackendParameters *param, Port *port);
***************
*** 4268,4273 **** ExitPostmaster(int status)
--- 4269,4365 ----
proc_exit(status);
}
+
+ /*
+ * ChildPostgresMain - start a new-style standalone postgres process
+ *
+ * This may not belong here, but it does share a lot of code with ConnCreate
+ * and BackendInitialize. Basically what it has to do is set up a
+ * MyProcPort structure and then hand off control to PostgresMain.
+ * Beware that not very much stuff is initialized yet.
+ *
+ * In the future it might be interesting to support a "standalone
+ * multiprocess" mode in which we have a postmaster process that doesn't
+ * listen for connections, but does supervise autovacuum, bgwriter, etc
+ * auxiliary processes. So that's another reason why postmaster.c might be
+ * the right place for this.
+ */
+ void
+ ChildPostgresMain(int argc, char *argv[], const char *username)
+ {
+ Port *port;
+ #ifdef WIN32
+ char paramHandleStr[32];
+ #endif
+
+ /*
+ * Fire up essential subsystems: error and memory management
+ */
+ MemoryContextInit();
+
+ /*
+ * Build a Port structure for the client connection
+ */
+ if (!(port = (Port *) calloc(1, sizeof(Port))))
+ ereport(FATAL,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+
+ /*
+ * GSSAPI specific state struct must exist even though we won't use it
+ */
+ #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
+ port->gss = (pg_gssinfo *) calloc(1, sizeof(pg_gssinfo));
+ if (!port->gss)
+ ereport(FATAL,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+ #endif
+
+ #ifndef WIN32
+ /* The file descriptor of the client socket is the argument of --child
*/
+ if (sscanf(argv[1], "--child=%d", &port->sock) != 1)
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid argument for --child: \"%s\"",
argv[1])));
+ #else
+ /* The file descriptor of the client socket is the argument of --child */
+ if (sscanf(argv[1], "--child=%s", paramHandleStr) != 1)
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid argument for --child: \"%s\"",
argv[1])));
+
+ read_standalone_child_variables(paramHandleStr, &port->sock);
+
+ #endif
+
+ /* Default assumption about protocol to use */
+ FrontendProtocol = port->proto = PG_PROTOCOL_LATEST;
+
+ /* save process start time */
+ port->SessionStartTime = GetCurrentTimestamp();
+ MyStartTime = timestamptz_to_time_t(port->SessionStartTime);
+
+ /* set these to empty in case they are needed */
+ port->remote_host = "";
+ port->remote_port = "";
+
+ MyProcPort = port;
+
+ /*
+ * We can now initialize libpq and then enable reporting of ereport
errors
+ * to the client.
+ */
+ pq_init(); /* initialize libpq to
talk to client */
+ whereToSendOutput = DestRemote; /* now safe to ereport to client */
+
+ /* And pass off control to PostgresMain */
+ PostgresMain(argc, argv, username);
+
+ abort(); /* not reached */
+ }
+
+
/*
* sigusr1_handler - handle signal conditions from child processes
*/
***************
*** 5073,5078 **** restore_backend_variables(BackendParameters *param, Port
*port)
--- 5165,5211 ----
}
+ #ifdef WIN32
+ static void
+ read_standalone_child_variables(char *id, int *psock)
+ {
+ HANDLE paramHandle;
+ InheritableSocket param;
+ InheritableSocket *paramp;
+
+ /* Win32 version uses mapped file */
+ #ifdef _WIN64
+ paramHandle = (HANDLE) _atoi64(id);
+ #else
+ paramHandle = (HANDLE) atol(id);
+ #endif
+ paramp = MapViewOfFile(paramHandle, FILE_MAP_READ, 0, 0, 0);
+ if (!paramp)
+ {
+ write_stderr("could not map view of standalone child variables:
error code %lu\n",
+ GetLastError());
+ exit(1);
+ }
+
+ memcpy(¶m, paramp, sizeof(InheritableSocket));
+
+ if (!UnmapViewOfFile(paramp))
+ {
+ write_stderr("could not unmap view of standalone child
variables: error code %lu\n",
+ GetLastError());
+ exit(1);
+ }
+
+ if (!CloseHandle(paramHandle))
+ {
+ write_stderr("could not close handle to standalone child
parameter variables: error code %lu\n",
+ GetLastError());
+ exit(1);
+ }
+
+ read_inheritable_socket(psock, ¶m);
+ }
+ #endif
Size
ShmemBackendArraySize(void)
{
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
***************
*** 3257,3264 **** process_postgres_switches(int argc, char *argv[], GucContext
ctx)
{
gucsource = PGC_S_ARGV; /* switches came from command line */
! /* Ignore the initial --single argument, if present */
! if (argc > 1 && strcmp(argv[1], "--single") == 0)
{
argv++;
argc--;
--- 3257,3266 ----
{
gucsource = PGC_S_ARGV; /* switches came from command line */
! /* Ignore the initial --single or --child argument, if present
*/
! if (argc > 1 &&
! (strcmp(argv[1], "--single") == 0 ||
! strncmp(argv[1], "--child=", 8) == 0))
{
argv++;
argc--;
***************
*** 3522,3539 **** PostgresMain(int argc, char *argv[], const char *username)
* standalone).
*/
if (!IsUnderPostmaster)
- {
MyProcPid = getpid();
MyStartTime = time(NULL);
- }
/*
* Fire up essential subsystems: error and memory management
*
! * If we are running under the postmaster, this is done already.
*/
! if (!IsUnderPostmaster)
MemoryContextInit();
SetProcessingMode(InitProcessing);
--- 3524,3541 ----
* standalone).
*/
if (!IsUnderPostmaster)
MyProcPid = getpid();
+ if (MyProcPort == NULL)
MyStartTime = time(NULL);
/*
* Fire up essential subsystems: error and memory management
*
! * If we are running under the postmaster, this is done already;
likewise
! * in child-postgres mode.
*/
! if (MyProcPort == NULL)
MemoryContextInit();
SetProcessingMode(InitProcessing);
*** a/src/include/postmaster/postmaster.h
--- b/src/include/postmaster/postmaster.h
***************
*** 47,52 **** extern int postmaster_alive_fds[2];
--- 47,55 ----
extern const char *progname;
extern void PostmasterMain(int argc, char *argv[]) __attribute__((noreturn));
+
+ extern void ChildPostgresMain(int argc, char *argv[], const char *username)
__attribute__((noreturn));
+
extern void ClosePostmasterPorts(bool am_syslogger);
extern int MaxLivePostmasterChildren(void);
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***************
*** 17,22 ****
--- 17,23 ----
#include <sys/types.h>
#include <sys/stat.h>
+ #include <sys/wait.h>
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
***************
*** 259,264 **** static const PQconninfoOption PQconninfoOptions[] = {
--- 260,271 ----
{"replication", NULL, NULL, NULL,
"Replication", "D", 5},
+ {"standalone_datadir", NULL, NULL, NULL,
+ "Standalone-Data-Directory", "D", 64},
+
+ {"standalone_backend", NULL, NULL, NULL,
+ "Standalone-Backend", "D", 64},
+
/* Terminating entry --- MUST BE LAST */
{NULL, NULL, NULL, NULL,
NULL, NULL, 0}
***************
*** 360,365 **** pqDropConnection(PGconn *conn)
--- 367,393 ----
if (conn->sock >= 0)
closesocket(conn->sock);
conn->sock = -1;
+ /* If we forked a child postgres process, wait for it to exit */
+ if (conn->postgres_pid > 0)
+ {
+ #ifdef WIN32
+ while (WaitForSingleObject(conn->proc_handle, INFINITE) !=
WAIT_OBJECT_0)
+ {
+ _dosmaperr(GetLastError());
+ /* If interrupted by signal, keep waiting */
+ if (errno != EINTR)
+ break;
+ }
+ #else
+ while (waitpid(conn->postgres_pid, NULL, 0) < 0)
+ {
+ /* If interrupted by signal, keep waiting */
+ if (errno != EINTR)
+ break;
+ }
+ #endif
+ }
+ conn->postgres_pid = -1;
/* Discard any unread/unsent data */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
***************
*** 643,648 **** fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
--- 671,680 ----
conn->pghost = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "port");
conn->pgport = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "standalone_datadir");
+ conn->standalone_datadir = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "standalone_backend");
+ conn->standalone_backend = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "tty");
conn->pgtty = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "options");
***************
*** 1311,1316 **** setKeepalivesWin32(PGconn *conn)
--- 1343,1682 ----
#endif /* SIO_KEEPALIVE_VALS */
#endif /* WIN32 */
+ #ifdef WIN32
+ int
+ pgsockpair(int handles[2], PGconn *conn)
+ {
+ SOCKET s;
+ struct sockaddr_in serv_addr;
+ int len = sizeof(serv_addr);
+
+ handles[0] = handles[1] = INVALID_SOCKET;
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("pgsockpair could not create
socket: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+
+ return -1;
+ }
+
+ memset((void *) &serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(0);
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (bind(s, (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("pgsockpair
could not bind: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+
+ closesocket(s);
+ return -1;
+ }
+ if (listen(s, 1) == SOCKET_ERROR)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("pgsockpair
could not listen: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+ closesocket(s);
+ return -1;
+ }
+ if (getsockname(s, (SOCKADDR *) & serv_addr, &len) == SOCKET_ERROR)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("pgsockpair could not
getsockname: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+ closesocket(s);
+ return -1;
+ }
+ if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("pgsockpair could not create
socket 2: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+
+ closesocket(s);
+ return -1;
+ }
+
+ if (connect(handles[1], (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("pgsockpair could not connect
socket: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+ closesocket(s);
+ return -1;
+ }
+ if ((handles[0] = accept(s, (SOCKADDR *) & serv_addr, &len)) ==
INVALID_SOCKET)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("pgsockpair could not accept
socket: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+ closesocket(handles[1]);
+ handles[1] = INVALID_SOCKET;
+ closesocket(s);
+ return -1;
+ }
+ closesocket(s);
+ return 0;
+ }
+
+ /*
+ * Fork and exec a command, connecting up a pair of anonymous sockets for
+ * communication. argv[fdarg] is modified by appending the child-side
+ * socket's file descriptor number. The parent-side socket's FD is returned
+ * in *psock, and the function result is the child's PID.
+ */
+ static pid_t
+ fork_backend_child(char **argv, int fdarg, PGconn *conn)
+ {
+ int socks[2];
+ char newfdarg[32];
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ int i;
+ int j;
+ char cmdLine[MAXPGPATH * 2];
+ typedef struct
+ {
+ SOCKET origsocket; /* Original socket value, or
PGINVALID_SOCKET
+ * if not a
socket */
+ WSAPROTOCOL_INFO wsainfo;
+ } InheritableSocket;
+ InheritableSocket *param;
+ HANDLE paramHandle;
+ SECURITY_ATTRIBUTES sa;
+ char paramHandleStr[32];
+
+
+ if (pgsockpair(socks, conn) < 0)
+ return -1;
+
+ /* Set up shared memory for parameter passing */
+ ZeroMemory(&sa, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ paramHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
+ &sa,
+
PAGE_READWRITE,
+ 0,
+
sizeof(InheritableSocket),
+ NULL);
+ if (paramHandle == INVALID_HANDLE_VALUE)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not
create standalone backend parameter file mapping: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+ return -1;
+ }
+
+ param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0,
sizeof(InheritableSocket));
+ if (!param)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not map backend parameter
memory: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+
+ CloseHandle(paramHandle);
+ return -1;
+ }
+
+ /* Insert temp file name instead of sockid incase of windows */
+ #ifdef _WIN64
+ sprintf(paramHandleStr, "%llu", (LONG_PTR) paramHandle);
+ #else
+ sprintf(paramHandleStr, "%lu", (DWORD) paramHandle);
+ #endif
+
+ snprintf(newfdarg, sizeof(newfdarg), "%s%s", argv[fdarg],
paramHandleStr);
+ argv[fdarg] = newfdarg;
+
+ /* Format the cmd line */
+ cmdLine[sizeof(cmdLine) - 1] = '\0';
+ cmdLine[sizeof(cmdLine) - 2] = '\0';
+ snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", argv[0]);
+
+ i = 0;
+ while (argv[++i] != NULL)
+ {
+ j = strlen(cmdLine);
+ snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"",
argv[i]);
+ }
+ if (cmdLine[sizeof(cmdLine) - 2] != '\0')
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("subprocess command line
too long: %s\n"));
+
+ return -1;
+ }
+
+ memset(&pi, 0, sizeof(pi));
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi))
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("CreateProcess
call failed: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+
+ return -1;
+ }
+
+
+ param->origsocket = socks[0];
+ if (socks[0] != 0 && socks[0] != PGINVALID_SOCKET)
+ {
+ /* Actual socket */
+ if (WSADuplicateSocket(socks[0], pi.dwProcessId,
¶m->wsainfo) != 0)
+ {
+ char sebuf[256];
+
+ if (!TerminateProcess(pi.hProcess, 255))
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not terminate unstarted
process: %s\n"),
+
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return -1;
+ }
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not duplicate
the socket: %s\n"),
+
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return -1;
+ }
+ }
+
+ /*
+ * Drop the parameter shared memory that is now inherited to the
+ * standalone chile
+ */
+ if (!UnmapViewOfFile(param))
+ {
+ char sebuf[256];
+
+ fprintf(stderr,
+ libpq_gettext("WARNING: could not unmap view of
standalone child variables: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO, sebuf,
sizeof(sebuf)));
+ }
+
+ if (!CloseHandle(paramHandle))
+ {
+ char sebuf[256];
+
+ fprintf(stderr,
+ libpq_gettext("WARNING: could not close handle
of standalone child variables: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO, sebuf,
sizeof(sebuf)));
+ }
+
+ /*
+ * Now that the socket information is shared, we start the child thread
+ */
+ if (ResumeThread(pi.hThread) == -1)
+ {
+ char sebuf[256];
+
+ if (!TerminateProcess(pi.hProcess, 255))
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not terminate unstarted
process: %s\n"),
+
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return -1;
+ }
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not resume thread of unstarted process:
%s\n"),
+ SOCK_STRERROR(SOCK_ERRNO,
sebuf, sizeof(sebuf)));
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return -1;
+ }
+ /* Don't close pi.hProcess here - the wait thread needs access to it */
+ CloseHandle(pi.hThread);
+
+ conn->sock = socks[1];
+ conn->proc_handle = pi.hProcess;
+ return pi.dwProcessId;
+ }
+ #else
+
+ /*
+ * Fork and exec a command, connecting up a pair of anonymous sockets for
+ * communication. argv[fdarg] is modified by appending the child-side
+ * socket's file descriptor number. The parent-side socket's FD is returned
+ * in *psock, and the function result is the child's PID.
+ */
+ static pid_t
+ fork_backend_child(char **argv, int fdarg, int *psock)
+ {
+ pid_t pid;
+ int socks[2];
+ char newfdarg[32];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0)
+ return -1;
+
+ pid = fork();
+
+ if (pid < 0)
+ {
+ /* fork failed */
+ close(socks[0]);
+ close(socks[1]);
+ return pid;
+ }
+ else if (pid == 0)
+ {
+ /* successful, in child process */
+ close(socks[1]);
+ snprintf(newfdarg, sizeof(newfdarg), "%s%d", argv[fdarg],
socks[0]);
+ argv[fdarg] = newfdarg;
+ execv(argv[0], argv);
+ perror(argv[0]);
+ exit(1);
+ }
+ else
+ {
+ /* successful, in parent process */
+ close(socks[0]);
+ *psock = socks[1];
+ }
+
+ return pid;
+ }
+ #endif
+
/* ----------
* connectDBStart -
* Begin the process of making a connection to the backend.
***************
*** 1339,1344 **** connectDBStart(PGconn *conn)
--- 1705,1765 ----
conn->outCount = 0;
/*
+ * If the standalone_datadir option was specified, ignore any host or
+ * port specifications and just try to fork a standalone backend.
+ */
+ if (conn->standalone_datadir && conn->standalone_datadir[0])
+ {
+ char *be_argv[10];
+
+ /*
+ * We set up the backend's command line in execv(3) style, so
that
+ * we don't need to cope with shell quoting rules.
+ */
+ if (conn->standalone_backend && conn->standalone_backend[0])
+ be_argv[0] = conn->standalone_backend;
+ else /* assume we should use
hard-wired path */
+ be_argv[0] = PGBINDIR "/postgres";
+
+ be_argv[1] = "--child=";
+ be_argv[2] = "-D";
+ be_argv[3] = conn->standalone_datadir;
+ be_argv[4] = (conn->dbName && conn->dbName[0]) ? conn->dbName :
NULL;
+ be_argv[5] = NULL;
+
+ #ifdef WIN32
+ conn->postgres_pid = fork_backend_child(be_argv, 1, conn);
+ if (conn->postgres_pid < 0)
+ goto connect_errReturn;
+ #else
+ conn->postgres_pid = fork_backend_child(be_argv, 1,
&conn->sock);
+ if (conn->postgres_pid < 0)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not fork
standalone backend: %s\n"),
+ pqStrerror(errno,
sebuf, sizeof(sebuf)));
+ goto connect_errReturn;
+ }
+ #endif
+
+ /*
+ * Go directly to CONNECTION_AUTH_OK state, since the standalone
+ * backend is not going to issue any authentication challenge
to us.
+ * We're just waiting for startup to conclude.
+ */
+ #ifdef USE_SSL
+ conn->allow_ssl_try = false;
+ #endif
+ conn->pversion = PG_PROTOCOL(3, 0);
+ conn->status = CONNECTION_AUTH_OK;
+ conn->asyncStatus = PGASYNC_BUSY;
+
+ return 1;
+ }
+
+ /*
* Determine the parameters to pass to pg_getaddrinfo_all.
*/
***************
*** 2708,2713 **** makeEmptyPGconn(void)
--- 3129,3135 ----
conn->auth_req_received = false;
conn->password_needed = false;
conn->dot_pgpass_used = false;
+ conn->postgres_pid = -1;
#ifdef USE_SSL
conn->allow_ssl_try = true;
conn->wait_ssl_try = false;
***************
*** 2784,2789 **** freePGconn(PGconn *conn)
--- 3206,3215 ----
free(conn->pgport);
if (conn->pgunixsocket)
free(conn->pgunixsocket);
+ if (conn->standalone_datadir)
+ free(conn->standalone_datadir);
+ if (conn->standalone_backend)
+ free(conn->standalone_backend);
if (conn->pgtty)
free(conn->pgtty);
if (conn->connect_timeout)
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
***************
*** 303,308 **** struct pg_conn
--- 303,310 ----
char *pgunixsocket; /* the Unix-domain socket that the
server is
* listening
on; if NULL, uses a default
* constructed
from pgport */
+ char *standalone_datadir; /* data directory for standalone
backend */
+ char *standalone_backend; /* executable for standalone backend */
char *pgtty; /* tty on which the backend
messages is
* displayed
(OBSOLETE, NOT USED) */
char *connect_timeout; /* connection timeout (numeric string)
*/
***************
*** 373,378 **** struct pg_conn
--- 375,383 ----
bool sigpipe_so; /* have we masked SIGPIPE via
SO_NOSIGPIPE? */
bool sigpipe_flag; /* can we mask SIGPIPE via
MSG_NOSIGNAL? */
+ /* If we forked a child postgres process, its PID is kept here */
+ pid_t postgres_pid; /* PID, or -1 if none */
+
/* Transient state needed while establishing connection */
struct addrinfo *addrlist; /* list of possible backend addresses */
struct addrinfo *addr_cur; /* the one currently being tried */
***************
*** 415,420 **** struct pg_conn
--- 420,429 ----
/* Status for asynchronous result construction */
PGresult *result; /* result being constructed */
PGresult *next_result; /* next result (used in single-row
mode) */
+ #ifdef WIN32
+ /* If we forked a child postgres process, process handle */
+ HANDLE proc_handle;
+ #endif
/* Assorted state for SSL, GSS, etc */
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers