From 5c4363ea0ea2220c45b262eb2af3e5c57499bf65 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Tue, 9 Oct 2018 15:01:30 +0200
Subject: [PATCH] Support custom socket directory during upgrades

The upgrade process will use CWD as the location for sockets dir, which
is limited by the sockaddr_un structure to around 100 bytes. In order to
avoid hitting the limit, support an optional command line parameter for
overriding the socket directory.
---
 doc/src/sgml/ref/pgupgrade.sgml |  8 ++++++++
 src/bin/pg_upgrade/option.c     | 20 +++++++++++++-------
 src/bin/pg_upgrade/pg_upgrade.h |  2 ++
 3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index d51146d641..83f08a9d70 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -163,6 +163,14 @@
       </para></listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>-s</option></term>
+      <term><option>--socketdir=</option><replaceable>dir</replaceable></term>
+      <listitem><para>directory to use for sockets during upgrade, default is
+      current working directory
+      </para></listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-U</option> <replaceable>username</replaceable></term>
       <term><option>--username=</option><replaceable>username</replaceable></term>
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index 9dbc9225a6..3ace73b7f1 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -52,6 +52,7 @@ parseCommandLine(int argc, char *argv[])
 		{"link", no_argument, NULL, 'k'},
 		{"retain", no_argument, NULL, 'r'},
 		{"jobs", required_argument, NULL, 'j'},
+		{"socketdir", required_argument, NULL, 's'},
 		{"verbose", no_argument, NULL, 'v'},
 		{NULL, 0, NULL, 0}
 	};
@@ -64,6 +65,9 @@ parseCommandLine(int argc, char *argv[])
 
 	user_opts.transfer_mode = TRANSFER_MODE_COPY;
 
+	user_opts.socketdir = pg_malloc(MAXPGPATH);
+	getcwd(user_opts.socketdir, MAXPGPATH);
+
 	os_info.progname = get_progname(argv[0]);
 
 	/* Process libpq env. variables; load values here for usage() output */
@@ -100,7 +104,7 @@ parseCommandLine(int argc, char *argv[])
 	if ((log_opts.internal = fopen_priv(INTERNAL_LOG_FILE, "a")) == NULL)
 		pg_fatal("could not write to log file \"%s\"\n", INTERNAL_LOG_FILE);
 
-	while ((option = getopt_long(argc, argv, "d:D:b:B:cj:ko:O:p:P:rU:v",
+	while ((option = getopt_long(argc, argv, "d:D:b:B:cj:ko:O:p:P:rs:U:v",
 								 long_options, &optindex)) != -1)
 	{
 		switch (option)
@@ -186,6 +190,10 @@ parseCommandLine(int argc, char *argv[])
 				log_opts.retain = true;
 				break;
 
+			case 's':
+				strlcpy(user_opts.socketdir, optarg, MAXPGPATH);
+				break;
+
 			case 'U':
 				pg_free(os_info.user);
 				os_info.user = pg_strdup(optarg);
@@ -246,6 +254,8 @@ parseCommandLine(int argc, char *argv[])
 							 "PGDATAOLD", "-d", _("old cluster data resides"));
 	check_required_directory(&new_cluster.pgdata, &new_cluster.pgconfig,
 							 "PGDATANEW", "-D", _("new cluster data resides"));
+	check_required_directory(&user_opts.socketdir, NULL, "PGSOCKETDIR", "-s",
+							 _("sockets will be created"));
 
 #ifdef WIN32
 
@@ -291,6 +301,7 @@ usage(void)
 	printf(_("  -P, --new-port=PORT           new cluster port number (default %d)\n"), new_cluster.port);
 	printf(_("  -r, --retain                  retain SQL and log files after success\n"));
 	printf(_("  -U, --username=NAME           cluster superuser (default \"%s\")\n"), os_info.user);
+	printf(_("  -s, --socketdir=DIR           socket directory during upgrades (default CWD)\n"));
 	printf(_("  -v, --verbose                 enable verbose internal logging\n"));
 	printf(_("  -V, --version                 display version information, then exit\n"));
 	printf(_("  -?, --help                    show this help, then exit\n"));
@@ -455,12 +466,7 @@ get_sock_dir(ClusterInfo *cluster, bool live_check)
 	if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
 	{
 		if (!live_check)
-		{
-			/* Use the current directory for the socket */
-			cluster->sockdir = pg_malloc(MAXPGPATH);
-			if (!getcwd(cluster->sockdir, MAXPGPATH))
-				pg_fatal("could not determine current directory\n");
-		}
+			cluster->sockdir = user_opts.socketdir;
 		else
 		{
 			/*
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index f83a3eeb67..d745ee101c 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -298,6 +298,8 @@ typedef struct
 								 * changes */
 	transferMode transfer_mode; /* copy files or link them? */
 	int			jobs;
+	char	   *socketdir;		/* directory to use for sockets, NULL means
+								 * using the default of CWD */
 } UserOpts;
 
 typedef struct
-- 
2.14.1.145.gb3622a4ee

