]> granicus.if.org Git - postgresql/commitdiff
Fix pg_upgrade to cope with non-default unix_socket_directory scenarios.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 3 Sep 2012 17:52:34 +0000 (13:52 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 3 Sep 2012 17:52:40 +0000 (13:52 -0400)
When starting either an old or new postmaster, force it to place its Unix
socket in the current directory.  This makes it even harder for accidental
connections to occur during pg_upgrade, and also works around some
scenarios where the default socket location isn't usable.  (For example,
if the default location is something other than "/tmp", it might not exist
during "make check".)

When checking an already-running old postmaster, find out its actual socket
directory location from postmaster.pid, if possible.  This dodges problems
with an old postmaster having a configured location different from the
default built into pg_upgrade's libpq.  We can't find that out if the old
postmaster is pre-9.1, so also document how to cope with such scenarios
manually.

In support of this, centralize handling of the connection-related command
line options passed to pg_upgrade's subsidiary programs, such as pg_dump.
This should make future changes easier.

Bruce Momjian and Tom Lane

contrib/pg_upgrade/check.c
contrib/pg_upgrade/dump.c
contrib/pg_upgrade/option.c
contrib/pg_upgrade/pg_upgrade.c
contrib/pg_upgrade/pg_upgrade.h
contrib/pg_upgrade/server.c
doc/src/sgml/pgupgrade.sgml

index 0fec73ec7dc82f395afe32d29b88e3f6c83c8fbf..efb080befd4355e68981b35dc32e9b954e10810b 100644 (file)
@@ -184,8 +184,8 @@ issue_warnings(char *sequence_script_file_name)
                {
                        prep_status("Adjusting sequences");
                        exec_prog(UTILITY_LOG_FILE, NULL, true,
-                                         "\"%s/psql\" " EXEC_PSQL_ARGS " --port %d --username \"%s\" -f \"%s\"",
-                                         new_cluster.bindir, new_cluster.port, os_info.user,
+                                         "\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"",
+                                         new_cluster.bindir, cluster_conn_opts(&new_cluster),
                                          sequence_script_file_name);
                        unlink(sequence_script_file_name);
                        check_ok();
index cfc4017d517a3ca093fef101df83c4b9914bbf14..b905ab084d7337dc4fc5c5b064e09c9c3ab00552 100644 (file)
@@ -24,8 +24,8 @@ generate_old_dump(void)
         * restores the frozenid's for databases and relations.
         */
        exec_prog(UTILITY_LOG_FILE, NULL, true,
-                         "\"%s/pg_dumpall\" --port %d --username \"%s\" --schema-only --binary-upgrade %s -f %s",
-                         new_cluster.bindir, old_cluster.port, os_info.user,
+                         "\"%s/pg_dumpall\" %s --schema-only --binary-upgrade %s -f %s",
+                         new_cluster.bindir, cluster_conn_opts(&old_cluster),
                          log_opts.verbose ? "--verbose" : "",
                          ALL_DUMP_FILE);
        check_ok();
index 94bce505cb6bda2473442ea1231bb439411ddabc..6d5a93a0a566d433222d97ab762a91bc39274a3f 100644 (file)
@@ -9,6 +9,8 @@
 
 #include "postgres.h"
 
+#include "miscadmin.h"
+
 #include "pg_upgrade.h"
 
 #include <getopt_long.h>
@@ -376,3 +378,64 @@ adjust_data_dir(ClusterInfo *cluster)
 
        check_ok();
 }
+
+
+/*
+ * get_sock_dir
+ *
+ * Identify the socket directory to use for this cluster.  If we're doing
+ * a live check (old cluster only), we need to find out where the postmaster
+ * is listening.  Otherwise, we're going to put the socket into the current
+ * directory.
+ */
+void
+get_sock_dir(ClusterInfo *cluster, bool live_check)
+{
+#ifdef HAVE_UNIX_SOCKETS
+       if (!live_check)
+       {
+               /* Use the current directory for the socket */
+               cluster->sockdir = pg_malloc(MAXPGPATH);
+               if (!getcwd(cluster->sockdir, MAXPGPATH))
+                       pg_log(PG_FATAL, "cannot find current directory\n");
+       }
+       else
+       {
+               /*
+                *      If we are doing a live check, we will use the old cluster's Unix
+                *      domain socket directory so we can connect to the live server.
+                */
+
+               /* sockdir was added to postmaster.pid in PG 9.1 */
+               if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
+               {
+                       char            filename[MAXPGPATH];
+                       FILE            *fp;
+                       int                     i;
+
+                       snprintf(filename, sizeof(filename), "%s/postmaster.pid",
+                                        cluster->pgdata);
+                       if ((fp = fopen(filename, "r")) == NULL)
+                               pg_log(PG_FATAL, "Could not get socket directory of the old server\n");
+
+                       cluster->sockdir = pg_malloc(MAXPGPATH);
+                       for (i = 0; i < LOCK_FILE_LINE_SOCKET_DIR; i++)
+                               if (fgets(cluster->sockdir, MAXPGPATH, fp) == NULL)
+                                       pg_log(PG_FATAL, "Could not get socket directory of the old server\n");
+
+                       fclose(fp);
+
+                       /* Remove trailing newline */
+                       if (strchr(cluster->sockdir, '\n') != NULL)
+                               *strchr(cluster->sockdir, '\n') = '\0';
+               }
+               else
+               {
+                       /* Can't get live sockdir, so assume the default is OK. */
+                       cluster->sockdir = NULL;
+               }
+       }
+#else /* !HAVE_UNIX_SOCKETS */
+       cluster->sockdir = NULL;
+#endif
+}
index c47c8bba4452da03fd2174682f0679ada45aa38c..ee3a1517f49042b31571e0d0ba3ad34975a2d2ee 100644 (file)
@@ -88,6 +88,9 @@ main(int argc, char **argv)
        check_cluster_versions();
        check_cluster_compatibility(live_check);
 
+       get_sock_dir(&old_cluster, live_check);
+       get_sock_dir(&new_cluster, false);
+
        check_old_cluster(live_check, &sequence_script_file_name);
 
 
@@ -211,8 +214,8 @@ prepare_new_cluster(void)
         */
        prep_status("Analyzing all rows in the new cluster");
        exec_prog(UTILITY_LOG_FILE, NULL, true,
-                         "\"%s/vacuumdb\" --port %d --username \"%s\" --all --analyze %s",
-                         new_cluster.bindir, new_cluster.port, os_info.user,
+                         "\"%s/vacuumdb\" %s --all --analyze %s",
+                         new_cluster.bindir, cluster_conn_opts(&new_cluster),
                          log_opts.verbose ? "--verbose" : "");
        check_ok();
 
@@ -224,8 +227,8 @@ prepare_new_cluster(void)
         */
        prep_status("Freezing all rows on the new cluster");
        exec_prog(UTILITY_LOG_FILE, NULL, true,
-                         "\"%s/vacuumdb\" --port %d --username \"%s\" --all --freeze %s",
-                         new_cluster.bindir, new_cluster.port, os_info.user,
+                         "\"%s/vacuumdb\" %s --all --freeze %s",
+                         new_cluster.bindir, cluster_conn_opts(&new_cluster),
                          log_opts.verbose ? "--verbose" : "");
        check_ok();
 
@@ -261,8 +264,8 @@ prepare_new_databases(void)
         * the template0 template.
         */
        exec_prog(RESTORE_LOG_FILE, NULL, true,
-                         "\"%s/psql\" " EXEC_PSQL_ARGS " --port %d --username \"%s\" -f \"%s\"",
-                         new_cluster.bindir, new_cluster.port, os_info.user,
+                         "\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"",
+                         new_cluster.bindir, cluster_conn_opts(&new_cluster),
                          GLOBALS_DUMP_FILE);
        check_ok();
 
@@ -290,8 +293,8 @@ create_new_objects(void)
 
        prep_status("Restoring database schema to new cluster");
        exec_prog(RESTORE_LOG_FILE, NULL, true,
-                         "\"%s/psql\" " EXEC_PSQL_ARGS " --port %d --username \"%s\" -f \"%s\"",
-                         new_cluster.bindir, new_cluster.port, os_info.user,
+                         "\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"",
+                         new_cluster.bindir, cluster_conn_opts(&new_cluster),
                          DB_DUMP_FILE);
        check_ok();
 
index fa4c6c0a478484da1a99f059cab33ff17502903e..7b19d916fff7201e0be1f60de865329c2c98061e 100644 (file)
@@ -226,6 +226,7 @@ typedef struct
        char       *bindir;                     /* pathname for cluster's executable directory */
        char       *pgopts;                     /* options to pass to the server, like pg_ctl
                                                                 * -o */
+       char       *sockdir;            /* directory for Unix Domain socket, if any */
        unsigned short port;            /* port number where postmaster is waiting */
        uint32          major_version;  /* PG_VERSION of cluster */
        char            major_version_str[64];  /* string PG_VERSION of cluster */
@@ -387,6 +388,7 @@ void print_maps(FileNameMap *maps, int n,
 
 void           parseCommandLine(int argc, char *argv[]);
 void           adjust_data_dir(ClusterInfo *cluster);
+void           get_sock_dir(ClusterInfo *cluster, bool live_check);
 
 /* relfilenode.c */
 
@@ -407,6 +409,8 @@ PGresult *
 executeQueryOrDie(PGconn *conn, const char *fmt,...)
 __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
 
+char      *cluster_conn_opts(ClusterInfo *cluster);
+
 void           start_postmaster(ClusterInfo *cluster);
 void           stop_postmaster(bool fast);
 uint32         get_major_server_version(ClusterInfo *cluster);
index 1fb0d6ccceb2d6efd750d00402778cd0314936b1..11e7e75d78f8947478be0b092cf135a2a7783614 100644 (file)
@@ -46,21 +46,54 @@ connectToServer(ClusterInfo *cluster, const char *db_name)
 /*
  * get_db_conn()
  *
- * get database connection
+ * get database connection, using named database + standard params for cluster
  */
 static PGconn *
 get_db_conn(ClusterInfo *cluster, const char *db_name)
 {
-       char            conn_opts[MAXPGPATH];
+       char            conn_opts[2 * NAMEDATALEN + MAXPGPATH + 100];
 
-       snprintf(conn_opts, sizeof(conn_opts),
-                        "dbname = '%s' user = '%s' port = %d", db_name, os_info.user,
-                        cluster->port);
+       if (cluster->sockdir)
+               snprintf(conn_opts, sizeof(conn_opts),
+                                "dbname = '%s' user = '%s' host = '%s' port = %d",
+                                db_name, os_info.user, cluster->sockdir, cluster->port);
+       else
+               snprintf(conn_opts, sizeof(conn_opts),
+                                "dbname = '%s' user = '%s' port = %d",
+                                db_name, os_info.user, cluster->port);
 
        return PQconnectdb(conn_opts);
 }
 
 
+/*
+ * cluster_conn_opts()
+ *
+ * Return standard command-line options for connecting to this cluster when
+ * using psql, pg_dump, etc.  Ideally this would match what get_db_conn()
+ * sets, but the utilities we need aren't very consistent about the treatment
+ * of database name options, so we leave that out.
+ *
+ * Note result is in static storage, so use it right away.
+ */
+char *
+cluster_conn_opts(ClusterInfo *cluster)
+{
+       static char     conn_opts[MAXPGPATH + NAMEDATALEN + 100];
+
+       if (cluster->sockdir)
+               snprintf(conn_opts, sizeof(conn_opts),
+                                "--host \"%s\" --port %d --username \"%s\"",
+                                cluster->sockdir, cluster->port, os_info.user);
+       else
+               snprintf(conn_opts, sizeof(conn_opts),
+                                "--port %d --username \"%s\"",
+                                cluster->port, os_info.user);
+
+       return conn_opts;
+}
+
+
 /*
  * executeQueryOrDie()
  *
@@ -140,10 +173,11 @@ stop_postmaster_atexit(void)
 void
 start_postmaster(ClusterInfo *cluster)
 {
-       char            cmd[MAXPGPATH];
+       char            cmd[MAXPGPATH * 4 + 1000];
        PGconn     *conn;
        bool            exit_hook_registered = false;
        bool            pg_ctl_return = false;
+       char            socket_string[MAXPGPATH + 200];
 
        if (!exit_hook_registered)
        {
@@ -151,6 +185,23 @@ start_postmaster(ClusterInfo *cluster)
                exit_hook_registered = true;
        }
 
+       socket_string[0] = '\0';
+
+#ifdef HAVE_UNIX_SOCKETS
+       /* prevent TCP/IP connections, restrict socket access */
+       strcat(socket_string,
+                  " -c listen_addresses='' -c unix_socket_permissions=0700");
+
+       /* Have a sockdir?  Tell the postmaster. */
+       if (cluster->sockdir)
+               snprintf(socket_string + strlen(socket_string),
+                                sizeof(socket_string) - strlen(socket_string),
+                                " -c %s='%s'",
+                                (GET_MAJOR_VERSION(cluster->major_version) < 903) ?
+                                "unix_socket_directory" : "unix_socket_directories",
+                                cluster->sockdir);
+#endif
+
        /*
         * Using autovacuum=off disables cleanup vacuum and analyze, but freeze
         * vacuums can still happen, so we set autovacuum_freeze_max_age to its
@@ -159,12 +210,12 @@ start_postmaster(ClusterInfo *cluster)
         * not touch them.
         */
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d %s %s\" start",
+                        "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d %s %s%s\" start",
                  cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
                         (cluster->controldata.cat_ver >=
                          BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" :
                         "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000",
-                        cluster->pgopts ? cluster->pgopts : "");
+                        cluster->pgopts ? cluster->pgopts : "", socket_string);
 
        /*
         * Don't throw an error right away, let connecting throw the error because
index b62aba26418d9cd3f5918455727e046fca0d4d42..9e43f3ce133ef6b29de12694bfa92bce3a1d0dac 100644 (file)
@@ -519,6 +519,14 @@ psql --username postgres --file script.sql postgres
    <literal>-d /real-data-directory -o '-D /configuration-directory'</>.
   </para>
 
+  <para>
+   If doing <option>--check</> with a running old server of a pre-9.1 version,
+   and the old server is using a Unix-domain socket directory that is
+   different from the default built into the new <productname>PostgreSQL</>
+   installation, set <envar>PGHOST</> to point to the socket location of the
+   old server.  (This is not relevant on Windows.)
+  </para>
+
   <para>
    A Log-Shipping Standby Server (<xref linkend="warm-standby">) cannot
    be upgraded because the server must allow writes.  The simplest way