PostgreSQL virtual hosting support

Started by David J. MacKenzieover 25 years ago29 messages
#1David J. MacKenzie
djm@web.us.uu.net

Your name : David MacKenzie
Your email address : djm@web.us.uu.net

System Configuration
---------------------
Architecture (example: Intel Pentium) : Intel x86

Operating System (example: Linux 2.0.26 ELF) : BSD/OS 4.0.1

PostgreSQL version (example: PostgreSQL-7.0): PostgreSQL-7.0.2

Compiler used (example: gcc 2.8.0) : gcc version 2.7.2.1

Please enter a FULL description of your problem:
------------------------------------------------

UUNET is looking into offering PostgreSQL as a part of a managed web
hosting product, on both shared and dedicated machines. We currently
offer Oracle and MySQL, and it would be a nice middle-ground.
However, as shipped, PostgreSQL lacks the following features we need
that MySQL has:

1. The ability to listen only on a particular IP address. Each
hosting customer has their own IP address, on which all of their
servers (http, ftp, real media, etc.) run.
2. The ability to place the Unix-domain socket in a mode 700 directory.
This allows us to automatically create an empty database, with an
empty DBA password, for new or upgrading customers without having
to interactively set a DBA password and communicate it to (or from)
the customer. This in turn cuts down our install and upgrade times.
3. The ability to connect to the Unix-domain socket from within a
change-rooted environment. We run CGI programs chrooted to the
user's home directory, which is another reason why we need to be
able to specify where the Unix-domain socket is, instead of /tmp.
4. The ability to, if run as root, open a pid file in /var/run as
root, and then setuid to the desired user. (mysqld -u can almost
do this; I had to patch it, too).

The patch below fixes problem 1-3. I plan to address #4, also, but
haven't done so yet. These diffs are big enough that they should give
the PG development team something to think about in the meantime :-)
Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get
out what I have, which works (for the problems it tackles), now.

With these changes, we can set up and run PostgreSQL with scripts the
same way we can with apache or proftpd or mysql.

In summary, this patch makes the following enhancements:

1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT,
and command line options -k --unix-socket to the relevant programs.
2. Adds a -h option to postmaster to set the hostname or IP address to
listen on instead of the default INADDR_ANY.
3. Extends some library interfaces to support the above.
4. Fixes a few memory leaks in PQconnectdb().

The default behavior is unchanged from stock 7.0.2; if you don't use
any of these new features, they don't change the operation.

Index: doc/src/sgml/layout.sgml
*** doc/src/sgml/layout.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/layout.sgml	2000/07/02 03:56:05	1.2
***************
*** 55,61 ****
  For example, if the database server machine is a remote machine, you
  will need to set the <envar>PGHOST</envar> environment variable to the name
  of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> may also have to be set.  The bottom line is this: if
  you try to start an application  program  and  it  complains
  that it cannot connect to the <Application>postmaster</Application>,
  you must go back and make sure that your
--- 55,62 ----
  For example, if the database server machine is a remote machine, you
  will need to set the <envar>PGHOST</envar> environment variable to the name
  of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> or <envar>PGUNIXSOCKET</envar> may also have to be set.
! The bottom line is this: if
  you try to start an application  program  and  it  complains
  that it cannot connect to the <Application>postmaster</Application>,
  you must go back and make sure that your
Index: doc/src/sgml/libpq++.sgml
*** doc/src/sgml/libpq++.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq++.sgml	2000/07/02 03:56:05	1.2
***************
*** 93,98 ****
--- 93,105 ----
        </listitem>
        <listitem>
         <para>
+ 	<envar>PGUNIXSOCKET</envar>  sets the full Unix domain socket
+ 	file name for communicating with the <productname>Postgres</productname>
+ 	backend.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
  	<envar>PGDATABASE</envar>  sets the default 
  	<productname>Postgres</productname> database name.
         </para>
Index: doc/src/sgml/libpq.sgml
*** doc/src/sgml/libpq.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq.sgml	2000/07/02 03:56:05	1.2
***************
*** 134,139 ****
--- 134,148 ----
      </varlistentry>
      <varlistentry>
+      <term><literal>unixsocket</literal></term>
+      <listitem>
+      <para>
+       Full path to Unix-domain socket file to connect to at the server host.
+      </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
       <term><literal>dbname</literal></term>
       <listitem>
       <para>
***************
*** 545,550 ****
--- 554,569 ----
  <listitem>
  <para>
+ <function>PQunixsocket</function>
+          Returns the name of the Unix-domain socket of the connection.
+ <synopsis>
+ char *PQunixsocket(const PGconn *conn)
+ </synopsis>
+ </para>
+ </listitem>
+ 
+ <listitem>
+ <para>
  <function>PQtty</function>
           Returns the debug tty of the connection.
  <synopsis>
***************
*** 1772,1777 ****
--- 1791,1803 ----
  <envar>PGHOST</envar> sets the default server name.
  If a non-zero-length string is specified, TCP/IP communication is used.
  Without a host name, libpq will connect using a local Unix domain socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <envar>PGPORT</envar>  sets the default port or local Unix domain socket
+ file extension for communicating with the <productname>Postgres</productname>
+ backend.
  </para>
  </listitem>
  <listitem>
Index: doc/src/sgml/start.sgml
*** doc/src/sgml/start.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/start.sgml	2000/07/02 03:56:05	1.2
***************
*** 110,117 ****
      will need to set the <acronym>PGHOST</acronym> environment
      variable to the name
      of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> may also have to be set.  The bottom
!     line is this: if
      you try to start an application  program  and  it  complains
      that it cannot connect to the <application>postmaster</application>,
      you should immediately consult your site administrator to make
--- 110,117 ----
      will need to set the <acronym>PGHOST</acronym> environment
      variable to the name
      of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> or <acronym>PGUNIXSOCKET</acronym> may also have to be set.
!     The bottom line is this: if
      you try to start an application  program  and  it  complains
      that it cannot connect to the <application>postmaster</application>,
      you should immediately consult your site administrator to make
Index: doc/src/sgml/ref/createdb.sgml
*** doc/src/sgml/ref/createdb.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
        </listitem>
       </varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/createlang.sgml
*** doc/src/sgml/ref/createlang.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createlang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
        </listitem>
       </varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/createuser.sgml
*** doc/src/sgml/ref/createuser.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,76 ----
        </listitem>
       </varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-e, --echo</term>
        <listitem>
Index: doc/src/sgml/ref/dropdb.sgml
*** doc/src/sgml/ref/dropdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
        </listitem>
       </varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/droplang.sgml
*** doc/src/sgml/ref/droplang.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/droplang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
        </listitem>
       </varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/dropuser.sgml
*** doc/src/sgml/ref/dropuser.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
        </listitem>
       </varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-e, --echo</term>
        <listitem>
Index: doc/src/sgml/ref/pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dump.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ]
      [ -t <replaceable class="parameter">table</replaceable> ]
      [ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
      [ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
--- 24,32 ----
    </refsynopsisdivinfo>
    <synopsis>
  pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ]
!     [ -k <replaceable class="parameter">path</replaceable> ]
!     [ -p <replaceable class="parameter">port</replaceable> ]
      [ -t <replaceable class="parameter">table</replaceable> ]
      [ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
      [ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
***************
*** 200,205 ****
--- 202,222 ----
  	<application>postmaster</application>
  	is running.  Defaults to using a local Unix domain socket
  	rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/ref/pg_dumpall.sgml
*** doc/src/sgml/ref/pg_dumpall.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dumpall.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
    </synopsis>
    <refsect2 id="R2-APP-PG-DUMPALL-1">
--- 24,33 ----
    </refsynopsisdivinfo>
    <synopsis>
  pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ]
!      [ -k <replaceable class="parameter">path</replaceable> ]
!      [ -p <replaceable class="parameter">port</replaceable> ]
!      [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
    </synopsis>
    <refsect2 id="R2-APP-PG-DUMPALL-1">
***************
*** 137,142 ****
--- 140,160 ----
  	<application>postmaster</application>
  	is running.  Defaults to using a local Unix domain socket
  	rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/ref/postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/postmaster.sgml	2000/07/06 07:48:31	1.7
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ] [ -i ] [ -l ]
      [ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
    </synopsis>
--- 24,32 ----
    </refsynopsisdivinfo>
    <synopsis>
  postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ]
!     [ -h <replaceable class="parameter">hostname</replaceable> ] [ -i ]
!     [ -k <replaceable class="parameter">path</replaceable> ] [ -l ]
      [ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
    </synopsis>
***************
*** 124,129 ****
--- 126,161 ----
       </varlistentry>
       <varlistentry>
+       <term>-h <replaceable class="parameter">hostName</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the TCP/IP hostname or address
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGHOST</envar> 
+ 	environment variable, or if <envar>PGHOST</envar>
+ 	is not set, then defaults to "all", meaning listen on all configured addresses
+ 	(including localhost).
+        </para>
+        <para>
+ 	If you use a hostname or address other than "all", do not try to run
+ 	multiple instances of <application>postmaster</application> on the
+ 	same IP address but different ports.  Doing so will result in them
+ 	attempting (incorrectly) to use the same shared memory segments.
+ 	Also, if you use a hostname other than "all", all of the host's IP addresses
+ 	on which <application>postmaster</application> instances are
+ 	listening must be distinct in the two last octets.
+        </para>
+        <para>
+ 	If you do use "all" (the default), then each instance must listen on a
+ 	different port (via -p or <envar>PGPORT</envar>).  And, of course, do
+ 	not try to use both approaches on one host.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term>-i</term>
        <listitem>
         <para>
***************
*** 135,140 ****
--- 167,201 ----
       </varlistentry>
       <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket path name
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGUNIXSOCKET</envar> 
+ 	environment variable, or if <envar>PGUNIXSOCKET</envar>
+ 	is not set, then defaults to a file in <filename>/tmp</filename>
+ 	constructed from the port number.
+        </para>
+        <para>
+         You can use this option to put the Unix-domain socket in a
+         directory that is private to one or more users using Unix
+ 	directory permissions.  This is necessary for securely
+ 	creating databases automatically on shared machines.
+         In that situation, also disallow all TCP/IP connections
+ 	initially in <filename>pg_hba.conf</filename>.
+ 	If you specify a socket path other than the
+ 	default then all frontend applications (including
+ 	<application>psql</application>) must specify the same
+ 	socket path using either command-line options or
+ 	<envar>PGUNIXSOCKET</envar>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term>-l</term>
        <listitem>
         <para>
Index: doc/src/sgml/ref/psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/psql-ref.sgml	2000/07/02 03:56:05	1.3
***************
*** 1329,1334 ****
--- 1329,1347 ----
      <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
+ 
+     <varlistentry>
        <term>-H, --html</term>
        <listitem>
        <para>
Index: doc/src/sgml/ref/vacuumdb.sgml
*** doc/src/sgml/ref/vacuumdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/vacuumdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --alldb | -a ] [ --verbose | -v ]
      [ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
    </synopsis>
--- 24,30 ----
    </refsynopsisdivinfo>
    <synopsis>
  vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --all | -a ] [ --verbose | -v ]
      [ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
    </synopsis>
***************
*** 128,133 ****
--- 128,145 ----
         </para>
        </listitem>
       </varlistentry>
+ 
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
       <varlistentry>
        <term>-U <replaceable class="parameter">username</replaceable></term>
Index: src/backend/libpq/pqcomm.c
*** src/backend/libpq/pqcomm.c	2000/06/30 21:15:40	1.1
--- src/backend/libpq/pqcomm.c	2000/07/01 18:50:46	1.3
***************
*** 42,47 ****
--- 42,48 ----
   *		StreamConnection	- Create new connection with client
   *		StreamClose			- Close a client/backend connection
   *		pq_getport		- return the PGPORT setting
+  *		pq_getunixsocket	- return the PGUNIXSOCKET setting
   *		pq_init			- initialize libpq at backend startup
   *		pq_close		- shutdown libpq at backend exit
   *
***************
*** 134,139 ****
--- 135,151 ----
  }
  /* --------------------------------
+  *		pq_getunixsocket - return the PGUNIXSOCKET setting.
+  *		If NULL, default to computing it based on the port.
+  * --------------------------------
+  */
+ char *
+ pq_getunixsocket(void)
+ {
+ 	return getenv("PGUNIXSOCKET");
+ }
+ 
+ /* --------------------------------
   *		pq_close - shutdown libpq at backend exit
   *
   * Note: in a standalone backend MyProcPort will be null,
***************
*** 177,189 ****
  /*
   * StreamServerPort -- open a sock stream "listening" port.
   *
!  * This initializes the Postmaster's connection-accepting port.
   *
   * RETURNS: STATUS_OK or STATUS_ERROR
   */
  int
! StreamServerPort(char *hostName, unsigned short portName, int *fdP)
  {
  	SockAddr	saddr;
  	int			fd,
--- 189,205 ----
  /*
   * StreamServerPort -- open a sock stream "listening" port.
   *
!  * This initializes the Postmaster's connection-accepting port fdP.
!  * If hostName is "any", listen on all configured IP addresses.
!  * If hostName is NULL, listen on a Unix-domain socket instead of TCP;
!  * if unixSocketName is NULL, a default path (constructed in UNIX_SOCK_PATH
!  * in include/libpq/pqcomm.h) based on portName is used.
   *
   * RETURNS: STATUS_OK or STATUS_ERROR
   */

int
! StreamServerPort(char *hostName, unsigned short portNumber, char *unixSocketName, int *fdP)
{
SockAddr saddr;
int fd,
***************
*** 227,233 ****
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! len = UNIXSOCK_PATH(saddr.un, portName);
strcpy(sock_path, saddr.un.sun_path);

  		/*
--- 243,250 ----
  	saddr.sa.sa_family = family;
  	if (family == AF_UNIX)
  	{
! 		UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
! 		len = UNIXSOCK_LEN(saddr.un);
  		strcpy(sock_path, saddr.un.sun_path);
  		/*
***************
*** 259,267 ****
  	}
  	else
  	{
! 		saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 		saddr.in.sin_port = htons(portName);
! 		len = sizeof(struct sockaddr_in);
  	}
  	err = bind(fd, &saddr.sa, len);
  	if (err < 0)
--- 276,305 ----
  	}
  	else
  	{
! 	  /* TCP/IP socket */
! 	  if (!strcmp(hostName, "all")) /* like for databases in pg_hba.conf.  */
! 	    saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 	  else
! 	    {
! 	      struct hostent *hp;
! 
! 	      hp = gethostbyname(hostName);
! 	      if ((hp == NULL) || (hp->h_addrtype != AF_INET))
! 		{
! 		  snprintf(PQerrormsg, PQERRORMSG_LENGTH,
! 			   "FATAL: StreamServerPort: gethostbyname(%s) failed: %s\n",
! 			   hostName, hstrerror(h_errno));
! 		  fputs(PQerrormsg, stderr);
! 		  pqdebug("%s", PQerrormsg);
! 		  return STATUS_ERROR;
! 		}
! 	      memmove((char *) &(saddr.in.sin_addr),
! 		      (char *) hp->h_addr,
! 		      hp->h_length);
! 	    }
! 
! 	  saddr.in.sin_port = htons(portNumber);
! 	  len = sizeof(struct sockaddr_in);
  	}
  	err = bind(fd, &saddr.sa, len);
  	if (err < 0)
Index: src/backend/postmaster/postmaster.c
*** src/backend/postmaster/postmaster.c	2000/06/30 21:15:42	1.1
--- src/backend/postmaster/postmaster.c	2000/07/06 07:38:21	1.5
***************
*** 136,143 ****
  /* list of ports associated with still open, but incomplete connections */
  static Dllist *PortList;

! static unsigned short PostPortName = 0;

   /*
    * This is a boolean indicating that there is at least one backend that
    * is accessing the current shared memory and semaphores. Between the
--- 136,150 ----
  /* list of ports associated with still open, but incomplete connections */
  static Dllist *PortList;

! /* Hostname of interface to listen on, or 'any'. */
! static char *HostName = NULL;

+ /* TCP/IP port number to listen on.  Also used to default the Unix-domain socket name.  */
+ static unsigned short PostPortNumber = 0;
+ 
+ /* Override of the default Unix-domain socket name to listen on, if non-NULL.  */
+ static char *UnixSocketName = NULL;
+ 
   /*
    * This is a boolean indicating that there is at least one backend that
    * is accessing the current shared memory and semaphores. Between the
***************
*** 274,280 ****
  static void SignalChildren(SIGNAL_ARGS);
  static int	CountChildren(void);
  static int
! SetOptsFile(char *progname, int port, char *datadir,
  			int assert, int nbuf, char *execfile,
  			int debuglvl, int netserver,
  #ifdef USE_SSL
--- 281,287 ----
  static void SignalChildren(SIGNAL_ARGS);
  static int	CountChildren(void);
  static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
  			int assert, int nbuf, char *execfile,
  			int debuglvl, int netserver,
  #ifdef USE_SSL
***************
*** 370,380 ****
  {
  	extern int	NBuffers;		/* from buffer/bufmgr.c */
  	int			opt;
- 	char	   *hostName;
  	int			status;
  	int			silentflag = 0;
  	bool		DataDirOK;		/* We have a usable PGDATA value */
- 	char		hostbuf[MAXHOSTNAMELEN];
  	int			nonblank_argc;
  	char		original_extraoptions[MAXPGPATH];
--- 377,385 ----
***************
*** 431,449 ****
  	 */
  	umask((mode_t) 0077);

- if (!(hostName = getenv("PGHOST")))
- {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

  	opterr = 0;
  	IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:ilm:MN:no:p:Ss")) != EOF)
  	{
  		switch (opt)
  		{
--- 436,447 ----
  	 */
  	umask((mode_t) 0077);

MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

  	opterr = 0;
  	IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:h:ik:lm:MN:no:p:Ss")) != EOF)
  	{
  		switch (opt)
  		{
***************
*** 498,506 ****
--- 496,511 ----
  				DebugLvl = atoi(optarg);
  				pg_options[TRACE_VERBOSE] = DebugLvl;
  				break;
+ 			case 'h':
+ 				HostName = optarg;
+ 				break;
  			case 'i':
  				NetServer = true;
  				break;
+ 			case 'k':
+ 				/* Set PGUNIXSOCKET by hand. */
+ 				UnixSocketName = optarg;
+ 				break;
  #ifdef USE_SSL
  			case 'l':
  				SecureNetServer = true;
***************
*** 545,551 ****
  				break;
  			case 'p':
  				/* Set PGPORT by hand. */
! 				PostPortName = (unsigned short) atoi(optarg);
  				break;
  			case 'S':
--- 550,556 ----
  				break;
  			case 'p':
  				/* Set PGPORT by hand. */
! 				PostPortNumber = (unsigned short) atoi(optarg);
  				break;
  			case 'S':

***************
*** 577,584 ****
/*
* Select default values for switches where needed
*/
! if (PostPortName == 0)
! PostPortName = (unsigned short) pq_getport();

  	/*
  	 * Check for invalid combinations of switches
--- 582,603 ----
  	/*
  	 * Select default values for switches where needed
  	 */
! 	if (HostName == NULL)
! 	{
! 		if (!(HostName = getenv("PGHOST")))
! 		{
! 			HostName = "any";
! 		}
! 	}
! 	else if (!NetServer)
! 	{
! 		fprintf(stderr, "%s: -h requires -i.\n", progname);
! 		exit(1);
! 	}
! 	if (PostPortNumber == 0)
! 		PostPortNumber = (unsigned short) pq_getport();
! 	if (UnixSocketName == NULL)
! 		UnixSocketName = pq_getunixsocket();

/*
* Check for invalid combinations of switches
***************
*** 622,628 ****

  	if (NetServer)
  	{
! 		status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
  		if (status != STATUS_OK)
  		{
  			fprintf(stderr, "%s: cannot create INET stream port\n",
--- 641,647 ----

if (NetServer)
{
! status = StreamServerPort(HostName, PostPortNumber, NULL, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
***************
*** 632,638 ****
}

  #if !defined(__CYGWIN32__) && !defined(__QNX__)
! 	status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);
  	if (status != STATUS_OK)
  	{
  		fprintf(stderr, "%s: cannot create UNIX stream port\n",
--- 651,657 ----
  	}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! status = StreamServerPort(NULL, PostPortNumber, UnixSocketName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
***************
*** 642,648 ****
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! reset_shared(PostPortName);

  	/*
  	 * Initialize the list of active backends.	This list is only used for
--- 661,667 ----
  #endif
  	/* set up shared memory and semaphores */
  	EnableMemoryContext(TRUE);
! 	reset_shared(PostPortNumber);
  	/*
  	 * Initialize the list of active backends.	This list is only used for
***************
*** 664,670 ****
  		{
  			if (SetOptsFile(
  							progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
  							DataDir,	/* PGDATA */
  							assert_enabled,		/* whether -A is specified
  												 * or not */
--- 683,691 ----
  		{
  			if (SetOptsFile(
  							progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
  							DataDir,	/* PGDATA */
  							assert_enabled,		/* whether -A is specified
  												 * or not */
***************
*** 753,759 ****
  		{
  			if (SetOptsFile(
  							progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
  							DataDir,	/* PGDATA */
  							assert_enabled,		/* whether -A is specified
  												 * or not */
--- 774,782 ----
  		{
  			if (SetOptsFile(
  							progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
  							DataDir,	/* PGDATA */
  							assert_enabled,		/* whether -A is specified
  												 * or not */
***************
*** 837,843 ****
--- 860,868 ----
  	fprintf(stderr, "\t-a system\tuse this authentication system\n");
  	fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
  	fprintf(stderr, "\t-d [1-5]\tset debugging level\n");
+ 	fprintf(stderr, "\t-h hostname\tspecify hostname or IP address or 'any' for postmaster to listen on (also use -i)\n");
  	fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+ 	fprintf(stderr, "\t-k path\tspecify Unix-domain socket name for postmaster to listen on\n");
  #ifdef USE_SSL
  	fprintf(stderr, " \t-l \t\tfor TCP/IP sockets, listen only on SSL connections\n");
  #endif
***************
*** 1318,1328 ****
--- 1343,1417 ----
  }
  /*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+ 	static unsigned short hostPort = 0;
+ 
+ 	if (hostPort == 0)
+ 	{
+ 		SockAddr	saddr;
+ 		struct hostent *hp;
+ 
+ 		hp = gethostbyname(HostName);
+ 		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+ 		{
+ 			char msg[1024];
+ 			snprintf(msg, sizeof(msg),
+ 				 "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+ 				 HostName, hstrerror(h_errno));
+ 			fputs(msg, stderr);
+ 			pqdebug("%s", msg);
+ 			exit(1);
+ 		}
+ 		memmove((char *) &(saddr.in.sin_addr),
+ 			(char *) hp->h_addr,
+ 			hp->h_length);
+ 		hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+ 	}
+ 
+ 	return hostPort;
+ }
+ 
+ /*
   * reset_shared -- reset shared memory and semaphores
   */
  static void
  reset_shared(unsigned short port)
  {
+ 	/*
+ 	 * A typical ipc_key is 5432001, which is port 5432, sequence
+ 	 * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+ 	 * The 32-bit INT_MAX is 2147483 6 47.
+ 	 *
+ 	 * The default algorithm for calculating the IPC keys assumes that all
+ 	 * instances of postmaster on a given host are listening on different
+ 	 * ports.  In order to work (prevent shared memory collisions) if you
+ 	 * run multiple PostgreSQL instances on the same port and different IP
+ 	 * addresses on a host, we change the algorithm if you give postmaster
+ 	 * the -h option, or set PGHOST, to a value other than the internal
+ 	 * default of "any".
+ 	 *
+ 	 * If HostName is not "any", then we generate the IPC keys using the
+ 	 * last two octets of the IP address instead of the port number.
+ 	 * This algorithm assumes that no one will run multiple PostgreSQL
+ 	 * instances on one host using two IP addresses that have the same two
+ 	 * last octets in different class C networks.  If anyone does, it
+ 	 * would be rare.
+ 	 *
+ 	 * So, if you use -h or PGHOST, don't try to run two instances of
+ 	 * PostgreSQL on the same IP address but different ports.  If you
+ 	 * don't use them, then you must use different ports (via -p or
+ 	 * PGPORT).  And, of course, don't try to use both approaches on one
+ 	 * host.
+ 	 */
+ 
+ 	if (strcmp(HostName, "any"))
+ 		port = get_host_port();
+ 
  	ipc_key = port * 1000 + shmem_seq * 100;
  	CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
  	shmem_seq += 1;
***************
*** 1540,1546 ****
  				ctime(&tnow));
  		fflush(stderr);
  		shmem_exit(0);
! 		reset_shared(PostPortName);
  		StartupPID = StartupDataBase();
  		return;
  	}
--- 1629,1635 ----
  				ctime(&tnow));
  		fflush(stderr);
  		shmem_exit(0);
! 		reset_shared(PostPortNumber);
  		StartupPID = StartupDataBase();
  		return;
  	}
***************
*** 1720,1726 ****
  	 * Set up the necessary environment variables for the backend This
  	 * should really be some sort of message....
  	 */
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
  	putenv(envEntry[0]);
  	sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
  	putenv(envEntry[1]);
--- 1809,1815 ----
  	 * Set up the necessary environment variables for the backend This
  	 * should really be some sort of message....
  	 */
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortNumber);
  	putenv(envEntry[0]);
  	sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
  	putenv(envEntry[1]);
***************
*** 2174,2180 ****
  	for (i = 0; i < 4; ++i)
  		MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
  	putenv(ssEntry[0]);
  	sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
  	putenv(ssEntry[1]);
--- 2263,2269 ----
  	for (i = 0; i < 4; ++i)
  		MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortNumber);
  	putenv(ssEntry[0]);
  	sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
  	putenv(ssEntry[1]);
***************
*** 2254,2260 ****
   * Create the opts file
   */
  static int
! SetOptsFile(char *progname, int port, char *datadir,
  			int assert, int nbuf, char *execfile,
  			int debuglvl, int netserver,
  #ifdef USE_SSL
--- 2343,2349 ----
   * Create the opts file
   */
  static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
  			int assert, int nbuf, char *execfile,
  			int debuglvl, int netserver,
  #ifdef USE_SSL
***************
*** 2279,2284 ****
--- 2368,2383 ----
  		return (-1);
  	}
  	snprintf(opts, sizeof(opts), "%s\n-p %d\n-D %s\n", progname, port, datadir);
+ 	if (netserver)
+ 	{
+ 		sprintf(buf, "-h %s\n", hostname);
+ 		strcat(opts, buf);
+ 	}
+ 	if (unixsocket)
+ 	{
+ 		sprintf(buf, "-k %s\n", unixsocket);
+ 		strcat(opts, buf);
+ 	}
  	if (assert)
  	{
  		sprintf(buf, "-A %d\n", assert);
Index: src/bin/pg_dump/pg_dump.c
*** src/bin/pg_dump/pg_dump.c	2000/06/30 21:15:44	1.1
--- src/bin/pg_dump/pg_dump.c	2000/07/01 18:41:22	1.2
***************
*** 140,145 ****
--- 140,146 ----
  		 "  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
  		 "  -h, --host <hostname>    server host name\n"
  		 "  -i, --ignore-version     proceed when database version != pg_dump version\n"
+ 		 "  -k, --unixsocket <path>  server Unix-domain socket name\n"
  	"  -n, --no-quotes          suppress most quotes around identifiers\n"
  	 "  -N, --quotes             enable most quotes around identifiers\n"
  		 "  -o, --oids               dump object ids (oids)\n"
***************
*** 158,163 ****
--- 159,165 ----
  		 "  -D                       dump data as INSERT commands with attribute names\n"
  		 "  -h <hostname>            server host name\n"
  		 "  -i                       proceed when database version != pg_dump version\n"
+ 		 "  -k <path>                server Unix-domain socket name\n"
  	"  -n                       suppress most quotes around identifiers\n"
  	 "  -N                       enable most quotes around identifiers\n"
  		 "  -o                       dump object ids (oids)\n"
***************
*** 579,584 ****
--- 581,587 ----
  	const char *dbname = NULL;
  	const char *pghost = NULL;
  	const char *pgport = NULL;
+ 	const char *pgunixsocket = NULL;
  	char	   *tablename = NULL;
  	bool		oids = false;
  	TableInfo  *tblinfo;
***************
*** 598,603 ****
--- 601,607 ----
  		{"attribute-inserts", no_argument, NULL, 'D'},
  		{"host", required_argument, NULL, 'h'},
  		{"ignore-version", no_argument, NULL, 'i'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
  		{"no-quotes", no_argument, NULL, 'n'},
  		{"quotes", no_argument, NULL, 'N'},
  		{"oids", no_argument, NULL, 'o'},
***************
*** 662,667 ****
--- 666,674 ----
  			case 'i':			/* ignore database version mismatch */
  				ignore_version = true;
  				break;
+ 			case 'k':			/* server Unix-domain socket */
+ 				pgunixsocket = optarg;
+ 				break;
  			case 'n':			/* Do not force double-quotes on
  								 * identifiers */
  				force_quotes = false;
***************
*** 782,788 ****
  		exit(1);
  	}
- 	/* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
  	if (pghost != NULL)
  	{
  		sprintf(tmp_string, "host=%s ", pghost);
--- 789,794 ----
***************
*** 791,796 ****
--- 797,807 ----
  	if (pgport != NULL)
  	{
  		sprintf(tmp_string, "port=%s ", pgport);
+ 		strcat(connect_string, tmp_string);
+ 	}
+ 	if (pgunixsocket != NULL)
+ 	{
+ 		sprintf(tmp_string, "unixsocket=%s ", pgunixsocket);
  		strcat(connect_string, tmp_string);
  	}
  	if (dbname != NULL)
Index: src/bin/psql/command.c
*** src/bin/psql/command.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/command.c	2000/07/01 18:20:40	1.2
***************
*** 1199,1204 ****
--- 1199,1205 ----
  	SetVariable(pset.vars, "USER", NULL);
  	SetVariable(pset.vars, "HOST", NULL);
  	SetVariable(pset.vars, "PORT", NULL);
+ 	SetVariable(pset.vars, "UNIXSOCKET", NULL);
  	SetVariable(pset.vars, "ENCODING", NULL);
  	/* If dbname is "" then use old name, else new one (even if NULL) */
***************
*** 1228,1233 ****
--- 1229,1235 ----
  	do
  	{
  		need_pass = false;
+ 		/* FIXME use PQconnectdb to support passing the Unix socket */
  		pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
  							   NULL, NULL, dbparam, userparam, pwparam);
***************
*** 1303,1308 ****
--- 1305,1311 ----
  	SetVariable(pset.vars, "USER", PQuser(pset.db));
  	SetVariable(pset.vars, "HOST", PQhost(pset.db));
  	SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
  	SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
  	pset.issuper = test_superuser(PQuser(pset.db));
Index: src/bin/psql/command.h
Index: src/bin/psql/common.c
*** src/bin/psql/common.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/common.c	2000/07/01 18:20:40	1.2
***************
*** 330,335 ****
--- 330,336 ----
  			SetVariable(pset.vars, "DBNAME", NULL);
  			SetVariable(pset.vars, "HOST", NULL);
  			SetVariable(pset.vars, "PORT", NULL);
+ 			SetVariable(pset.vars, "UNIXSOCKET", NULL);
  			SetVariable(pset.vars, "USER", NULL);
  			SetVariable(pset.vars, "ENCODING", NULL);
  			return NULL;
***************
*** 509,514 ****
--- 510,516 ----
  				SetVariable(pset.vars, "DBNAME", NULL);
  				SetVariable(pset.vars, "HOST", NULL);
  				SetVariable(pset.vars, "PORT", NULL);
+ 				SetVariable(pset.vars, "UNIXSOCKET", NULL);
  				SetVariable(pset.vars, "USER", NULL);
  				SetVariable(pset.vars, "ENCODING", NULL);
  				return false;
Index: src/bin/psql/help.c
*** src/bin/psql/help.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/help.c	2000/07/01 18:20:40	1.2
***************
*** 103,108 ****
--- 103,118 ----
  	puts(")");
  	puts("  -H              HTML table output mode (-P format=html)");
+ 
+ 	/* Display default Unix-domain socket */
+ 	env = getenv("PGUNIXSOCKET");
+ 	printf("  -k <path>       Specify Unix domain socket name (default: ");
+ 	if (env)
+ 		fputs(env, stdout);
+ 	else
+ 		fputs("computed from the port", stdout);
+ 	puts(")");
+ 
  	puts("  -l              List available databases, then exit");
  	puts("  -n              Disable readline");
  	puts("  -o <filename>   Send query output to filename (or |pipe)");
Index: src/bin/psql/prompt.c
*** src/bin/psql/prompt.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/prompt.c	2000/07/01 18:20:40	1.2
***************
*** 189,194 ****
--- 189,199 ----
  					if (pset.db && PQport(pset.db))
  						strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
  					break;
+ 					/* DB server Unix-domain socket */
+ 				case '<':
+ 					if (pset.db && PQunixsocket(pset.db))
+ 						strncpy(buf, PQunixsocket(pset.db), MAX_PROMPT_SIZE);
+ 					break;
  					/* DB server user name */
  				case 'n':
  					if (pset.db)
Index: src/bin/psql/prompt.h
Index: src/bin/psql/settings.h
Index: src/bin/psql/startup.c
*** src/bin/psql/startup.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/startup.c	2000/07/01 18:20:40	1.2
***************
*** 66,71 ****
--- 66,72 ----
  	char	   *dbname;
  	char	   *host;
  	char	   *port;
+ 	char	   *unixsocket;
  	char	   *username;
  	enum _actions action;
  	char	   *action_string;
***************
*** 158,163 ****
--- 159,165 ----
  	do
  	{
  		need_pass = false;
+ 		/* FIXME use PQconnectdb to allow setting the unix socket */
  		pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
  			options.action == ACT_LIST_DB ? "template1" : options.dbname,
  							   username, password);
***************
*** 202,207 ****
--- 204,210 ----
  	SetVariable(pset.vars, "USER", PQuser(pset.db));
  	SetVariable(pset.vars, "HOST", PQhost(pset.db));
  	SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
  	SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
  #ifndef WIN32
***************
*** 313,318 ****
--- 316,322 ----
  		{"field-separator", required_argument, NULL, 'F'},
  		{"host", required_argument, NULL, 'h'},
  		{"html", no_argument, NULL, 'H'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
  		{"list", no_argument, NULL, 'l'},
  		{"no-readline", no_argument, NULL, 'n'},
  		{"output", required_argument, NULL, 'o'},
***************
*** 346,359 ****
  	memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

  	/*
  	 * Be sure to leave the '-' in here, so we can catch accidental long
  	 * options.
  	 */
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?-")) != -1)
  #endif	 /* not HAVE_GETOPT_LONG */
  	{
  		switch (c)
--- 350,363 ----
  	memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

  	/*
  	 * Be sure to leave the '-' in here, so we can catch accidental long
  	 * options.
  	 */
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
  #endif	 /* not HAVE_GETOPT_LONG */
  	{
  		switch (c)
***************
*** 398,403 ****
--- 402,410 ----
  				break;
  			case 'l':
  				options->action = ACT_LIST_DB;
+ 				break;
+ 			case 'k':
+ 				options->unixsocket = optarg;
  				break;
  			case 'n':
  				options->no_readline = true;
Index: src/bin/scripts/createdb
*** src/bin/scripts/createdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createdb	2000/07/04 04:46:45	1.2
***************
*** 50,55 ****
--- 50,64 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 114,119 ****
--- 123,129 ----
  	echo "  -E, --encoding=ENCODING         Multibyte encoding for the database"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/createlang.sh
*** src/bin/scripts/createlang.sh	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createlang.sh	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 126,131 ****
--- 135,141 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -d, --dbname=DBNAME             Database to install language in"
Index: src/bin/scripts/createuser
*** src/bin/scripts/createuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createuser	2000/07/04 04:46:45	1.2
***************
*** 63,68 ****
--- 63,77 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  # Note: These two specify the user to connect as (like in psql),
  #       not the user you're creating.
  	--username|-U)
***************
*** 135,140 ****
--- 144,150 ----
  	echo "  -P, --pwprompt                  Assign a password to new user"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as (not the one to create)"
  	echo "  -W, --password                  Prompt for password to connect"
  	echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/dropdb
*** src/bin/scripts/dropdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropdb	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 103,108 ****
--- 112,118 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/droplang
*** src/bin/scripts/droplang	2000/06/30 21:15:46	1.1
--- src/bin/scripts/droplang	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 113,118 ****
--- 122,128 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -d, --dbname=DBNAME             Database to remove language from"
Index: src/bin/scripts/dropuser
*** src/bin/scripts/dropuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropuser	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  # Note: These two specify the user to connect as (like in psql),
  #       not the user you're dropping.
  	--username|-U)
***************
*** 105,110 ****
--- 114,120 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as (not the one to drop)"
  	echo "  -W, --password                  Prompt for password to connect"
  	echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/vacuumdb
*** src/bin/scripts/vacuumdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/vacuumdb	2000/07/04 04:46:45	1.2
***************
*** 52,57 ****
--- 52,66 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 121,126 ****
--- 130,136 ----
          echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -d, --dbname=DBNAME             Database to vacuum"
Index: src/include/libpq/libpq.h
*** src/include/libpq/libpq.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/libpq.h	2000/07/01 18:20:40	1.2
***************
*** 236,246 ****
  /*
   * prototypes for functions in pqcomm.c
   */
! extern int	StreamServerPort(char *hostName, unsigned short portName, int *fdP);
  extern int	StreamConnection(int server_fd, Port *port);
  extern void StreamClose(int sock);
  extern void pq_init(void);
  extern int	pq_getport(void);
  extern void pq_close(void);
  extern int	pq_getbytes(char *s, size_t len);
  extern int	pq_getstring(StringInfo s);
--- 236,247 ----
  /*
   * prototypes for functions in pqcomm.c
   */
! extern int	StreamServerPort(char *hostName, unsigned short portName, char *unixSocketName, int *fdP);
  extern int	StreamConnection(int server_fd, Port *port);
  extern void StreamClose(int sock);
  extern void pq_init(void);
  extern int	pq_getport(void);
+ extern char	*pq_getunixsocket(void);
  extern void pq_close(void);
  extern int	pq_getbytes(char *s, size_t len);
  extern int	pq_getstring(StringInfo s);
Index: src/include/libpq/password.h
Index: src/include/libpq/pqcomm.h
*** src/include/libpq/pqcomm.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/pqcomm.h	2000/07/01 18:59:33	1.6
***************
*** 42,53 ****
  /* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), \
! strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

  /*
--- 42,56 ----
  /* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

  /*
Index: src/interfaces/libpq/fe-connect.c
*** src/interfaces/libpq/fe-connect.c	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/fe-connect.c	2000/07/01 18:50:47	1.3
***************
*** 125,130 ****
--- 125,133 ----
  	{"port", "PGPORT", DEF_PGPORT, NULL,
  	"Database-Port", "", 6},
+ 	{"unixsocket", "PGUNIXSOCKET", NULL, NULL,
+ 	"Unix-Socket", "", 80},
+ 
  	{"tty", "PGTTY", DefaultTty, NULL,
  	"Backend-Debug-TTY", "D", 40},
***************
*** 293,298 ****
--- 296,303 ----
  	conn->pghost = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "port");
  	conn->pgport = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "unixsocket");
+ 	conn->pgunixsocket = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "tty");
  	conn->pgtty = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "options");
***************
*** 369,374 ****
--- 374,382 ----
   *	  PGPORT	   identifies TCP port to which to connect if <pgport> argument
   *				   is NULL or a null string.
   *
+  *	  PGUNIXSOCKET	   identifies Unix-domain socket to which to connect; default
+  *				   is computed from the TCP port.
+  *
   *	  PGTTY		   identifies tty to which to send messages if <pgtty> argument
   *				   is NULL or a null string.
   *
***************
*** 422,427 ****
--- 430,439 ----
  	else
  		conn->pgport = strdup(pgport);
+ 	conn->pgunixsocket = getenv("PGUNIXSOCKET");
+ 	if (conn->pgunixsocket)
+ 		conn->pgunixsocket = strdup(conn->pgunixsocket);
+ 
  	if ((pgtty == NULL) || pgtty[0] == '\0')
  	{
  		if ((tmp = getenv("PGTTY")) == NULL)
***************
*** 489,501 ****

/*
* update_db_info -
! * get all additional infos out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp,
*old = conn->dbName;

  	if (strchr(conn->dbName, '@') != NULL)
--- 501,513 ----

/*
* update_db_info -
! * get all additional info out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp, *tmp2,
*old = conn->dbName;

  	if (strchr(conn->dbName, '@') != NULL)
***************
*** 504,509 ****
--- 516,523 ----
  		tmp = strrchr(conn->dbName, ':');
  		if (tmp != NULL)		/* port number given */
  		{
+ 			if (conn->pgport)
+ 				free(conn->pgport);
  			conn->pgport = strdup(tmp + 1);
  			*tmp = '\0';
  		}
***************
*** 511,516 ****
--- 525,532 ----
  		tmp = strrchr(conn->dbName, '@');
  		if (tmp != NULL)		/* host name given */
  		{
+ 			if (conn->pghost)
+ 				free(conn->pghost);
  			conn->pghost = strdup(tmp + 1);
  			*tmp = '\0';
  		}
***************
*** 537,549 ****

/*
* new style:
! * <tcp|unix>:postgresql://server[:port][/dbname][?options]
*/
offset += strlen("postgresql://");

  			tmp = strrchr(conn->dbName + offset, '?');
  			if (tmp != NULL)	/* options given */
  			{
  				conn->pgoptions = strdup(tmp + 1);
  				*tmp = '\0';
  			}
--- 553,567 ----

/*
* new style:
! * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL) /* options given */
{
+ if (conn->pgoptions)
+ free(conn->pgoptions);
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 551,576 ****
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL) /* database name given */
{
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
if ((tmp = getenv("PGDATABASE")) != NULL)
conn->dbName = strdup(tmp);
else if (conn->pguser)
conn->dbName = strdup(conn->pguser);
}

tmp = strrchr(old + offset, ':');
! if (tmp != NULL) /* port number given */
{
- conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}

  			if (strncmp(old, "unix:", 5) == 0)
  			{
  				conn->pghost = NULL;
  				if (strcmp(old + offset, "localhost") != 0)
  				{
--- 569,630 ----
  			tmp = strrchr(conn->dbName + offset, '/');
  			if (tmp != NULL)	/* database name given */
  			{
+ 				if (conn->dbName)
+ 					free(conn->dbName);
  				conn->dbName = strdup(tmp + 1);
  				*tmp = '\0';
  			}
  			else
  			{
+ 				/* Why do we default only this value from the environment again?  */
  				if ((tmp = getenv("PGDATABASE")) != NULL)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
  					conn->dbName = strdup(tmp);
+ 				}
  				else if (conn->pguser)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
  					conn->dbName = strdup(conn->pguser);
+ 				}
  			}
  			tmp = strrchr(old + offset, ':');
! 			if (tmp != NULL)	/* port number or Unix socket path given */
  			{
  				*tmp = '\0';
+ 				if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
+ 				{
+ 					if (strncmp(old, "unix:", 5) != 0)
+ 					{
+ 						printfPQExpBuffer(&conn->errorMessage,
+ 								  "connectDBStart() -- "
+ 								  "socket name can only be specified with "
+ 								  "non-TCP\n");
+ 						return 1; 
+ 					}
+ 					*tmp2 = '\0';
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = strdup(tmp + 1);
+ 				}
+ 				else
+ 				{
+ 					if (conn->pgport)
+ 						free(conn->pgport);
+ 					conn->pgport = strdup(tmp + 1);
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = NULL;
+ 				}
  			}
  			if (strncmp(old, "unix:", 5) == 0)
  			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
  				conn->pghost = NULL;
  				if (strcmp(old + offset, "localhost") != 0)
  				{
***************
*** 582,589 ****
  				}
  			}
  			else
  				conn->pghost = strdup(old + offset);
! 
  			free(old);
  		}
  	}
--- 636,646 ----
  				}
  			}
  			else
+ 			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
  				conn->pghost = strdup(old + offset);
! 			}
  			free(old);
  		}
  	}
***************
*** 743,749 ****
  	}
  #if !defined(WIN32) && !defined(__CYGWIN32__)
  	else
! 		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
  #endif
--- 800,809 ----
  	}
  #if !defined(WIN32) && !defined(__CYGWIN32__)
  	else
! 	{
! 		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
! 		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
! 	}
  #endif
***************
*** 892,898 ****
  							  conn->pghost ? conn->pghost : "localhost",
  							  (family == AF_INET) ?
  							  "TCP/IP port" : "Unix socket",
! 							  conn->pgport);
  			goto connect_errReturn;
  		}
  	}
--- 952,959 ----
  							  conn->pghost ? conn->pghost : "localhost",
  							  (family == AF_INET) ?
  							  "TCP/IP port" : "Unix socket",
! 							  (family == AF_UNIX && conn->pgunixsocket) ?
! 							  conn->pgunixsocket : conn->pgport);
  			goto connect_errReturn;
  		}
  	}
***************
*** 1123,1129 ****
  							   conn->pghost ? conn->pghost : "localhost",
  								  (conn->raddr.sa.sa_family == AF_INET) ?
  									  "TCP/IP port" : "Unix socket",
! 									  conn->pgport);
  					goto error_return;
  				}
--- 1184,1191 ----
  							   conn->pghost ? conn->pghost : "localhost",
  								  (conn->raddr.sa.sa_family == AF_INET) ?
  									  "TCP/IP port" : "Unix socket",
! 							  (conn->raddr.sa.sa_family == AF_UNIX && conn->pgunixsocket) ?
! 									  conn->pgunixsocket : conn->pgport);
  					goto error_return;
  				}
***************
*** 1799,1804 ****
--- 1861,1868 ----
  		free(conn->pghostaddr);
  	if (conn->pgport)
  		free(conn->pgport);
+ 	if (conn->pgunixsocket)
+ 		free(conn->pgunixsocket);
  	if (conn->pgtty)
  		free(conn->pgtty);
  	if (conn->pgoptions)
***************
*** 2383,2388 ****
--- 2447,2460 ----
  	if (!conn)
  		return (char *) NULL;
  	return conn->pgport;
+ }
+ 
+ char *
+ PQunixsocket(const PGconn *conn)
+ {
+ 	if (!conn)
+ 		return (char *) NULL;
+ 	return conn->pgunixsocket;
  }
  char *
Index: src/interfaces/libpq/libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-fe.h	2000/07/01 18:20:40	1.2
***************
*** 214,219 ****
--- 214,220 ----
  	extern char *PQpass(const PGconn *conn);
  	extern char *PQhost(const PGconn *conn);
  	extern char *PQport(const PGconn *conn);
+ 	extern char *PQunixsocket(const PGconn *conn);
  	extern char *PQtty(const PGconn *conn);
  	extern char *PQoptions(const PGconn *conn);
  	extern ConnStatusType PQstatus(const PGconn *conn);
Index: src/interfaces/libpq/libpq-int.h
*** src/interfaces/libpq/libpq-int.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-int.h	2000/07/01 18:20:40	1.2
***************
*** 202,207 ****
--- 202,209 ----
  								 * numbers-and-dots notation. Takes
  								 * precedence over above. */
  	char	   *pgport;			/* the server's communication port */
+ 	char	   *pgunixsocket;		/* the Unix-domain socket that the server is listening on;
+ 						 * if NULL, uses a default constructed from pgport */
  	char	   *pgtty;			/* tty on which the backend messages is
  								 * displayed (NOT ACTUALLY USED???) */
  	char	   *pgoptions;		/* options to start the backend with */
Index: src/interfaces/libpq/libpqdll.def
*** src/interfaces/libpq/libpqdll.def	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpqdll.def	2000/07/01 18:20:40	1.2
***************
*** 79,81 ****
--- 79,82 ----
  	destroyPQExpBuffer	@ 76
  	createPQExpBuffer	@ 77
  	PQconninfoFree		@ 78
+ 	PQunixsocket		@ 79
#2Peter Eisentraut
peter_e@gmx.net
In reply to: David J. MacKenzie (#1)
Re: [PATCHES] PostgreSQL virtual hosting support

David J. MacKenzie writes:

Greetings,

These sound like interesting features, but you need to start with the
current sources. The options handling in particular has changed, look in
src/backend/utils/misc/guc.c.

4. The ability to, if run as root, open a pid file in /var/run as
root, and then setuid to the desired user. (mysqld -u can almost
do this; I had to patch it, too).

I've been wondering about this too. If we could set the user name in the
configuration file then this would certainly make the installation
procedures a lot simpler. Actually, initdb could use such an option as
well. Maybe this would work:

if test `pg_id -u` -eq 0 ; then
su -l "$user" "$0 $*"
exit
fi

where $user is the value of the --user/-u option.

1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT,
and command line options -k --unix-socket to the relevant programs.

Here's the trick question, what does this do: `psql -k foo -h bar'?
Perhaps we can integrate this into the -h option:

psql -h /tmp/foo => Unix socket
psql -h tmp.foo => TCP/IP
psql -h foo => TCP/IP
psql -h ./foo => Unix socket

That way we don't have to add a new option everywhere. Just an idea.

2. Adds a -h option to postmaster to set the hostname or IP address to
listen on instead of the default INADDR_ANY.

That sounds like something that needs to be added into guc.c. You'll be
the first to add a string option, so it probably won't work. :)

--
Peter Eisentraut Sernanders v�g 10:115
peter_e@gmx.net 75262 Uppsala
http://yi.org/peter-e/ Sweden

#3Bruce Momjian
pgman@candle.pha.pa.us
In reply to: David J. MacKenzie (#1)
Re: [PATCHES] PostgreSQL virtual hosting support

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Any objections?

Your name : David MacKenzie
Your email address : djm@web.us.uu.net

System Configuration
---------------------
Architecture (example: Intel Pentium) : Intel x86

Operating System (example: Linux 2.0.26 ELF) : BSD/OS 4.0.1

PostgreSQL version (example: PostgreSQL-7.0): PostgreSQL-7.0.2

Compiler used (example: gcc 2.8.0) : gcc version 2.7.2.1

Please enter a FULL description of your problem:
------------------------------------------------

UUNET is looking into offering PostgreSQL as a part of a managed web
hosting product, on both shared and dedicated machines. We currently
offer Oracle and MySQL, and it would be a nice middle-ground.
However, as shipped, PostgreSQL lacks the following features we need
that MySQL has:

1. The ability to listen only on a particular IP address. Each
hosting customer has their own IP address, on which all of their
servers (http, ftp, real media, etc.) run.
2. The ability to place the Unix-domain socket in a mode 700 directory.
This allows us to automatically create an empty database, with an
empty DBA password, for new or upgrading customers without having
to interactively set a DBA password and communicate it to (or from)
the customer. This in turn cuts down our install and upgrade times.
3. The ability to connect to the Unix-domain socket from within a
change-rooted environment. We run CGI programs chrooted to the
user's home directory, which is another reason why we need to be
able to specify where the Unix-domain socket is, instead of /tmp.
4. The ability to, if run as root, open a pid file in /var/run as
root, and then setuid to the desired user. (mysqld -u can almost
do this; I had to patch it, too).

The patch below fixes problem 1-3. I plan to address #4, also, but
haven't done so yet. These diffs are big enough that they should give
the PG development team something to think about in the meantime :-)
Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get
out what I have, which works (for the problems it tackles), now.

With these changes, we can set up and run PostgreSQL with scripts the
same way we can with apache or proftpd or mysql.

In summary, this patch makes the following enhancements:

1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT,
and command line options -k --unix-socket to the relevant programs.
2. Adds a -h option to postmaster to set the hostname or IP address to
listen on instead of the default INADDR_ANY.
3. Extends some library interfaces to support the above.
4. Fixes a few memory leaks in PQconnectdb().

The default behavior is unchanged from stock 7.0.2; if you don't use
any of these new features, they don't change the operation.

Index: doc/src/sgml/layout.sgml
*** doc/src/sgml/layout.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/layout.sgml	2000/07/02 03:56:05	1.2
***************
*** 55,61 ****
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> may also have to be set.  The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
--- 55,62 ----
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> or <envar>PGUNIXSOCKET</envar> may also have to be set.
! The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
Index: doc/src/sgml/libpq++.sgml
*** doc/src/sgml/libpq++.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq++.sgml	2000/07/02 03:56:05	1.2
***************
*** 93,98 ****
--- 93,105 ----
</listitem>
<listitem>
<para>
+ 	<envar>PGUNIXSOCKET</envar>  sets the full Unix domain socket
+ 	file name for communicating with the <productname>Postgres</productname>
+ 	backend.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
<envar>PGDATABASE</envar>  sets the default 
<productname>Postgres</productname> database name.
</para>
Index: doc/src/sgml/libpq.sgml
*** doc/src/sgml/libpq.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq.sgml	2000/07/02 03:56:05	1.2
***************
*** 134,139 ****
--- 134,148 ----
</varlistentry>
<varlistentry>
+      <term><literal>unixsocket</literal></term>
+      <listitem>
+      <para>
+       Full path to Unix-domain socket file to connect to at the server host.
+      </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
<term><literal>dbname</literal></term>
<listitem>
<para>
***************
*** 545,550 ****
--- 554,569 ----
<listitem>
<para>
+ <function>PQunixsocket</function>
+          Returns the name of the Unix-domain socket of the connection.
+ <synopsis>
+ char *PQunixsocket(const PGconn *conn)
+ </synopsis>
+ </para>
+ </listitem>
+ 
+ <listitem>
+ <para>
<function>PQtty</function>
Returns the debug tty of the connection.
<synopsis>
***************
*** 1772,1777 ****
--- 1791,1803 ----
<envar>PGHOST</envar> sets the default server name.
If a non-zero-length string is specified, TCP/IP communication is used.
Without a host name, libpq will connect using a local Unix domain socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <envar>PGPORT</envar>  sets the default port or local Unix domain socket
+ file extension for communicating with the <productname>Postgres</productname>
+ backend.
</para>
</listitem>
<listitem>
Index: doc/src/sgml/start.sgml
*** doc/src/sgml/start.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/start.sgml	2000/07/02 03:56:05	1.2
***************
*** 110,117 ****
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> may also have to be set.  The bottom
!     line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
--- 110,117 ----
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> or <acronym>PGUNIXSOCKET</acronym> may also have to be set.
!     The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
Index: doc/src/sgml/ref/createdb.sgml
*** doc/src/sgml/ref/createdb.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createlang.sgml
*** doc/src/sgml/ref/createlang.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createlang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createuser.sgml
*** doc/src/sgml/ref/createuser.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,76 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/dropdb.sgml
*** doc/src/sgml/ref/dropdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/droplang.sgml
*** doc/src/sgml/ref/droplang.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/droplang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/dropuser.sgml
*** doc/src/sgml/ref/dropuser.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dump.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ]
!     [ -k <replaceable class="parameter">path</replaceable> ]
!     [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
***************
*** 200,205 ****
--- 202,222 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/pg_dumpall.sgml
*** doc/src/sgml/ref/pg_dumpall.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dumpall.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
--- 24,33 ----
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ]
!      [ -k <replaceable class="parameter">path</replaceable> ]
!      [ -p <replaceable class="parameter">port</replaceable> ]
!      [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
***************
*** 137,142 ****
--- 140,160 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/postmaster.sgml	2000/07/06 07:48:31	1.7
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ] [ -i ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ]
!     [ -h <replaceable class="parameter">hostname</replaceable> ] [ -i ]
!     [ -k <replaceable class="parameter">path</replaceable> ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
***************
*** 124,129 ****
--- 126,161 ----
</varlistentry>
<varlistentry>
+       <term>-h <replaceable class="parameter">hostName</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the TCP/IP hostname or address
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGHOST</envar> 
+ 	environment variable, or if <envar>PGHOST</envar>
+ 	is not set, then defaults to "all", meaning listen on all configured addresses
+ 	(including localhost).
+        </para>
+        <para>
+ 	If you use a hostname or address other than "all", do not try to run
+ 	multiple instances of <application>postmaster</application> on the
+ 	same IP address but different ports.  Doing so will result in them
+ 	attempting (incorrectly) to use the same shared memory segments.
+ 	Also, if you use a hostname other than "all", all of the host's IP addresses
+ 	on which <application>postmaster</application> instances are
+ 	listening must be distinct in the two last octets.
+        </para>
+        <para>
+ 	If you do use "all" (the default), then each instance must listen on a
+ 	different port (via -p or <envar>PGPORT</envar>).  And, of course, do
+ 	not try to use both approaches on one host.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-i</term>
<listitem>
<para>
***************
*** 135,140 ****
--- 167,201 ----
</varlistentry>
<varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket path name
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGUNIXSOCKET</envar> 
+ 	environment variable, or if <envar>PGUNIXSOCKET</envar>
+ 	is not set, then defaults to a file in <filename>/tmp</filename>
+ 	constructed from the port number.
+        </para>
+        <para>
+         You can use this option to put the Unix-domain socket in a
+         directory that is private to one or more users using Unix
+ 	directory permissions.  This is necessary for securely
+ 	creating databases automatically on shared machines.
+         In that situation, also disallow all TCP/IP connections
+ 	initially in <filename>pg_hba.conf</filename>.
+ 	If you specify a socket path other than the
+ 	default then all frontend applications (including
+ 	<application>psql</application>) must specify the same
+ 	socket path using either command-line options or
+ 	<envar>PGUNIXSOCKET</envar>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-l</term>
<listitem>
<para>
Index: doc/src/sgml/ref/psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/psql-ref.sgml	2000/07/02 03:56:05	1.3
***************
*** 1329,1334 ****
--- 1329,1347 ----
<varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
+ 
+     <varlistentry>
<term>-H, --html</term>
<listitem>
<para>
Index: doc/src/sgml/ref/vacuumdb.sgml
*** doc/src/sgml/ref/vacuumdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/vacuumdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --alldb | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
--- 24,30 ----
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --all | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
***************
*** 128,133 ****
--- 128,145 ----
</para>
</listitem>
</varlistentry>
+ 
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
<varlistentry>
<term>-U <replaceable class="parameter">username</replaceable></term>
Index: src/backend/libpq/pqcomm.c
*** src/backend/libpq/pqcomm.c	2000/06/30 21:15:40	1.1
--- src/backend/libpq/pqcomm.c	2000/07/01 18:50:46	1.3
***************
*** 42,47 ****
--- 42,48 ----
*		StreamConnection	- Create new connection with client
*		StreamClose			- Close a client/backend connection
*		pq_getport		- return the PGPORT setting
+  *		pq_getunixsocket	- return the PGUNIXSOCKET setting
*		pq_init			- initialize libpq at backend startup
*		pq_close		- shutdown libpq at backend exit
*
***************
*** 134,139 ****
--- 135,151 ----
}
/* --------------------------------
+  *		pq_getunixsocket - return the PGUNIXSOCKET setting.
+  *		If NULL, default to computing it based on the port.
+  * --------------------------------
+  */
+ char *
+ pq_getunixsocket(void)
+ {
+ 	return getenv("PGUNIXSOCKET");
+ }
+ 
+ /* --------------------------------
*		pq_close - shutdown libpq at backend exit
*
* Note: in a standalone backend MyProcPort will be null,
***************
*** 177,189 ****
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/
int
! StreamServerPort(char *hostName, unsigned short portName, int *fdP)
{
SockAddr	saddr;
int			fd,
--- 189,205 ----
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port fdP.
!  * If hostName is "any", listen on all configured IP addresses.
!  * If hostName is NULL, listen on a Unix-domain socket instead of TCP;
!  * if unixSocketName is NULL, a default path (constructed in UNIX_SOCK_PATH
!  * in include/libpq/pqcomm.h) based on portName is used.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/

int
! StreamServerPort(char *hostName, unsigned short portNumber, char *unixSocketName, int *fdP)
{
SockAddr saddr;
int fd,
***************
*** 227,233 ****
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! len = UNIXSOCK_PATH(saddr.un, portName);
strcpy(sock_path, saddr.un.sun_path);

/*
--- 243,250 ----
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! 		UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
! 		len = UNIXSOCK_LEN(saddr.un);
strcpy(sock_path, saddr.un.sun_path);
/*
***************
*** 259,267 ****
}
else
{
! 		saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 		saddr.in.sin_port = htons(portName);
! 		len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
--- 276,305 ----
}
else
{
! 	  /* TCP/IP socket */
! 	  if (!strcmp(hostName, "all")) /* like for databases in pg_hba.conf.  */
! 	    saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 	  else
! 	    {
! 	      struct hostent *hp;
! 
! 	      hp = gethostbyname(hostName);
! 	      if ((hp == NULL) || (hp->h_addrtype != AF_INET))
! 		{
! 		  snprintf(PQerrormsg, PQERRORMSG_LENGTH,
! 			   "FATAL: StreamServerPort: gethostbyname(%s) failed: %s\n",
! 			   hostName, hstrerror(h_errno));
! 		  fputs(PQerrormsg, stderr);
! 		  pqdebug("%s", PQerrormsg);
! 		  return STATUS_ERROR;
! 		}
! 	      memmove((char *) &(saddr.in.sin_addr),
! 		      (char *) hp->h_addr,
! 		      hp->h_length);
! 	    }
! 
! 	  saddr.in.sin_port = htons(portNumber);
! 	  len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
Index: src/backend/postmaster/postmaster.c
*** src/backend/postmaster/postmaster.c	2000/06/30 21:15:42	1.1
--- src/backend/postmaster/postmaster.c	2000/07/06 07:38:21	1.5
***************
*** 136,143 ****
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! static unsigned short PostPortName = 0;

/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
--- 136,150 ----
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! /* Hostname of interface to listen on, or 'any'. */
! static char *HostName = NULL;

+ /* TCP/IP port number to listen on.  Also used to default the Unix-domain socket name.  */
+ static unsigned short PostPortNumber = 0;
+ 
+ /* Override of the default Unix-domain socket name to listen on, if non-NULL.  */
+ static char *UnixSocketName = NULL;
+ 
/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
***************
*** 274,280 ****
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 281,287 ----
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 370,380 ****
{
extern int	NBuffers;		/* from buffer/bufmgr.c */
int			opt;
- 	char	   *hostName;
int			status;
int			silentflag = 0;
bool		DataDirOK;		/* We have a usable PGDATA value */
- 	char		hostbuf[MAXHOSTNAMELEN];
int			nonblank_argc;
char		original_extraoptions[MAXPGPATH];
--- 377,385 ----
***************
*** 431,449 ****
*/
umask((mode_t) 0077);

- if (!(hostName = getenv("PGHOST")))
- {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:ilm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
--- 436,447 ----
*/
umask((mode_t) 0077);

MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:h:ik:lm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
***************
*** 498,506 ****
--- 496,511 ----
DebugLvl = atoi(optarg);
pg_options[TRACE_VERBOSE] = DebugLvl;
break;
+ 			case 'h':
+ 				HostName = optarg;
+ 				break;
case 'i':
NetServer = true;
break;
+ 			case 'k':
+ 				/* Set PGUNIXSOCKET by hand. */
+ 				UnixSocketName = optarg;
+ 				break;
#ifdef USE_SSL
case 'l':
SecureNetServer = true;
***************
*** 545,551 ****
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortName = (unsigned short) atoi(optarg);
break;
case 'S':
--- 550,556 ----
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortNumber = (unsigned short) atoi(optarg);
break;
case 'S':

***************
*** 577,584 ****
/*
* Select default values for switches where needed
*/
! if (PostPortName == 0)
! PostPortName = (unsigned short) pq_getport();

/*
* Check for invalid combinations of switches
--- 582,603 ----
/*
* Select default values for switches where needed
*/
! 	if (HostName == NULL)
! 	{
! 		if (!(HostName = getenv("PGHOST")))
! 		{
! 			HostName = "any";
! 		}
! 	}
! 	else if (!NetServer)
! 	{
! 		fprintf(stderr, "%s: -h requires -i.\n", progname);
! 		exit(1);
! 	}
! 	if (PostPortNumber == 0)
! 		PostPortNumber = (unsigned short) pq_getport();
! 	if (UnixSocketName == NULL)
! 		UnixSocketName = pq_getunixsocket();

/*
* Check for invalid combinations of switches
***************
*** 622,628 ****

if (NetServer)
{
! 		status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
--- 641,647 ----

if (NetServer)
{
! status = StreamServerPort(HostName, PostPortNumber, NULL, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
***************
*** 632,638 ****
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! 	status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
--- 651,657 ----
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! status = StreamServerPort(NULL, PostPortNumber, UnixSocketName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
***************
*** 642,648 ****
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! reset_shared(PostPortName);

/*
* Initialize the list of active backends.	This list is only used for
--- 661,667 ----
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! 	reset_shared(PostPortNumber);
/*
* Initialize the list of active backends.	This list is only used for
***************
*** 664,670 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 683,691 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 753,759 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 774,782 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 837,843 ****
--- 860,868 ----
fprintf(stderr, "\t-a system\tuse this authentication system\n");
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
fprintf(stderr, "\t-d [1-5]\tset debugging level\n");
+ 	fprintf(stderr, "\t-h hostname\tspecify hostname or IP address or 'any' for postmaster to listen on (also use -i)\n");
fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+ 	fprintf(stderr, "\t-k path\tspecify Unix-domain socket name for postmaster to listen on\n");
#ifdef USE_SSL
fprintf(stderr, " \t-l \t\tfor TCP/IP sockets, listen only on SSL connections\n");
#endif
***************
*** 1318,1328 ****
--- 1343,1417 ----
}
/*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+ 	static unsigned short hostPort = 0;
+ 
+ 	if (hostPort == 0)
+ 	{
+ 		SockAddr	saddr;
+ 		struct hostent *hp;
+ 
+ 		hp = gethostbyname(HostName);
+ 		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+ 		{
+ 			char msg[1024];
+ 			snprintf(msg, sizeof(msg),
+ 				 "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+ 				 HostName, hstrerror(h_errno));
+ 			fputs(msg, stderr);
+ 			pqdebug("%s", msg);
+ 			exit(1);
+ 		}
+ 		memmove((char *) &(saddr.in.sin_addr),
+ 			(char *) hp->h_addr,
+ 			hp->h_length);
+ 		hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+ 	}
+ 
+ 	return hostPort;
+ }
+ 
+ /*
* reset_shared -- reset shared memory and semaphores
*/
static void
reset_shared(unsigned short port)
{
+ 	/*
+ 	 * A typical ipc_key is 5432001, which is port 5432, sequence
+ 	 * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+ 	 * The 32-bit INT_MAX is 2147483 6 47.
+ 	 *
+ 	 * The default algorithm for calculating the IPC keys assumes that all
+ 	 * instances of postmaster on a given host are listening on different
+ 	 * ports.  In order to work (prevent shared memory collisions) if you
+ 	 * run multiple PostgreSQL instances on the same port and different IP
+ 	 * addresses on a host, we change the algorithm if you give postmaster
+ 	 * the -h option, or set PGHOST, to a value other than the internal
+ 	 * default of "any".
+ 	 *
+ 	 * If HostName is not "any", then we generate the IPC keys using the
+ 	 * last two octets of the IP address instead of the port number.
+ 	 * This algorithm assumes that no one will run multiple PostgreSQL
+ 	 * instances on one host using two IP addresses that have the same two
+ 	 * last octets in different class C networks.  If anyone does, it
+ 	 * would be rare.
+ 	 *
+ 	 * So, if you use -h or PGHOST, don't try to run two instances of
+ 	 * PostgreSQL on the same IP address but different ports.  If you
+ 	 * don't use them, then you must use different ports (via -p or
+ 	 * PGPORT).  And, of course, don't try to use both approaches on one
+ 	 * host.
+ 	 */
+ 
+ 	if (strcmp(HostName, "any"))
+ 		port = get_host_port();
+ 
ipc_key = port * 1000 + shmem_seq * 100;
CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
shmem_seq += 1;
***************
*** 1540,1546 ****
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortName);
StartupPID = StartupDataBase();
return;
}
--- 1629,1635 ----
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortNumber);
StartupPID = StartupDataBase();
return;
}
***************
*** 1720,1726 ****
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
--- 1809,1815 ----
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
***************
*** 2174,2180 ****
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
--- 2263,2269 ----
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
***************
*** 2254,2260 ****
* Create the opts file
*/
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 2343,2349 ----
* Create the opts file
*/
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 2279,2284 ****
--- 2368,2383 ----
return (-1);
}
snprintf(opts, sizeof(opts), "%s\n-p %d\n-D %s\n", progname, port, datadir);
+ 	if (netserver)
+ 	{
+ 		sprintf(buf, "-h %s\n", hostname);
+ 		strcat(opts, buf);
+ 	}
+ 	if (unixsocket)
+ 	{
+ 		sprintf(buf, "-k %s\n", unixsocket);
+ 		strcat(opts, buf);
+ 	}
if (assert)
{
sprintf(buf, "-A %d\n", assert);
Index: src/bin/pg_dump/pg_dump.c
*** src/bin/pg_dump/pg_dump.c	2000/06/30 21:15:44	1.1
--- src/bin/pg_dump/pg_dump.c	2000/07/01 18:41:22	1.2
***************
*** 140,145 ****
--- 140,146 ----
"  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
"  -h, --host <hostname>    server host name\n"
"  -i, --ignore-version     proceed when database version != pg_dump version\n"
+ 		 "  -k, --unixsocket <path>  server Unix-domain socket name\n"
"  -n, --no-quotes          suppress most quotes around identifiers\n"
"  -N, --quotes             enable most quotes around identifiers\n"
"  -o, --oids               dump object ids (oids)\n"
***************
*** 158,163 ****
--- 159,165 ----
"  -D                       dump data as INSERT commands with attribute names\n"
"  -h <hostname>            server host name\n"
"  -i                       proceed when database version != pg_dump version\n"
+ 		 "  -k <path>                server Unix-domain socket name\n"
"  -n                       suppress most quotes around identifiers\n"
"  -N                       enable most quotes around identifiers\n"
"  -o                       dump object ids (oids)\n"
***************
*** 579,584 ****
--- 581,587 ----
const char *dbname = NULL;
const char *pghost = NULL;
const char *pgport = NULL;
+ 	const char *pgunixsocket = NULL;
char	   *tablename = NULL;
bool		oids = false;
TableInfo  *tblinfo;
***************
*** 598,603 ****
--- 601,607 ----
{"attribute-inserts", no_argument, NULL, 'D'},
{"host", required_argument, NULL, 'h'},
{"ignore-version", no_argument, NULL, 'i'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"no-quotes", no_argument, NULL, 'n'},
{"quotes", no_argument, NULL, 'N'},
{"oids", no_argument, NULL, 'o'},
***************
*** 662,667 ****
--- 666,674 ----
case 'i':			/* ignore database version mismatch */
ignore_version = true;
break;
+ 			case 'k':			/* server Unix-domain socket */
+ 				pgunixsocket = optarg;
+ 				break;
case 'n':			/* Do not force double-quotes on
* identifiers */
force_quotes = false;
***************
*** 782,788 ****
exit(1);
}
- 	/* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
if (pghost != NULL)
{
sprintf(tmp_string, "host=%s ", pghost);
--- 789,794 ----
***************
*** 791,796 ****
--- 797,807 ----
if (pgport != NULL)
{
sprintf(tmp_string, "port=%s ", pgport);
+ 		strcat(connect_string, tmp_string);
+ 	}
+ 	if (pgunixsocket != NULL)
+ 	{
+ 		sprintf(tmp_string, "unixsocket=%s ", pgunixsocket);
strcat(connect_string, tmp_string);
}
if (dbname != NULL)
Index: src/bin/psql/command.c
*** src/bin/psql/command.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/command.c	2000/07/01 18:20:40	1.2
***************
*** 1199,1204 ****
--- 1199,1205 ----
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 	SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
/* If dbname is "" then use old name, else new one (even if NULL) */
***************
*** 1228,1233 ****
--- 1229,1235 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to support passing the Unix socket */
pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
NULL, NULL, dbparam, userparam, pwparam);
***************
*** 1303,1308 ****
--- 1305,1311 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
pset.issuper = test_superuser(PQuser(pset.db));
Index: src/bin/psql/command.h
Index: src/bin/psql/common.c
*** src/bin/psql/common.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/common.c	2000/07/01 18:20:40	1.2
***************
*** 330,335 ****
--- 330,336 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 			SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return NULL;
***************
*** 509,514 ****
--- 510,516 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 				SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return false;
Index: src/bin/psql/help.c
*** src/bin/psql/help.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/help.c	2000/07/01 18:20:40	1.2
***************
*** 103,108 ****
--- 103,118 ----
puts(")");
puts("  -H              HTML table output mode (-P format=html)");
+ 
+ 	/* Display default Unix-domain socket */
+ 	env = getenv("PGUNIXSOCKET");
+ 	printf("  -k <path>       Specify Unix domain socket name (default: ");
+ 	if (env)
+ 		fputs(env, stdout);
+ 	else
+ 		fputs("computed from the port", stdout);
+ 	puts(")");
+ 
puts("  -l              List available databases, then exit");
puts("  -n              Disable readline");
puts("  -o <filename>   Send query output to filename (or |pipe)");
Index: src/bin/psql/prompt.c
*** src/bin/psql/prompt.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/prompt.c	2000/07/01 18:20:40	1.2
***************
*** 189,194 ****
--- 189,199 ----
if (pset.db && PQport(pset.db))
strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
break;
+ 					/* DB server Unix-domain socket */
+ 				case '<':
+ 					if (pset.db && PQunixsocket(pset.db))
+ 						strncpy(buf, PQunixsocket(pset.db), MAX_PROMPT_SIZE);
+ 					break;
/* DB server user name */
case 'n':
if (pset.db)
Index: src/bin/psql/prompt.h
Index: src/bin/psql/settings.h
Index: src/bin/psql/startup.c
*** src/bin/psql/startup.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/startup.c	2000/07/01 18:20:40	1.2
***************
*** 66,71 ****
--- 66,72 ----
char	   *dbname;
char	   *host;
char	   *port;
+ 	char	   *unixsocket;
char	   *username;
enum _actions action;
char	   *action_string;
***************
*** 158,163 ****
--- 159,165 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to allow setting the unix socket */
pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
options.action == ACT_LIST_DB ? "template1" : options.dbname,
username, password);
***************
*** 202,207 ****
--- 204,210 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
#ifndef WIN32
***************
*** 313,318 ****
--- 316,322 ----
{"field-separator", required_argument, NULL, 'F'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"list", no_argument, NULL, 'l'},
{"no-readline", no_argument, NULL, 'n'},
{"output", required_argument, NULL, 'o'},
***************
*** 346,359 ****
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
--- 350,363 ----
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
***************
*** 398,403 ****
--- 402,410 ----
break;
case 'l':
options->action = ACT_LIST_DB;
+ 				break;
+ 			case 'k':
+ 				options->unixsocket = optarg;
break;
case 'n':
options->no_readline = true;
Index: src/bin/scripts/createdb
*** src/bin/scripts/createdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createdb	2000/07/04 04:46:45	1.2
***************
*** 50,55 ****
--- 50,64 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 114,119 ****
--- 123,129 ----
echo "  -E, --encoding=ENCODING         Multibyte encoding for the database"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/createlang.sh
*** src/bin/scripts/createlang.sh	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createlang.sh	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 126,131 ****
--- 135,141 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to install language in"
Index: src/bin/scripts/createuser
*** src/bin/scripts/createuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createuser	2000/07/04 04:46:45	1.2
***************
*** 63,68 ****
--- 63,77 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're creating.
--username|-U)
***************
*** 135,140 ****
--- 144,150 ----
echo "  -P, --pwprompt                  Assign a password to new user"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to create)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/dropdb
*** src/bin/scripts/dropdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropdb	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 103,108 ****
--- 112,118 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/droplang
*** src/bin/scripts/droplang	2000/06/30 21:15:46	1.1
--- src/bin/scripts/droplang	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 113,118 ****
--- 122,128 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to remove language from"
Index: src/bin/scripts/dropuser
*** src/bin/scripts/dropuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropuser	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're dropping.
--username|-U)
***************
*** 105,110 ****
--- 114,120 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to drop)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/vacuumdb
*** src/bin/scripts/vacuumdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/vacuumdb	2000/07/04 04:46:45	1.2
***************
*** 52,57 ****
--- 52,66 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 121,126 ****
--- 130,136 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to vacuum"
Index: src/include/libpq/libpq.h
*** src/include/libpq/libpq.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/libpq.h	2000/07/01 18:20:40	1.2
***************
*** 236,246 ****
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
--- 236,247 ----
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, char *unixSocketName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
+ extern char	*pq_getunixsocket(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
Index: src/include/libpq/password.h
Index: src/include/libpq/pqcomm.h
*** src/include/libpq/pqcomm.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/pqcomm.h	2000/07/01 18:59:33	1.6
***************
*** 42,53 ****
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), \
! strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
--- 42,56 ----
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
Index: src/interfaces/libpq/fe-connect.c
*** src/interfaces/libpq/fe-connect.c	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/fe-connect.c	2000/07/01 18:50:47	1.3
***************
*** 125,130 ****
--- 125,133 ----
{"port", "PGPORT", DEF_PGPORT, NULL,
"Database-Port", "", 6},
+ 	{"unixsocket", "PGUNIXSOCKET", NULL, NULL,
+ 	"Unix-Socket", "", 80},
+ 
{"tty", "PGTTY", DefaultTty, NULL,
"Backend-Debug-TTY", "D", 40},
***************
*** 293,298 ****
--- 296,303 ----
conn->pghost = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "port");
conn->pgport = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "unixsocket");
+ 	conn->pgunixsocket = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "tty");
conn->pgtty = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "options");
***************
*** 369,374 ****
--- 374,382 ----
*	  PGPORT	   identifies TCP port to which to connect if <pgport> argument
*				   is NULL or a null string.
*
+  *	  PGUNIXSOCKET	   identifies Unix-domain socket to which to connect; default
+  *				   is computed from the TCP port.
+  *
*	  PGTTY		   identifies tty to which to send messages if <pgtty> argument
*				   is NULL or a null string.
*
***************
*** 422,427 ****
--- 430,439 ----
else
conn->pgport = strdup(pgport);
+ 	conn->pgunixsocket = getenv("PGUNIXSOCKET");
+ 	if (conn->pgunixsocket)
+ 		conn->pgunixsocket = strdup(conn->pgunixsocket);
+ 
if ((pgtty == NULL) || pgtty[0] == '\0')
{
if ((tmp = getenv("PGTTY")) == NULL)
***************
*** 489,501 ****

/*
* update_db_info -
! * get all additional infos out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
--- 501,513 ----

/*
* update_db_info -
! * get all additional info out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp, *tmp2,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
***************
*** 504,509 ****
--- 516,523 ----
tmp = strrchr(conn->dbName, ':');
if (tmp != NULL)		/* port number given */
{
+ 			if (conn->pgport)
+ 				free(conn->pgport);
conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 511,516 ****
--- 525,532 ----
tmp = strrchr(conn->dbName, '@');
if (tmp != NULL)		/* host name given */
{
+ 			if (conn->pghost)
+ 				free(conn->pghost);
conn->pghost = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 537,549 ****

/*
* new style:
! * <tcp|unix>:postgresql://server[:port][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL)	/* options given */
{
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
--- 553,567 ----

/*
* new style:
! * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL) /* options given */
{
+ if (conn->pgoptions)
+ free(conn->pgoptions);
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 551,576 ****
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL) /* database name given */
{
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
if ((tmp = getenv("PGDATABASE")) != NULL)
conn->dbName = strdup(tmp);
else if (conn->pguser)
conn->dbName = strdup(conn->pguser);
}

tmp = strrchr(old + offset, ':');
! if (tmp != NULL) /* port number given */
{
- conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}

if (strncmp(old, "unix:", 5) == 0)
{
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
--- 569,630 ----
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL)	/* database name given */
{
+ 				if (conn->dbName)
+ 					free(conn->dbName);
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
+ 				/* Why do we default only this value from the environment again?  */
if ((tmp = getenv("PGDATABASE")) != NULL)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(tmp);
+ 				}
else if (conn->pguser)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(conn->pguser);
+ 				}
}
tmp = strrchr(old + offset, ':');
! 			if (tmp != NULL)	/* port number or Unix socket path given */
{
*tmp = '\0';
+ 				if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
+ 				{
+ 					if (strncmp(old, "unix:", 5) != 0)
+ 					{
+ 						printfPQExpBuffer(&conn->errorMessage,
+ 								  "connectDBStart() -- "
+ 								  "socket name can only be specified with "
+ 								  "non-TCP\n");
+ 						return 1; 
+ 					}
+ 					*tmp2 = '\0';
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = strdup(tmp + 1);
+ 				}
+ 				else
+ 				{
+ 					if (conn->pgport)
+ 						free(conn->pgport);
+ 					conn->pgport = strdup(tmp + 1);
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = NULL;
+ 				}
}
if (strncmp(old, "unix:", 5) == 0)
{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
***************
*** 582,589 ****
}
}
else
conn->pghost = strdup(old + offset);
! 
free(old);
}
}
--- 636,646 ----
}
}
else
+ 			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = strdup(old + offset);
! 			}
free(old);
}
}
***************
*** 743,749 ****
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
#endif
--- 800,809 ----
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 	{
! 		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
! 		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
! 	}
#endif
***************
*** 892,898 ****
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  conn->pgport);
goto connect_errReturn;
}
}
--- 952,959 ----
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (family == AF_UNIX && conn->pgunixsocket) ?
! 							  conn->pgunixsocket : conn->pgport);
goto connect_errReturn;
}
}
***************
*** 1123,1129 ****
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 									  conn->pgport);
goto error_return;
}
--- 1184,1191 ----
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (conn->raddr.sa.sa_family == AF_UNIX && conn->pgunixsocket) ?
! 									  conn->pgunixsocket : conn->pgport);
goto error_return;
}
***************
*** 1799,1804 ****
--- 1861,1868 ----
free(conn->pghostaddr);
if (conn->pgport)
free(conn->pgport);
+ 	if (conn->pgunixsocket)
+ 		free(conn->pgunixsocket);
if (conn->pgtty)
free(conn->pgtty);
if (conn->pgoptions)
***************
*** 2383,2388 ****
--- 2447,2460 ----
if (!conn)
return (char *) NULL;
return conn->pgport;
+ }
+ 
+ char *
+ PQunixsocket(const PGconn *conn)
+ {
+ 	if (!conn)
+ 		return (char *) NULL;
+ 	return conn->pgunixsocket;
}
char *
Index: src/interfaces/libpq/libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-fe.h	2000/07/01 18:20:40	1.2
***************
*** 214,219 ****
--- 214,220 ----
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
extern char *PQport(const PGconn *conn);
+ 	extern char *PQunixsocket(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(const PGconn *conn);
Index: src/interfaces/libpq/libpq-int.h
*** src/interfaces/libpq/libpq-int.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-int.h	2000/07/01 18:20:40	1.2
***************
*** 202,207 ****
--- 202,209 ----
* numbers-and-dots notation. Takes
* precedence over above. */
char	   *pgport;			/* the server's communication port */
+ 	char	   *pgunixsocket;		/* the Unix-domain socket that the server is listening on;
+ 						 * if NULL, uses a default constructed from pgport */
char	   *pgtty;			/* tty on which the backend messages is
* displayed (NOT ACTUALLY USED???) */
char	   *pgoptions;		/* options to start the backend with */
Index: src/interfaces/libpq/libpqdll.def
*** src/interfaces/libpq/libpqdll.def	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpqdll.def	2000/07/01 18:20:40	1.2
***************
*** 79,81 ****
--- 79,82 ----
destroyPQExpBuffer	@ 76
createPQExpBuffer	@ 77
PQconninfoFree		@ 78
+ 	PQunixsocket		@ 79
-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#4The Hermit Hacker
scrappy@hub.org
In reply to: Bruce Momjian (#3)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

On Tue, 10 Oct 2000, Bruce Momjian wrote:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Any objections?

From a quick read of his "description of problem", it sounds like he has
addressed the original patches problem where it bound only to 127.0.0.1,
and allows you to bind to any IP on that machine ...

looks like a go for inclusion from what I can see ...

Your name : David MacKenzie
Your email address : djm@web.us.uu.net

System Configuration
---------------------
Architecture (example: Intel Pentium) : Intel x86

Operating System (example: Linux 2.0.26 ELF) : BSD/OS 4.0.1

PostgreSQL version (example: PostgreSQL-7.0): PostgreSQL-7.0.2

Compiler used (example: gcc 2.8.0) : gcc version 2.7.2.1

Please enter a FULL description of your problem:
------------------------------------------------

UUNET is looking into offering PostgreSQL as a part of a managed web
hosting product, on both shared and dedicated machines. We currently
offer Oracle and MySQL, and it would be a nice middle-ground.
However, as shipped, PostgreSQL lacks the following features we need
that MySQL has:

1. The ability to listen only on a particular IP address. Each
hosting customer has their own IP address, on which all of their
servers (http, ftp, real media, etc.) run.
2. The ability to place the Unix-domain socket in a mode 700 directory.
This allows us to automatically create an empty database, with an
empty DBA password, for new or upgrading customers without having
to interactively set a DBA password and communicate it to (or from)
the customer. This in turn cuts down our install and upgrade times.
3. The ability to connect to the Unix-domain socket from within a
change-rooted environment. We run CGI programs chrooted to the
user's home directory, which is another reason why we need to be
able to specify where the Unix-domain socket is, instead of /tmp.
4. The ability to, if run as root, open a pid file in /var/run as
root, and then setuid to the desired user. (mysqld -u can almost
do this; I had to patch it, too).

The patch below fixes problem 1-3. I plan to address #4, also, but
haven't done so yet. These diffs are big enough that they should give
the PG development team something to think about in the meantime :-)
Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get
out what I have, which works (for the problems it tackles), now.

With these changes, we can set up and run PostgreSQL with scripts the
same way we can with apache or proftpd or mysql.

In summary, this patch makes the following enhancements:

1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT,
and command line options -k --unix-socket to the relevant programs.
2. Adds a -h option to postmaster to set the hostname or IP address to
listen on instead of the default INADDR_ANY.
3. Extends some library interfaces to support the above.
4. Fixes a few memory leaks in PQconnectdb().

The default behavior is unchanged from stock 7.0.2; if you don't use
any of these new features, they don't change the operation.

Index: doc/src/sgml/layout.sgml
*** doc/src/sgml/layout.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/layout.sgml	2000/07/02 03:56:05	1.2
***************
*** 55,61 ****
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> may also have to be set.  The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
--- 55,62 ----
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> or <envar>PGUNIXSOCKET</envar> may also have to be set.
! The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
Index: doc/src/sgml/libpq++.sgml
*** doc/src/sgml/libpq++.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq++.sgml	2000/07/02 03:56:05	1.2
***************
*** 93,98 ****
--- 93,105 ----
</listitem>
<listitem>
<para>
+ 	<envar>PGUNIXSOCKET</envar>  sets the full Unix domain socket
+ 	file name for communicating with the <productname>Postgres</productname>
+ 	backend.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
<envar>PGDATABASE</envar>  sets the default 
<productname>Postgres</productname> database name.
</para>
Index: doc/src/sgml/libpq.sgml
*** doc/src/sgml/libpq.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq.sgml	2000/07/02 03:56:05	1.2
***************
*** 134,139 ****
--- 134,148 ----
</varlistentry>
<varlistentry>
+      <term><literal>unixsocket</literal></term>
+      <listitem>
+      <para>
+       Full path to Unix-domain socket file to connect to at the server host.
+      </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
<term><literal>dbname</literal></term>
<listitem>
<para>
***************
*** 545,550 ****
--- 554,569 ----
<listitem>
<para>
+ <function>PQunixsocket</function>
+          Returns the name of the Unix-domain socket of the connection.
+ <synopsis>
+ char *PQunixsocket(const PGconn *conn)
+ </synopsis>
+ </para>
+ </listitem>
+ 
+ <listitem>
+ <para>
<function>PQtty</function>
Returns the debug tty of the connection.
<synopsis>
***************
*** 1772,1777 ****
--- 1791,1803 ----
<envar>PGHOST</envar> sets the default server name.
If a non-zero-length string is specified, TCP/IP communication is used.
Without a host name, libpq will connect using a local Unix domain socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <envar>PGPORT</envar>  sets the default port or local Unix domain socket
+ file extension for communicating with the <productname>Postgres</productname>
+ backend.
</para>
</listitem>
<listitem>
Index: doc/src/sgml/start.sgml
*** doc/src/sgml/start.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/start.sgml	2000/07/02 03:56:05	1.2
***************
*** 110,117 ****
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> may also have to be set.  The bottom
!     line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
--- 110,117 ----
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> or <acronym>PGUNIXSOCKET</acronym> may also have to be set.
!     The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
Index: doc/src/sgml/ref/createdb.sgml
*** doc/src/sgml/ref/createdb.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createlang.sgml
*** doc/src/sgml/ref/createlang.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createlang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createuser.sgml
*** doc/src/sgml/ref/createuser.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,76 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/dropdb.sgml
*** doc/src/sgml/ref/dropdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/droplang.sgml
*** doc/src/sgml/ref/droplang.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/droplang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/dropuser.sgml
*** doc/src/sgml/ref/dropuser.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dump.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ]
!     [ -k <replaceable class="parameter">path</replaceable> ]
!     [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
***************
*** 200,205 ****
--- 202,222 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/pg_dumpall.sgml
*** doc/src/sgml/ref/pg_dumpall.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dumpall.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
--- 24,33 ----
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ]
!      [ -k <replaceable class="parameter">path</replaceable> ]
!      [ -p <replaceable class="parameter">port</replaceable> ]
!      [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
***************
*** 137,142 ****
--- 140,160 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/postmaster.sgml	2000/07/06 07:48:31	1.7
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ] [ -i ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ]
!     [ -h <replaceable class="parameter">hostname</replaceable> ] [ -i ]
!     [ -k <replaceable class="parameter">path</replaceable> ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
***************
*** 124,129 ****
--- 126,161 ----
</varlistentry>
<varlistentry>
+       <term>-h <replaceable class="parameter">hostName</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the TCP/IP hostname or address
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGHOST</envar> 
+ 	environment variable, or if <envar>PGHOST</envar>
+ 	is not set, then defaults to "all", meaning listen on all configured addresses
+ 	(including localhost).
+        </para>
+        <para>
+ 	If you use a hostname or address other than "all", do not try to run
+ 	multiple instances of <application>postmaster</application> on the
+ 	same IP address but different ports.  Doing so will result in them
+ 	attempting (incorrectly) to use the same shared memory segments.
+ 	Also, if you use a hostname other than "all", all of the host's IP addresses
+ 	on which <application>postmaster</application> instances are
+ 	listening must be distinct in the two last octets.
+        </para>
+        <para>
+ 	If you do use "all" (the default), then each instance must listen on a
+ 	different port (via -p or <envar>PGPORT</envar>).  And, of course, do
+ 	not try to use both approaches on one host.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-i</term>
<listitem>
<para>
***************
*** 135,140 ****
--- 167,201 ----
</varlistentry>
<varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket path name
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGUNIXSOCKET</envar> 
+ 	environment variable, or if <envar>PGUNIXSOCKET</envar>
+ 	is not set, then defaults to a file in <filename>/tmp</filename>
+ 	constructed from the port number.
+        </para>
+        <para>
+         You can use this option to put the Unix-domain socket in a
+         directory that is private to one or more users using Unix
+ 	directory permissions.  This is necessary for securely
+ 	creating databases automatically on shared machines.
+         In that situation, also disallow all TCP/IP connections
+ 	initially in <filename>pg_hba.conf</filename>.
+ 	If you specify a socket path other than the
+ 	default then all frontend applications (including
+ 	<application>psql</application>) must specify the same
+ 	socket path using either command-line options or
+ 	<envar>PGUNIXSOCKET</envar>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-l</term>
<listitem>
<para>
Index: doc/src/sgml/ref/psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/psql-ref.sgml	2000/07/02 03:56:05	1.3
***************
*** 1329,1334 ****
--- 1329,1347 ----
<varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
+ 
+     <varlistentry>
<term>-H, --html</term>
<listitem>
<para>
Index: doc/src/sgml/ref/vacuumdb.sgml
*** doc/src/sgml/ref/vacuumdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/vacuumdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --alldb | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
--- 24,30 ----
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --all | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
***************
*** 128,133 ****
--- 128,145 ----
</para>
</listitem>
</varlistentry>
+ 
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
<varlistentry>
<term>-U <replaceable class="parameter">username</replaceable></term>
Index: src/backend/libpq/pqcomm.c
*** src/backend/libpq/pqcomm.c	2000/06/30 21:15:40	1.1
--- src/backend/libpq/pqcomm.c	2000/07/01 18:50:46	1.3
***************
*** 42,47 ****
--- 42,48 ----
*		StreamConnection	- Create new connection with client
*		StreamClose			- Close a client/backend connection
*		pq_getport		- return the PGPORT setting
+  *		pq_getunixsocket	- return the PGUNIXSOCKET setting
*		pq_init			- initialize libpq at backend startup
*		pq_close		- shutdown libpq at backend exit
*
***************
*** 134,139 ****
--- 135,151 ----
}
/* --------------------------------
+  *		pq_getunixsocket - return the PGUNIXSOCKET setting.
+  *		If NULL, default to computing it based on the port.
+  * --------------------------------
+  */
+ char *
+ pq_getunixsocket(void)
+ {
+ 	return getenv("PGUNIXSOCKET");
+ }
+ 
+ /* --------------------------------
*		pq_close - shutdown libpq at backend exit
*
* Note: in a standalone backend MyProcPort will be null,
***************
*** 177,189 ****
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/
int
! StreamServerPort(char *hostName, unsigned short portName, int *fdP)
{
SockAddr	saddr;
int			fd,
--- 189,205 ----
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port fdP.
!  * If hostName is "any", listen on all configured IP addresses.
!  * If hostName is NULL, listen on a Unix-domain socket instead of TCP;
!  * if unixSocketName is NULL, a default path (constructed in UNIX_SOCK_PATH
!  * in include/libpq/pqcomm.h) based on portName is used.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/

int
! StreamServerPort(char *hostName, unsigned short portNumber, char *unixSocketName, int *fdP)
{
SockAddr saddr;
int fd,
***************
*** 227,233 ****
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! len = UNIXSOCK_PATH(saddr.un, portName);
strcpy(sock_path, saddr.un.sun_path);

/*
--- 243,250 ----
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! 		UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
! 		len = UNIXSOCK_LEN(saddr.un);
strcpy(sock_path, saddr.un.sun_path);
/*
***************
*** 259,267 ****
}
else
{
! 		saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 		saddr.in.sin_port = htons(portName);
! 		len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
--- 276,305 ----
}
else
{
! 	  /* TCP/IP socket */
! 	  if (!strcmp(hostName, "all")) /* like for databases in pg_hba.conf.  */
! 	    saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 	  else
! 	    {
! 	      struct hostent *hp;
! 
! 	      hp = gethostbyname(hostName);
! 	      if ((hp == NULL) || (hp->h_addrtype != AF_INET))
! 		{
! 		  snprintf(PQerrormsg, PQERRORMSG_LENGTH,
! 			   "FATAL: StreamServerPort: gethostbyname(%s) failed: %s\n",
! 			   hostName, hstrerror(h_errno));
! 		  fputs(PQerrormsg, stderr);
! 		  pqdebug("%s", PQerrormsg);
! 		  return STATUS_ERROR;
! 		}
! 	      memmove((char *) &(saddr.in.sin_addr),
! 		      (char *) hp->h_addr,
! 		      hp->h_length);
! 	    }
! 
! 	  saddr.in.sin_port = htons(portNumber);
! 	  len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
Index: src/backend/postmaster/postmaster.c
*** src/backend/postmaster/postmaster.c	2000/06/30 21:15:42	1.1
--- src/backend/postmaster/postmaster.c	2000/07/06 07:38:21	1.5
***************
*** 136,143 ****
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! static unsigned short PostPortName = 0;

/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
--- 136,150 ----
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! /* Hostname of interface to listen on, or 'any'. */
! static char *HostName = NULL;

+ /* TCP/IP port number to listen on.  Also used to default the Unix-domain socket name.  */
+ static unsigned short PostPortNumber = 0;
+ 
+ /* Override of the default Unix-domain socket name to listen on, if non-NULL.  */
+ static char *UnixSocketName = NULL;
+ 
/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
***************
*** 274,280 ****
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 281,287 ----
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 370,380 ****
{
extern int	NBuffers;		/* from buffer/bufmgr.c */
int			opt;
- 	char	   *hostName;
int			status;
int			silentflag = 0;
bool		DataDirOK;		/* We have a usable PGDATA value */
- 	char		hostbuf[MAXHOSTNAMELEN];
int			nonblank_argc;
char		original_extraoptions[MAXPGPATH];
--- 377,385 ----
***************
*** 431,449 ****
*/
umask((mode_t) 0077);

- if (!(hostName = getenv("PGHOST")))
- {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:ilm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
--- 436,447 ----
*/
umask((mode_t) 0077);

MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:h:ik:lm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
***************
*** 498,506 ****
--- 496,511 ----
DebugLvl = atoi(optarg);
pg_options[TRACE_VERBOSE] = DebugLvl;
break;
+ 			case 'h':
+ 				HostName = optarg;
+ 				break;
case 'i':
NetServer = true;
break;
+ 			case 'k':
+ 				/* Set PGUNIXSOCKET by hand. */
+ 				UnixSocketName = optarg;
+ 				break;
#ifdef USE_SSL
case 'l':
SecureNetServer = true;
***************
*** 545,551 ****
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortName = (unsigned short) atoi(optarg);
break;
case 'S':
--- 550,556 ----
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortNumber = (unsigned short) atoi(optarg);
break;
case 'S':

***************
*** 577,584 ****
/*
* Select default values for switches where needed
*/
! if (PostPortName == 0)
! PostPortName = (unsigned short) pq_getport();

/*
* Check for invalid combinations of switches
--- 582,603 ----
/*
* Select default values for switches where needed
*/
! 	if (HostName == NULL)
! 	{
! 		if (!(HostName = getenv("PGHOST")))
! 		{
! 			HostName = "any";
! 		}
! 	}
! 	else if (!NetServer)
! 	{
! 		fprintf(stderr, "%s: -h requires -i.\n", progname);
! 		exit(1);
! 	}
! 	if (PostPortNumber == 0)
! 		PostPortNumber = (unsigned short) pq_getport();
! 	if (UnixSocketName == NULL)
! 		UnixSocketName = pq_getunixsocket();

/*
* Check for invalid combinations of switches
***************
*** 622,628 ****

if (NetServer)
{
! 		status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
--- 641,647 ----

if (NetServer)
{
! status = StreamServerPort(HostName, PostPortNumber, NULL, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
***************
*** 632,638 ****
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! 	status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
--- 651,657 ----
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! status = StreamServerPort(NULL, PostPortNumber, UnixSocketName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
***************
*** 642,648 ****
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! reset_shared(PostPortName);

/*
* Initialize the list of active backends.	This list is only used for
--- 661,667 ----
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! 	reset_shared(PostPortNumber);
/*
* Initialize the list of active backends.	This list is only used for
***************
*** 664,670 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 683,691 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 753,759 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 774,782 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 837,843 ****
--- 860,868 ----
fprintf(stderr, "\t-a system\tuse this authentication system\n");
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
fprintf(stderr, "\t-d [1-5]\tset debugging level\n");
+ 	fprintf(stderr, "\t-h hostname\tspecify hostname or IP address or 'any' for postmaster to listen on (also use -i)\n");
fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+ 	fprintf(stderr, "\t-k path\tspecify Unix-domain socket name for postmaster to listen on\n");
#ifdef USE_SSL
fprintf(stderr, " \t-l \t\tfor TCP/IP sockets, listen only on SSL connections\n");
#endif
***************
*** 1318,1328 ****
--- 1343,1417 ----
}
/*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+ 	static unsigned short hostPort = 0;
+ 
+ 	if (hostPort == 0)
+ 	{
+ 		SockAddr	saddr;
+ 		struct hostent *hp;
+ 
+ 		hp = gethostbyname(HostName);
+ 		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+ 		{
+ 			char msg[1024];
+ 			snprintf(msg, sizeof(msg),
+ 				 "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+ 				 HostName, hstrerror(h_errno));
+ 			fputs(msg, stderr);
+ 			pqdebug("%s", msg);
+ 			exit(1);
+ 		}
+ 		memmove((char *) &(saddr.in.sin_addr),
+ 			(char *) hp->h_addr,
+ 			hp->h_length);
+ 		hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+ 	}
+ 
+ 	return hostPort;
+ }
+ 
+ /*
* reset_shared -- reset shared memory and semaphores
*/
static void
reset_shared(unsigned short port)
{
+ 	/*
+ 	 * A typical ipc_key is 5432001, which is port 5432, sequence
+ 	 * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+ 	 * The 32-bit INT_MAX is 2147483 6 47.
+ 	 *
+ 	 * The default algorithm for calculating the IPC keys assumes that all
+ 	 * instances of postmaster on a given host are listening on different
+ 	 * ports.  In order to work (prevent shared memory collisions) if you
+ 	 * run multiple PostgreSQL instances on the same port and different IP
+ 	 * addresses on a host, we change the algorithm if you give postmaster
+ 	 * the -h option, or set PGHOST, to a value other than the internal
+ 	 * default of "any".
+ 	 *
+ 	 * If HostName is not "any", then we generate the IPC keys using the
+ 	 * last two octets of the IP address instead of the port number.
+ 	 * This algorithm assumes that no one will run multiple PostgreSQL
+ 	 * instances on one host using two IP addresses that have the same two
+ 	 * last octets in different class C networks.  If anyone does, it
+ 	 * would be rare.
+ 	 *
+ 	 * So, if you use -h or PGHOST, don't try to run two instances of
+ 	 * PostgreSQL on the same IP address but different ports.  If you
+ 	 * don't use them, then you must use different ports (via -p or
+ 	 * PGPORT).  And, of course, don't try to use both approaches on one
+ 	 * host.
+ 	 */
+ 
+ 	if (strcmp(HostName, "any"))
+ 		port = get_host_port();
+ 
ipc_key = port * 1000 + shmem_seq * 100;
CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
shmem_seq += 1;
***************
*** 1540,1546 ****
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortName);
StartupPID = StartupDataBase();
return;
}
--- 1629,1635 ----
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortNumber);
StartupPID = StartupDataBase();
return;
}
***************
*** 1720,1726 ****
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
--- 1809,1815 ----
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
***************
*** 2174,2180 ****
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
--- 2263,2269 ----
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
***************
*** 2254,2260 ****
* Create the opts file
*/
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 2343,2349 ----
* Create the opts file
*/
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 2279,2284 ****
--- 2368,2383 ----
return (-1);
}
snprintf(opts, sizeof(opts), "%s\n-p %d\n-D %s\n", progname, port, datadir);
+ 	if (netserver)
+ 	{
+ 		sprintf(buf, "-h %s\n", hostname);
+ 		strcat(opts, buf);
+ 	}
+ 	if (unixsocket)
+ 	{
+ 		sprintf(buf, "-k %s\n", unixsocket);
+ 		strcat(opts, buf);
+ 	}
if (assert)
{
sprintf(buf, "-A %d\n", assert);
Index: src/bin/pg_dump/pg_dump.c
*** src/bin/pg_dump/pg_dump.c	2000/06/30 21:15:44	1.1
--- src/bin/pg_dump/pg_dump.c	2000/07/01 18:41:22	1.2
***************
*** 140,145 ****
--- 140,146 ----
"  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
"  -h, --host <hostname>    server host name\n"
"  -i, --ignore-version     proceed when database version != pg_dump version\n"
+ 		 "  -k, --unixsocket <path>  server Unix-domain socket name\n"
"  -n, --no-quotes          suppress most quotes around identifiers\n"
"  -N, --quotes             enable most quotes around identifiers\n"
"  -o, --oids               dump object ids (oids)\n"
***************
*** 158,163 ****
--- 159,165 ----
"  -D                       dump data as INSERT commands with attribute names\n"
"  -h <hostname>            server host name\n"
"  -i                       proceed when database version != pg_dump version\n"
+ 		 "  -k <path>                server Unix-domain socket name\n"
"  -n                       suppress most quotes around identifiers\n"
"  -N                       enable most quotes around identifiers\n"
"  -o                       dump object ids (oids)\n"
***************
*** 579,584 ****
--- 581,587 ----
const char *dbname = NULL;
const char *pghost = NULL;
const char *pgport = NULL;
+ 	const char *pgunixsocket = NULL;
char	   *tablename = NULL;
bool		oids = false;
TableInfo  *tblinfo;
***************
*** 598,603 ****
--- 601,607 ----
{"attribute-inserts", no_argument, NULL, 'D'},
{"host", required_argument, NULL, 'h'},
{"ignore-version", no_argument, NULL, 'i'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"no-quotes", no_argument, NULL, 'n'},
{"quotes", no_argument, NULL, 'N'},
{"oids", no_argument, NULL, 'o'},
***************
*** 662,667 ****
--- 666,674 ----
case 'i':			/* ignore database version mismatch */
ignore_version = true;
break;
+ 			case 'k':			/* server Unix-domain socket */
+ 				pgunixsocket = optarg;
+ 				break;
case 'n':			/* Do not force double-quotes on
* identifiers */
force_quotes = false;
***************
*** 782,788 ****
exit(1);
}
- 	/* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
if (pghost != NULL)
{
sprintf(tmp_string, "host=%s ", pghost);
--- 789,794 ----
***************
*** 791,796 ****
--- 797,807 ----
if (pgport != NULL)
{
sprintf(tmp_string, "port=%s ", pgport);
+ 		strcat(connect_string, tmp_string);
+ 	}
+ 	if (pgunixsocket != NULL)
+ 	{
+ 		sprintf(tmp_string, "unixsocket=%s ", pgunixsocket);
strcat(connect_string, tmp_string);
}
if (dbname != NULL)
Index: src/bin/psql/command.c
*** src/bin/psql/command.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/command.c	2000/07/01 18:20:40	1.2
***************
*** 1199,1204 ****
--- 1199,1205 ----
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 	SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
/* If dbname is "" then use old name, else new one (even if NULL) */
***************
*** 1228,1233 ****
--- 1229,1235 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to support passing the Unix socket */
pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
NULL, NULL, dbparam, userparam, pwparam);
***************
*** 1303,1308 ****
--- 1305,1311 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
pset.issuper = test_superuser(PQuser(pset.db));
Index: src/bin/psql/command.h
Index: src/bin/psql/common.c
*** src/bin/psql/common.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/common.c	2000/07/01 18:20:40	1.2
***************
*** 330,335 ****
--- 330,336 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 			SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return NULL;
***************
*** 509,514 ****
--- 510,516 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 				SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return false;
Index: src/bin/psql/help.c
*** src/bin/psql/help.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/help.c	2000/07/01 18:20:40	1.2
***************
*** 103,108 ****
--- 103,118 ----
puts(")");
puts("  -H              HTML table output mode (-P format=html)");
+ 
+ 	/* Display default Unix-domain socket */
+ 	env = getenv("PGUNIXSOCKET");
+ 	printf("  -k <path>       Specify Unix domain socket name (default: ");
+ 	if (env)
+ 		fputs(env, stdout);
+ 	else
+ 		fputs("computed from the port", stdout);
+ 	puts(")");
+ 
puts("  -l              List available databases, then exit");
puts("  -n              Disable readline");
puts("  -o <filename>   Send query output to filename (or |pipe)");
Index: src/bin/psql/prompt.c
*** src/bin/psql/prompt.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/prompt.c	2000/07/01 18:20:40	1.2
***************
*** 189,194 ****
--- 189,199 ----
if (pset.db && PQport(pset.db))
strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
break;
+ 					/* DB server Unix-domain socket */
+ 				case '<':
+ 					if (pset.db && PQunixsocket(pset.db))
+ 						strncpy(buf, PQunixsocket(pset.db), MAX_PROMPT_SIZE);
+ 					break;
/* DB server user name */
case 'n':
if (pset.db)
Index: src/bin/psql/prompt.h
Index: src/bin/psql/settings.h
Index: src/bin/psql/startup.c
*** src/bin/psql/startup.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/startup.c	2000/07/01 18:20:40	1.2
***************
*** 66,71 ****
--- 66,72 ----
char	   *dbname;
char	   *host;
char	   *port;
+ 	char	   *unixsocket;
char	   *username;
enum _actions action;
char	   *action_string;
***************
*** 158,163 ****
--- 159,165 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to allow setting the unix socket */
pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
options.action == ACT_LIST_DB ? "template1" : options.dbname,
username, password);
***************
*** 202,207 ****
--- 204,210 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
#ifndef WIN32
***************
*** 313,318 ****
--- 316,322 ----
{"field-separator", required_argument, NULL, 'F'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"list", no_argument, NULL, 'l'},
{"no-readline", no_argument, NULL, 'n'},
{"output", required_argument, NULL, 'o'},
***************
*** 346,359 ****
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
--- 350,363 ----
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
***************
*** 398,403 ****
--- 402,410 ----
break;
case 'l':
options->action = ACT_LIST_DB;
+ 				break;
+ 			case 'k':
+ 				options->unixsocket = optarg;
break;
case 'n':
options->no_readline = true;
Index: src/bin/scripts/createdb
*** src/bin/scripts/createdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createdb	2000/07/04 04:46:45	1.2
***************
*** 50,55 ****
--- 50,64 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 114,119 ****
--- 123,129 ----
echo "  -E, --encoding=ENCODING         Multibyte encoding for the database"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/createlang.sh
*** src/bin/scripts/createlang.sh	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createlang.sh	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 126,131 ****
--- 135,141 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to install language in"
Index: src/bin/scripts/createuser
*** src/bin/scripts/createuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createuser	2000/07/04 04:46:45	1.2
***************
*** 63,68 ****
--- 63,77 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're creating.
--username|-U)
***************
*** 135,140 ****
--- 144,150 ----
echo "  -P, --pwprompt                  Assign a password to new user"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to create)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/dropdb
*** src/bin/scripts/dropdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropdb	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 103,108 ****
--- 112,118 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/droplang
*** src/bin/scripts/droplang	2000/06/30 21:15:46	1.1
--- src/bin/scripts/droplang	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 113,118 ****
--- 122,128 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to remove language from"
Index: src/bin/scripts/dropuser
*** src/bin/scripts/dropuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropuser	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're dropping.
--username|-U)
***************
*** 105,110 ****
--- 114,120 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to drop)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/vacuumdb
*** src/bin/scripts/vacuumdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/vacuumdb	2000/07/04 04:46:45	1.2
***************
*** 52,57 ****
--- 52,66 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 121,126 ****
--- 130,136 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to vacuum"
Index: src/include/libpq/libpq.h
*** src/include/libpq/libpq.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/libpq.h	2000/07/01 18:20:40	1.2
***************
*** 236,246 ****
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
--- 236,247 ----
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, char *unixSocketName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
+ extern char	*pq_getunixsocket(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
Index: src/include/libpq/password.h
Index: src/include/libpq/pqcomm.h
*** src/include/libpq/pqcomm.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/pqcomm.h	2000/07/01 18:59:33	1.6
***************
*** 42,53 ****
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), \
! strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
--- 42,56 ----
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
Index: src/interfaces/libpq/fe-connect.c
*** src/interfaces/libpq/fe-connect.c	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/fe-connect.c	2000/07/01 18:50:47	1.3
***************
*** 125,130 ****
--- 125,133 ----
{"port", "PGPORT", DEF_PGPORT, NULL,
"Database-Port", "", 6},
+ 	{"unixsocket", "PGUNIXSOCKET", NULL, NULL,
+ 	"Unix-Socket", "", 80},
+ 
{"tty", "PGTTY", DefaultTty, NULL,
"Backend-Debug-TTY", "D", 40},
***************
*** 293,298 ****
--- 296,303 ----
conn->pghost = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "port");
conn->pgport = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "unixsocket");
+ 	conn->pgunixsocket = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "tty");
conn->pgtty = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "options");
***************
*** 369,374 ****
--- 374,382 ----
*	  PGPORT	   identifies TCP port to which to connect if <pgport> argument
*				   is NULL or a null string.
*
+  *	  PGUNIXSOCKET	   identifies Unix-domain socket to which to connect; default
+  *				   is computed from the TCP port.
+  *
*	  PGTTY		   identifies tty to which to send messages if <pgtty> argument
*				   is NULL or a null string.
*
***************
*** 422,427 ****
--- 430,439 ----
else
conn->pgport = strdup(pgport);
+ 	conn->pgunixsocket = getenv("PGUNIXSOCKET");
+ 	if (conn->pgunixsocket)
+ 		conn->pgunixsocket = strdup(conn->pgunixsocket);
+ 
if ((pgtty == NULL) || pgtty[0] == '\0')
{
if ((tmp = getenv("PGTTY")) == NULL)
***************
*** 489,501 ****

/*
* update_db_info -
! * get all additional infos out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
--- 501,513 ----

/*
* update_db_info -
! * get all additional info out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp, *tmp2,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
***************
*** 504,509 ****
--- 516,523 ----
tmp = strrchr(conn->dbName, ':');
if (tmp != NULL)		/* port number given */
{
+ 			if (conn->pgport)
+ 				free(conn->pgport);
conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 511,516 ****
--- 525,532 ----
tmp = strrchr(conn->dbName, '@');
if (tmp != NULL)		/* host name given */
{
+ 			if (conn->pghost)
+ 				free(conn->pghost);
conn->pghost = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 537,549 ****

/*
* new style:
! * <tcp|unix>:postgresql://server[:port][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL)	/* options given */
{
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
--- 553,567 ----

/*
* new style:
! * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL) /* options given */
{
+ if (conn->pgoptions)
+ free(conn->pgoptions);
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 551,576 ****
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL) /* database name given */
{
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
if ((tmp = getenv("PGDATABASE")) != NULL)
conn->dbName = strdup(tmp);
else if (conn->pguser)
conn->dbName = strdup(conn->pguser);
}

tmp = strrchr(old + offset, ':');
! if (tmp != NULL) /* port number given */
{
- conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}

if (strncmp(old, "unix:", 5) == 0)
{
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
--- 569,630 ----
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL)	/* database name given */
{
+ 				if (conn->dbName)
+ 					free(conn->dbName);
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
+ 				/* Why do we default only this value from the environment again?  */
if ((tmp = getenv("PGDATABASE")) != NULL)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(tmp);
+ 				}
else if (conn->pguser)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(conn->pguser);
+ 				}
}
tmp = strrchr(old + offset, ':');
! 			if (tmp != NULL)	/* port number or Unix socket path given */
{
*tmp = '\0';
+ 				if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
+ 				{
+ 					if (strncmp(old, "unix:", 5) != 0)
+ 					{
+ 						printfPQExpBuffer(&conn->errorMessage,
+ 								  "connectDBStart() -- "
+ 								  "socket name can only be specified with "
+ 								  "non-TCP\n");
+ 						return 1; 
+ 					}
+ 					*tmp2 = '\0';
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = strdup(tmp + 1);
+ 				}
+ 				else
+ 				{
+ 					if (conn->pgport)
+ 						free(conn->pgport);
+ 					conn->pgport = strdup(tmp + 1);
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = NULL;
+ 				}
}
if (strncmp(old, "unix:", 5) == 0)
{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
***************
*** 582,589 ****
}
}
else
conn->pghost = strdup(old + offset);
! 
free(old);
}
}
--- 636,646 ----
}
}
else
+ 			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = strdup(old + offset);
! 			}
free(old);
}
}
***************
*** 743,749 ****
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
#endif
--- 800,809 ----
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 	{
! 		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
! 		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
! 	}
#endif
***************
*** 892,898 ****
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  conn->pgport);
goto connect_errReturn;
}
}
--- 952,959 ----
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (family == AF_UNIX && conn->pgunixsocket) ?
! 							  conn->pgunixsocket : conn->pgport);
goto connect_errReturn;
}
}
***************
*** 1123,1129 ****
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 									  conn->pgport);
goto error_return;
}
--- 1184,1191 ----
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (conn->raddr.sa.sa_family == AF_UNIX && conn->pgunixsocket) ?
! 									  conn->pgunixsocket : conn->pgport);
goto error_return;
}
***************
*** 1799,1804 ****
--- 1861,1868 ----
free(conn->pghostaddr);
if (conn->pgport)
free(conn->pgport);
+ 	if (conn->pgunixsocket)
+ 		free(conn->pgunixsocket);
if (conn->pgtty)
free(conn->pgtty);
if (conn->pgoptions)
***************
*** 2383,2388 ****
--- 2447,2460 ----
if (!conn)
return (char *) NULL;
return conn->pgport;
+ }
+ 
+ char *
+ PQunixsocket(const PGconn *conn)
+ {
+ 	if (!conn)
+ 		return (char *) NULL;
+ 	return conn->pgunixsocket;
}
char *
Index: src/interfaces/libpq/libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-fe.h	2000/07/01 18:20:40	1.2
***************
*** 214,219 ****
--- 214,220 ----
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
extern char *PQport(const PGconn *conn);
+ 	extern char *PQunixsocket(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(const PGconn *conn);
Index: src/interfaces/libpq/libpq-int.h
*** src/interfaces/libpq/libpq-int.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-int.h	2000/07/01 18:20:40	1.2
***************
*** 202,207 ****
--- 202,209 ----
* numbers-and-dots notation. Takes
* precedence over above. */
char	   *pgport;			/* the server's communication port */
+ 	char	   *pgunixsocket;		/* the Unix-domain socket that the server is listening on;
+ 						 * if NULL, uses a default constructed from pgport */
char	   *pgtty;			/* tty on which the backend messages is
* displayed (NOT ACTUALLY USED???) */
char	   *pgoptions;		/* options to start the backend with */
Index: src/interfaces/libpq/libpqdll.def
*** src/interfaces/libpq/libpqdll.def	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpqdll.def	2000/07/01 18:20:40	1.2
***************
*** 79,81 ****
--- 79,82 ----
destroyPQExpBuffer	@ 76
createPQExpBuffer	@ 77
PQconninfoFree		@ 78
+ 	PQunixsocket		@ 79
-- 
Bruce Momjian                        |  http://candle.pha.pa.us
pgman@candle.pha.pa.us               |  (610) 853-3000
+  If your life is a hard drive,     |  830 Blythe Avenue
+  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Marc G. Fournier ICQ#7615664 IRC Nick: Scrappy
Systems Administrator @ hub.org
primary: scrappy@hub.org secondary: scrappy@{freebsd|postgresql}.org

#5Lamar Owen
lamar.owen@wgcr.org
In reply to: Bruce Momjian (#3)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian wrote:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

A cursory inspection makes it look like the socket file can be placed
_anywhere_ -- even under a chroot jail. This would make more than one
person's day, Bruce. This would allow a chrooted webserver to connect
to a postmaster outside the jail -- while not terribly appealing from a
security standpoint (as any pipe out of a jail could be exploited), it
IS appealing when you need more than one chrooted webserver (doing
virtual hosting) to connect ot a common database (for hosting-site-wide
services).

If this patch passes muster (muster pass Tom Lane's eyes), and you feel
comfortable with it, I don't see why not -- this might not be a major
feature, but it IS a nice one, IMHO.

Now, if I'm wrong about the placement of the socket, well, I'm just
wrong -- but the vhosting feature is still nice.

--
Lamar Owen
WGCR Internet Radio
1 Peter 4:11

#6Alfred Perlstein
bright@wintelcom.net
In reply to: Bruce Momjian (#3)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

* Bruce Momjian <pgman@candle.pha.pa.us> [001010 18:36] wrote:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Any objections?

I know several other people were struggling with having multiple instances
of postgresql running on a box, especially keeping the unix domain pipe
hidden, this looks like a great thing to add.

-Alfred

#7Peter Eisentraut
peter_e@gmx.net
In reply to: Bruce Momjian (#3)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian writes:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Postmaster options are evil, please put something in backend/utils/guc.c.
(This is not the fault of the patch submitter, since this interface is new
for 7.1, but that still doesn't mean we should subvert it.)

2. The ability to place the Unix-domain socket in a mode 700 directory.

This would be a rather sharp instrument to offer to the world at large,
because the socket file is also a lock file, so you can't just get rid of
it.

If we were to offer that anyway, I'd opine that we reuse the -h option
(e.g., leading slash means Unix socket) rather than adding a -k option
everywhere.

--
Peter Eisentraut peter_e@gmx.net http://yi.org/peter-e/

#8David J. MacKenzie
djm@web.us.uu.net
In reply to: Peter Eisentraut (#7)
Re: [PATCHES] PostgreSQL virtual hosting support

I have created the following patch with applies to the current source
tree. However, there have been significant changes since 7.0, and even
my patch does not incorporate all the other changes.

I am not sure what to recommend. It would be optimal if you could take
your patch, grab our current snapshot, and submit a new patch that works
with our current code. Another option if you are too busy is to have
one of our folks massage my patch to more properly merge into the
existing code.

Please let me know how you would like to proceed. My version of your patch
is attached.

First of all, thank you for taking the time to work on my submission!
I would prefer if someone who's already familiar with what's changed since
7.0 would make whatever adjustments are needed. I'm occupied with
other projects at the moment. If it turns out that no one else has time
to work on it, I'll be the fallback.

#9Bruce Momjian
pgman@candle.pha.pa.us
In reply to: David J. MacKenzie (#1)
1 attachment(s)
Re: PostgreSQL virtual hosting support

I have finally merged this patch into our current tree, and have created
a diff file that I have attached to this email. If no one objects, I
will apply this change to the current tree tomorrow. It allows the
postmaster to listen to only certain hosts and to place the socket file
in a certain directory.

The only item not done is that PQsetdbLogin() does not have a parameter
to accept the unix socket path. Not sure we want to change that API
just to allow unix socket path specification.

Your name : David MacKenzie
Your email address : djm@web.us.uu.net

System Configuration
---------------------
Architecture (example: Intel Pentium) : Intel x86

Operating System (example: Linux 2.0.26 ELF) : BSD/OS 4.0.1

PostgreSQL version (example: PostgreSQL-7.0): PostgreSQL-7.0.2

Compiler used (example: gcc 2.8.0) : gcc version 2.7.2.1

Please enter a FULL description of your problem:
------------------------------------------------

UUNET is looking into offering PostgreSQL as a part of a managed web
hosting product, on both shared and dedicated machines. We currently
offer Oracle and MySQL, and it would be a nice middle-ground.
However, as shipped, PostgreSQL lacks the following features we need
that MySQL has:

1. The ability to listen only on a particular IP address. Each
hosting customer has their own IP address, on which all of their
servers (http, ftp, real media, etc.) run.
2. The ability to place the Unix-domain socket in a mode 700 directory.
This allows us to automatically create an empty database, with an
empty DBA password, for new or upgrading customers without having
to interactively set a DBA password and communicate it to (or from)
the customer. This in turn cuts down our install and upgrade times.
3. The ability to connect to the Unix-domain socket from within a
change-rooted environment. We run CGI programs chrooted to the
user's home directory, which is another reason why we need to be
able to specify where the Unix-domain socket is, instead of /tmp.
4. The ability to, if run as root, open a pid file in /var/run as
root, and then setuid to the desired user. (mysqld -u can almost
do this; I had to patch it, too).

The patch below fixes problem 1-3. I plan to address #4, also, but
haven't done so yet. These diffs are big enough that they should give
the PG development team something to think about in the meantime :-)
Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get
out what I have, which works (for the problems it tackles), now.

With these changes, we can set up and run PostgreSQL with scripts the
same way we can with apache or proftpd or mysql.

In summary, this patch makes the following enhancements:

1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT,
and command line options -k --unix-socket to the relevant programs.
2. Adds a -h option to postmaster to set the hostname or IP address to
listen on instead of the default INADDR_ANY.
3. Extends some library interfaces to support the above.
4. Fixes a few memory leaks in PQconnectdb().

The default behavior is unchanged from stock 7.0.2; if you don't use
any of these new features, they don't change the operation.

Index: doc/src/sgml/layout.sgml
*** doc/src/sgml/layout.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/layout.sgml	2000/07/02 03:56:05	1.2
***************
*** 55,61 ****
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> may also have to be set.  The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
--- 55,62 ----
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> or <envar>PGUNIXSOCKET</envar> may also have to be set.
! The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
Index: doc/src/sgml/libpq++.sgml
*** doc/src/sgml/libpq++.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq++.sgml	2000/07/02 03:56:05	1.2
***************
*** 93,98 ****
--- 93,105 ----
</listitem>
<listitem>
<para>
+ 	<envar>PGUNIXSOCKET</envar>  sets the full Unix domain socket
+ 	file name for communicating with the <productname>Postgres</productname>
+ 	backend.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
<envar>PGDATABASE</envar>  sets the default 
<productname>Postgres</productname> database name.
</para>
Index: doc/src/sgml/libpq.sgml
*** doc/src/sgml/libpq.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq.sgml	2000/07/02 03:56:05	1.2
***************
*** 134,139 ****
--- 134,148 ----
</varlistentry>
<varlistentry>
+      <term><literal>unixsocket</literal></term>
+      <listitem>
+      <para>
+       Full path to Unix-domain socket file to connect to at the server host.
+      </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
<term><literal>dbname</literal></term>
<listitem>
<para>
***************
*** 545,550 ****
--- 554,569 ----
<listitem>
<para>
+ <function>PQunixsocket</function>
+          Returns the name of the Unix-domain socket of the connection.
+ <synopsis>
+ char *PQunixsocket(const PGconn *conn)
+ </synopsis>
+ </para>
+ </listitem>
+ 
+ <listitem>
+ <para>
<function>PQtty</function>
Returns the debug tty of the connection.
<synopsis>
***************
*** 1772,1777 ****
--- 1791,1803 ----
<envar>PGHOST</envar> sets the default server name.
If a non-zero-length string is specified, TCP/IP communication is used.
Without a host name, libpq will connect using a local Unix domain socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <envar>PGPORT</envar>  sets the default port or local Unix domain socket
+ file extension for communicating with the <productname>Postgres</productname>
+ backend.
</para>
</listitem>
<listitem>
Index: doc/src/sgml/start.sgml
*** doc/src/sgml/start.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/start.sgml	2000/07/02 03:56:05	1.2
***************
*** 110,117 ****
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> may also have to be set.  The bottom
!     line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
--- 110,117 ----
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> or <acronym>PGUNIXSOCKET</acronym> may also have to be set.
!     The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
Index: doc/src/sgml/ref/createdb.sgml
*** doc/src/sgml/ref/createdb.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createlang.sgml
*** doc/src/sgml/ref/createlang.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createlang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createuser.sgml
*** doc/src/sgml/ref/createuser.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,76 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/dropdb.sgml
*** doc/src/sgml/ref/dropdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/droplang.sgml
*** doc/src/sgml/ref/droplang.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/droplang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/dropuser.sgml
*** doc/src/sgml/ref/dropuser.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dump.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ]
!     [ -k <replaceable class="parameter">path</replaceable> ]
!     [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
***************
*** 200,205 ****
--- 202,222 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/pg_dumpall.sgml
*** doc/src/sgml/ref/pg_dumpall.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dumpall.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
--- 24,33 ----
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ]
!      [ -k <replaceable class="parameter">path</replaceable> ]
!      [ -p <replaceable class="parameter">port</replaceable> ]
!      [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
***************
*** 137,142 ****
--- 140,160 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/postmaster.sgml	2000/07/06 07:48:31	1.7
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ] [ -i ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ]
!     [ -h <replaceable class="parameter">hostname</replaceable> ] [ -i ]
!     [ -k <replaceable class="parameter">path</replaceable> ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
***************
*** 124,129 ****
--- 126,161 ----
</varlistentry>
<varlistentry>
+       <term>-h <replaceable class="parameter">hostName</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the TCP/IP hostname or address
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGHOST</envar> 
+ 	environment variable, or if <envar>PGHOST</envar>
+ 	is not set, then defaults to "all", meaning listen on all configured addresses
+ 	(including localhost).
+        </para>
+        <para>
+ 	If you use a hostname or address other than "all", do not try to run
+ 	multiple instances of <application>postmaster</application> on the
+ 	same IP address but different ports.  Doing so will result in them
+ 	attempting (incorrectly) to use the same shared memory segments.
+ 	Also, if you use a hostname other than "all", all of the host's IP addresses
+ 	on which <application>postmaster</application> instances are
+ 	listening must be distinct in the two last octets.
+        </para>
+        <para>
+ 	If you do use "all" (the default), then each instance must listen on a
+ 	different port (via -p or <envar>PGPORT</envar>).  And, of course, do
+ 	not try to use both approaches on one host.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-i</term>
<listitem>
<para>
***************
*** 135,140 ****
--- 167,201 ----
</varlistentry>
<varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket path name
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGUNIXSOCKET</envar> 
+ 	environment variable, or if <envar>PGUNIXSOCKET</envar>
+ 	is not set, then defaults to a file in <filename>/tmp</filename>
+ 	constructed from the port number.
+        </para>
+        <para>
+         You can use this option to put the Unix-domain socket in a
+         directory that is private to one or more users using Unix
+ 	directory permissions.  This is necessary for securely
+ 	creating databases automatically on shared machines.
+         In that situation, also disallow all TCP/IP connections
+ 	initially in <filename>pg_hba.conf</filename>.
+ 	If you specify a socket path other than the
+ 	default then all frontend applications (including
+ 	<application>psql</application>) must specify the same
+ 	socket path using either command-line options or
+ 	<envar>PGUNIXSOCKET</envar>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-l</term>
<listitem>
<para>
Index: doc/src/sgml/ref/psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/psql-ref.sgml	2000/07/02 03:56:05	1.3
***************
*** 1329,1334 ****
--- 1329,1347 ----
<varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
+ 
+     <varlistentry>
<term>-H, --html</term>
<listitem>
<para>
Index: doc/src/sgml/ref/vacuumdb.sgml
*** doc/src/sgml/ref/vacuumdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/vacuumdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --alldb | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
--- 24,30 ----
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --all | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
***************
*** 128,133 ****
--- 128,145 ----
</para>
</listitem>
</varlistentry>
+ 
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
<varlistentry>
<term>-U <replaceable class="parameter">username</replaceable></term>
Index: src/backend/libpq/pqcomm.c
*** src/backend/libpq/pqcomm.c	2000/06/30 21:15:40	1.1
--- src/backend/libpq/pqcomm.c	2000/07/01 18:50:46	1.3
***************
*** 42,47 ****
--- 42,48 ----
*		StreamConnection	- Create new connection with client
*		StreamClose			- Close a client/backend connection
*		pq_getport		- return the PGPORT setting
+  *		pq_getunixsocket	- return the PGUNIXSOCKET setting
*		pq_init			- initialize libpq at backend startup
*		pq_close		- shutdown libpq at backend exit
*
***************
*** 134,139 ****
--- 135,151 ----
}
/* --------------------------------
+  *		pq_getunixsocket - return the PGUNIXSOCKET setting.
+  *		If NULL, default to computing it based on the port.
+  * --------------------------------
+  */
+ char *
+ pq_getunixsocket(void)
+ {
+ 	return getenv("PGUNIXSOCKET");
+ }
+ 
+ /* --------------------------------
*		pq_close - shutdown libpq at backend exit
*
* Note: in a standalone backend MyProcPort will be null,
***************
*** 177,189 ****
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/
int
! StreamServerPort(char *hostName, unsigned short portName, int *fdP)
{
SockAddr	saddr;
int			fd,
--- 189,205 ----
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port fdP.
!  * If hostName is "any", listen on all configured IP addresses.
!  * If hostName is NULL, listen on a Unix-domain socket instead of TCP;
!  * if unixSocketName is NULL, a default path (constructed in UNIX_SOCK_PATH
!  * in include/libpq/pqcomm.h) based on portName is used.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/

int
! StreamServerPort(char *hostName, unsigned short portNumber, char *unixSocketName, int *fdP)
{
SockAddr saddr;
int fd,
***************
*** 227,233 ****
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! len = UNIXSOCK_PATH(saddr.un, portName);
strcpy(sock_path, saddr.un.sun_path);

/*
--- 243,250 ----
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! 		UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
! 		len = UNIXSOCK_LEN(saddr.un);
strcpy(sock_path, saddr.un.sun_path);
/*
***************
*** 259,267 ****
}
else
{
! 		saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 		saddr.in.sin_port = htons(portName);
! 		len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
--- 276,305 ----
}
else
{
! 	  /* TCP/IP socket */
! 	  if (!strcmp(hostName, "all")) /* like for databases in pg_hba.conf.  */
! 	    saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 	  else
! 	    {
! 	      struct hostent *hp;
! 
! 	      hp = gethostbyname(hostName);
! 	      if ((hp == NULL) || (hp->h_addrtype != AF_INET))
! 		{
! 		  snprintf(PQerrormsg, PQERRORMSG_LENGTH,
! 			   "FATAL: StreamServerPort: gethostbyname(%s) failed: %s\n",
! 			   hostName, hstrerror(h_errno));
! 		  fputs(PQerrormsg, stderr);
! 		  pqdebug("%s", PQerrormsg);
! 		  return STATUS_ERROR;
! 		}
! 	      memmove((char *) &(saddr.in.sin_addr),
! 		      (char *) hp->h_addr,
! 		      hp->h_length);
! 	    }
! 
! 	  saddr.in.sin_port = htons(portNumber);
! 	  len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
Index: src/backend/postmaster/postmaster.c
*** src/backend/postmaster/postmaster.c	2000/06/30 21:15:42	1.1
--- src/backend/postmaster/postmaster.c	2000/07/06 07:38:21	1.5
***************
*** 136,143 ****
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! static unsigned short PostPortName = 0;

/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
--- 136,150 ----
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! /* Hostname of interface to listen on, or 'any'. */
! static char *HostName = NULL;

+ /* TCP/IP port number to listen on.  Also used to default the Unix-domain socket name.  */
+ static unsigned short PostPortNumber = 0;
+ 
+ /* Override of the default Unix-domain socket name to listen on, if non-NULL.  */
+ static char *UnixSocketName = NULL;
+ 
/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
***************
*** 274,280 ****
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 281,287 ----
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 370,380 ****
{
extern int	NBuffers;		/* from buffer/bufmgr.c */
int			opt;
- 	char	   *hostName;
int			status;
int			silentflag = 0;
bool		DataDirOK;		/* We have a usable PGDATA value */
- 	char		hostbuf[MAXHOSTNAMELEN];
int			nonblank_argc;
char		original_extraoptions[MAXPGPATH];
--- 377,385 ----
***************
*** 431,449 ****
*/
umask((mode_t) 0077);

- if (!(hostName = getenv("PGHOST")))
- {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:ilm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
--- 436,447 ----
*/
umask((mode_t) 0077);

MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:h:ik:lm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
***************
*** 498,506 ****
--- 496,511 ----
DebugLvl = atoi(optarg);
pg_options[TRACE_VERBOSE] = DebugLvl;
break;
+ 			case 'h':
+ 				HostName = optarg;
+ 				break;
case 'i':
NetServer = true;
break;
+ 			case 'k':
+ 				/* Set PGUNIXSOCKET by hand. */
+ 				UnixSocketName = optarg;
+ 				break;
#ifdef USE_SSL
case 'l':
SecureNetServer = true;
***************
*** 545,551 ****
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortName = (unsigned short) atoi(optarg);
break;
case 'S':
--- 550,556 ----
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortNumber = (unsigned short) atoi(optarg);
break;
case 'S':

***************
*** 577,584 ****
/*
* Select default values for switches where needed
*/
! if (PostPortName == 0)
! PostPortName = (unsigned short) pq_getport();

/*
* Check for invalid combinations of switches
--- 582,603 ----
/*
* Select default values for switches where needed
*/
! 	if (HostName == NULL)
! 	{
! 		if (!(HostName = getenv("PGHOST")))
! 		{
! 			HostName = "any";
! 		}
! 	}
! 	else if (!NetServer)
! 	{
! 		fprintf(stderr, "%s: -h requires -i.\n", progname);
! 		exit(1);
! 	}
! 	if (PostPortNumber == 0)
! 		PostPortNumber = (unsigned short) pq_getport();
! 	if (UnixSocketName == NULL)
! 		UnixSocketName = pq_getunixsocket();

/*
* Check for invalid combinations of switches
***************
*** 622,628 ****

if (NetServer)
{
! 		status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
--- 641,647 ----

if (NetServer)
{
! status = StreamServerPort(HostName, PostPortNumber, NULL, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
***************
*** 632,638 ****
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! 	status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
--- 651,657 ----
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! status = StreamServerPort(NULL, PostPortNumber, UnixSocketName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
***************
*** 642,648 ****
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! reset_shared(PostPortName);

/*
* Initialize the list of active backends.	This list is only used for
--- 661,667 ----
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! 	reset_shared(PostPortNumber);
/*
* Initialize the list of active backends.	This list is only used for
***************
*** 664,670 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 683,691 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 753,759 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 774,782 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 837,843 ****
--- 860,868 ----
fprintf(stderr, "\t-a system\tuse this authentication system\n");
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
fprintf(stderr, "\t-d [1-5]\tset debugging level\n");
+ 	fprintf(stderr, "\t-h hostname\tspecify hostname or IP address or 'any' for postmaster to listen on (also use -i)\n");
fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+ 	fprintf(stderr, "\t-k path\tspecify Unix-domain socket name for postmaster to listen on\n");
#ifdef USE_SSL
fprintf(stderr, " \t-l \t\tfor TCP/IP sockets, listen only on SSL connections\n");
#endif
***************
*** 1318,1328 ****
--- 1343,1417 ----
}
/*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+ 	static unsigned short hostPort = 0;
+ 
+ 	if (hostPort == 0)
+ 	{
+ 		SockAddr	saddr;
+ 		struct hostent *hp;
+ 
+ 		hp = gethostbyname(HostName);
+ 		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+ 		{
+ 			char msg[1024];
+ 			snprintf(msg, sizeof(msg),
+ 				 "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+ 				 HostName, hstrerror(h_errno));
+ 			fputs(msg, stderr);
+ 			pqdebug("%s", msg);
+ 			exit(1);
+ 		}
+ 		memmove((char *) &(saddr.in.sin_addr),
+ 			(char *) hp->h_addr,
+ 			hp->h_length);
+ 		hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+ 	}
+ 
+ 	return hostPort;
+ }
+ 
+ /*
* reset_shared -- reset shared memory and semaphores
*/
static void
reset_shared(unsigned short port)
{
+ 	/*
+ 	 * A typical ipc_key is 5432001, which is port 5432, sequence
+ 	 * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+ 	 * The 32-bit INT_MAX is 2147483 6 47.
+ 	 *
+ 	 * The default algorithm for calculating the IPC keys assumes that all
+ 	 * instances of postmaster on a given host are listening on different
+ 	 * ports.  In order to work (prevent shared memory collisions) if you
+ 	 * run multiple PostgreSQL instances on the same port and different IP
+ 	 * addresses on a host, we change the algorithm if you give postmaster
+ 	 * the -h option, or set PGHOST, to a value other than the internal
+ 	 * default of "any".
+ 	 *
+ 	 * If HostName is not "any", then we generate the IPC keys using the
+ 	 * last two octets of the IP address instead of the port number.
+ 	 * This algorithm assumes that no one will run multiple PostgreSQL
+ 	 * instances on one host using two IP addresses that have the same two
+ 	 * last octets in different class C networks.  If anyone does, it
+ 	 * would be rare.
+ 	 *
+ 	 * So, if you use -h or PGHOST, don't try to run two instances of
+ 	 * PostgreSQL on the same IP address but different ports.  If you
+ 	 * don't use them, then you must use different ports (via -p or
+ 	 * PGPORT).  And, of course, don't try to use both approaches on one
+ 	 * host.
+ 	 */
+ 
+ 	if (strcmp(HostName, "any"))
+ 		port = get_host_port();
+ 
ipc_key = port * 1000 + shmem_seq * 100;
CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
shmem_seq += 1;
***************
*** 1540,1546 ****
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortName);
StartupPID = StartupDataBase();
return;
}
--- 1629,1635 ----
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortNumber);
StartupPID = StartupDataBase();
return;
}
***************
*** 1720,1726 ****
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
--- 1809,1815 ----
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
***************
*** 2174,2180 ****
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
--- 2263,2269 ----
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
***************
*** 2254,2260 ****
* Create the opts file
*/
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 2343,2349 ----
* Create the opts file
*/
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 2279,2284 ****
--- 2368,2383 ----
return (-1);
}
snprintf(opts, sizeof(opts), "%s\n-p %d\n-D %s\n", progname, port, datadir);
+ 	if (netserver)
+ 	{
+ 		sprintf(buf, "-h %s\n", hostname);
+ 		strcat(opts, buf);
+ 	}
+ 	if (unixsocket)
+ 	{
+ 		sprintf(buf, "-k %s\n", unixsocket);
+ 		strcat(opts, buf);
+ 	}
if (assert)
{
sprintf(buf, "-A %d\n", assert);
Index: src/bin/pg_dump/pg_dump.c
*** src/bin/pg_dump/pg_dump.c	2000/06/30 21:15:44	1.1
--- src/bin/pg_dump/pg_dump.c	2000/07/01 18:41:22	1.2
***************
*** 140,145 ****
--- 140,146 ----
"  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
"  -h, --host <hostname>    server host name\n"
"  -i, --ignore-version     proceed when database version != pg_dump version\n"
+ 		 "  -k, --unixsocket <path>  server Unix-domain socket name\n"
"  -n, --no-quotes          suppress most quotes around identifiers\n"
"  -N, --quotes             enable most quotes around identifiers\n"
"  -o, --oids               dump object ids (oids)\n"
***************
*** 158,163 ****
--- 159,165 ----
"  -D                       dump data as INSERT commands with attribute names\n"
"  -h <hostname>            server host name\n"
"  -i                       proceed when database version != pg_dump version\n"
+ 		 "  -k <path>                server Unix-domain socket name\n"
"  -n                       suppress most quotes around identifiers\n"
"  -N                       enable most quotes around identifiers\n"
"  -o                       dump object ids (oids)\n"
***************
*** 579,584 ****
--- 581,587 ----
const char *dbname = NULL;
const char *pghost = NULL;
const char *pgport = NULL;
+ 	const char *pgunixsocket = NULL;
char	   *tablename = NULL;
bool		oids = false;
TableInfo  *tblinfo;
***************
*** 598,603 ****
--- 601,607 ----
{"attribute-inserts", no_argument, NULL, 'D'},
{"host", required_argument, NULL, 'h'},
{"ignore-version", no_argument, NULL, 'i'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"no-quotes", no_argument, NULL, 'n'},
{"quotes", no_argument, NULL, 'N'},
{"oids", no_argument, NULL, 'o'},
***************
*** 662,667 ****
--- 666,674 ----
case 'i':			/* ignore database version mismatch */
ignore_version = true;
break;
+ 			case 'k':			/* server Unix-domain socket */
+ 				pgunixsocket = optarg;
+ 				break;
case 'n':			/* Do not force double-quotes on
* identifiers */
force_quotes = false;
***************
*** 782,788 ****
exit(1);
}
- 	/* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
if (pghost != NULL)
{
sprintf(tmp_string, "host=%s ", pghost);
--- 789,794 ----
***************
*** 791,796 ****
--- 797,807 ----
if (pgport != NULL)
{
sprintf(tmp_string, "port=%s ", pgport);
+ 		strcat(connect_string, tmp_string);
+ 	}
+ 	if (pgunixsocket != NULL)
+ 	{
+ 		sprintf(tmp_string, "unixsocket=%s ", pgunixsocket);
strcat(connect_string, tmp_string);
}
if (dbname != NULL)
Index: src/bin/psql/command.c
*** src/bin/psql/command.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/command.c	2000/07/01 18:20:40	1.2
***************
*** 1199,1204 ****
--- 1199,1205 ----
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 	SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
/* If dbname is "" then use old name, else new one (even if NULL) */
***************
*** 1228,1233 ****
--- 1229,1235 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to support passing the Unix socket */
pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
NULL, NULL, dbparam, userparam, pwparam);
***************
*** 1303,1308 ****
--- 1305,1311 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
pset.issuper = test_superuser(PQuser(pset.db));
Index: src/bin/psql/command.h
Index: src/bin/psql/common.c
*** src/bin/psql/common.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/common.c	2000/07/01 18:20:40	1.2
***************
*** 330,335 ****
--- 330,336 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 			SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return NULL;
***************
*** 509,514 ****
--- 510,516 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 				SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return false;
Index: src/bin/psql/help.c
*** src/bin/psql/help.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/help.c	2000/07/01 18:20:40	1.2
***************
*** 103,108 ****
--- 103,118 ----
puts(")");
puts("  -H              HTML table output mode (-P format=html)");
+ 
+ 	/* Display default Unix-domain socket */
+ 	env = getenv("PGUNIXSOCKET");
+ 	printf("  -k <path>       Specify Unix domain socket name (default: ");
+ 	if (env)
+ 		fputs(env, stdout);
+ 	else
+ 		fputs("computed from the port", stdout);
+ 	puts(")");
+ 
puts("  -l              List available databases, then exit");
puts("  -n              Disable readline");
puts("  -o <filename>   Send query output to filename (or |pipe)");
Index: src/bin/psql/prompt.c
*** src/bin/psql/prompt.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/prompt.c	2000/07/01 18:20:40	1.2
***************
*** 189,194 ****
--- 189,199 ----
if (pset.db && PQport(pset.db))
strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
break;
+ 					/* DB server Unix-domain socket */
+ 				case '<':
+ 					if (pset.db && PQunixsocket(pset.db))
+ 						strncpy(buf, PQunixsocket(pset.db), MAX_PROMPT_SIZE);
+ 					break;
/* DB server user name */
case 'n':
if (pset.db)
Index: src/bin/psql/prompt.h
Index: src/bin/psql/settings.h
Index: src/bin/psql/startup.c
*** src/bin/psql/startup.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/startup.c	2000/07/01 18:20:40	1.2
***************
*** 66,71 ****
--- 66,72 ----
char	   *dbname;
char	   *host;
char	   *port;
+ 	char	   *unixsocket;
char	   *username;
enum _actions action;
char	   *action_string;
***************
*** 158,163 ****
--- 159,165 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to allow setting the unix socket */
pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
options.action == ACT_LIST_DB ? "template1" : options.dbname,
username, password);
***************
*** 202,207 ****
--- 204,210 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
#ifndef WIN32
***************
*** 313,318 ****
--- 316,322 ----
{"field-separator", required_argument, NULL, 'F'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"list", no_argument, NULL, 'l'},
{"no-readline", no_argument, NULL, 'n'},
{"output", required_argument, NULL, 'o'},
***************
*** 346,359 ****
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
--- 350,363 ----
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
***************
*** 398,403 ****
--- 402,410 ----
break;
case 'l':
options->action = ACT_LIST_DB;
+ 				break;
+ 			case 'k':
+ 				options->unixsocket = optarg;
break;
case 'n':
options->no_readline = true;
Index: src/bin/scripts/createdb
*** src/bin/scripts/createdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createdb	2000/07/04 04:46:45	1.2
***************
*** 50,55 ****
--- 50,64 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 114,119 ****
--- 123,129 ----
echo "  -E, --encoding=ENCODING         Multibyte encoding for the database"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/createlang.sh
*** src/bin/scripts/createlang.sh	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createlang.sh	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 126,131 ****
--- 135,141 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to install language in"
Index: src/bin/scripts/createuser
*** src/bin/scripts/createuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createuser	2000/07/04 04:46:45	1.2
***************
*** 63,68 ****
--- 63,77 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're creating.
--username|-U)
***************
*** 135,140 ****
--- 144,150 ----
echo "  -P, --pwprompt                  Assign a password to new user"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to create)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/dropdb
*** src/bin/scripts/dropdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropdb	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 103,108 ****
--- 112,118 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/droplang
*** src/bin/scripts/droplang	2000/06/30 21:15:46	1.1
--- src/bin/scripts/droplang	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 113,118 ****
--- 122,128 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to remove language from"
Index: src/bin/scripts/dropuser
*** src/bin/scripts/dropuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropuser	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're dropping.
--username|-U)
***************
*** 105,110 ****
--- 114,120 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to drop)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/vacuumdb
*** src/bin/scripts/vacuumdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/vacuumdb	2000/07/04 04:46:45	1.2
***************
*** 52,57 ****
--- 52,66 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 121,126 ****
--- 130,136 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to vacuum"
Index: src/include/libpq/libpq.h
*** src/include/libpq/libpq.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/libpq.h	2000/07/01 18:20:40	1.2
***************
*** 236,246 ****
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
--- 236,247 ----
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, char *unixSocketName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
+ extern char	*pq_getunixsocket(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
Index: src/include/libpq/password.h
Index: src/include/libpq/pqcomm.h
*** src/include/libpq/pqcomm.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/pqcomm.h	2000/07/01 18:59:33	1.6
***************
*** 42,53 ****
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), \
! strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
--- 42,56 ----
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
Index: src/interfaces/libpq/fe-connect.c
*** src/interfaces/libpq/fe-connect.c	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/fe-connect.c	2000/07/01 18:50:47	1.3
***************
*** 125,130 ****
--- 125,133 ----
{"port", "PGPORT", DEF_PGPORT, NULL,
"Database-Port", "", 6},
+ 	{"unixsocket", "PGUNIXSOCKET", NULL, NULL,
+ 	"Unix-Socket", "", 80},
+ 
{"tty", "PGTTY", DefaultTty, NULL,
"Backend-Debug-TTY", "D", 40},
***************
*** 293,298 ****
--- 296,303 ----
conn->pghost = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "port");
conn->pgport = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "unixsocket");
+ 	conn->pgunixsocket = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "tty");
conn->pgtty = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "options");
***************
*** 369,374 ****
--- 374,382 ----
*	  PGPORT	   identifies TCP port to which to connect if <pgport> argument
*				   is NULL or a null string.
*
+  *	  PGUNIXSOCKET	   identifies Unix-domain socket to which to connect; default
+  *				   is computed from the TCP port.
+  *
*	  PGTTY		   identifies tty to which to send messages if <pgtty> argument
*				   is NULL or a null string.
*
***************
*** 422,427 ****
--- 430,439 ----
else
conn->pgport = strdup(pgport);
+ 	conn->pgunixsocket = getenv("PGUNIXSOCKET");
+ 	if (conn->pgunixsocket)
+ 		conn->pgunixsocket = strdup(conn->pgunixsocket);
+ 
if ((pgtty == NULL) || pgtty[0] == '\0')
{
if ((tmp = getenv("PGTTY")) == NULL)
***************
*** 489,501 ****

/*
* update_db_info -
! * get all additional infos out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
--- 501,513 ----

/*
* update_db_info -
! * get all additional info out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp, *tmp2,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
***************
*** 504,509 ****
--- 516,523 ----
tmp = strrchr(conn->dbName, ':');
if (tmp != NULL)		/* port number given */
{
+ 			if (conn->pgport)
+ 				free(conn->pgport);
conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 511,516 ****
--- 525,532 ----
tmp = strrchr(conn->dbName, '@');
if (tmp != NULL)		/* host name given */
{
+ 			if (conn->pghost)
+ 				free(conn->pghost);
conn->pghost = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 537,549 ****

/*
* new style:
! * <tcp|unix>:postgresql://server[:port][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL)	/* options given */
{
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
--- 553,567 ----

/*
* new style:
! * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL) /* options given */
{
+ if (conn->pgoptions)
+ free(conn->pgoptions);
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 551,576 ****
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL) /* database name given */
{
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
if ((tmp = getenv("PGDATABASE")) != NULL)
conn->dbName = strdup(tmp);
else if (conn->pguser)
conn->dbName = strdup(conn->pguser);
}

tmp = strrchr(old + offset, ':');
! if (tmp != NULL) /* port number given */
{
- conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}

if (strncmp(old, "unix:", 5) == 0)
{
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
--- 569,630 ----
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL)	/* database name given */
{
+ 				if (conn->dbName)
+ 					free(conn->dbName);
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
+ 				/* Why do we default only this value from the environment again?  */
if ((tmp = getenv("PGDATABASE")) != NULL)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(tmp);
+ 				}
else if (conn->pguser)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(conn->pguser);
+ 				}
}
tmp = strrchr(old + offset, ':');
! 			if (tmp != NULL)	/* port number or Unix socket path given */
{
*tmp = '\0';
+ 				if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
+ 				{
+ 					if (strncmp(old, "unix:", 5) != 0)
+ 					{
+ 						printfPQExpBuffer(&conn->errorMessage,
+ 								  "connectDBStart() -- "
+ 								  "socket name can only be specified with "
+ 								  "non-TCP\n");
+ 						return 1; 
+ 					}
+ 					*tmp2 = '\0';
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = strdup(tmp + 1);
+ 				}
+ 				else
+ 				{
+ 					if (conn->pgport)
+ 						free(conn->pgport);
+ 					conn->pgport = strdup(tmp + 1);
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = NULL;
+ 				}
}
if (strncmp(old, "unix:", 5) == 0)
{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
***************
*** 582,589 ****
}
}
else
conn->pghost = strdup(old + offset);
! 
free(old);
}
}
--- 636,646 ----
}
}
else
+ 			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = strdup(old + offset);
! 			}
free(old);
}
}
***************
*** 743,749 ****
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
#endif
--- 800,809 ----
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 	{
! 		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
! 		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
! 	}
#endif
***************
*** 892,898 ****
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  conn->pgport);
goto connect_errReturn;
}
}
--- 952,959 ----
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (family == AF_UNIX && conn->pgunixsocket) ?
! 							  conn->pgunixsocket : conn->pgport);
goto connect_errReturn;
}
}
***************
*** 1123,1129 ****
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 									  conn->pgport);
goto error_return;
}
--- 1184,1191 ----
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (conn->raddr.sa.sa_family == AF_UNIX && conn->pgunixsocket) ?
! 									  conn->pgunixsocket : conn->pgport);
goto error_return;
}
***************
*** 1799,1804 ****
--- 1861,1868 ----
free(conn->pghostaddr);
if (conn->pgport)
free(conn->pgport);
+ 	if (conn->pgunixsocket)
+ 		free(conn->pgunixsocket);
if (conn->pgtty)
free(conn->pgtty);
if (conn->pgoptions)
***************
*** 2383,2388 ****
--- 2447,2460 ----
if (!conn)
return (char *) NULL;
return conn->pgport;
+ }
+ 
+ char *
+ PQunixsocket(const PGconn *conn)
+ {
+ 	if (!conn)
+ 		return (char *) NULL;
+ 	return conn->pgunixsocket;
}
char *
Index: src/interfaces/libpq/libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-fe.h	2000/07/01 18:20:40	1.2
***************
*** 214,219 ****
--- 214,220 ----
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
extern char *PQport(const PGconn *conn);
+ 	extern char *PQunixsocket(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(const PGconn *conn);
Index: src/interfaces/libpq/libpq-int.h
*** src/interfaces/libpq/libpq-int.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-int.h	2000/07/01 18:20:40	1.2
***************
*** 202,207 ****
--- 202,209 ----
* numbers-and-dots notation. Takes
* precedence over above. */
char	   *pgport;			/* the server's communication port */
+ 	char	   *pgunixsocket;		/* the Unix-domain socket that the server is listening on;
+ 						 * if NULL, uses a default constructed from pgport */
char	   *pgtty;			/* tty on which the backend messages is
* displayed (NOT ACTUALLY USED???) */
char	   *pgoptions;		/* options to start the backend with */
Index: src/interfaces/libpq/libpqdll.def
*** src/interfaces/libpq/libpqdll.def	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpqdll.def	2000/07/01 18:20:40	1.2
***************
*** 79,81 ****
--- 79,82 ----
destroyPQExpBuffer	@ 76
createPQExpBuffer	@ 77
PQconninfoFree		@ 78
+ 	PQunixsocket		@ 79
-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Attachments:

/root/diff.newtext/plainDownload
? config.log
? config.cache
? config.status
? GNUmakefile
? src/Makefile.custom
? src/GNUmakefile
? src/Makefile.global
? src/log
? src/crtags
? src/backend/postgres
? src/backend/catalog/global.description
? src/backend/catalog/global.bki
? src/backend/catalog/template1.bki
? src/backend/catalog/template1.description
? src/backend/port/Makefile
? src/bin/initdb/initdb
? src/bin/initlocation/initlocation
? src/bin/ipcclean/ipcclean
? src/bin/pg_config/pg_config
? src/bin/pg_ctl/pg_ctl
? src/bin/pg_dump/pg_dump
? src/bin/pg_dump/pg_restore
? src/bin/pg_dump/pg_dumpall
? src/bin/pg_id/pg_id
? src/bin/pg_passwd/pg_passwd
? src/bin/pgaccess/pgaccess
? src/bin/pgtclsh/Makefile.tkdefs
? src/bin/pgtclsh/Makefile.tcldefs
? src/bin/pgtclsh/pgtclsh
? src/bin/pgtclsh/pgtksh
? src/bin/psql/psql
? src/bin/scripts/createlang
? src/include/config.h
? src/include/stamp-h
? src/interfaces/ecpg/lib/libecpg.so.3.2.0
? src/interfaces/ecpg/preproc/ecpg
? src/interfaces/libpgeasy/libpgeasy.so.2.1
? src/interfaces/libpgtcl/libpgtcl.so.2.1
? src/interfaces/libpq/libpq.so.2.1
? src/interfaces/perl5/blib
? src/interfaces/perl5/Makefile
? src/interfaces/perl5/pm_to_blib
? src/interfaces/perl5/Pg.c
? src/interfaces/perl5/Pg.bs
? src/pl/plperl/blib
? src/pl/plperl/Makefile
? src/pl/plperl/pm_to_blib
? src/pl/plperl/SPI.c
? src/pl/plperl/plperl.bs
? src/pl/plpgsql/src/libplpgsql.so.1.0
? src/pl/tcl/Makefile.tcldefs
? src/test/regress/pg_regress
? src/test/regress/regress.out
? src/test/regress/results
? src/test/regress/regression.diffs
? src/test/regress/expected/copy.out
? src/test/regress/expected/create_function_1.out
? src/test/regress/expected/create_function_2.out
? src/test/regress/expected/misc.out
? src/test/regress/expected/constraints.out
? src/test/regress/sql/copy.sql
? src/test/regress/sql/misc.sql
? src/test/regress/sql/create_function_1.sql
? src/test/regress/sql/create_function_2.sql
? src/test/regress/sql/constraints.sql
Index: doc/src/sgml/environ.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/environ.sgml,v
retrieving revision 1.5
diff -c -r1.5 environ.sgml
*** doc/src/sgml/environ.sgml	2000/05/02 20:01:51	1.5
--- doc/src/sgml/environ.sgml	2000/11/13 05:26:14
***************
*** 47,62 ****
  </Para>
  
  <Para>
! If your site administrator has not set things up in the
! default  way,  you may have some more work to do.  For example, if the database
!  server machine is a remote machine, you
! will need to set the <Acronym>PGHOST</Acronym> environment variable to the name
! of the database server machine.   The  environment  variable
! <Acronym>PGPORT</Acronym> may also have to be set.  The bottom line is this: if
! you try to start an application  program  and  it  complains
! that it cannot connect to the <Application>postmaster</Application>,
!  you should immediately consult your site administrator to make sure that your
! environment is properly set up.
! </Para>
  
  </Chapter>
--- 47,63 ----
  </Para>
  
  <Para>
! 
! If your site administrator has not set things up in the default  way, 
! you may have some more work to do.  For example, if the database server
! machine is a remote machine, you will need to set the
! <Acronym>PGHOST</Acronym> environment variable to the name of the
! database server machine.   The  environment  variable
! <Acronym>PGPORT</Acronym> or <envar>PGUNIXSOCKET</envar> may also have
! to be set.  The bottom line is this: if you try to start an application 
! program  and  it  complains that it cannot connect to the
! <Application>postmaster</Application>, you should immediately consult
! your site administrator to make sure that your environment is properly
! set up. </Para>
  
  </Chapter>
Index: doc/src/sgml/libpq++.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/libpq++.sgml,v
retrieving revision 1.17
diff -c -r1.17 libpq++.sgml
*** doc/src/sgml/libpq++.sgml	2000/09/29 20:21:34	1.17
--- doc/src/sgml/libpq++.sgml	2000/11/13 05:26:14
***************
*** 93,98 ****
--- 93,105 ----
        </listitem>
        <listitem>
         <para>
+ 	<envar>PGUNIXSOCKET</envar>  sets the full Unix domain socket
+ 	file name for communicating with the <productname>Postgres</productname>
+ 	backend.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
  	<envar>PGDATABASE</envar>  sets the default 
  	<productname>Postgres</productname> database name.
         </para>
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/libpq.sgml,v
retrieving revision 1.44
diff -c -r1.44 libpq.sgml
*** doc/src/sgml/libpq.sgml	2000/10/17 14:27:50	1.44
--- doc/src/sgml/libpq.sgml	2000/11/13 05:26:16
***************
*** 134,139 ****
--- 134,148 ----
      </varlistentry>
  
      <varlistentry>
+      <term><literal>unixsocket</literal></term>
+      <listitem>
+      <para>
+       Full path to Unix-domain socket file to connect to at the server host.
+      </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
       <term><literal>dbname</literal></term>
       <listitem>
       <para>
***************
*** 556,561 ****
--- 565,580 ----
  
  <listitem>
  <para>
+ <function>PQunixsocket</function>
+          Returns the name of the Unix-domain socket of the connection.
+ <synopsis>
+ char *PQunixsocket(const PGconn *conn)
+ </synopsis>
+ </para>
+ </listitem>
+ 
+ <listitem>
+ <para>
  <function>PQtty</function>
           Returns the debug tty of the connection.
  <synopsis>
***************
*** 1821,1826 ****
--- 1840,1852 ----
  <envar>PGHOST</envar> sets the default server name.
  If a non-zero-length string is specified, TCP/IP communication is used.
  Without a host name, libpq will connect using a local Unix domain socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <envar>PGPORT</envar>  sets the default port or local Unix domain socket
+ file extension for communicating with the <productname>Postgres</productname>
+ backend.
  </para>
  </listitem>
  <listitem>
Index: doc/src/sgml/start.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/start.sgml,v
retrieving revision 1.13
diff -c -r1.13 start.sgml
*** doc/src/sgml/start.sgml	2000/09/29 20:21:34	1.13
--- doc/src/sgml/start.sgml	2000/11/13 05:26:16
***************
*** 110,117 ****
      will need to set the <acronym>PGHOST</acronym> environment
      variable to the name
      of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> may also have to be set.  The bottom
!     line is this: if
      you try to start an application  program  and  it  complains
      that it cannot connect to the <application>postmaster</application>,
      you should immediately consult your site administrator to make
--- 110,117 ----
      will need to set the <acronym>PGHOST</acronym> environment
      variable to the name
      of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> or <acronym>PGUNIXSOCKET</acronym> may also have to be set.
!     The bottom line is this: if
      you try to start an application  program  and  it  complains
      that it cannot connect to the <application>postmaster</application>,
      you should immediately consult your site administrator to make
Index: doc/src/sgml/ref/createdb.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/createdb.sgml,v
retrieving revision 1.11
diff -c -r1.11 createdb.sgml
*** doc/src/sgml/ref/createdb.sgml	2000/11/11 23:01:38	1.11
--- doc/src/sgml/ref/createdb.sgml	2000/11/13 05:26:16
***************
*** 56,61 ****
--- 56,73 ----
        </listitem>
       </varlistentry>
  
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/createlang.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/createlang.sgml,v
retrieving revision 1.10
diff -c -r1.10 createlang.sgml
*** doc/src/sgml/ref/createlang.sgml	2000/11/11 23:01:38	1.10
--- doc/src/sgml/ref/createlang.sgml	2000/11/13 05:26:16
***************
*** 101,106 ****
--- 101,118 ----
        </listitem>
       </varlistentry>
  
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/createuser.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/createuser.sgml,v
retrieving revision 1.10
diff -c -r1.10 createuser.sgml
*** doc/src/sgml/ref/createuser.sgml	2000/11/11 23:01:40	1.10
--- doc/src/sgml/ref/createuser.sgml	2000/11/13 05:26:16
***************
*** 55,60 ****
--- 55,72 ----
        </listitem>
       </varlistentry>
  
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-e, --echo</term>
        <listitem>
Index: doc/src/sgml/ref/dropdb.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/dropdb.sgml,v
retrieving revision 1.4
diff -c -r1.4 dropdb.sgml
*** doc/src/sgml/ref/dropdb.sgml	2000/11/11 23:01:45	1.4
--- doc/src/sgml/ref/dropdb.sgml	2000/11/13 05:26:16
***************
*** 55,60 ****
--- 55,72 ----
        </listitem>
       </varlistentry>
  
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/droplang.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/droplang.sgml,v
retrieving revision 1.4
diff -c -r1.4 droplang.sgml
*** doc/src/sgml/ref/droplang.sgml	2000/11/11 23:01:45	1.4
--- doc/src/sgml/ref/droplang.sgml	2000/11/13 05:26:16
***************
*** 101,106 ****
--- 101,118 ----
        </listitem>
       </varlistentry>
  
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U, --username <replaceable class="parameter">username</replaceable></term>
        <listitem>
Index: doc/src/sgml/ref/dropuser.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/dropuser.sgml,v
retrieving revision 1.5
diff -c -r1.5 dropuser.sgml
*** doc/src/sgml/ref/dropuser.sgml	2000/11/11 23:01:45	1.5
--- doc/src/sgml/ref/dropuser.sgml	2000/11/13 05:26:16
***************
*** 55,60 ****
--- 55,72 ----
        </listitem>
       </varlistentry>
  
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-e, --echo</term>
        <listitem>
Index: doc/src/sgml/ref/pg_dump.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v
retrieving revision 1.20
diff -c -r1.20 pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml	2000/10/05 19:48:18	1.20
--- doc/src/sgml/ref/pg_dump.sgml	2000/11/13 05:26:17
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ]
      [ -t <replaceable class="parameter">table</replaceable> ]
      [ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
      [ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
--- 24,32 ----
    </refsynopsisdivinfo>
    <synopsis>
  pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ]
!     [ -k <replaceable class="parameter">path</replaceable> ]
!     [ -p <replaceable class="parameter">port</replaceable> ]
      [ -t <replaceable class="parameter">table</replaceable> ]
      [ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
      [ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
***************
*** 200,205 ****
--- 202,222 ----
  	<application>postmaster</application>
  	is running.  Defaults to using a local Unix domain socket
  	rather than an IP connection.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/ref/pg_dumpall.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/pg_dumpall.sgml,v
retrieving revision 1.11
diff -c -r1.11 pg_dumpall.sgml
*** doc/src/sgml/ref/pg_dumpall.sgml	2000/11/02 21:13:31	1.11
--- doc/src/sgml/ref/pg_dumpall.sgml	2000/11/13 05:26:17
***************
*** 23,29 ****
     <date>1999-07-20</date>
    </refsynopsisdivinfo>
    <synopsis>
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ] [ --accounts-only ]
    </synopsis>
  
    <refsect2 id="R2-APP-PG-DUMPALL-1">
--- 23,29 ----
     <date>1999-07-20</date>
    </refsynopsisdivinfo>
    <synopsis>
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -k <replaceable class="parameter">path</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ] [ --accounts-only ]
    </synopsis>
  
    <refsect2 id="R2-APP-PG-DUMPALL-1">
***************
*** 145,150 ****
--- 145,165 ----
  	<application>postmaster</application>
  	is running.  Defaults to using a local Unix domain socket
  	rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/ref/postmaster.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/postmaster.sgml,v
retrieving revision 1.12
diff -c -r1.12 postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml	2000/10/05 19:48:18	1.12
--- doc/src/sgml/ref/postmaster.sgml	2000/11/13 05:26:17
***************
*** 24,30 ****
    </refsynopsisdivinfo>
    <synopsis>
  postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ] [ -i ] [ -l ]
      [ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
    </synopsis>
  
--- 24,32 ----
    </refsynopsisdivinfo>
    <synopsis>
  postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ]
!     [ -h <replaceable class="parameter">hostname</replaceable> ] [ -i ]
!     [ -k <replaceable class="parameter">path</replaceable> ] [ -l ]
      [ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
    </synopsis>
  
***************
*** 124,135 ****
--- 126,196 ----
       </varlistentry>
  
       <varlistentry>
+       <term>-h <replaceable class="parameter">hostName</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the TCP/IP hostname or address
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGHOST</envar> 
+ 	environment variable, or if <envar>PGHOST</envar>
+ 	is not set, then defaults to "all", meaning listen on all configured addresses
+ 	(including localhost).
+        </para>
+        <para>
+ 	If you use a hostname or address other than "all", do not try to run
+ 	multiple instances of <application>postmaster</application> on the
+ 	same IP address but different ports.  Doing so will result in them
+ 	attempting (incorrectly) to use the same shared memory segments.
+ 	Also, if you use a hostname other than "all", all of the host's IP addresses
+ 	on which <application>postmaster</application> instances are
+ 	listening must be distinct in the two last octets.
+        </para>
+        <para>
+ 	If you do use "all" (the default), then each instance must listen on a
+ 	different port (via -p or <envar>PGPORT</envar>).  And, of course, do
+ 	not try to use both approaches on one host.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term>-i</term>
        <listitem>
         <para>
          Allows clients to connect via TCP/IP (Internet domain) connections.
  	Without this option, only local Unix domain socket connections are
  	accepted.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket path name
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGUNIXSOCKET</envar> 
+ 	environment variable, or if <envar>PGUNIXSOCKET</envar>
+ 	is not set, then defaults to a file in <filename>/tmp</filename>
+ 	constructed from the port number.
+        </para>
+        <para>
+         You can use this option to put the Unix-domain socket in a
+         directory that is private to one or more users using Unix
+ 	directory permissions.  This is necessary for securely
+ 	creating databases automatically on shared machines.
+         In that situation, also disallow all TCP/IP connections
+ 	initially in <filename>pg_hba.conf</filename>.
+ 	If you specify a socket path other than the
+ 	default then all frontend applications (including
+ 	<application>psql</application>) must specify the same
+ 	socket path using either command-line options or
+ 	<envar>PGUNIXSOCKET</envar>.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/ref/psql-ref.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v
retrieving revision 1.40
diff -c -r1.40 psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	2000/10/24 01:38:21	1.40
--- doc/src/sgml/ref/psql-ref.sgml	2000/11/13 05:26:22
***************
*** 1330,1335 ****
--- 1330,1348 ----
  
  
      <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
+ 
+     <varlistentry>
        <term>-H, --html</term>
        <listitem>
        <para>
Index: doc/src/sgml/ref/vacuumdb.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/vacuumdb.sgml,v
retrieving revision 1.10
diff -c -r1.10 vacuumdb.sgml
*** doc/src/sgml/ref/vacuumdb.sgml	2000/11/11 23:01:45	1.10
--- doc/src/sgml/ref/vacuumdb.sgml	2000/11/13 05:26:22
***************
*** 136,141 ****
--- 136,153 ----
        </listitem>
       </varlistentry>
  
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
       <varlistentry>
        <term>-U <replaceable class="parameter">username</replaceable></term>
        <term>--username <replaceable class="parameter">username</replaceable></term>
Index: src/backend/libpq/pqcomm.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/pqcomm.c,v
retrieving revision 1.109
diff -c -r1.109 pqcomm.c
*** src/backend/libpq/pqcomm.c	2000/11/01 21:14:01	1.109
--- src/backend/libpq/pqcomm.c	2000/11/13 05:26:22
***************
*** 169,181 ****
  /*
   * StreamServerPort -- open a sock stream "listening" port.
   *
!  * This initializes the Postmaster's connection-accepting port.
   *
   * RETURNS: STATUS_OK or STATUS_ERROR
   */
  
  int
! StreamServerPort(int family, unsigned short portName, int *fdP)
  {
  	SockAddr	saddr;
  	int			fd,
--- 169,182 ----
  /*
   * StreamServerPort -- open a sock stream "listening" port.
   *
!  * This initializes the Postmaster's connection-accepting port fdP.
   *
   * RETURNS: STATUS_OK or STATUS_ERROR
   */
  
  int
! StreamServerPort(int family, char *hostName, unsigned short portName,
! 				 char *unixSocketName, int *fdP)
  {
  	SockAddr	saddr;
  	int			fd,
***************
*** 218,224 ****
  #ifdef HAVE_UNIX_SOCKETS
  	if (family == AF_UNIX)
  	{
! 		len = UNIXSOCK_PATH(saddr.un, portName);
  		strcpy(sock_path, saddr.un.sun_path);
  		/*
  		 * If the socket exists but nobody has an advisory lock on it we
--- 219,226 ----
  #ifdef HAVE_UNIX_SOCKETS
  	if (family == AF_UNIX)
  	{
! 		UNIXSOCK_PATH(saddr.un, portName, unixSocketName);
! 		len = UNIXSOCK_LEN(saddr.un);
  		strcpy(sock_path, saddr.un.sun_path);
  		/*
  		 * If the socket exists but nobody has an advisory lock on it we
***************
*** 242,248 ****
  
      if (family == AF_INET) 
      {
! 		saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
  		saddr.in.sin_port = htons(portName);
  		len = sizeof(struct sockaddr_in);
  	}
--- 244,270 ----
  
      if (family == AF_INET) 
      {
! 		/* TCP/IP socket */
! 		if (hostName[0] == '\0')
! 	 		saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 		else
! 	    {
! 			struct hostent *hp;
! 	
! 			hp = gethostbyname(hostName);
! 			if ((hp == NULL) || (hp->h_addrtype != AF_INET))
! 			{
! 				snprintf(PQerrormsg, PQERRORMSG_LENGTH,
! 					   "FATAL: StreamServerPort: gethostbyname(%s) failed: %s\n",
! 					   hostName, hstrerror(h_errno));
! 					   fputs(PQerrormsg, stderr);
! 					   pqdebug("%s", PQerrormsg);
! 				return STATUS_ERROR;
! 			}
! 			memmove((char *) &(saddr.in.sin_addr), (char *) hp->h_addr,
! 					hp->h_length);
! 		}
! 	
  		saddr.in.sin_port = htons(portName);
  		len = sizeof(struct sockaddr_in);
  	}
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.181
diff -c -r1.181 postmaster.c
*** src/backend/postmaster/postmaster.c	2000/11/09 11:25:59	1.181
--- src/backend/postmaster/postmaster.c	2000/11/13 05:26:25
***************
*** 114,119 ****
--- 114,121 ----
  static Dllist *PortList;
  
  int PostPortName;
+ char * UnixSocketName;
+ char * HostName;
  
   /*
    * This is a boolean indicating that there is at least one backend that
***************
*** 234,240 ****
  static void pmdaemonize(int argc, char *argv[]);
  static Port *ConnCreate(int serverFd);
  static void ConnFree(Port *port);
! static void reset_shared(int port);
  static void SIGHUP_handler(SIGNAL_ARGS);
  static void pmdie(SIGNAL_ARGS);
  static void reaper(SIGNAL_ARGS);
--- 236,242 ----
  static void pmdaemonize(int argc, char *argv[]);
  static Port *ConnCreate(int serverFd);
  static void ConnFree(Port *port);
! static void reset_shared(unsigned short port);
  static void SIGHUP_handler(SIGNAL_ARGS);
  static void pmdie(SIGNAL_ARGS);
  static void reaper(SIGNAL_ARGS);
***************
*** 376,382 ****
  	 * will occur.
  	 */
  	opterr = 1;
! 	while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Film:MN:no:p:SsV-:?")) != EOF)
  	{
  		switch(opt)
  		{
--- 378,384 ----
  	 * will occur.
  	 */
  	opterr = 1;
! 	while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:SsV-:?")) != EOF)
  	{
  		switch(opt)
  		{
***************
*** 432,438 ****
  #ifdef HAVE_INT_OPTRESET
  	optreset = 1;
  #endif
! 	while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Film:MN:no:p:SsV-:?")) != EOF)
  	{
  		switch (opt)
  		{
--- 434,440 ----
  #ifdef HAVE_INT_OPTRESET
  	optreset = 1;
  #endif
! 	while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:SsV-:?")) != EOF)
  	{
  		switch (opt)
  		{
***************
*** 466,474 ****
--- 468,483 ----
  			case 'F':
  				enableFsync = false;
  				break;
+ 			case 'h':
+ 				HostName = optarg;
+ 				break;
  			case 'i':
  				NetServer = true;
  				break;
+ 			case 'k':
+ 				/* Set PGUNIXSOCKET by hand. */
+ 				UnixSocketName = optarg;
+ 				break;
  #ifdef USE_SSL
  			case 'l':
  			        EnableSSL = true;
***************
*** 600,606 ****
  
  	if (NetServer)
  	{
! 		status = StreamServerPort(AF_INET, (unsigned short)PostPortName, &ServerSock_INET);
  		if (status != STATUS_OK)
  		{
  			fprintf(stderr, "%s: cannot create INET stream port\n",
--- 609,616 ----
  
  	if (NetServer)
  	{
! 		status = StreamServerPort(AF_INET, HostName,
! 				(unsigned short)PostPortName, UnixSocketName, &ServerSock_INET);
  		if (status != STATUS_OK)
  		{
  			fprintf(stderr, "%s: cannot create INET stream port\n",
***************
*** 610,616 ****
  	}
  
  #ifdef HAVE_UNIX_SOCKETS
! 	status = StreamServerPort(AF_UNIX, (unsigned short)PostPortName, &ServerSock_UNIX);
  	if (status != STATUS_OK)
  	{
  		fprintf(stderr, "%s: cannot create UNIX stream port\n",
--- 620,627 ----
  	}
  
  #ifdef HAVE_UNIX_SOCKETS
! 	status = StreamServerPort(AF_UNIX, HostName,
! 			(unsigned short)PostPortName, UnixSocketName, &ServerSock_UNIX);
  	if (status != STATUS_OK)
  	{
  		fprintf(stderr, "%s: cannot create UNIX stream port\n",
***************
*** 780,786 ****
--- 791,799 ----
  	printf("  -d 1-5          debugging level\n");
  	printf("  -D <directory>  database directory\n");
  	printf("  -F              turn fsync off\n");
+ 	printf("  -h hostname     specify hostname or IP address\n");
  	printf("  -i              enable TCP/IP connections\n");
+ 	printf("  -k path         specify Unix-domain socket name\n");
  #ifdef USE_SSL
  	printf("  -l              enable SSL connections\n");
  #endif
***************
*** 1294,1304 ****
  }
  
  /*
   * reset_shared -- reset shared memory and semaphores
   */
  static void
! reset_shared(int port)
  {
  	ipc_key = port * 1000 + shmem_seq * 100;
  	CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
  	shmem_seq += 1;
--- 1307,1381 ----
  }
  
  /*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+ 	static unsigned short hostPort = 0;
+ 
+ 	if (hostPort == 0)
+ 	{
+ 		SockAddr	saddr;
+ 		struct hostent *hp;
+ 
+ 		hp = gethostbyname(HostName);
+ 		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+ 		{
+ 			char msg[1024];
+ 			snprintf(msg, sizeof(msg),
+ 				 "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+ 				 HostName, hstrerror(h_errno));
+ 			fputs(msg, stderr);
+ 			pqdebug("%s", msg);
+ 			exit(1);
+ 		}
+ 		memmove((char *) &(saddr.in.sin_addr),
+ 			(char *) hp->h_addr,
+ 			hp->h_length);
+ 		hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+ 	}
+ 
+ 	return hostPort;
+ }
+ 
+ /*
   * reset_shared -- reset shared memory and semaphores
   */
  static void
! reset_shared(unsigned short port)
  {
+ 	/*
+ 	 * A typical ipc_key is 5432001, which is port 5432, sequence
+ 	 * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+ 	 * The 32-bit INT_MAX is 2147483 6 47.
+ 	 *
+ 	 * The default algorithm for calculating the IPC keys assumes that all
+ 	 * instances of postmaster on a given host are listening on different
+ 	 * ports.  In order to work (prevent shared memory collisions) if you
+ 	 * run multiple PostgreSQL instances on the same port and different IP
+ 	 * addresses on a host, we change the algorithm if you give postmaster
+ 	 * the -h option, or set PGHOST, to a value other than the internal
+ 	 * default.
+ 	 *
+ 	 * If HostName is set, then we generate the IPC keys using the
+ 	 * last two octets of the IP address instead of the port number.
+ 	 * This algorithm assumes that no one will run multiple PostgreSQL
+ 	 * instances on one host using two IP addresses that have the same two
+ 	 * last octets in different class C networks.  If anyone does, it
+ 	 * would be rare.
+ 	 *
+ 	 * So, if you use -h or PGHOST, don't try to run two instances of
+ 	 * PostgreSQL on the same IP address but different ports.  If you
+ 	 * don't use them, then you must use different ports (via -p or
+ 	 * PGPORT).  And, of course, don't try to use both approaches on one
+ 	 * host.
+ 	 */
+ 
+ 	if (HostName[0] != '\0')
+ 		port = get_host_port();
+ 
  	ipc_key = port * 1000 + shmem_seq * 100;
  	CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
  	shmem_seq += 1;
***************
*** 2205,2210 ****
--- 2282,2289 ----
  		char		nbbuf[ARGV_SIZE];
  		char		dbbuf[ARGV_SIZE];
  		char		xlbuf[ARGV_SIZE];
+ 		char		hsbuf[ARGV_SIZE];
+ 		char		skbuf[ARGV_SIZE];
  
  		/* Lose the postmaster's on-exit routines and port connections */
  		on_exit_reset();
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.16
diff -c -r1.16 guc.c
*** src/backend/utils/misc/guc.c	2000/11/09 11:25:59	1.16
--- src/backend/utils/misc/guc.c	2000/11/13 05:26:26
***************
*** 304,309 ****
--- 304,315 ----
  	{"unix_socket_group",         PGC_POSTMASTER,       &Unix_socket_group,
  	 "", NULL},
  
+ 	{"unixsocket",         		  PGC_POSTMASTER,       &UnixSocketName,
+ 	 "", NULL},
+ 
+ 	{"hostname",         		  PGC_POSTMASTER,       &HostName,
+ 	 "", NULL},
+ 
  	{NULL, 0, NULL, NULL, NULL}
  };
  
Index: src/bin/pg_dump/pg_backup.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v
retrieving revision 1.4
diff -c -r1.4 pg_backup.h
*** src/bin/pg_dump/pg_backup.h	2000/08/01 15:51:44	1.4
--- src/bin/pg_dump/pg_backup.h	2000/11/13 05:26:26
***************
*** 99,106 ****
  
  	int			useDB;
  	char		*dbname;
- 	char		*pgport;
  	char		*pghost;
  	int			ignoreVersion;
  	int			requirePassword;
  
--- 99,107 ----
  
  	int			useDB;
  	char		*dbname;
  	char		*pghost;
+ 	char		*pgport;
+ 	char		*pgunixsocket;
  	int			ignoreVersion;
  	int			requirePassword;
  
***************
*** 122,127 ****
--- 123,129 ----
  		const char* 	dbname,
  		const char*	pghost,
  		const char*	pgport,
+ 		const char*	pgunixsocket,
  		const int	reqPwd,
  		const int	ignoreVersion);
  
Index: src/bin/pg_dump/pg_backup_archiver.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v
retrieving revision 1.10
diff -c -r1.10 pg_backup_archiver.c
*** src/bin/pg_dump/pg_backup_archiver.c	2000/10/31 14:20:30	1.10
--- src/bin/pg_dump/pg_backup_archiver.c	2000/11/13 05:26:27
***************
*** 131,138 ****
  		if (AH->version < K_VERS_1_3)
  			die_horribly(AH, "Direct database connections are not supported in pre-1.3 archives");
  
! 		ConnectDatabase(AHX, ropt->dbname, ropt->pghost, ropt->pgport, 
! 							ropt->requirePassword, ropt->ignoreVersion);
  
  		/*
  		 * If no superuser was specified then see if the current user will do...
--- 131,139 ----
  		if (AH->version < K_VERS_1_3)
  			die_horribly(AH, "Direct database connections are not supported in pre-1.3 archives");
  
! 		ConnectDatabase(AHX, ropt->dbname, ropt->pghost, ropt->pgport,
! 							ropt->pgunixsocket, ropt->requirePassword,
! 							ropt->ignoreVersion);
  
  		/*
  		 * If no superuser was specified then see if the current user will do...
Index: src/bin/pg_dump/pg_backup_archiver.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.h,v
retrieving revision 1.16
diff -c -r1.16 pg_backup_archiver.h
*** src/bin/pg_dump/pg_backup_archiver.h	2000/10/31 14:20:30	1.16
--- src/bin/pg_dump/pg_backup_archiver.h	2000/11/13 05:26:27
***************
*** 187,192 ****
--- 187,193 ----
  	char				*archdbname;		/* DB name *read* from archive */
  	char				*pghost;
  	char				*pgport;
+ 	char				*pgunixsocket;
  	PGconn				*connection;
  	PGconn				*blobConnection;	/* Connection for BLOB xref */
  	int					txActive;			/* Flag set if TX active on connection */
Index: src/bin/pg_dump/pg_backup_db.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v
retrieving revision 1.8
diff -c -r1.8 pg_backup_db.c
*** src/bin/pg_dump/pg_backup_db.c	2000/10/31 14:20:30	1.8
--- src/bin/pg_dump/pg_backup_db.c	2000/11/13 05:26:27
***************
*** 1,7 ****
  /*-------------------------------------------------------------------------
   *
   *
! *-------------------------------------------------------------------------
   */
  
  #include <unistd.h>				/* for getopt() */
--- 1,7 ----
  /*-------------------------------------------------------------------------
   *
   *
!  *-------------------------------------------------------------------------
   */
  
  #include <unistd.h>				/* for getopt() */
***************
*** 273,278 ****
--- 273,279 ----
  		const char* 	dbname,
  		const char* 	pghost,
  		const char* 	pgport,
+ 		const char* 	pgunixsocket,
  		const int		reqPwd,
  		const int		ignoreVersion)
  {
***************
*** 306,311 ****
--- 307,321 ----
  	}
  	else
  	    AH->pgport = NULL;
+ 
+ 	if (pgunixsocket != NULL)
+ 	{
+ 		AH->pgport = strdup(pgunixsocket);
+ 		sprintf(tmp_string, "unixsocket=%s ", AH->pgunixsocket);
+ 		strcat(connect_string, tmp_string);
+ 	}
+ 	else
+ 	    AH->pgunixsocket = NULL;
  
  	sprintf(tmp_string, "dbname=%s ", AH->dbname);
  	strcat(connect_string, tmp_string);
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.177
diff -c -r1.177 pg_dump.c
*** src/bin/pg_dump/pg_dump.c	2000/10/31 14:20:30	1.177
--- src/bin/pg_dump/pg_dump.c	2000/11/13 05:26:30
***************
*** 200,205 ****
--- 200,206 ----
  		"  -F, --format {c|f|p}     output file format (custom, files, plain text)\n"
  		"  -h, --host <hostname>    server host name\n"
  		"  -i, --ignore-version     proceed when database version != pg_dump version\n"
+ 		"  -k, --unixsocket <path>  server Unix-domain socket name\n"
  		"  -n, --no-quotes          suppress most quotes around identifiers\n"
  		"  -N, --quotes             enable most quotes around identifiers\n"
  		"  -o, --oids               dump object ids (oids)\n"
***************
*** 226,231 ****
--- 227,233 ----
  		"  -F {c|f|p}               output file format (custom, files, plain text)\n"
  		"  -h <hostname>            server host name\n"
  		"  -i                       proceed when database version != pg_dump version\n"
+ 		"  -k <path>                server Unix-domain socket name\n"
  		"  -n                       suppress most quotes around identifiers\n"
  		"  -N                       enable most quotes around identifiers\n"
  		"  -o                       dump object ids (oids)\n"
***************
*** 629,634 ****
--- 631,637 ----
  	const char *dbname = NULL;
  	const char *pghost = NULL;
  	const char *pgport = NULL;
+ 	const char *pgunixsocket = NULL;
  	char	   *tablename = NULL;
  	bool		oids = false;
  	TableInfo  *tblinfo;
***************
*** 658,663 ****
--- 661,667 ----
  		{"attribute-inserts", no_argument, NULL, 'D'},
  		{"host", required_argument, NULL, 'h'},
  		{"ignore-version", no_argument, NULL, 'i'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
  		{"no-reconnect", no_argument, NULL, 'R'},
  		{"no-quotes", no_argument, NULL, 'n'},
  		{"quotes", no_argument, NULL, 'N'},
***************
*** 752,757 ****
--- 756,765 ----
  				ignore_version = true;
  				break;
  
+ 			case 'k':			/* server Unix-domain socket */
+ 				pgunixsocket = optarg;
+ 				break;
+ 
  			case 'n':			/* Do not force double-quotes on
  								 * identifiers */
  				force_quotes = false;
***************
*** 948,954 ****
  	dbname = argv[optind];
  
  	/* Open the database using the Archiver, so it knows about it. Errors mean death */
! 	g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, use_password, ignore_version);
  
  	/*
  	 * Start serializable transaction to dump consistent data
--- 956,963 ----
  	dbname = argv[optind];
  
  	/* Open the database using the Archiver, so it knows about it. Errors mean death */
! 	g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, pgunixsocket,
! 							 use_password, ignore_version);
  
  	/*
  	 * Start serializable transaction to dump consistent data
Index: src/bin/pg_dump/pg_restore.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v
retrieving revision 1.8
diff -c -r1.8 pg_restore.c
*** src/bin/pg_dump/pg_restore.c	2000/10/16 14:34:08	1.8
--- src/bin/pg_dump/pg_restore.c	2000/11/13 05:26:30
***************
*** 101,106 ****
--- 101,107 ----
  				{ "ignore-version", 0, NULL, 'i'},
  				{ "index", 2, NULL, 'I'},
  				{ "list", 0, NULL, 'l'},
+ 				{ "unixsocket", 1, NULL, 'k' },
  				{ "no-acl", 0, NULL, 'x' },
  				{ "no-owner", 0, NULL, 'O'},
  				{ "no-reconnect", 0, NULL, 'R' },
***************
*** 132,140 ****
  	progname = *argv;
  
  #ifdef HAVE_GETOPT_LONG
! 	while ((c = getopt_long(argc, argv, "acCd:f:F:h:i:lNoOp:P:rRsS:t:T:uU:vx", cmdopts, NULL)) != EOF)
  #else
! 	while ((c = getopt(argc, argv, "acCd:f:F:h:i:lNoOp:P:rRsS:t:T:uU:vx")) != -1)
  #endif
  	{
  		switch (c)
--- 133,141 ----
  	progname = *argv;
  
  #ifdef HAVE_GETOPT_LONG
! 	while ((c = getopt_long(argc, argv, "acCd:f:F:h:i:k:lNoOp:P:rRsS:t:T:uU:vx", cmdopts, NULL)) != EOF)
  #else
! 	while ((c = getopt(argc, argv, "acCd:f:F:h:i:k:lNoOp:P:rRsS:t:T:uU:vx")) != -1)
  #endif
  	{
  		switch (c)
***************
*** 169,174 ****
--- 170,179 ----
  				break;
  			case 'i':
  				opts->ignoreVersion = 1;
+ 				break;
+ 			case 'k':
+ 				if (strlen(optarg) != 0)
+ 					opts->pgunixsocket = strdup(optarg);
  				break;
  			case 'N':
  				opts->origOrder = 1;
Index: src/bin/psql/command.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.36
diff -c -r1.36 command.c
*** src/bin/psql/command.c	2000/09/17 20:33:45	1.36
--- src/bin/psql/command.c	2000/11/13 05:26:31
***************
*** 1202,1207 ****
--- 1202,1208 ----
  	SetVariable(pset.vars, "USER", NULL);
  	SetVariable(pset.vars, "HOST", NULL);
  	SetVariable(pset.vars, "PORT", NULL);
+ 	SetVariable(pset.vars, "UNIXSOCKET", NULL);
  	SetVariable(pset.vars, "ENCODING", NULL);
  
  	/* If dbname is "" then use old name, else new one (even if NULL) */
***************
*** 1231,1236 ****
--- 1232,1238 ----
  	do
  	{
  		need_pass = false;
+ 		/* FIXME use PQconnectdb to support passing the Unix socket */
  		pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
  							   NULL, NULL, dbparam, userparam, pwparam);
  
***************
*** 1307,1312 ****
--- 1309,1315 ----
  	SetVariable(pset.vars, "USER", PQuser(pset.db));
  	SetVariable(pset.vars, "HOST", PQhost(pset.db));
  	SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
  	SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
  
  	pset.issuper = test_superuser(PQuser(pset.db));
Index: src/bin/psql/common.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/psql/common.c,v
retrieving revision 1.23
diff -c -r1.23 common.c
*** src/bin/psql/common.c	2000/08/29 09:36:48	1.23
--- src/bin/psql/common.c	2000/11/13 05:26:31
***************
*** 329,334 ****
--- 329,335 ----
  			SetVariable(pset.vars, "DBNAME", NULL);
  			SetVariable(pset.vars, "HOST", NULL);
  			SetVariable(pset.vars, "PORT", NULL);
+ 			SetVariable(pset.vars, "UNIXSOCKET", NULL);
  			SetVariable(pset.vars, "USER", NULL);
  			SetVariable(pset.vars, "ENCODING", NULL);
  			return NULL;
***************
*** 508,513 ****
--- 509,515 ----
  				SetVariable(pset.vars, "DBNAME", NULL);
  				SetVariable(pset.vars, "HOST", NULL);
  				SetVariable(pset.vars, "PORT", NULL);
+ 				SetVariable(pset.vars, "UNIXSOCKET", NULL);
  				SetVariable(pset.vars, "USER", NULL);
  				SetVariable(pset.vars, "ENCODING", NULL);
  				return false;
Index: src/bin/psql/help.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/psql/help.c,v
retrieving revision 1.32
diff -c -r1.32 help.c
*** src/bin/psql/help.c	2000/09/22 23:02:00	1.32
--- src/bin/psql/help.c	2000/11/13 05:26:33
***************
*** 103,108 ****
--- 103,118 ----
  	puts(")");
  
  	puts("  -H              HTML table output mode (-P format=html)");
+ 
+ 	/* Display default Unix-domain socket */
+ 	env = getenv("PGUNIXSOCKET");
+ 	printf("  -k <path>       Specify Unix domain socket name (default: ");
+ 	if (env)
+ 		fputs(env, stdout);
+ 	else
+ 		fputs("computed from the port", stdout);
+ 	puts(")");
+ 
  	puts("  -l              List available databases, then exit");
  	puts("  -n              Disable readline");
  	puts("  -o <filename>   Send query output to filename (or |pipe)");
Index: src/bin/psql/prompt.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/psql/prompt.c,v
retrieving revision 1.13
diff -c -r1.13 prompt.c
*** src/bin/psql/prompt.c	2000/08/20 10:55:34	1.13
--- src/bin/psql/prompt.c	2000/11/13 05:26:33
***************
*** 190,195 ****
--- 190,200 ----
  					if (pset.db && PQport(pset.db))
  						strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
  					break;
+ 					/* DB server Unix-domain socket */
+ 				case '<':
+ 					if (pset.db && PQunixsocket(pset.db))
+ 						strncpy(buf, PQunixsocket(pset.db), MAX_PROMPT_SIZE);
+ 					break;
  					/* DB server user name */
  				case 'n':
  					if (pset.db)
Index: src/bin/psql/startup.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/psql/startup.c,v
retrieving revision 1.37
diff -c -r1.37 startup.c
*** src/bin/psql/startup.c	2000/09/17 20:33:45	1.37
--- src/bin/psql/startup.c	2000/11/13 05:26:34
***************
*** 65,70 ****
--- 65,71 ----
  	char	   *dbname;
  	char	   *host;
  	char	   *port;
+ 	char	   *unixsocket;
  	char	   *username;
  	enum _actions action;
  	char	   *action_string;
***************
*** 161,166 ****
--- 162,168 ----
  	do
  	{
  		need_pass = false;
+ 		/* FIXME use PQconnectdb to allow setting the unix socket */
  		pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
  			options.action == ACT_LIST_DB ? "template1" : options.dbname,
  							   username, password);
***************
*** 206,211 ****
--- 208,214 ----
  	SetVariable(pset.vars, "USER", PQuser(pset.db));
  	SetVariable(pset.vars, "HOST", PQhost(pset.db));
  	SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
  	SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
  
  #ifndef WIN32
***************
*** 320,325 ****
--- 323,329 ----
  		{"field-separator", required_argument, NULL, 'F'},
  		{"host", required_argument, NULL, 'h'},
  		{"html", no_argument, NULL, 'H'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
  		{"list", no_argument, NULL, 'l'},
  		{"no-readline", no_argument, NULL, 'n'},
  		{"output", required_argument, NULL, 'o'},
***************
*** 353,366 ****
  	memset(options, 0, sizeof *options);
  
  #ifdef HAVE_GETOPT_LONG
! 	while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
  #else							/* not HAVE_GETOPT_LONG */
  
  	/*
  	 * Be sure to leave the '-' in here, so we can catch accidental long
  	 * options.
  	 */
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?-")) != -1)
  #endif	 /* not HAVE_GETOPT_LONG */
  	{
  		switch (c)
--- 357,370 ----
  	memset(options, 0, sizeof *options);
  
  #ifdef HAVE_GETOPT_LONG
! 	while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
  #else							/* not HAVE_GETOPT_LONG */
  
  	/*
  	 * Be sure to leave the '-' in here, so we can catch accidental long
  	 * options.
  	 */
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
  #endif	 /* not HAVE_GETOPT_LONG */
  	{
  		switch (c)
***************
*** 405,410 ****
--- 409,417 ----
  				break;
  			case 'l':
  				options->action = ACT_LIST_DB;
+ 				break;
+ 			case 'k':
+ 				options->unixsocket = optarg;
  				break;
  			case 'n':
  				options->no_readline = true;
Index: src/bin/scripts/createdb
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/scripts/createdb,v
retrieving revision 1.9
diff -c -r1.9 createdb
*** src/bin/scripts/createdb	2000/11/11 22:59:48	1.9
--- src/bin/scripts/createdb	2000/11/13 05:26:34
***************
*** 50,55 ****
--- 50,64 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 114,119 ****
--- 123,129 ----
  	echo "  -E, --encoding=ENCODING         Multibyte encoding for the database"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/createlang.sh
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/scripts/createlang.sh,v
retrieving revision 1.17
diff -c -r1.17 createlang.sh
*** src/bin/scripts/createlang.sh	2000/11/11 22:59:48	1.17
--- src/bin/scripts/createlang.sh	2000/11/13 05:26:34
***************
*** 65,70 ****
--- 65,79 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 126,131 ****
--- 135,141 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -d, --dbname=DBNAME             Database to install language in"
Index: src/bin/scripts/createuser
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/scripts/createuser,v
retrieving revision 1.12
diff -c -r1.12 createuser
*** src/bin/scripts/createuser	2000/11/11 22:59:48	1.12
--- src/bin/scripts/createuser	2000/11/13 05:26:34
***************
*** 63,68 ****
--- 63,77 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  # Note: These two specify the user to connect as (like in psql),
  #       not the user you're creating.
  	--username|-U)
***************
*** 135,140 ****
--- 144,150 ----
  	echo "  -P, --pwprompt                  Assign a password to new user"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as (not the one to create)"
  	echo "  -W, --password                  Prompt for password to connect"
  	echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/dropdb
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/scripts/dropdb,v
retrieving revision 1.7
diff -c -r1.7 dropdb
*** src/bin/scripts/dropdb	2000/11/11 22:59:48	1.7
--- src/bin/scripts/dropdb	2000/11/13 05:26:34
***************
*** 59,64 ****
--- 59,73 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 103,108 ****
--- 112,118 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/droplang
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/scripts/droplang,v
retrieving revision 1.8
diff -c -r1.8 droplang
*** src/bin/scripts/droplang	2000/11/11 22:59:48	1.8
--- src/bin/scripts/droplang	2000/11/13 05:26:34
***************
*** 65,70 ****
--- 65,79 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 113,118 ****
--- 122,128 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -d, --dbname=DBNAME             Database to remove language from"
Index: src/bin/scripts/dropuser
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/scripts/dropuser,v
retrieving revision 1.7
diff -c -r1.7 dropuser
*** src/bin/scripts/dropuser	2000/11/11 22:59:48	1.7
--- src/bin/scripts/dropuser	2000/11/13 05:26:34
***************
*** 59,64 ****
--- 59,73 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  # Note: These two specify the user to connect as (like in psql),
  #       not the user you're dropping.
  	--username|-U)
***************
*** 105,110 ****
--- 114,120 ----
  	echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as (not the one to drop)"
  	echo "  -W, --password                  Prompt for password to connect"
  	echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/vacuumdb
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/scripts/vacuumdb,v
retrieving revision 1.10
diff -c -r1.10 vacuumdb
*** src/bin/scripts/vacuumdb	2000/11/11 22:59:48	1.10
--- src/bin/scripts/vacuumdb	2000/11/13 05:26:34
***************
*** 52,57 ****
--- 52,66 ----
          --port=*)
                  PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
                  ;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
  	--username|-U)
  		PSQLOPT="$PSQLOPT -U $2"
  		shift;;
***************
*** 121,126 ****
--- 130,136 ----
          echo "Options:"
  	echo "  -h, --host=HOSTNAME             Database server host"
  	echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
  	echo "  -U, --username=USERNAME         Username to connect as"
  	echo "  -W, --password                  Prompt for password"
  	echo "  -d, --dbname=DBNAME             Database to vacuum"
Index: src/include/libpq/libpq.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/libpq/libpq.h,v
retrieving revision 1.39
diff -c -r1.39 libpq.h
*** src/include/libpq/libpq.h	2000/07/08 03:04:30	1.39
--- src/include/libpq/libpq.h	2000/11/13 05:26:34
***************
*** 55,61 ****
  /*
   * prototypes for functions in pqcomm.c
   */
! extern int	StreamServerPort(int family, unsigned short portName, int *fdP);
  extern int	StreamConnection(int server_fd, Port *port);
  extern void StreamClose(int sock);
  extern void pq_init(void);
--- 55,62 ----
  /*
   * prototypes for functions in pqcomm.c
   */
! extern int	StreamServerPort(int family, char *hostName,
! 			unsigned short portName, char *unixSocketName, int *fdP);
  extern int	StreamConnection(int server_fd, Port *port);
  extern void StreamClose(int sock);
  extern void pq_init(void);
Index: src/include/libpq/pqcomm.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/libpq/pqcomm.h,v
retrieving revision 1.43
diff -c -r1.43 pqcomm.h
*** src/include/libpq/pqcomm.h	2000/11/01 21:14:03	1.43
--- src/include/libpq/pqcomm.h	2000/11/13 05:26:35
***************
*** 51,62 ****
  /* Configure the UNIX socket address for the well known port. */
  
  #if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port) \
! 	(sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), SUN_LEN(&(sun)))
  #else
! #define UNIXSOCK_PATH(sun,port) \
! 	(sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), \
! 	 strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
  #endif
  
  /*
--- 51,65 ----
  /* Configure the UNIX socket address for the well known port. */
  
  #if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port,defpath) \
!         ((defpath && defpath[0] != '\0') ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
!         (SUN_LEN(&(sun)))
  #else
! #define UNIXSOCK_PATH(sun,port,defpath) \
!         ((defpath && defpath[0] != '\0') ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
!         (strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
  #endif
  
  /*
***************
*** 176,180 ****
--- 179,185 ----
  extern int Unix_socket_permissions;
  
  extern char * Unix_socket_group;
+ extern char * UnixSocketName;
+ extern char * HostName;
  
  #endif	 /* PQCOMM_H */
Index: src/interfaces/libpq/fe-connect.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.144
diff -c -r1.144 fe-connect.c
*** src/interfaces/libpq/fe-connect.c	2000/11/04 02:27:56	1.144
--- src/interfaces/libpq/fe-connect.c	2000/11/13 05:26:39
***************
*** 130,135 ****
--- 130,138 ----
  	{"port", "PGPORT", DEF_PGPORT_STR, NULL,
  	"Database-Port", "", 6},
  
+ 	{"unixsocket", "PGUNIXSOCKET", NULL, NULL,
+ 	"Unix-Socket", "", 80},
+ 
  	{"tty", "PGTTY", DefaultTty, NULL,
  	"Backend-Debug-TTY", "D", 40},
  
***************
*** 305,310 ****
--- 308,315 ----
  	conn->pghost = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "port");
  	conn->pgport = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "unixsocket");
+ 	conn->pgunixsocket = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "tty");
  	conn->pgtty = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "options");
***************
*** 385,390 ****
--- 390,398 ----
   *	  PGPORT	   identifies TCP port to which to connect if <pgport> argument
   *				   is NULL or a null string.
   *
+  *	  PGUNIXSOCKET	   identifies Unix-domain socket to which to connect; default
+  *				   is computed from the TCP port.
+  *
   *	  PGTTY		   identifies tty to which to send messages if <pgtty> argument
   *				   is NULL or a null string.
   *
***************
*** 435,440 ****
--- 443,456 ----
  	else
  		conn->pgport = strdup(pgport);
  
+ #if FIX_ME
+ 	/* we need to modify the function to accept a unix socket path */
+ 	if (pgunixsocket)
+ 		conn->pgunixsocket = strdup(pgunixsocket);
+ 	else if ((tmp = getenv("PGUNIXSOCKET")) != NULL)
+ 		conn->pgunixsocket = strdup(tmp);
+ #endif
+ 
  	if (pgtty == NULL)
  	{
  		if ((tmp = getenv("PGTTY")) == NULL)
***************
*** 510,522 ****
  
  /*
   * update_db_info -
!  * get all additional infos out of dbName
   *
   */
  static int
  update_db_info(PGconn *conn)
  {
! 	char	   *tmp,
  			   *old = conn->dbName;
  
  	if (strchr(conn->dbName, '@') != NULL)
--- 526,538 ----
  
  /*
   * update_db_info -
!  * get all additional info out of dbName
   *
   */
  static int
  update_db_info(PGconn *conn)
  {
! 	char	   *tmp, *tmp2,
  			   *old = conn->dbName;
  
  	if (strchr(conn->dbName, '@') != NULL)
***************
*** 525,530 ****
--- 541,548 ----
  		tmp = strrchr(conn->dbName, ':');
  		if (tmp != NULL)		/* port number given */
  		{
+ 			if (conn->pgport)
+ 				free(conn->pgport);
  			conn->pgport = strdup(tmp + 1);
  			*tmp = '\0';
  		}
***************
*** 532,537 ****
--- 550,557 ----
  		tmp = strrchr(conn->dbName, '@');
  		if (tmp != NULL)		/* host name given */
  		{
+ 			if (conn->pghost)
+ 				free(conn->pghost);
  			conn->pghost = strdup(tmp + 1);
  			*tmp = '\0';
  		}
***************
*** 558,570 ****
  
  			/*
  			 * new style:
! 			 * <tcp|unix>:postgresql://server[:port][/dbname][?options]
  			 */
  			offset += strlen("postgresql://");
  
  			tmp = strrchr(conn->dbName + offset, '?');
  			if (tmp != NULL)	/* options given */
  			{
  				conn->pgoptions = strdup(tmp + 1);
  				*tmp = '\0';
  			}
--- 578,592 ----
  
  			/*
  			 * new style:
! 			 * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:][/dbname][?options]
  			 */
  			offset += strlen("postgresql://");
  
  			tmp = strrchr(conn->dbName + offset, '?');
  			if (tmp != NULL)	/* options given */
  			{
+ 				if (conn->pgoptions)
+ 					free(conn->pgoptions);
  				conn->pgoptions = strdup(tmp + 1);
  				*tmp = '\0';
  			}
***************
*** 572,597 ****
  			tmp = strrchr(conn->dbName + offset, '/');
  			if (tmp != NULL)	/* database name given */
  			{
  				conn->dbName = strdup(tmp + 1);
  				*tmp = '\0';
  			}
  			else
  			{
  				if ((tmp = getenv("PGDATABASE")) != NULL)
  					conn->dbName = strdup(tmp);
  				else if (conn->pguser)
  					conn->dbName = strdup(conn->pguser);
  			}
  
  			tmp = strrchr(old + offset, ':');
! 			if (tmp != NULL)	/* port number given */
  			{
- 				conn->pgport = strdup(tmp + 1);
  				*tmp = '\0';
  			}
  
  			if (strncmp(old, "unix:", 5) == 0)
  			{
  				conn->pghost = NULL;
  				if (strcmp(old + offset, "localhost") != 0)
  				{
--- 594,655 ----
  			tmp = strrchr(conn->dbName + offset, '/');
  			if (tmp != NULL)	/* database name given */
  			{
+ 				if (conn->dbName)
+ 					free(conn->dbName);
  				conn->dbName = strdup(tmp + 1);
  				*tmp = '\0';
  			}
  			else
  			{
+ 				/* Why do we default only this value from the environment again?  */
  				if ((tmp = getenv("PGDATABASE")) != NULL)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
  					conn->dbName = strdup(tmp);
+ 				}
  				else if (conn->pguser)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
  					conn->dbName = strdup(conn->pguser);
+ 				}
  			}
  
  			tmp = strrchr(old + offset, ':');
! 			if (tmp != NULL)	/* port number or Unix socket path given */
  			{
  				*tmp = '\0';
+ 				if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
+ 				{
+ 					if (strncmp(old, "unix:", 5) != 0)
+ 					{
+ 						printfPQExpBuffer(&conn->errorMessage,
+ 								  "connectDBStart() -- "
+ 								  "socket name can only be specified with "
+ 								  "non-TCP\n");
+ 						return 1; 
+ 					}
+ 					*tmp2 = '\0';
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = strdup(tmp + 1);
+ 				}
+ 				else
+ 				{
+ 					if (conn->pgport)
+ 						free(conn->pgport);
+ 					conn->pgport = strdup(tmp + 1);
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = NULL;
+ 				}
  			}
  
  			if (strncmp(old, "unix:", 5) == 0)
  			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
  				conn->pghost = NULL;
  				if (strcmp(old + offset, "localhost") != 0)
  				{
***************
*** 603,610 ****
  				}
  			}
  			else
  				conn->pghost = strdup(old + offset);
! 
  			free(old);
  		}
  	}
--- 661,671 ----
  				}
  			}
  			else
+ 			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
  				conn->pghost = strdup(old + offset);
! 			}
  			free(old);
  		}
  	}
***************
*** 763,769 ****
  	}
  #ifdef HAVE_UNIX_SOCKETS
  	else
! 		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
  #endif
  
  
--- 824,833 ----
  	}
  #ifdef HAVE_UNIX_SOCKETS
  	else
! 	{
! 		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
! 		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
! 	}
  #endif
  
  
***************
*** 842,848 ****
  							  conn->pghost ? conn->pghost : "localhost",
  							  (family == AF_INET) ?
  							  "TCP/IP port" : "Unix socket",
! 							  conn->pgport);
  			goto connect_errReturn;
  		}
  	}
--- 906,913 ----
  							  conn->pghost ? conn->pghost : "localhost",
  							  (family == AF_INET) ?
  							  "TCP/IP port" : "Unix socket",
! 							  (family == AF_UNIX && conn->pgunixsocket) ?
! 							  conn->pgunixsocket : conn->pgport);
  			goto connect_errReturn;
  		}
  	}
***************
*** 1143,1149 ****
  							   conn->pghost ? conn->pghost : "localhost",
  								  (conn->raddr.sa.sa_family == AF_INET) ?
  									  "TCP/IP port" : "Unix socket",
! 									  conn->pgport);
  					goto error_return;
  				}
  
--- 1208,1215 ----
  							   conn->pghost ? conn->pghost : "localhost",
  								  (conn->raddr.sa.sa_family == AF_INET) ?
  									  "TCP/IP port" : "Unix socket",
! 							  (conn->raddr.sa.sa_family == AF_UNIX && conn->pgunixsocket) ?
! 									  conn->pgunixsocket : conn->pgport);
  					goto error_return;
  				}
  
***************
*** 1819,1824 ****
--- 1885,1892 ----
  		free(conn->pghostaddr);
  	if (conn->pgport)
  		free(conn->pgport);
+ 	if (conn->pgunixsocket)
+ 		free(conn->pgunixsocket);
  	if (conn->pgtty)
  		free(conn->pgtty);
  	if (conn->pgoptions)
***************
*** 2526,2531 ****
--- 2594,2607 ----
  	if (!conn)
  		return (char *) NULL;
  	return conn->pgport;
+ }
+ 
+ char *
+ PQunixsocket(const PGconn *conn)
+ {
+ 	if (!conn)
+ 		return (char *) NULL;
+ 	return conn->pgunixsocket;
  }
  
  char *
Index: src/interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.67
diff -c -r1.67 libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	2000/08/30 14:54:23	1.67
--- src/interfaces/libpq/libpq-fe.h	2000/11/13 05:26:39
***************
*** 217,222 ****
--- 217,223 ----
  	extern char *PQpass(const PGconn *conn);
  	extern char *PQhost(const PGconn *conn);
  	extern char *PQport(const PGconn *conn);
+ 	extern char *PQunixsocket(const PGconn *conn);
  	extern char *PQtty(const PGconn *conn);
  	extern char *PQoptions(const PGconn *conn);
  	extern ConnStatusType PQstatus(const PGconn *conn);
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.27
diff -c -r1.27 libpq-int.h
*** src/interfaces/libpq/libpq-int.h	2000/08/30 14:54:24	1.27
--- src/interfaces/libpq/libpq-int.h	2000/11/13 05:26:39
***************
*** 203,208 ****
--- 203,210 ----
  								 * numbers-and-dots notation. Takes
  								 * precedence over above. */
  	char	   *pgport;			/* the server's communication port */
+ 	char	   *pgunixsocket;		/* the Unix-domain socket that the server is listening on;
+ 						 * if NULL, uses a default constructed from pgport */
  	char	   *pgtty;			/* tty on which the backend messages is
  								 * displayed (NOT ACTUALLY USED???) */
  	char	   *pgoptions;		/* options to start the backend with */
Index: src/interfaces/libpq/libpqdll.def
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/libpqdll.def,v
retrieving revision 1.10
diff -c -r1.10 libpqdll.def
*** src/interfaces/libpq/libpqdll.def	2000/03/11 03:08:37	1.10
--- src/interfaces/libpq/libpqdll.def	2000/11/13 05:26:39
***************
*** 79,81 ****
--- 79,82 ----
  	destroyPQExpBuffer	@ 76
  	createPQExpBuffer	@ 77
  	PQconninfoFree		@ 78
+ 	PQunixsocket		@ 79
#10Bruce Momjian
pgman@candle.pha.pa.us
In reply to: David J. MacKenzie (#1)
Re: PostgreSQL virtual hosting support

OK, I have applied my version of patch. The only change is that '-h
any' is not supported. If you use -h, you must use an IP address. Not
using -h is the same as -h any.

;> Your name : David MacKenzie

Your email address : djm@web.us.uu.net

System Configuration
---------------------
Architecture (example: Intel Pentium) : Intel x86

Operating System (example: Linux 2.0.26 ELF) : BSD/OS 4.0.1

PostgreSQL version (example: PostgreSQL-7.0): PostgreSQL-7.0.2

Compiler used (example: gcc 2.8.0) : gcc version 2.7.2.1

Please enter a FULL description of your problem:
------------------------------------------------

UUNET is looking into offering PostgreSQL as a part of a managed web
hosting product, on both shared and dedicated machines. We currently
offer Oracle and MySQL, and it would be a nice middle-ground.
However, as shipped, PostgreSQL lacks the following features we need
that MySQL has:

1. The ability to listen only on a particular IP address. Each
hosting customer has their own IP address, on which all of their
servers (http, ftp, real media, etc.) run.
2. The ability to place the Unix-domain socket in a mode 700 directory.
This allows us to automatically create an empty database, with an
empty DBA password, for new or upgrading customers without having
to interactively set a DBA password and communicate it to (or from)
the customer. This in turn cuts down our install and upgrade times.
3. The ability to connect to the Unix-domain socket from within a
change-rooted environment. We run CGI programs chrooted to the
user's home directory, which is another reason why we need to be
able to specify where the Unix-domain socket is, instead of /tmp.
4. The ability to, if run as root, open a pid file in /var/run as
root, and then setuid to the desired user. (mysqld -u can almost
do this; I had to patch it, too).

The patch below fixes problem 1-3. I plan to address #4, also, but
haven't done so yet. These diffs are big enough that they should give
the PG development team something to think about in the meantime :-)
Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get
out what I have, which works (for the problems it tackles), now.

With these changes, we can set up and run PostgreSQL with scripts the
same way we can with apache or proftpd or mysql.

In summary, this patch makes the following enhancements:

1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT,
and command line options -k --unix-socket to the relevant programs.
2. Adds a -h option to postmaster to set the hostname or IP address to
listen on instead of the default INADDR_ANY.
3. Extends some library interfaces to support the above.
4. Fixes a few memory leaks in PQconnectdb().

The default behavior is unchanged from stock 7.0.2; if you don't use
any of these new features, they don't change the operation.

Index: doc/src/sgml/layout.sgml
*** doc/src/sgml/layout.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/layout.sgml	2000/07/02 03:56:05	1.2
***************
*** 55,61 ****
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> may also have to be set.  The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
--- 55,62 ----
For example, if the database server machine is a remote machine, you
will need to set the <envar>PGHOST</envar> environment variable to the name
of the database server machine.   The  environment  variable
! <envar>PGPORT</envar> or <envar>PGUNIXSOCKET</envar> may also have to be set.
! The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <Application>postmaster</Application>,
you must go back and make sure that your
Index: doc/src/sgml/libpq++.sgml
*** doc/src/sgml/libpq++.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq++.sgml	2000/07/02 03:56:05	1.2
***************
*** 93,98 ****
--- 93,105 ----
</listitem>
<listitem>
<para>
+ 	<envar>PGUNIXSOCKET</envar>  sets the full Unix domain socket
+ 	file name for communicating with the <productname>Postgres</productname>
+ 	backend.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
<envar>PGDATABASE</envar>  sets the default 
<productname>Postgres</productname> database name.
</para>
Index: doc/src/sgml/libpq.sgml
*** doc/src/sgml/libpq.sgml	2000/06/30 21:15:36	1.1
--- doc/src/sgml/libpq.sgml	2000/07/02 03:56:05	1.2
***************
*** 134,139 ****
--- 134,148 ----
</varlistentry>
<varlistentry>
+      <term><literal>unixsocket</literal></term>
+      <listitem>
+      <para>
+       Full path to Unix-domain socket file to connect to at the server host.
+      </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
<term><literal>dbname</literal></term>
<listitem>
<para>
***************
*** 545,550 ****
--- 554,569 ----
<listitem>
<para>
+ <function>PQunixsocket</function>
+          Returns the name of the Unix-domain socket of the connection.
+ <synopsis>
+ char *PQunixsocket(const PGconn *conn)
+ </synopsis>
+ </para>
+ </listitem>
+ 
+ <listitem>
+ <para>
<function>PQtty</function>
Returns the debug tty of the connection.
<synopsis>
***************
*** 1772,1777 ****
--- 1791,1803 ----
<envar>PGHOST</envar> sets the default server name.
If a non-zero-length string is specified, TCP/IP communication is used.
Without a host name, libpq will connect using a local Unix domain socket.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <envar>PGPORT</envar>  sets the default port or local Unix domain socket
+ file extension for communicating with the <productname>Postgres</productname>
+ backend.
</para>
</listitem>
<listitem>
Index: doc/src/sgml/start.sgml
*** doc/src/sgml/start.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/start.sgml	2000/07/02 03:56:05	1.2
***************
*** 110,117 ****
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> may also have to be set.  The bottom
!     line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
--- 110,117 ----
will need to set the <acronym>PGHOST</acronym> environment
variable to the name
of the database server machine.   The  environment  variable
!     <acronym>PGPORT</acronym> or <acronym>PGUNIXSOCKET</acronym> may also have to be set.
!     The bottom line is this: if
you try to start an application  program  and  it  complains
that it cannot connect to the <application>postmaster</application>,
you should immediately consult your site administrator to make
Index: doc/src/sgml/ref/createdb.sgml
*** doc/src/sgml/ref/createdb.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createlang.sgml
*** doc/src/sgml/ref/createlang.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createlang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/createuser.sgml
*** doc/src/sgml/ref/createuser.sgml	2000/06/30 21:15:37	1.1
--- doc/src/sgml/ref/createuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,76 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/dropdb.sgml
*** doc/src/sgml/ref/dropdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/droplang.sgml
*** doc/src/sgml/ref/droplang.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/droplang.sgml	2000/07/04 04:46:45	1.2
***************
*** 96,101 ****
--- 96,113 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-U, --username <replaceable class="parameter">username</replaceable></term>
<listitem>
Index: doc/src/sgml/ref/dropuser.sgml
*** doc/src/sgml/ref/dropuser.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/dropuser.sgml	2000/07/04 04:46:45	1.2
***************
*** 58,63 ****
--- 58,75 ----
</listitem>
</varlistentry>
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
<varlistentry>
<term>-e, --echo</term>
<listitem>
Index: doc/src/sgml/ref/pg_dump.sgml
*** doc/src/sgml/ref/pg_dump.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dump.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
pg_dump [ <replaceable class="parameter">dbname</replaceable> ]
! pg_dump [ -h <replaceable class="parameter">host</replaceable> ]
!     [ -k <replaceable class="parameter">path</replaceable> ]
!     [ -p <replaceable class="parameter">port</replaceable> ]
[ -t <replaceable class="parameter">table</replaceable> ]
[ -a ] [ -c ] [ -d ] [ -D ] [ -i ] [ -n ] [ -N ]
[ -o ] [ -s ] [ -u ] [ -v ] [ -x ]
***************
*** 200,205 ****
--- 202,222 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/pg_dumpall.sgml
*** doc/src/sgml/ref/pg_dumpall.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/pg_dumpall.sgml	2000/07/01 18:41:22	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
--- 24,33 ----
</refsynopsisdivinfo>
<synopsis>
pg_dumpall
! pg_dumpall [ -h <replaceable class="parameter">host</replaceable> ]
!      [ -k <replaceable class="parameter">path</replaceable> ]
!      [ -p <replaceable class="parameter">port</replaceable> ]
!      [ -a ] [ -d ] [ -D ] [ -O ] [ -s ] [ -u ] [ -v ] [ -x ]
</synopsis>
<refsect2 id="R2-APP-PG-DUMPALL-1">
***************
*** 137,142 ****
--- 140,160 ----
<application>postmaster</application>
is running.  Defaults to using a local Unix domain socket
rather than an IP connection..
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket file path
+ 	on which the <application>postmaster</application>
+ 	is listening for connections.
+         Without this option, the socket path name defaults to
+         the value of the <envar>PGUNIXSOCKET</envar> environment
+ 	variable (if set), otherwise it is constructed
+         from the port number.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/postmaster.sgml	2000/07/06 07:48:31	1.7
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ] [ -i ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
--- 24,32 ----
</refsynopsisdivinfo>
<synopsis>
postmaster [ -B <replaceable class="parameter">nBuffers</replaceable> ] [ -D <replaceable class="parameter">DataDir</replaceable> ] [ -N <replaceable class="parameter">maxBackends</replaceable> ] [ -S ]
!     [ -d <replaceable class="parameter">DebugLevel</replaceable> ]
!     [ -h <replaceable class="parameter">hostname</replaceable> ] [ -i ]
!     [ -k <replaceable class="parameter">path</replaceable> ] [ -l ]
[ -o <replaceable class="parameter">BackendOptions</replaceable> ] [ -p <replaceable class="parameter">port</replaceable> ] [ -n | -s ]
</synopsis>
***************
*** 124,129 ****
--- 126,161 ----
</varlistentry>
<varlistentry>
+       <term>-h <replaceable class="parameter">hostName</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the TCP/IP hostname or address
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGHOST</envar> 
+ 	environment variable, or if <envar>PGHOST</envar>
+ 	is not set, then defaults to "all", meaning listen on all configured addresses
+ 	(including localhost).
+        </para>
+        <para>
+ 	If you use a hostname or address other than "all", do not try to run
+ 	multiple instances of <application>postmaster</application> on the
+ 	same IP address but different ports.  Doing so will result in them
+ 	attempting (incorrectly) to use the same shared memory segments.
+ 	Also, if you use a hostname other than "all", all of the host's IP addresses
+ 	on which <application>postmaster</application> instances are
+ 	listening must be distinct in the two last octets.
+        </para>
+        <para>
+ 	If you do use "all" (the default), then each instance must listen on a
+ 	different port (via -p or <envar>PGPORT</envar>).  And, of course, do
+ 	not try to use both approaches on one host.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-i</term>
<listitem>
<para>
***************
*** 135,140 ****
--- 167,201 ----
</varlistentry>
<varlistentry>
+       <term>-k <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+        <para>
+ 	Specifies the local Unix domain socket path name
+ 	on which the <application>postmaster</application>
+ 	is to listen for connections from frontend applications.  Defaults to
+ 	the value of the 
+ 	<envar>PGUNIXSOCKET</envar> 
+ 	environment variable, or if <envar>PGUNIXSOCKET</envar>
+ 	is not set, then defaults to a file in <filename>/tmp</filename>
+ 	constructed from the port number.
+        </para>
+        <para>
+         You can use this option to put the Unix-domain socket in a
+         directory that is private to one or more users using Unix
+ 	directory permissions.  This is necessary for securely
+ 	creating databases automatically on shared machines.
+         In that situation, also disallow all TCP/IP connections
+ 	initially in <filename>pg_hba.conf</filename>.
+ 	If you specify a socket path other than the
+ 	default then all frontend applications (including
+ 	<application>psql</application>) must specify the same
+ 	socket path using either command-line options or
+ 	<envar>PGUNIXSOCKET</envar>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
<term>-l</term>
<listitem>
<para>
Index: doc/src/sgml/ref/psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/psql-ref.sgml	2000/07/02 03:56:05	1.3
***************
*** 1329,1334 ****
--- 1329,1347 ----
<varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
+ 
+ 
+     <varlistentry>
<term>-H, --html</term>
<listitem>
<para>
Index: doc/src/sgml/ref/vacuumdb.sgml
*** doc/src/sgml/ref/vacuumdb.sgml	2000/06/30 21:15:38	1.1
--- doc/src/sgml/ref/vacuumdb.sgml	2000/07/04 04:46:45	1.2
***************
*** 24,30 ****
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --alldb | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
--- 24,30 ----
</refsynopsisdivinfo>
<synopsis>
vacuumdb [ <replaceable class="parameter">options</replaceable> ] [ --analyze | -z ]
!     [ --all | -a ] [ --verbose | -v ]
[ --table '<replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [,...] ) ]' ] [ [-d] <replaceable class="parameter">dbname</replaceable> ]
</synopsis>
***************
*** 128,133 ****
--- 128,145 ----
</para>
</listitem>
</varlistentry>
+ 
+     <varlistentry>
+       <term>-k, --unixsocket <replaceable class="parameter">path</replaceable></term>
+       <listitem>
+       <para>
+       Specifies the Unix-domain socket on which the
+       <application>postmaster</application> is running.
+       Without this option, the socket is created in <filename>/tmp</filename>
+       based on the port number.
+       </para>
+       </listitem>
+     </varlistentry>
<varlistentry>
<term>-U <replaceable class="parameter">username</replaceable></term>
Index: src/backend/libpq/pqcomm.c
*** src/backend/libpq/pqcomm.c	2000/06/30 21:15:40	1.1
--- src/backend/libpq/pqcomm.c	2000/07/01 18:50:46	1.3
***************
*** 42,47 ****
--- 42,48 ----
*		StreamConnection	- Create new connection with client
*		StreamClose			- Close a client/backend connection
*		pq_getport		- return the PGPORT setting
+  *		pq_getunixsocket	- return the PGUNIXSOCKET setting
*		pq_init			- initialize libpq at backend startup
*		pq_close		- shutdown libpq at backend exit
*
***************
*** 134,139 ****
--- 135,151 ----
}
/* --------------------------------
+  *		pq_getunixsocket - return the PGUNIXSOCKET setting.
+  *		If NULL, default to computing it based on the port.
+  * --------------------------------
+  */
+ char *
+ pq_getunixsocket(void)
+ {
+ 	return getenv("PGUNIXSOCKET");
+ }
+ 
+ /* --------------------------------
*		pq_close - shutdown libpq at backend exit
*
* Note: in a standalone backend MyProcPort will be null,
***************
*** 177,189 ****
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/
int
! StreamServerPort(char *hostName, unsigned short portName, int *fdP)
{
SockAddr	saddr;
int			fd,
--- 189,205 ----
/*
* StreamServerPort -- open a sock stream "listening" port.
*
!  * This initializes the Postmaster's connection-accepting port fdP.
!  * If hostName is "any", listen on all configured IP addresses.
!  * If hostName is NULL, listen on a Unix-domain socket instead of TCP;
!  * if unixSocketName is NULL, a default path (constructed in UNIX_SOCK_PATH
!  * in include/libpq/pqcomm.h) based on portName is used.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/

int
! StreamServerPort(char *hostName, unsigned short portNumber, char *unixSocketName, int *fdP)
{
SockAddr saddr;
int fd,
***************
*** 227,233 ****
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! len = UNIXSOCK_PATH(saddr.un, portName);
strcpy(sock_path, saddr.un.sun_path);

/*
--- 243,250 ----
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
! 		UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
! 		len = UNIXSOCK_LEN(saddr.un);
strcpy(sock_path, saddr.un.sun_path);
/*
***************
*** 259,267 ****
}
else
{
! 		saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 		saddr.in.sin_port = htons(portName);
! 		len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
--- 276,305 ----
}
else
{
! 	  /* TCP/IP socket */
! 	  if (!strcmp(hostName, "all")) /* like for databases in pg_hba.conf.  */
! 	    saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
! 	  else
! 	    {
! 	      struct hostent *hp;
! 
! 	      hp = gethostbyname(hostName);
! 	      if ((hp == NULL) || (hp->h_addrtype != AF_INET))
! 		{
! 		  snprintf(PQerrormsg, PQERRORMSG_LENGTH,
! 			   "FATAL: StreamServerPort: gethostbyname(%s) failed: %s\n",
! 			   hostName, hstrerror(h_errno));
! 		  fputs(PQerrormsg, stderr);
! 		  pqdebug("%s", PQerrormsg);
! 		  return STATUS_ERROR;
! 		}
! 	      memmove((char *) &(saddr.in.sin_addr),
! 		      (char *) hp->h_addr,
! 		      hp->h_length);
! 	    }
! 
! 	  saddr.in.sin_port = htons(portNumber);
! 	  len = sizeof(struct sockaddr_in);
}
err = bind(fd, &saddr.sa, len);
if (err < 0)
Index: src/backend/postmaster/postmaster.c
*** src/backend/postmaster/postmaster.c	2000/06/30 21:15:42	1.1
--- src/backend/postmaster/postmaster.c	2000/07/06 07:38:21	1.5
***************
*** 136,143 ****
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! static unsigned short PostPortName = 0;

/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
--- 136,150 ----
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;

! /* Hostname of interface to listen on, or 'any'. */
! static char *HostName = NULL;

+ /* TCP/IP port number to listen on.  Also used to default the Unix-domain socket name.  */
+ static unsigned short PostPortNumber = 0;
+ 
+ /* Override of the default Unix-domain socket name to listen on, if non-NULL.  */
+ static char *UnixSocketName = NULL;
+ 
/*
* This is a boolean indicating that there is at least one backend that
* is accessing the current shared memory and semaphores. Between the
***************
*** 274,280 ****
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 281,287 ----
static void SignalChildren(SIGNAL_ARGS);
static int	CountChildren(void);
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 370,380 ****
{
extern int	NBuffers;		/* from buffer/bufmgr.c */
int			opt;
- 	char	   *hostName;
int			status;
int			silentflag = 0;
bool		DataDirOK;		/* We have a usable PGDATA value */
- 	char		hostbuf[MAXHOSTNAMELEN];
int			nonblank_argc;
char		original_extraoptions[MAXPGPATH];
--- 377,385 ----
***************
*** 431,449 ****
*/
umask((mode_t) 0077);

- if (!(hostName = getenv("PGHOST")))
- {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:ilm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
--- 436,447 ----
*/
umask((mode_t) 0077);

MyProcPid = getpid();
DataDir = getenv("PGDATA"); /* default value */

opterr = 0;
IgnoreSystemIndexes(false);
! 	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:d:h:ik:lm:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
***************
*** 498,506 ****
--- 496,511 ----
DebugLvl = atoi(optarg);
pg_options[TRACE_VERBOSE] = DebugLvl;
break;
+ 			case 'h':
+ 				HostName = optarg;
+ 				break;
case 'i':
NetServer = true;
break;
+ 			case 'k':
+ 				/* Set PGUNIXSOCKET by hand. */
+ 				UnixSocketName = optarg;
+ 				break;
#ifdef USE_SSL
case 'l':
SecureNetServer = true;
***************
*** 545,551 ****
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortName = (unsigned short) atoi(optarg);
break;
case 'S':
--- 550,556 ----
break;
case 'p':
/* Set PGPORT by hand. */
! 				PostPortNumber = (unsigned short) atoi(optarg);
break;
case 'S':

***************
*** 577,584 ****
/*
* Select default values for switches where needed
*/
! if (PostPortName == 0)
! PostPortName = (unsigned short) pq_getport();

/*
* Check for invalid combinations of switches
--- 582,603 ----
/*
* Select default values for switches where needed
*/
! 	if (HostName == NULL)
! 	{
! 		if (!(HostName = getenv("PGHOST")))
! 		{
! 			HostName = "any";
! 		}
! 	}
! 	else if (!NetServer)
! 	{
! 		fprintf(stderr, "%s: -h requires -i.\n", progname);
! 		exit(1);
! 	}
! 	if (PostPortNumber == 0)
! 		PostPortNumber = (unsigned short) pq_getport();
! 	if (UnixSocketName == NULL)
! 		UnixSocketName = pq_getunixsocket();

/*
* Check for invalid combinations of switches
***************
*** 622,628 ****

if (NetServer)
{
! 		status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
--- 641,647 ----

if (NetServer)
{
! status = StreamServerPort(HostName, PostPortNumber, NULL, &ServerSock_INET);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create INET stream port\n",
***************
*** 632,638 ****
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! 	status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
--- 651,657 ----
}

#if !defined(__CYGWIN32__) && !defined(__QNX__)
! status = StreamServerPort(NULL, PostPortNumber, UnixSocketName, &ServerSock_UNIX);
if (status != STATUS_OK)
{
fprintf(stderr, "%s: cannot create UNIX stream port\n",
***************
*** 642,648 ****
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! reset_shared(PostPortName);

/*
* Initialize the list of active backends.	This list is only used for
--- 661,667 ----
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
! 	reset_shared(PostPortNumber);
/*
* Initialize the list of active backends.	This list is only used for
***************
*** 664,670 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 683,691 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 753,759 ****
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							PostPortName,		/* port number */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
--- 774,782 ----
{
if (SetOptsFile(
progname,	/* postmaster executable file */
! 							HostName, /* IP address to bind to */
! 							PostPortNumber,		/* port number */
! 							UnixSocketName,	/* PGUNIXSOCKET */
DataDir,	/* PGDATA */
assert_enabled,		/* whether -A is specified
* or not */
***************
*** 837,843 ****
--- 860,868 ----
fprintf(stderr, "\t-a system\tuse this authentication system\n");
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
fprintf(stderr, "\t-d [1-5]\tset debugging level\n");
+ 	fprintf(stderr, "\t-h hostname\tspecify hostname or IP address or 'any' for postmaster to listen on (also use -i)\n");
fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+ 	fprintf(stderr, "\t-k path\tspecify Unix-domain socket name for postmaster to listen on\n");
#ifdef USE_SSL
fprintf(stderr, " \t-l \t\tfor TCP/IP sockets, listen only on SSL connections\n");
#endif
***************
*** 1318,1328 ****
--- 1343,1417 ----
}
/*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+ 	static unsigned short hostPort = 0;
+ 
+ 	if (hostPort == 0)
+ 	{
+ 		SockAddr	saddr;
+ 		struct hostent *hp;
+ 
+ 		hp = gethostbyname(HostName);
+ 		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+ 		{
+ 			char msg[1024];
+ 			snprintf(msg, sizeof(msg),
+ 				 "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+ 				 HostName, hstrerror(h_errno));
+ 			fputs(msg, stderr);
+ 			pqdebug("%s", msg);
+ 			exit(1);
+ 		}
+ 		memmove((char *) &(saddr.in.sin_addr),
+ 			(char *) hp->h_addr,
+ 			hp->h_length);
+ 		hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+ 	}
+ 
+ 	return hostPort;
+ }
+ 
+ /*
* reset_shared -- reset shared memory and semaphores
*/
static void
reset_shared(unsigned short port)
{
+ 	/*
+ 	 * A typical ipc_key is 5432001, which is port 5432, sequence
+ 	 * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+ 	 * The 32-bit INT_MAX is 2147483 6 47.
+ 	 *
+ 	 * The default algorithm for calculating the IPC keys assumes that all
+ 	 * instances of postmaster on a given host are listening on different
+ 	 * ports.  In order to work (prevent shared memory collisions) if you
+ 	 * run multiple PostgreSQL instances on the same port and different IP
+ 	 * addresses on a host, we change the algorithm if you give postmaster
+ 	 * the -h option, or set PGHOST, to a value other than the internal
+ 	 * default of "any".
+ 	 *
+ 	 * If HostName is not "any", then we generate the IPC keys using the
+ 	 * last two octets of the IP address instead of the port number.
+ 	 * This algorithm assumes that no one will run multiple PostgreSQL
+ 	 * instances on one host using two IP addresses that have the same two
+ 	 * last octets in different class C networks.  If anyone does, it
+ 	 * would be rare.
+ 	 *
+ 	 * So, if you use -h or PGHOST, don't try to run two instances of
+ 	 * PostgreSQL on the same IP address but different ports.  If you
+ 	 * don't use them, then you must use different ports (via -p or
+ 	 * PGPORT).  And, of course, don't try to use both approaches on one
+ 	 * host.
+ 	 */
+ 
+ 	if (strcmp(HostName, "any"))
+ 		port = get_host_port();
+ 
ipc_key = port * 1000 + shmem_seq * 100;
CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
shmem_seq += 1;
***************
*** 1540,1546 ****
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortName);
StartupPID = StartupDataBase();
return;
}
--- 1629,1635 ----
ctime(&tnow));
fflush(stderr);
shmem_exit(0);
! 		reset_shared(PostPortNumber);
StartupPID = StartupDataBase();
return;
}
***************
*** 1720,1726 ****
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
--- 1809,1815 ----
* Set up the necessary environment variables for the backend This
* should really be some sort of message....
*/
! 	sprintf(envEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
***************
*** 2174,2180 ****
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
--- 2263,2269 ----
for (i = 0; i < 4; ++i)
MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
! 	sprintf(ssEntry[0], "POSTPORT=%d", PostPortNumber);
putenv(ssEntry[0]);
sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
putenv(ssEntry[1]);
***************
*** 2254,2260 ****
* Create the opts file
*/
static int
! SetOptsFile(char *progname, int port, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
--- 2343,2349 ----
* Create the opts file
*/
static int
! SetOptsFile(char *progname, char *hostname, int port, char *unixsocket, char *datadir,
int assert, int nbuf, char *execfile,
int debuglvl, int netserver,
#ifdef USE_SSL
***************
*** 2279,2284 ****
--- 2368,2383 ----
return (-1);
}
snprintf(opts, sizeof(opts), "%s\n-p %d\n-D %s\n", progname, port, datadir);
+ 	if (netserver)
+ 	{
+ 		sprintf(buf, "-h %s\n", hostname);
+ 		strcat(opts, buf);
+ 	}
+ 	if (unixsocket)
+ 	{
+ 		sprintf(buf, "-k %s\n", unixsocket);
+ 		strcat(opts, buf);
+ 	}
if (assert)
{
sprintf(buf, "-A %d\n", assert);
Index: src/bin/pg_dump/pg_dump.c
*** src/bin/pg_dump/pg_dump.c	2000/06/30 21:15:44	1.1
--- src/bin/pg_dump/pg_dump.c	2000/07/01 18:41:22	1.2
***************
*** 140,145 ****
--- 140,146 ----
"  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
"  -h, --host <hostname>    server host name\n"
"  -i, --ignore-version     proceed when database version != pg_dump version\n"
+ 		 "  -k, --unixsocket <path>  server Unix-domain socket name\n"
"  -n, --no-quotes          suppress most quotes around identifiers\n"
"  -N, --quotes             enable most quotes around identifiers\n"
"  -o, --oids               dump object ids (oids)\n"
***************
*** 158,163 ****
--- 159,165 ----
"  -D                       dump data as INSERT commands with attribute names\n"
"  -h <hostname>            server host name\n"
"  -i                       proceed when database version != pg_dump version\n"
+ 		 "  -k <path>                server Unix-domain socket name\n"
"  -n                       suppress most quotes around identifiers\n"
"  -N                       enable most quotes around identifiers\n"
"  -o                       dump object ids (oids)\n"
***************
*** 579,584 ****
--- 581,587 ----
const char *dbname = NULL;
const char *pghost = NULL;
const char *pgport = NULL;
+ 	const char *pgunixsocket = NULL;
char	   *tablename = NULL;
bool		oids = false;
TableInfo  *tblinfo;
***************
*** 598,603 ****
--- 601,607 ----
{"attribute-inserts", no_argument, NULL, 'D'},
{"host", required_argument, NULL, 'h'},
{"ignore-version", no_argument, NULL, 'i'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"no-quotes", no_argument, NULL, 'n'},
{"quotes", no_argument, NULL, 'N'},
{"oids", no_argument, NULL, 'o'},
***************
*** 662,667 ****
--- 666,674 ----
case 'i':			/* ignore database version mismatch */
ignore_version = true;
break;
+ 			case 'k':			/* server Unix-domain socket */
+ 				pgunixsocket = optarg;
+ 				break;
case 'n':			/* Do not force double-quotes on
* identifiers */
force_quotes = false;
***************
*** 782,788 ****
exit(1);
}
- 	/* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
if (pghost != NULL)
{
sprintf(tmp_string, "host=%s ", pghost);
--- 789,794 ----
***************
*** 791,796 ****
--- 797,807 ----
if (pgport != NULL)
{
sprintf(tmp_string, "port=%s ", pgport);
+ 		strcat(connect_string, tmp_string);
+ 	}
+ 	if (pgunixsocket != NULL)
+ 	{
+ 		sprintf(tmp_string, "unixsocket=%s ", pgunixsocket);
strcat(connect_string, tmp_string);
}
if (dbname != NULL)
Index: src/bin/psql/command.c
*** src/bin/psql/command.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/command.c	2000/07/01 18:20:40	1.2
***************
*** 1199,1204 ****
--- 1199,1205 ----
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 	SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
/* If dbname is "" then use old name, else new one (even if NULL) */
***************
*** 1228,1233 ****
--- 1229,1235 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to support passing the Unix socket */
pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
NULL, NULL, dbparam, userparam, pwparam);
***************
*** 1303,1308 ****
--- 1305,1311 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
pset.issuper = test_superuser(PQuser(pset.db));
Index: src/bin/psql/command.h
Index: src/bin/psql/common.c
*** src/bin/psql/common.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/common.c	2000/07/01 18:20:40	1.2
***************
*** 330,335 ****
--- 330,336 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 			SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return NULL;
***************
*** 509,514 ****
--- 510,516 ----
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
+ 				SetVariable(pset.vars, "UNIXSOCKET", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "ENCODING", NULL);
return false;
Index: src/bin/psql/help.c
*** src/bin/psql/help.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/help.c	2000/07/01 18:20:40	1.2
***************
*** 103,108 ****
--- 103,118 ----
puts(")");
puts("  -H              HTML table output mode (-P format=html)");
+ 
+ 	/* Display default Unix-domain socket */
+ 	env = getenv("PGUNIXSOCKET");
+ 	printf("  -k <path>       Specify Unix domain socket name (default: ");
+ 	if (env)
+ 		fputs(env, stdout);
+ 	else
+ 		fputs("computed from the port", stdout);
+ 	puts(")");
+ 
puts("  -l              List available databases, then exit");
puts("  -n              Disable readline");
puts("  -o <filename>   Send query output to filename (or |pipe)");
Index: src/bin/psql/prompt.c
*** src/bin/psql/prompt.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/prompt.c	2000/07/01 18:20:40	1.2
***************
*** 189,194 ****
--- 189,199 ----
if (pset.db && PQport(pset.db))
strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
break;
+ 					/* DB server Unix-domain socket */
+ 				case '<':
+ 					if (pset.db && PQunixsocket(pset.db))
+ 						strncpy(buf, PQunixsocket(pset.db), MAX_PROMPT_SIZE);
+ 					break;
/* DB server user name */
case 'n':
if (pset.db)
Index: src/bin/psql/prompt.h
Index: src/bin/psql/settings.h
Index: src/bin/psql/startup.c
*** src/bin/psql/startup.c	2000/06/30 21:15:46	1.1
--- src/bin/psql/startup.c	2000/07/01 18:20:40	1.2
***************
*** 66,71 ****
--- 66,72 ----
char	   *dbname;
char	   *host;
char	   *port;
+ 	char	   *unixsocket;
char	   *username;
enum _actions action;
char	   *action_string;
***************
*** 158,163 ****
--- 159,165 ----
do
{
need_pass = false;
+ 		/* FIXME use PQconnectdb to allow setting the unix socket */
pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
options.action == ACT_LIST_DB ? "template1" : options.dbname,
username, password);
***************
*** 202,207 ****
--- 204,210 ----
SetVariable(pset.vars, "USER", PQuser(pset.db));
SetVariable(pset.vars, "HOST", PQhost(pset.db));
SetVariable(pset.vars, "PORT", PQport(pset.db));
+ 	SetVariable(pset.vars, "UNIXSOCKET", PQunixsocket(pset.db));
SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
#ifndef WIN32
***************
*** 313,318 ****
--- 316,322 ----
{"field-separator", required_argument, NULL, 'F'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
+ 		{"unixsocket", required_argument, NULL, 'k'},
{"list", no_argument, NULL, 'l'},
{"no-readline", no_argument, NULL, 'n'},
{"output", required_argument, NULL, 'o'},
***************
*** 346,359 ****
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hno:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
--- 350,363 ----
memset(options, 0, sizeof *options);

#ifdef HAVE_GETOPT_LONG
! while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?", long_options, &optindex)) != -1)
#else /* not HAVE_GETOPT_LONG */

/*
* Be sure to leave the '-' in here, so we can catch accidental long
* options.
*/
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:lh:Hk:no:p:P:qRsStT:uU:v:VWxX?-")) != -1)
#endif	 /* not HAVE_GETOPT_LONG */
{
switch (c)
***************
*** 398,403 ****
--- 402,410 ----
break;
case 'l':
options->action = ACT_LIST_DB;
+ 				break;
+ 			case 'k':
+ 				options->unixsocket = optarg;
break;
case 'n':
options->no_readline = true;
Index: src/bin/scripts/createdb
*** src/bin/scripts/createdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createdb	2000/07/04 04:46:45	1.2
***************
*** 50,55 ****
--- 50,64 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 114,119 ****
--- 123,129 ----
echo "  -E, --encoding=ENCODING         Multibyte encoding for the database"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/createlang.sh
*** src/bin/scripts/createlang.sh	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createlang.sh	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 126,131 ****
--- 135,141 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to install language in"
Index: src/bin/scripts/createuser
*** src/bin/scripts/createuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/createuser	2000/07/04 04:46:45	1.2
***************
*** 63,68 ****
--- 63,77 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're creating.
--username|-U)
***************
*** 135,140 ****
--- 144,150 ----
echo "  -P, --pwprompt                  Assign a password to new user"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to create)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -e, --echo                      Show the query being sent to the backend"
Index: src/bin/scripts/dropdb
*** src/bin/scripts/dropdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropdb	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 103,108 ****
--- 112,118 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/droplang
*** src/bin/scripts/droplang	2000/06/30 21:15:46	1.1
--- src/bin/scripts/droplang	2000/07/04 04:46:45	1.2
***************
*** 65,70 ****
--- 65,79 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 113,118 ****
--- 122,128 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to remove language from"
Index: src/bin/scripts/dropuser
*** src/bin/scripts/dropuser	2000/06/30 21:15:46	1.1
--- src/bin/scripts/dropuser	2000/07/04 04:46:45	1.2
***************
*** 59,64 ****
--- 59,73 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
# Note: These two specify the user to connect as (like in psql),
#       not the user you're dropping.
--username|-U)
***************
*** 105,110 ****
--- 114,120 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as (not the one to drop)"
echo "  -W, --password                  Prompt for password to connect"
echo "  -i, --interactive               Prompt before deleting anything"
Index: src/bin/scripts/vacuumdb
*** src/bin/scripts/vacuumdb	2000/06/30 21:15:46	1.1
--- src/bin/scripts/vacuumdb	2000/07/04 04:46:45	1.2
***************
*** 52,57 ****
--- 52,66 ----
--port=*)
PSQLOPT="$PSQLOPT -p "`echo $1 | sed 's/^--port=//'`
;;
+ 	--unixsocket|-k)
+ 		PSQLOPT="$PSQLOPT -k $2"
+ 		shift;;
+         -k*)
+                 PSQLOPT="$PSQLOPT $1"
+                 ;;
+         --unixsocket=*)
+                 PSQLOPT="$PSQLOPT -k "`echo $1 | sed 's/^--unixsocket=//'`
+                 ;;
--username|-U)
PSQLOPT="$PSQLOPT -U $2"
shift;;
***************
*** 121,126 ****
--- 130,136 ----
echo "Options:"
echo "  -h, --host=HOSTNAME             Database server host"
echo "  -p, --port=PORT                 Database server port"
+ 	echo "  -k, --unixsocket=PATH           Database server Unix-domain socket name"
echo "  -U, --username=USERNAME         Username to connect as"
echo "  -W, --password                  Prompt for password"
echo "  -d, --dbname=DBNAME             Database to vacuum"
Index: src/include/libpq/libpq.h
*** src/include/libpq/libpq.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/libpq.h	2000/07/01 18:20:40	1.2
***************
*** 236,246 ****
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
--- 236,247 ----
/*
* prototypes for functions in pqcomm.c
*/
! extern int	StreamServerPort(char *hostName, unsigned short portName, char *unixSocketName, int *fdP);
extern int	StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);
extern void pq_init(void);
extern int	pq_getport(void);
+ extern char	*pq_getunixsocket(void);
extern void pq_close(void);
extern int	pq_getbytes(char *s, size_t len);
extern int	pq_getstring(StringInfo s);
Index: src/include/libpq/password.h
Index: src/include/libpq/pqcomm.h
*** src/include/libpq/pqcomm.h	2000/06/30 21:15:47	1.1
--- src/include/libpq/pqcomm.h	2000/07/01 18:59:33	1.6
***************
*** 42,53 ****
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port) \
! (sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)), \
! strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
--- 42,56 ----
/* Configure the UNIX socket address for the well known port. */

#if defined(SUN_LEN)
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (SUN_LEN(&(sun)))
#else
! #define UNIXSOCK_PATH(sun,port,defpath) \
! (defpath ? (strncpy((sun).sun_path, defpath, sizeof((sun).sun_path)), (sun).sun_path[sizeof((sun).sun_path)-1] = '\0') : sprintf((sun).sun_path, "/tmp/.s.PGSQL.%d", (port)))
! #define UNIXSOCK_LEN(sun) \
! (strlen((sun).sun_path)+ offsetof(struct sockaddr_un, sun_path))
#endif

/*
Index: src/interfaces/libpq/fe-connect.c
*** src/interfaces/libpq/fe-connect.c	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/fe-connect.c	2000/07/01 18:50:47	1.3
***************
*** 125,130 ****
--- 125,133 ----
{"port", "PGPORT", DEF_PGPORT, NULL,
"Database-Port", "", 6},
+ 	{"unixsocket", "PGUNIXSOCKET", NULL, NULL,
+ 	"Unix-Socket", "", 80},
+ 
{"tty", "PGTTY", DefaultTty, NULL,
"Backend-Debug-TTY", "D", 40},
***************
*** 293,298 ****
--- 296,303 ----
conn->pghost = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "port");
conn->pgport = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "unixsocket");
+ 	conn->pgunixsocket = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "tty");
conn->pgtty = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "options");
***************
*** 369,374 ****
--- 374,382 ----
*	  PGPORT	   identifies TCP port to which to connect if <pgport> argument
*				   is NULL or a null string.
*
+  *	  PGUNIXSOCKET	   identifies Unix-domain socket to which to connect; default
+  *				   is computed from the TCP port.
+  *
*	  PGTTY		   identifies tty to which to send messages if <pgtty> argument
*				   is NULL or a null string.
*
***************
*** 422,427 ****
--- 430,439 ----
else
conn->pgport = strdup(pgport);
+ 	conn->pgunixsocket = getenv("PGUNIXSOCKET");
+ 	if (conn->pgunixsocket)
+ 		conn->pgunixsocket = strdup(conn->pgunixsocket);
+ 
if ((pgtty == NULL) || pgtty[0] == '\0')
{
if ((tmp = getenv("PGTTY")) == NULL)
***************
*** 489,501 ****

/*
* update_db_info -
! * get all additional infos out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
--- 501,513 ----

/*
* update_db_info -
! * get all additional info out of dbName
*
*/
static int
update_db_info(PGconn *conn)
{
! char *tmp, *tmp2,
*old = conn->dbName;

if (strchr(conn->dbName, '@') != NULL)
***************
*** 504,509 ****
--- 516,523 ----
tmp = strrchr(conn->dbName, ':');
if (tmp != NULL)		/* port number given */
{
+ 			if (conn->pgport)
+ 				free(conn->pgport);
conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 511,516 ****
--- 525,532 ----
tmp = strrchr(conn->dbName, '@');
if (tmp != NULL)		/* host name given */
{
+ 			if (conn->pghost)
+ 				free(conn->pghost);
conn->pghost = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 537,549 ****

/*
* new style:
! * <tcp|unix>:postgresql://server[:port][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL)	/* options given */
{
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
--- 553,567 ----

/*
* new style:
! * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:][/dbname][?options]
*/
offset += strlen("postgresql://");

tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL) /* options given */
{
+ if (conn->pgoptions)
+ free(conn->pgoptions);
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
***************
*** 551,576 ****
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL) /* database name given */
{
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
if ((tmp = getenv("PGDATABASE")) != NULL)
conn->dbName = strdup(tmp);
else if (conn->pguser)
conn->dbName = strdup(conn->pguser);
}

tmp = strrchr(old + offset, ':');
! if (tmp != NULL) /* port number given */
{
- conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}

if (strncmp(old, "unix:", 5) == 0)
{
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
--- 569,630 ----
tmp = strrchr(conn->dbName + offset, '/');
if (tmp != NULL)	/* database name given */
{
+ 				if (conn->dbName)
+ 					free(conn->dbName);
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
+ 				/* Why do we default only this value from the environment again?  */
if ((tmp = getenv("PGDATABASE")) != NULL)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(tmp);
+ 				}
else if (conn->pguser)
+ 				{
+ 					if (conn->dbName)
+ 						free(conn->dbName);
conn->dbName = strdup(conn->pguser);
+ 				}
}
tmp = strrchr(old + offset, ':');
! 			if (tmp != NULL)	/* port number or Unix socket path given */
{
*tmp = '\0';
+ 				if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
+ 				{
+ 					if (strncmp(old, "unix:", 5) != 0)
+ 					{
+ 						printfPQExpBuffer(&conn->errorMessage,
+ 								  "connectDBStart() -- "
+ 								  "socket name can only be specified with "
+ 								  "non-TCP\n");
+ 						return 1; 
+ 					}
+ 					*tmp2 = '\0';
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = strdup(tmp + 1);
+ 				}
+ 				else
+ 				{
+ 					if (conn->pgport)
+ 						free(conn->pgport);
+ 					conn->pgport = strdup(tmp + 1);
+ 					if (conn->pgunixsocket)
+ 						free(conn->pgunixsocket);
+ 					conn->pgunixsocket = NULL;
+ 				}
}
if (strncmp(old, "unix:", 5) == 0)
{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
***************
*** 582,589 ****
}
}
else
conn->pghost = strdup(old + offset);
! 
free(old);
}
}
--- 636,646 ----
}
}
else
+ 			{
+ 				if (conn->pghost)
+ 					free(conn->pghost);
conn->pghost = strdup(old + offset);
! 			}
free(old);
}
}
***************
*** 743,749 ****
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 		conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
#endif
--- 800,809 ----
}
#if !defined(WIN32) && !defined(__CYGWIN32__)
else
! 	{
! 		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
! 		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
! 	}
#endif
***************
*** 892,898 ****
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  conn->pgport);
goto connect_errReturn;
}
}
--- 952,959 ----
conn->pghost ? conn->pghost : "localhost",
(family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (family == AF_UNIX && conn->pgunixsocket) ?
! 							  conn->pgunixsocket : conn->pgport);
goto connect_errReturn;
}
}
***************
*** 1123,1129 ****
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 									  conn->pgport);
goto error_return;
}
--- 1184,1191 ----
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
! 							  (conn->raddr.sa.sa_family == AF_UNIX && conn->pgunixsocket) ?
! 									  conn->pgunixsocket : conn->pgport);
goto error_return;
}
***************
*** 1799,1804 ****
--- 1861,1868 ----
free(conn->pghostaddr);
if (conn->pgport)
free(conn->pgport);
+ 	if (conn->pgunixsocket)
+ 		free(conn->pgunixsocket);
if (conn->pgtty)
free(conn->pgtty);
if (conn->pgoptions)
***************
*** 2383,2388 ****
--- 2447,2460 ----
if (!conn)
return (char *) NULL;
return conn->pgport;
+ }
+ 
+ char *
+ PQunixsocket(const PGconn *conn)
+ {
+ 	if (!conn)
+ 		return (char *) NULL;
+ 	return conn->pgunixsocket;
}
char *
Index: src/interfaces/libpq/libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-fe.h	2000/07/01 18:20:40	1.2
***************
*** 214,219 ****
--- 214,220 ----
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
extern char *PQport(const PGconn *conn);
+ 	extern char *PQunixsocket(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(const PGconn *conn);
Index: src/interfaces/libpq/libpq-int.h
*** src/interfaces/libpq/libpq-int.h	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpq-int.h	2000/07/01 18:20:40	1.2
***************
*** 202,207 ****
--- 202,209 ----
* numbers-and-dots notation. Takes
* precedence over above. */
char	   *pgport;			/* the server's communication port */
+ 	char	   *pgunixsocket;		/* the Unix-domain socket that the server is listening on;
+ 						 * if NULL, uses a default constructed from pgport */
char	   *pgtty;			/* tty on which the backend messages is
* displayed (NOT ACTUALLY USED???) */
char	   *pgoptions;		/* options to start the backend with */
Index: src/interfaces/libpq/libpqdll.def
*** src/interfaces/libpq/libpqdll.def	2000/06/30 21:15:51	1.1
--- src/interfaces/libpq/libpqdll.def	2000/07/01 18:20:40	1.2
***************
*** 79,81 ****
--- 79,82 ----
destroyPQExpBuffer	@ 76
createPQExpBuffer	@ 77
PQconninfoFree		@ 78
+ 	PQunixsocket		@ 79
-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#11Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Peter Eisentraut (#7)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian writes:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Postmaster options are evil, please put something in backend/utils/guc.c.
(This is not the fault of the patch submitter, since this interface is new
for 7.1, but that still doesn't mean we should subvert it.)

I have put code in guc.c to handle this, but there still are postmaster
options for it too.

2. The ability to place the Unix-domain socket in a mode 700 directory.

This would be a rather sharp instrument to offer to the world at large,
because the socket file is also a lock file, so you can't just get rid of
it.

If we were to offer that anyway, I'd opine that we reuse the -h option
(e.g., leading slash means Unix socket) rather than adding a -k option
everywhere.

Interesting idea, thought kind of cryptic.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#12Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Bruce Momjian (#11)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian writes:

Bruce Momjian writes:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Postmaster options are evil, please put something in backend/utils/guc.c.
(This is not the fault of the patch submitter, since this interface is new
for 7.1, but that still doesn't mean we should subvert it.)

I have put code in guc.c to handle this, but there still are postmaster
options for it too.

What happened to the concerns that were raised? The socket file is a lock
file, you cannot just move it around.

Uhh, not sure. The administrator can control it. If they bypass our
checks by specifying a non-standard location, aren't they on their own?

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#13Peter Eisentraut
peter_e@gmx.net
In reply to: Bruce Momjian (#11)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian writes:

Bruce Momjian writes:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Postmaster options are evil, please put something in backend/utils/guc.c.
(This is not the fault of the patch submitter, since this interface is new
for 7.1, but that still doesn't mean we should subvert it.)

I have put code in guc.c to handle this, but there still are postmaster
options for it too.

What happened to the concerns that were raised? The socket file is a lock
file, you cannot just move it around.

--
Peter Eisentraut peter_e@gmx.net http://yi.org/peter-e/

#14Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Bruce Momjian (#12)
1 attachment(s)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

OK, I have removed the -k unix socketpath option from the client side of
this patch, and modified libpq so if they specify a host with a leading
slash, it will be considered a unix socket path. Attached is the
relevant patch to libpq.

Bruce Momjian writes:

Bruce Momjian writes:

I am tempted to apply this. This is the second person who asked for
binding to a single port. The patch looks quite complete, with doc
changes. It appears to be a thorough job.

Postmaster options are evil, please put something in backend/utils/guc.c.
(This is not the fault of the patch submitter, since this interface is new
for 7.1, but that still doesn't mean we should subvert it.)

I have put code in guc.c to handle this, but there still are postmaster
options for it too.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Attachments:

/bjm/diff2text/plainDownload
Index: fe-connect.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.145
diff -c -r1.145 fe-connect.c
*** fe-connect.c	2000/11/13 15:18:15	1.145
--- fe-connect.c	2000/11/13 23:36:38
***************
*** 332,337 ****
--- 332,356 ----
  	PQconninfoFree(connOptions);
  
  	/* ----------
+ 	 * Allow unix socket specification in the host name
+ 	 * ----------
+ 	 */
+ 	if (conn->pghost && conn->pghost[0] == '/')
+ 	{
+ 		if (conn->pgunixsocket)
+ 			free(conn->pgunixsocket);
+ 		conn->pgunixsocket = conn->pghost;
+ 		conn->pghost = NULL;
+ 	}
+ 	if (conn->pghostaddr && conn->pghostaddr[0] == '/')
+ 	{
+ 		if (conn->pgunixsocket)
+ 			free(conn->pgunixsocket);
+ 		conn->pgunixsocket = conn->pghostaddr;
+ 		conn->pghostaddr = NULL;
+ 	}
+ 
+ 	/* ----------
  	 * Connect to the database
  	 * ----------
  	 */
***************
*** 443,455 ****
  	else
  		conn->pgport = strdup(pgport);
  
! #if FIX_ME
! 	/* we need to modify the function to accept a unix socket path */
! 	if (pgunixsocket)
! 		conn->pgunixsocket = strdup(pgunixsocket);
! 	else if ((tmp = getenv("PGUNIXSOCKET")) != NULL)
! 		conn->pgunixsocket = strdup(tmp);
! #endif
  
  	if (pgtty == NULL)
  	{
--- 462,486 ----
  	else
  		conn->pgport = strdup(pgport);
  
! 	/* ----------
! 	 * We don't allow unix socket path as a function parameter.
! 	 * This allows unix socket specification in the host name.
! 	 * ----------
! 	 */
! 	if (conn->pghost && conn->pghost[0] == '/')
! 	{
! 		if (conn->pgunixsocket)
! 			free(conn->pgunixsocket);
! 		conn->pgunixsocket = conn->pghost;
! 		conn->pghost = NULL;
! 	}
! 	if (conn->pghostaddr && conn->pghostaddr[0] == '/')
! 	{
! 		if (conn->pgunixsocket)
! 			free(conn->pgunixsocket);
! 		conn->pgunixsocket = conn->pghostaddr;
! 		conn->pghostaddr = NULL;
! 	}
  
  	if (pgtty == NULL)
  	{
***************
*** 778,784 ****
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  "connectDBStart() -- "
! 						 "invalid host address: %s\n", conn->pghostaddr);
  			goto connect_errReturn;
  		}
  
--- 809,815 ----
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  "connectDBStart() -- "
! 						 	  "invalid host address: %s\n", conn->pghostaddr);
  			goto connect_errReturn;
  		}
  
#15Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#14)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian <pgman@candle.pha.pa.us> writes:

+ 	if (conn->pghostaddr && conn->pghostaddr[0] == '/')
+ 	{
+ 		if (conn->pgunixsocket)
+ 			free(conn->pgunixsocket);
+ 		conn->pgunixsocket = conn->pghostaddr;
+ 		conn->pghostaddr = NULL;
+ 	}

I would be inclined to think you should NOT look for a path in
pghostaddr, since my understanding is that that's supposed to be a
numeric IP address and nothing but. Otherwise this looks pretty
reasonable.

regards, tom lane

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#13)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Peter Eisentraut <peter_e@gmx.net> writes:

What happened to the concerns that were raised? The socket file is a lock
file, you cannot just move it around.

Good point. IIRC, we rely on the socket file lock to ensure that you
can't start two postmasters with the same port number. (If both are
started with -i, then you'll get a conflict on the IP port address,
but if one or both is started without, then the socket-file lock is
the only line of defense.) This is important because shared memory
keys are derived from the port number. I'm not sure that the code
will behave in a pleasant manner when two postmasters try to use the
same shared memory block --- most likely, death and destruction will
ensue.

I think we had some discussions about changing the way that shared
memory keys are generated, which might make this a less critical issue.
But until something's done about that, this patch looks awfully
dangerous.

regards, tom lane

#17Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#15)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian <pgman@candle.pha.pa.us> writes:

+ 	if (conn->pghostaddr && conn->pghostaddr[0] == '/')
+ 	{
+ 		if (conn->pgunixsocket)
+ 			free(conn->pgunixsocket);
+ 		conn->pgunixsocket = conn->pghostaddr;
+ 		conn->pghostaddr = NULL;
+ 	}

I would be inclined to think you should NOT look for a path in
pghostaddr, since my understanding is that that's supposed to be a
numeric IP address and nothing but. Otherwise this looks pretty
reasonable.

Fixed. Thanks.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#18Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#16)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Peter Eisentraut <peter_e@gmx.net> writes:

What happened to the concerns that were raised? The socket file is a lock
file, you cannot just move it around.

Good point. IIRC, we rely on the socket file lock to ensure that you
can't start two postmasters with the same port number. (If both are
started with -i, then you'll get a conflict on the IP port address,
but if one or both is started without, then the socket-file lock is
the only line of defense.) This is important because shared memory
keys are derived from the port number. I'm not sure that the code
will behave in a pleasant manner when two postmasters try to use the
same shared memory block --- most likely, death and destruction will
ensue.

I think we had some discussions about changing the way that shared
memory keys are generated, which might make this a less critical issue.
But until something's done about that, this patch looks awfully
dangerous.

But do we yank it out for that reason? I don't think so.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#19Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#18)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian <pgman@candle.pha.pa.us> writes:

I think we had some discussions about changing the way that shared
memory keys are generated, which might make this a less critical issue.
But until something's done about that, this patch looks awfully
dangerous.

But do we yank it out for that reason? I don't think so.

Do you want to put a bright red "THIS FEATURE MAY BE HAZARDOUS TO YOUR
DATA" warning in the manual? I think it'd be rather irresponsible of
us to ship the patch without such a warning, unless someone builds a
replacement interlock capability (or gets rid of the need for the
interlock).

regards, tom lane

#20Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#19)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian <pgman@candle.pha.pa.us> writes:

I think we had some discussions about changing the way that shared
memory keys are generated, which might make this a less critical issue.
But until something's done about that, this patch looks awfully
dangerous.

But do we yank it out for that reason? I don't think so.

Do you want to put a bright red "THIS FEATURE MAY BE HAZARDOUS TO YOUR
DATA" warning in the manual? I think it'd be rather irresponsible of
us to ship the patch without such a warning, unless someone builds a
replacement interlock capability (or gets rid of the need for the
interlock).

Seeing that we went many releases with no lock, and people really have
to try to have the problem by specifying a non-standard socket file, I
don't feel terribly concerned.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#21Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#20)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

BTW, I thought you were backing out the unnecessary changes to the
client applications? pg_dump seems not to be reverted yet, for one...

regards, tom lane

#22Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#21)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

BTW, I thought you were backing out the unnecessary changes to the
client applications? pg_dump seems not to be reverted yet, for one...

I thought I had. I don't see them here. Can you tell me what you see.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#23Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#22)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian <pgman@candle.pha.pa.us> writes:

BTW, I thought you were backing out the unnecessary changes to the
client applications? pg_dump seems not to be reverted yet, for one...

I thought I had. I don't see them here. Can you tell me what you see.

My apologies. I must have been looking at the wrong file versions ...

regards, tom lane

#24Peter Eisentraut
peter_e@gmx.net
In reply to: Bruce Momjian (#18)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

Bruce Momjian writes:

I think we had some discussions about changing the way that shared
memory keys are generated, which might make this a less critical issue.
But until something's done about that, this patch looks awfully
dangerous.

But do we yank it out for that reason? I don't think so.

Now that I read the author's description of this feature, I'm no longer
sure what it's good for:

You can use this option to put the Unix domain socket in a
directory that is private to one or more users using Unix
directory permissions. This is necessary for securely
creating databases automatically on shared machines. In that
situation, also disallow all TCP/IP connections initially in
<filename>pg_hba.conf</filename>.

You can do that in a more stylish and safer manner by using the
unix_socket_permissions and unix_socket_group options.

I won't argue for removing it, but let's not spread the word too widely
before we fix the issues. :-)

--
Peter Eisentraut peter_e@gmx.net http://yi.org/peter-e/

#25Noname
djm@web.us.uu.net
In reply to: Peter Eisentraut (#24)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

You can do that in a more stylish and safer manner by using the
unix_socket_permissions and unix_socket_group options.

Moving the socket file is also necessary for running in
a chrooted environment. And I'm not sure whether it's relevant,
but the 7.0 method of computing the socket file name (based
only on the port number) doesn't work for multiple instances
listening on the same port on different IP addresses.

#26Tom Lane
tgl@sss.pgh.pa.us
In reply to: Noname (#25)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

djm@web.us.uu.net (David J. MacKenzie) writes:

but the 7.0 method of computing the socket file name (based
only on the port number) doesn't work for multiple instances
listening on the same port on different IP addresses.

I was afraid you were planning to run that way. Did you absorb the
point about shared memory keys being based (only) on the port number?
Unless something's done about that, the above configuration will NOT
work, because the different instances will try to use the same
shared memory and semaphore sets.

regards, tom lane

#27Noname
djm@web.us.uu.net
In reply to: Tom Lane (#26)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

I was afraid you were planning to run that way. Did you absorb the
point about shared memory keys being based (only) on the port number?
Unless something's done about that, the above configuration will NOT
work, because the different instances will try to use the same
shared memory and semaphore sets.

Yes, my patch addresses that issue, as well as I could figure out to do.
Here's part of the code I submitted in postmaster.c:

  /*
+  * get_host_port -- return a pseudo port number (16 bits)
+  * derived from the primary IP address of HostName.
+  */
+ static unsigned short
+ get_host_port(void)
+ {
+       static unsigned short hostPort = 0;
+ 
+       if (hostPort == 0)
+       {
+               SockAddr        saddr;
+               struct hostent *hp;
+ 
+               hp = gethostbyname(HostName);
+               if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+               {
+                       char msg[1024];
+                       snprintf(msg, sizeof(msg),
+                                "FATAL: get_host_port: gethostbyname(%s) failed: %s\n",
+                                HostName, hstrerror(h_errno));
+                       fputs(msg, stderr);
+                       pqdebug("%s", msg);
+                       exit(1);
+               }
+               memmove((char *) &(saddr.in.sin_addr),
+                       (char *) hp->h_addr,
+                       hp->h_length);
+               hostPort = ntohl(saddr.in.sin_addr.s_addr) & 0xFFFF;
+       }
+ 
+       return hostPort;
+ }
+ 
+ /*
   * reset_shared -- reset shared memory and semaphores
   */
  static void
  reset_shared(unsigned short port)
  {
+       /*
+        * A typical ipc_key is 5432001, which is port 5432, sequence
+        * number 0, and 01 as the index in IPCKeyGetBufferMemoryKey().
+        * The 32-bit INT_MAX is 2147483 6 47.
+        *
+        * The default algorithm for calculating the IPC keys assumes that all
+        * instances of postmaster on a given host are listening on different
+        * ports.  In order to work (prevent shared memory collisions) if you
+        * run multiple PostgreSQL instances on the same port and different IP
+        * addresses on a host, we change the algorithm if you give postmaster
+        * the -h option, or set PGHOST, to a value other than the internal
+        * default of "any".
+        *
+        * If HostName is not "any", then we generate the IPC keys using the
+        * last two octets of the IP address instead of the port number.
+        * This algorithm assumes that no one will run multiple PostgreSQL
+        * instances on one host using two IP addresses that have the same two
+        * last octets in different class C networks.  If anyone does, it
+        * would be rare.
+        *
+        * So, if you use -h or PGHOST, don't try to run two instances of
+        * PostgreSQL on the same IP address but different ports.  If you
+        * don't use them, then you must use different ports (via -p or
+        * PGPORT).  And, of course, don't try to use both approaches on one
+        * host.
+        */
+ 
+       if (strcmp(HostName, "any"))
+               port = get_host_port();
+ 
        ipc_key = port * 1000 + shmem_seq * 100;
        CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
#28Tom Lane
tgl@sss.pgh.pa.us
In reply to: Noname (#27)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

djm@web.us.uu.net (David J. MacKenzie) writes:

I was afraid you were planning to run that way. Did you absorb the
point about shared memory keys being based (only) on the port number?

+        * So, if you use -h or PGHOST, don't try to run two instances of
+        * PostgreSQL on the same IP address but different ports.  If you
+        * don't use them, then you must use different ports (via -p or
+        * PGPORT).  And, of course, don't try to use both approaches on one
+        * host.

So it's still eminently breakable if the dbadmin does the wrong thing,
and it still doesn't detect that the dbadmin has done the wrong thing.
This doesn't calm my fears very much.

I think that in the last discussion of shared memory key assignment,
we had come up with a plan for detecting key collisions directly instead
of hoping they wouldn't happen. I don't have time to pursue this right
now, but according to my todo list there was a pghackers thread about it
around 4/30/00.

regards, tom lane

#29Ross J. Reedstrom
reedstrm@rice.edu
In reply to: Tom Lane (#28)
Re: Re: [PATCHES] PostgreSQL virtual hosting support

On Tue, Nov 14, 2000 at 03:05:04PM -0500, Tom Lane wrote:

I think that in the last discussion of shared memory key assignment,
we had come up with a plan for detecting key collisions directly instead
of hoping they wouldn't happen. I don't have time to pursue this right
now, but according to my todo list there was a pghackers thread about it
around 4/30/00.

Tom's TODO list as index into pghackers archive: seems so appropriate ;-)

Ross
--
Open source code is like a natural resource, it's the result of providing
food and sunshine to programmers, and then staying out of their way.
[...] [It] is not going away because it has utility for both the developers
and users independent of economic motivations. Jim Flynn, Sunnyvale, Calif.