]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/server.c
On Windows, have pg_upgrade use different two files to log pg_ctl
[postgresql] / contrib / pg_upgrade / server.c
1 /*
2  *      server.c
3  *
4  *      database server functions
5  *
6  *      Copyright (c) 2010-2012, PostgreSQL Global Development Group
7  *      contrib/pg_upgrade/server.c
8  */
9
10 #include "postgres.h"
11
12 #include "pg_upgrade.h"
13
14
15 static PGconn *get_db_conn(ClusterInfo *cluster, const char *db_name);
16
17
18 /*
19  * connectToServer()
20  *
21  *      Connects to the desired database on the designated server.
22  *      If the connection attempt fails, this function logs an error
23  *      message and calls exit() to kill the program.
24  */
25 PGconn *
26 connectToServer(ClusterInfo *cluster, const char *db_name)
27 {
28         PGconn     *conn = get_db_conn(cluster, db_name);
29
30         if (conn == NULL || PQstatus(conn) != CONNECTION_OK)
31         {
32                 pg_log(PG_REPORT, "connection to database failed: %s\n",
33                            PQerrorMessage(conn));
34
35                 if (conn)
36                         PQfinish(conn);
37
38                 printf("Failure, exiting\n");
39                 exit(1);
40         }
41
42         return conn;
43 }
44
45
46 /*
47  * get_db_conn()
48  *
49  * get database connection
50  */
51 static PGconn *
52 get_db_conn(ClusterInfo *cluster, const char *db_name)
53 {
54         char            conn_opts[MAXPGPATH];
55
56         snprintf(conn_opts, sizeof(conn_opts),
57                          "dbname = '%s' user = '%s' port = %d", db_name, os_info.user,
58                          cluster->port);
59
60         return PQconnectdb(conn_opts);
61 }
62
63
64 /*
65  * executeQueryOrDie()
66  *
67  *      Formats a query string from the given arguments and executes the
68  *      resulting query.  If the query fails, this function logs an error
69  *      message and calls exit() to kill the program.
70  */
71 PGresult *
72 executeQueryOrDie(PGconn *conn, const char *fmt,...)
73 {
74         static char command[8192];
75         va_list         args;
76         PGresult   *result;
77         ExecStatusType status;
78
79         va_start(args, fmt);
80         vsnprintf(command, sizeof(command), fmt, args);
81         va_end(args);
82
83         pg_log(PG_VERBOSE, "executing: %s\n", command);
84         result = PQexec(conn, command);
85         status = PQresultStatus(result);
86
87         if ((status != PGRES_TUPLES_OK) && (status != PGRES_COMMAND_OK))
88         {
89                 pg_log(PG_REPORT, "SQL command failed\n%s\n%s\n", command,
90                            PQerrorMessage(conn));
91                 PQclear(result);
92                 PQfinish(conn);
93                 printf("Failure, exiting\n");
94                 exit(1);
95         }
96         else
97                 return result;
98 }
99
100
101 /*
102  * get_major_server_version()
103  *
104  * gets the version (in unsigned int form) for the given datadir. Assumes
105  * that datadir is an absolute path to a valid pgdata directory. The version
106  * is retrieved by reading the PG_VERSION file.
107  */
108 uint32
109 get_major_server_version(ClusterInfo *cluster)
110 {
111         FILE       *version_fd;
112         char            ver_filename[MAXPGPATH];
113         int                     integer_version = 0;
114         int                     fractional_version = 0;
115
116         snprintf(ver_filename, sizeof(ver_filename), "%s/PG_VERSION",
117                          cluster->pgdata);
118         if ((version_fd = fopen(ver_filename, "r")) == NULL)
119                 return 0;
120
121         if (fscanf(version_fd, "%63s", cluster->major_version_str) == 0 ||
122                 sscanf(cluster->major_version_str, "%d.%d", &integer_version,
123                            &fractional_version) != 2)
124                 pg_log(PG_FATAL, "could not get version from %s\n", cluster->pgdata);
125
126         fclose(version_fd);
127
128         return (100 * integer_version + fractional_version) * 100;
129 }
130
131
132 static void
133 stop_postmaster_atexit(void)
134 {
135         stop_postmaster(true);
136
137 }
138
139
140 void
141 start_postmaster(ClusterInfo *cluster)
142 {
143         char            cmd[MAXPGPATH];
144         PGconn     *conn;
145         bool            exit_hook_registered = false;
146         int                     pg_ctl_return = 0;
147
148         if (!exit_hook_registered)
149         {
150                 atexit(stop_postmaster_atexit);
151                 exit_hook_registered = true;
152         }
153
154         /*
155          * Using autovacuum=off disables cleanup vacuum and analyze, but freeze
156          * vacuums can still happen, so we set autovacuum_freeze_max_age to its
157          * maximum.  We assume all datfrozenxid and relfrozen values are less than
158          * a gap of 2000000000 from the current xid counter, so autovacuum will
159          * not touch them.
160          */
161         snprintf(cmd, sizeof(cmd),
162                          SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" "
163                          "-o \"-p %d %s %s\" start >> \"%s\" 2>&1" SYSTEMQUOTE,
164                          cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
165                          (cluster->controldata.cat_ver >=
166                           BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" :
167                          "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000",
168                          cluster->pgopts ? cluster->pgopts : "", SERVER_START_LOG_FILE);
169
170         /*
171          * Don't throw an error right away, let connecting throw the error because
172          * it might supply a reason for the failure.
173          */
174         pg_ctl_return = exec_prog(false, true,
175                                         /* pass both file names if the differ */
176                                         (strcmp(SERVER_LOG_FILE, SERVER_START_LOG_FILE) == 0) ?
177                                                 SERVER_LOG_FILE :
178                                                 SERVER_LOG_FILE " or " SERVER_START_LOG_FILE,
179                                         "%s", cmd);
180
181         /* Check to see if we can connect to the server; if not, report it. */
182         if ((conn = get_db_conn(cluster, "template1")) == NULL ||
183                 PQstatus(conn) != CONNECTION_OK)
184         {
185                 pg_log(PG_REPORT, "\nconnection to database failed: %s\n",
186                            PQerrorMessage(conn));
187                 if (conn)
188                         PQfinish(conn);
189                 pg_log(PG_FATAL, "could not connect to %s postmaster started with the command: %s\n",
190                            CLUSTER_NAME(cluster), cmd);
191         }
192         PQfinish(conn);
193
194         /* If the connection didn't fail, fail now */
195         if (pg_ctl_return != 0)
196                 pg_log(PG_FATAL, "pg_ctl failed to start the %s server\n",
197                            CLUSTER_NAME(cluster));
198
199         os_info.running_cluster = cluster;
200 }
201
202
203 void
204 stop_postmaster(bool fast)
205 {
206         char            cmd[MAXPGPATH];
207         ClusterInfo *cluster;
208
209         if (os_info.running_cluster == &old_cluster)
210                 cluster = &old_cluster;
211         else if (os_info.running_cluster == &new_cluster)
212                 cluster = &new_cluster;
213         else
214                 return;         /* no cluster running */
215
216         snprintf(cmd, sizeof(cmd),
217                          SYSTEMQUOTE "\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" "
218                          "%s stop >> \"%s\" 2>&1" SYSTEMQUOTE,
219                          cluster->bindir, cluster->pgconfig,
220                          cluster->pgopts ? cluster->pgopts : "",
221                         fast ? "-m fast" : "", SERVER_STOP_LOG_FILE);
222
223         exec_prog(fast ? false : true, true, SERVER_STOP_LOG_FILE, "%s", cmd);
224
225         os_info.running_cluster = NULL;
226 }
227
228
229 /*
230  * check_pghost_envvar()
231  *
232  * Tests that PGHOST does not point to a non-local server
233  */
234 void
235 check_pghost_envvar(void)
236 {
237         PQconninfoOption *option;
238         PQconninfoOption *start;
239
240         /* Get valid libpq env vars from the PQconndefaults function */
241
242         start = PQconndefaults();
243
244         for (option = start; option->keyword != NULL; option++)
245         {
246                 if (option->envvar && (strcmp(option->envvar, "PGHOST") == 0 ||
247                                                            strcmp(option->envvar, "PGHOSTADDR") == 0))
248                 {
249                         const char *value = getenv(option->envvar);
250
251                         if (value && strlen(value) > 0 &&
252                         /* check for 'local' host values */
253                                 (strcmp(value, "localhost") != 0 && strcmp(value, "127.0.0.1") != 0 &&
254                                  strcmp(value, "::1") != 0 && value[0] != '/'))
255                                 pg_log(PG_FATAL,
256                                            "libpq environment variable %s has a non-local server value: %s\n",
257                                            option->envvar, value);
258                 }
259         }
260
261         /* Free the memory that libpq allocated on our behalf */
262         PQconninfoFree(start);
263 }