mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-05 19:09:58 +08:00
Add a --socketdir option to pg_upgrade.
This allows control of the directory in which the postmaster sockets are created for the temporary postmasters started by pg_upgrade. The default location remains the current working directory, which is typically fine, but if it is deeply nested then its pathname might be too long to be a socket name. In passing, clean up some messiness in pg_upgrade's option handling, particularly the confusing and undocumented way that configuration-only datadirs were handled. And fix check_required_directory's substantially under-baked cleanup of directory pathnames. Daniel Gustafsson, reviewed by Hironobu Suzuki, some code cleanup by me Discussion: https://postgr.es/m/E72DD5C3-2268-48A5-A907-ED4B34BEC223@yesql.se
This commit is contained in:
parent
7d4524aed3
commit
2d34ad8430
@ -163,6 +163,14 @@
|
|||||||
</para></listitem>
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-s</option> <replaceable>dir</replaceable></term>
|
||||||
|
<term><option>--socketdir=</option><replaceable>dir</replaceable></term>
|
||||||
|
<listitem><para>directory to use for postmaster sockets during upgrade;
|
||||||
|
default is current working directory; environment
|
||||||
|
variable <envar>PGSOCKETDIR</envar></para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-U</option> <replaceable>username</replaceable></term>
|
<term><option>-U</option> <replaceable>username</replaceable></term>
|
||||||
<term><option>--username=</option><replaceable>username</replaceable></term>
|
<term><option>--username=</option><replaceable>username</replaceable></term>
|
||||||
@ -709,11 +717,21 @@ psql --username=postgres --file=script.sql postgres
|
|||||||
<title>Notes</title>
|
<title>Notes</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<application>pg_upgrade</application> does not support upgrading of databases
|
<application>pg_upgrade</application> creates various working files, such
|
||||||
containing table columns using these <type>reg*</type> OID-referencing system data types:
|
as schema dumps, in the current working directory. For security, be sure
|
||||||
<type>regproc</type>, <type>regprocedure</type>, <type>regoper</type>,
|
that that directory is not readable or writable by any other users.
|
||||||
<type>regoperator</type>, <type>regconfig</type>, and
|
</para>
|
||||||
<type>regdictionary</type>. (<type>regtype</type> can be upgraded.)
|
|
||||||
|
<para>
|
||||||
|
<application>pg_upgrade</application> launches short-lived postmasters in
|
||||||
|
the old and new data directories. Temporary Unix socket files for
|
||||||
|
communication with these postmasters are, by default, made in the current
|
||||||
|
working directory. In some situations the path name for the current
|
||||||
|
directory might be too long to be a valid socket name. In that case you
|
||||||
|
can use the <option>-s</option> option to put the socket files in some
|
||||||
|
directory with a shorter path name. For security, be sure that that
|
||||||
|
directory is not readable or writable by any other users.
|
||||||
|
(This is not relevant on Windows.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -732,6 +750,14 @@ psql --username=postgres --file=script.sql postgres
|
|||||||
insert dummy data, and upgrade that.
|
insert dummy data, and upgrade that.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<application>pg_upgrade</application> does not support upgrading of databases
|
||||||
|
containing table columns using these <type>reg*</type> OID-referencing system data types:
|
||||||
|
<type>regproc</type>, <type>regprocedure</type>, <type>regoper</type>,
|
||||||
|
<type>regoperator</type>, <type>regconfig</type>, and
|
||||||
|
<type>regdictionary</type>. (<type>regtype</type> can be upgraded.)
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If you are upgrading a pre-<productname>PostgreSQL</productname> 9.2 cluster
|
If you are upgrading a pre-<productname>PostgreSQL</productname> 9.2 cluster
|
||||||
that uses a configuration-file-only directory, you must pass the
|
that uses a configuration-file-only directory, you must pass the
|
||||||
|
@ -21,8 +21,9 @@
|
|||||||
|
|
||||||
|
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
static void check_required_directory(char **dirpath, char **configpath,
|
static void check_required_directory(char **dirpath,
|
||||||
const char *envVarName, const char *cmdLineOption, const char *description);
|
const char *envVarName, bool useCwd,
|
||||||
|
const char *cmdLineOption, const char *description);
|
||||||
#define FIX_DEFAULT_READ_ONLY "-c default_transaction_read_only=false"
|
#define FIX_DEFAULT_READ_ONLY "-c default_transaction_read_only=false"
|
||||||
|
|
||||||
|
|
||||||
@ -52,6 +53,7 @@ parseCommandLine(int argc, char *argv[])
|
|||||||
{"link", no_argument, NULL, 'k'},
|
{"link", no_argument, NULL, 'k'},
|
||||||
{"retain", no_argument, NULL, 'r'},
|
{"retain", no_argument, NULL, 'r'},
|
||||||
{"jobs", required_argument, NULL, 'j'},
|
{"jobs", required_argument, NULL, 'j'},
|
||||||
|
{"socketdir", required_argument, NULL, 's'},
|
||||||
{"verbose", no_argument, NULL, 'v'},
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
{"clone", no_argument, NULL, 1},
|
{"clone", no_argument, NULL, 1},
|
||||||
|
|
||||||
@ -102,7 +104,7 @@ parseCommandLine(int argc, char *argv[])
|
|||||||
if ((log_opts.internal = fopen_priv(INTERNAL_LOG_FILE, "a")) == NULL)
|
if ((log_opts.internal = fopen_priv(INTERNAL_LOG_FILE, "a")) == NULL)
|
||||||
pg_fatal("could not write to log file \"%s\"\n", INTERNAL_LOG_FILE);
|
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)
|
long_options, &optindex)) != -1)
|
||||||
{
|
{
|
||||||
switch (option)
|
switch (option)
|
||||||
@ -121,12 +123,10 @@ parseCommandLine(int argc, char *argv[])
|
|||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
old_cluster.pgdata = pg_strdup(optarg);
|
old_cluster.pgdata = pg_strdup(optarg);
|
||||||
old_cluster.pgconfig = pg_strdup(optarg);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
new_cluster.pgdata = pg_strdup(optarg);
|
new_cluster.pgdata = pg_strdup(optarg);
|
||||||
new_cluster.pgconfig = pg_strdup(optarg);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'j':
|
case 'j':
|
||||||
@ -188,6 +188,10 @@ parseCommandLine(int argc, char *argv[])
|
|||||||
log_opts.retain = true;
|
log_opts.retain = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
user_opts.socketdir = pg_strdup(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
pg_free(os_info.user);
|
pg_free(os_info.user);
|
||||||
os_info.user = pg_strdup(optarg);
|
os_info.user = pg_strdup(optarg);
|
||||||
@ -244,14 +248,16 @@ parseCommandLine(int argc, char *argv[])
|
|||||||
pg_putenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY);
|
pg_putenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY);
|
||||||
|
|
||||||
/* Get values from env if not already set */
|
/* Get values from env if not already set */
|
||||||
check_required_directory(&old_cluster.bindir, NULL, "PGBINOLD", "-b",
|
check_required_directory(&old_cluster.bindir, "PGBINOLD", false,
|
||||||
_("old cluster binaries reside"));
|
"-b", _("old cluster binaries reside"));
|
||||||
check_required_directory(&new_cluster.bindir, NULL, "PGBINNEW", "-B",
|
check_required_directory(&new_cluster.bindir, "PGBINNEW", false,
|
||||||
_("new cluster binaries reside"));
|
"-B", _("new cluster binaries reside"));
|
||||||
check_required_directory(&old_cluster.pgdata, &old_cluster.pgconfig,
|
check_required_directory(&old_cluster.pgdata, "PGDATAOLD", false,
|
||||||
"PGDATAOLD", "-d", _("old cluster data resides"));
|
"-d", _("old cluster data resides"));
|
||||||
check_required_directory(&new_cluster.pgdata, &new_cluster.pgconfig,
|
check_required_directory(&new_cluster.pgdata, "PGDATANEW", false,
|
||||||
"PGDATANEW", "-D", _("new cluster data resides"));
|
"-D", _("new cluster data resides"));
|
||||||
|
check_required_directory(&user_opts.socketdir, "PGSOCKETDIR", true,
|
||||||
|
"-s", _("sockets will be created"));
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
||||||
@ -296,6 +302,7 @@ usage(void)
|
|||||||
printf(_(" -p, --old-port=PORT old cluster port number (default %d)\n"), old_cluster.port);
|
printf(_(" -p, --old-port=PORT old cluster port number (default %d)\n"), old_cluster.port);
|
||||||
printf(_(" -P, --new-port=PORT new cluster port number (default %d)\n"), new_cluster.port);
|
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(_(" -r, --retain retain SQL and log files after success\n"));
|
||||||
|
printf(_(" -s, --socketdir=DIR socket directory to use (default CWD)\n"));
|
||||||
printf(_(" -U, --username=NAME cluster superuser (default \"%s\")\n"), os_info.user);
|
printf(_(" -U, --username=NAME cluster superuser (default \"%s\")\n"), os_info.user);
|
||||||
printf(_(" -v, --verbose enable verbose internal logging\n"));
|
printf(_(" -v, --verbose enable verbose internal logging\n"));
|
||||||
printf(_(" -V, --version display version information, then exit\n"));
|
printf(_(" -V, --version display version information, then exit\n"));
|
||||||
@ -337,29 +344,32 @@ usage(void)
|
|||||||
* check_required_directory()
|
* check_required_directory()
|
||||||
*
|
*
|
||||||
* Checks a directory option.
|
* Checks a directory option.
|
||||||
* dirpath - the directory name supplied on the command line
|
* dirpath - the directory name supplied on the command line, or NULL
|
||||||
* configpath - optional configuration directory
|
|
||||||
* envVarName - the name of an environment variable to get if dirpath is NULL
|
* envVarName - the name of an environment variable to get if dirpath is NULL
|
||||||
* cmdLineOption - the command line option corresponds to this directory (-o, -O, -n, -N)
|
* useCwd - true if OK to default to CWD
|
||||||
|
* cmdLineOption - the command line option for this directory
|
||||||
* description - a description of this directory option
|
* description - a description of this directory option
|
||||||
*
|
*
|
||||||
* We use the last two arguments to construct a meaningful error message if the
|
* We use the last two arguments to construct a meaningful error message if the
|
||||||
* user hasn't provided the required directory name.
|
* user hasn't provided the required directory name.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
check_required_directory(char **dirpath, char **configpath,
|
check_required_directory(char **dirpath, const char *envVarName, bool useCwd,
|
||||||
const char *envVarName, const char *cmdLineOption,
|
const char *cmdLineOption, const char *description)
|
||||||
const char *description)
|
|
||||||
{
|
{
|
||||||
if (*dirpath == NULL || strlen(*dirpath) == 0)
|
if (*dirpath == NULL || strlen(*dirpath) == 0)
|
||||||
{
|
{
|
||||||
const char *envVar;
|
const char *envVar;
|
||||||
|
|
||||||
if ((envVar = getenv(envVarName)) && strlen(envVar))
|
if ((envVar = getenv(envVarName)) && strlen(envVar))
|
||||||
{
|
|
||||||
*dirpath = pg_strdup(envVar);
|
*dirpath = pg_strdup(envVar);
|
||||||
if (configpath)
|
else if (useCwd)
|
||||||
*configpath = pg_strdup(envVar);
|
{
|
||||||
|
char cwd[MAXPGPATH];
|
||||||
|
|
||||||
|
if (!getcwd(cwd, MAXPGPATH))
|
||||||
|
pg_fatal("could not determine current directory\n");
|
||||||
|
*dirpath = pg_strdup(cwd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
pg_fatal("You must identify the directory where the %s.\n"
|
pg_fatal("You must identify the directory where the %s.\n"
|
||||||
@ -368,16 +378,10 @@ check_required_directory(char **dirpath, char **configpath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trim off any trailing path separators because we construct paths by
|
* Clean up the path, in particular trimming any trailing path separators,
|
||||||
* appending to this path.
|
* because we construct paths by appending to this path.
|
||||||
*/
|
*/
|
||||||
#ifndef WIN32
|
canonicalize_path(*dirpath);
|
||||||
if ((*dirpath)[strlen(*dirpath) - 1] == '/')
|
|
||||||
#else
|
|
||||||
if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
|
|
||||||
(*dirpath)[strlen(*dirpath) - 1] == '\\')
|
|
||||||
#endif
|
|
||||||
(*dirpath)[strlen(*dirpath) - 1] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -386,6 +390,10 @@ check_required_directory(char **dirpath, char **configpath,
|
|||||||
* If a configuration-only directory was specified, find the real data dir
|
* If a configuration-only directory was specified, find the real data dir
|
||||||
* by querying the running server. This has limited checking because we
|
* by querying the running server. This has limited checking because we
|
||||||
* can't check for a running server because we can't find postmaster.pid.
|
* can't check for a running server because we can't find postmaster.pid.
|
||||||
|
*
|
||||||
|
* On entry, cluster->pgdata has been set from command line or env variable,
|
||||||
|
* but cluster->pgconfig isn't set. We fill both variables with corrected
|
||||||
|
* values.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
adjust_data_dir(ClusterInfo *cluster)
|
adjust_data_dir(ClusterInfo *cluster)
|
||||||
@ -396,6 +404,9 @@ adjust_data_dir(ClusterInfo *cluster)
|
|||||||
FILE *fp,
|
FILE *fp,
|
||||||
*output;
|
*output;
|
||||||
|
|
||||||
|
/* Initially assume config dir and data dir are the same */
|
||||||
|
cluster->pgconfig = pg_strdup(cluster->pgdata);
|
||||||
|
|
||||||
/* If there is no postgresql.conf, it can't be a config-only dir */
|
/* If there is no postgresql.conf, it can't be a config-only dir */
|
||||||
snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
|
snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
|
||||||
if ((fp = fopen(filename, "r")) == NULL)
|
if ((fp = fopen(filename, "r")) == NULL)
|
||||||
@ -462,12 +473,7 @@ get_sock_dir(ClusterInfo *cluster, bool live_check)
|
|||||||
if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
|
if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
|
||||||
{
|
{
|
||||||
if (!live_check)
|
if (!live_check)
|
||||||
{
|
cluster->sockdir = user_opts.socketdir;
|
||||||
/* 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");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -298,7 +298,8 @@ typedef struct
|
|||||||
bool check; /* true -> ask user for permission to make
|
bool check; /* true -> ask user for permission to make
|
||||||
* changes */
|
* changes */
|
||||||
transferMode transfer_mode; /* copy files or link them? */
|
transferMode transfer_mode; /* copy files or link them? */
|
||||||
int jobs;
|
int jobs; /* number of processes/threads to use */
|
||||||
|
char *socketdir; /* directory to use for Unix sockets */
|
||||||
} UserOpts;
|
} UserOpts;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -374,7 +375,7 @@ bool pid_lock_file_exists(const char *datadir);
|
|||||||
/* file.c */
|
/* file.c */
|
||||||
|
|
||||||
void cloneFile(const char *src, const char *dst,
|
void cloneFile(const char *src, const char *dst,
|
||||||
const char *schemaName, const char *relName);
|
const char *schemaName, const char *relName);
|
||||||
void copyFile(const char *src, const char *dst,
|
void copyFile(const char *src, const char *dst,
|
||||||
const char *schemaName, const char *relName);
|
const char *schemaName, const char *relName);
|
||||||
void linkFile(const char *src, const char *dst,
|
void linkFile(const char *src, const char *dst,
|
||||||
|
Loading…
Reference in New Issue
Block a user