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(&param, 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, &param);
+ }
+ #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, 
&param->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

Reply via email to