~ubuntu-branches/ubuntu/precise/postgresql-9.1/precise-security

« back to all changes in this revision

Viewing changes to contrib/pg_upgrade/server.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      server.c
 
3
 *
 
4
 *      database server functions
 
5
 *
 
6
 *      Copyright (c) 2010-2011, PostgreSQL Global Development Group
 
7
 *      contrib/pg_upgrade/server.c
 
8
 */
 
9
 
 
10
#include "pg_upgrade.h"
 
11
 
 
12
 
 
13
static PGconn *get_db_conn(ClusterInfo *cluster, const char *db_name);
 
14
 
 
15
 
 
16
/*
 
17
 * connectToServer()
 
18
 *
 
19
 *      Connects to the desired database on the designated server.
 
20
 *      If the connection attempt fails, this function logs an error
 
21
 *      message and calls exit() to kill the program.
 
22
 */
 
23
PGconn *
 
24
connectToServer(ClusterInfo *cluster, const char *db_name)
 
25
{
 
26
        PGconn     *conn = get_db_conn(cluster, db_name);
 
27
 
 
28
        if (conn == NULL || PQstatus(conn) != CONNECTION_OK)
 
29
        {
 
30
                pg_log(PG_REPORT, "Connection to database failed: %s\n",
 
31
                           PQerrorMessage(conn));
 
32
 
 
33
                if (conn)
 
34
                        PQfinish(conn);
 
35
 
 
36
                printf("Failure, exiting\n");
 
37
                exit(1);
 
38
        }
 
39
 
 
40
        return conn;
 
41
}
 
42
 
 
43
 
 
44
/*
 
45
 * get_db_conn()
 
46
 *
 
47
 * get database connection
 
48
 */
 
49
static PGconn *
 
50
get_db_conn(ClusterInfo *cluster, const char *db_name)
 
51
{
 
52
        char            conn_opts[MAXPGPATH];
 
53
 
 
54
        snprintf(conn_opts, sizeof(conn_opts),
 
55
                 "dbname = '%s' user = '%s' port = %d", db_name, os_info.user,
 
56
                 cluster->port);
 
57
 
 
58
        return PQconnectdb(conn_opts);
 
59
}
 
60
 
 
61
 
 
62
/*
 
63
 * executeQueryOrDie()
 
64
 *
 
65
 *      Formats a query string from the given arguments and executes the
 
66
 *      resulting query.  If the query fails, this function logs an error
 
67
 *      message and calls exit() to kill the program.
 
68
 */
 
69
PGresult *
 
70
executeQueryOrDie(PGconn *conn, const char *fmt,...)
 
71
{
 
72
        static char command[8192];
 
73
        va_list         args;
 
74
        PGresult   *result;
 
75
        ExecStatusType status;
 
76
 
 
77
        va_start(args, fmt);
 
78
        vsnprintf(command, sizeof(command), fmt, args);
 
79
        va_end(args);
 
80
 
 
81
        pg_log(PG_DEBUG, "executing: %s\n", command);
 
82
        result = PQexec(conn, command);
 
83
        status = PQresultStatus(result);
 
84
 
 
85
        if ((status != PGRES_TUPLES_OK) && (status != PGRES_COMMAND_OK))
 
86
        {
 
87
                pg_log(PG_REPORT, "DB command failed\n%s\n%s\n", command,
 
88
                           PQerrorMessage(conn));
 
89
                PQclear(result);
 
90
                PQfinish(conn);
 
91
                printf("Failure, exiting\n");
 
92
                exit(1);
 
93
        }
 
94
        else
 
95
                return result;
 
96
}
 
97
 
 
98
 
 
99
/*
 
100
 * get_major_server_version()
 
101
 *
 
102
 * gets the version (in unsigned int form) for the given "datadir". Assumes
 
103
 * that datadir is an absolute path to a valid pgdata directory. The version
 
104
 * is retrieved by reading the PG_VERSION file.
 
105
 */
 
106
uint32
 
107
get_major_server_version(ClusterInfo *cluster)
 
108
{
 
109
        const char *datadir = cluster->pgdata;
 
110
        FILE       *version_fd;
 
111
        char            ver_filename[MAXPGPATH];
 
112
        int                     integer_version = 0;
 
113
        int                     fractional_version = 0;
 
114
 
 
115
        snprintf(ver_filename, sizeof(ver_filename), "%s/PG_VERSION", datadir);
 
116
        if ((version_fd = fopen(ver_filename, "r")) == NULL)
 
117
                return 0;
 
118
 
 
119
        if (fscanf(version_fd, "%63s", cluster->major_version_str) == 0 ||
 
120
                sscanf(cluster->major_version_str, "%d.%d", &integer_version,
 
121
                           &fractional_version) != 2)
 
122
                pg_log(PG_FATAL, "could not get version from %s\n", datadir);
 
123
 
 
124
        fclose(version_fd);
 
125
 
 
126
        return (100 * integer_version + fractional_version) * 100;
 
127
}
 
128
 
 
129
 
 
130
static void
 
131
#ifdef HAVE_ATEXIT
 
132
stop_postmaster_atexit(void)
 
133
#else
 
134
stop_postmaster_on_exit(int exitstatus, void *arg)
 
135
#endif
 
136
{
 
137
        stop_postmaster(true);
 
138
 
 
139
}
 
140
 
 
141
 
 
142
void
 
143
start_postmaster(ClusterInfo *cluster)
 
144
{
 
145
        char            cmd[MAXPGPATH];
 
146
        PGconn     *conn;
 
147
        bool            exit_hook_registered = false;
 
148
#ifndef WIN32
 
149
        char            *output_filename = log_opts.filename;
 
150
#else
 
151
        /*
 
152
         * On Win32, we can't send both pg_upgrade output and pg_ctl output to the
 
153
         * same file because we get the error: "The process cannot access the file
 
154
         * because it is being used by another process." so we have to send all
 
155
         * other output to 'nul'.
 
156
         */
 
157
        char            *output_filename = DEVNULL;
 
158
#endif
 
159
 
 
160
        if (!exit_hook_registered)
 
161
        {
 
162
#ifdef HAVE_ATEXIT
 
163
                atexit(stop_postmaster_atexit);
 
164
#else
 
165
                on_exit(stop_postmaster_on_exit);
 
166
#endif
 
167
                exit_hook_registered = true;
 
168
        }
 
169
 
 
170
        /*
 
171
         * Using autovacuum=off disables cleanup vacuum and analyze, but freeze
 
172
         * vacuums can still happen, so we set autovacuum_freeze_max_age to its
 
173
         * maximum.  We assume all datfrozenxid and relfrozen values are less than
 
174
         * a gap of 2000000000 from the current xid counter, so autovacuum will
 
175
         * not touch them.
 
176
         */
 
177
        snprintf(cmd, sizeof(cmd),
 
178
                         SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" "
 
179
                         "-o \"-p %d %s\" start >> \"%s\" 2>&1" SYSTEMQUOTE,
 
180
                         cluster->bindir, output_filename, cluster->pgdata, cluster->port,
 
181
                         (cluster->controldata.cat_ver >=
 
182
                                BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" :
 
183
                                "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000",
 
184
                         log_opts.filename);
 
185
 
 
186
        exec_prog(true, "%s", cmd);
 
187
 
 
188
        /* Check to see if we can connect to the server; if not, report it. */
 
189
        if ((conn = get_db_conn(cluster, "template1")) == NULL ||
 
190
                PQstatus(conn) != CONNECTION_OK)
 
191
        {
 
192
                if (conn)
 
193
                        PQfinish(conn);
 
194
                pg_log(PG_FATAL, "unable to connect to %s postmaster started with the command: %s\n"
 
195
                           "Perhaps pg_hba.conf was not set to \"trust\".",
 
196
                           CLUSTER_NAME(cluster), cmd);
 
197
        }
 
198
        PQfinish(conn);
 
199
 
 
200
        os_info.running_cluster = cluster;
 
201
}
 
202
 
 
203
 
 
204
void
 
205
stop_postmaster(bool fast)
 
206
{
 
207
        char            cmd[MAXPGPATH];
 
208
        const char *bindir;
 
209
        const char *datadir;
 
210
#ifndef WIN32
 
211
        char            *output_filename = log_opts.filename;
 
212
#else
 
213
        /* See comment in start_postmaster() about why win32 output is ignored. */
 
214
        char            *output_filename = DEVNULL;
 
215
#endif
 
216
 
 
217
        if (os_info.running_cluster == &old_cluster)
 
218
        {
 
219
                bindir = old_cluster.bindir;
 
220
                datadir = old_cluster.pgdata;
 
221
        }
 
222
        else if (os_info.running_cluster == &new_cluster)
 
223
        {
 
224
                bindir = new_cluster.bindir;
 
225
                datadir = new_cluster.pgdata;
 
226
        }
 
227
        else
 
228
                return;                                 /* no cluster running */
 
229
 
 
230
        snprintf(cmd, sizeof(cmd),
 
231
                         SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" %s stop >> "
 
232
                         "\"%s\" 2>&1" SYSTEMQUOTE,
 
233
                         bindir, output_filename, datadir, fast ? "-m fast" : "",
 
234
                         output_filename);
 
235
 
 
236
        exec_prog(fast ? false : true, "%s", cmd);
 
237
 
 
238
        os_info.running_cluster = NULL;
 
239
}
 
240
 
 
241
 
 
242
/*
 
243
 * check_for_libpq_envvars()
 
244
 *
 
245
 * tests whether any libpq environment variables are set.
 
246
 * Since pg_upgrade connects to both the old and the new server,
 
247
 * it is potentially dangerous to have any of these set.
 
248
 *
 
249
 * If any are found, will log them and cancel.
 
250
 */
 
251
void
 
252
check_for_libpq_envvars(void)
 
253
{
 
254
        PQconninfoOption *option;
 
255
        PQconninfoOption *start;
 
256
        bool            found = false;
 
257
 
 
258
        /* Get valid libpq env vars from the PQconndefaults function */
 
259
 
 
260
        start = PQconndefaults();
 
261
 
 
262
        for (option = start; option->keyword != NULL; option++)
 
263
        {
 
264
                if (option->envvar)
 
265
                {
 
266
                        const char *value;
 
267
 
 
268
                        if (strcmp(option->envvar, "PGCLIENTENCODING") == 0)
 
269
                                continue;
 
270
 
 
271
                        value = getenv(option->envvar);
 
272
                        if (value && strlen(value) > 0)
 
273
                        {
 
274
                                found = true;
 
275
 
 
276
                                pg_log(PG_WARNING,
 
277
                                           "libpq env var %-20s is currently set to: %s\n", option->envvar, value);
 
278
                        }
 
279
                }
 
280
        }
 
281
 
 
282
        /* Free the memory that libpq allocated on our behalf */
 
283
        PQconninfoFree(start);
 
284
 
 
285
        if (found)
 
286
                pg_log(PG_FATAL,
 
287
                           "libpq env vars have been found and listed above, please unset them for pg_upgrade\n");
 
288
}