| 1 | /* |
| 2 | * server.c |
| 3 | * |
| 4 | * database server functions |
| 5 | * |
| 6 | * Copyright (c) 2010-2019, PostgreSQL Global Development Group |
| 7 | * src/bin/pg_upgrade/server.c |
| 8 | */ |
| 9 | |
| 10 | #include "postgres_fe.h" |
| 11 | |
| 12 | #include "fe_utils/connect.h" |
| 13 | #include "fe_utils/string_utils.h" |
| 14 | #include "pg_upgrade.h" |
| 15 | |
| 16 | |
| 17 | static PGconn *get_db_conn(ClusterInfo *cluster, const char *db_name); |
| 18 | |
| 19 | |
| 20 | /* |
| 21 | * connectToServer() |
| 22 | * |
| 23 | * Connects to the desired database on the designated server. |
| 24 | * If the connection attempt fails, this function logs an error |
| 25 | * message and calls exit() to kill the program. |
| 26 | */ |
| 27 | PGconn * |
| 28 | connectToServer(ClusterInfo *cluster, const char *db_name) |
| 29 | { |
| 30 | PGconn *conn = get_db_conn(cluster, db_name); |
| 31 | |
| 32 | if (conn == NULL || PQstatus(conn) != CONNECTION_OK) |
| 33 | { |
| 34 | pg_log(PG_REPORT, "connection to database failed: %s" , |
| 35 | PQerrorMessage(conn)); |
| 36 | |
| 37 | if (conn) |
| 38 | PQfinish(conn); |
| 39 | |
| 40 | printf(_("Failure, exiting\n" )); |
| 41 | exit(1); |
| 42 | } |
| 43 | |
| 44 | PQclear(executeQueryOrDie(conn, ALWAYS_SECURE_SEARCH_PATH_SQL)); |
| 45 | |
| 46 | return conn; |
| 47 | } |
| 48 | |
| 49 | |
| 50 | /* |
| 51 | * get_db_conn() |
| 52 | * |
| 53 | * get database connection, using named database + standard params for cluster |
| 54 | */ |
| 55 | static PGconn * |
| 56 | get_db_conn(ClusterInfo *cluster, const char *db_name) |
| 57 | { |
| 58 | PQExpBufferData conn_opts; |
| 59 | PGconn *conn; |
| 60 | |
| 61 | /* Build connection string with proper quoting */ |
| 62 | initPQExpBuffer(&conn_opts); |
| 63 | appendPQExpBufferStr(&conn_opts, "dbname=" ); |
| 64 | appendConnStrVal(&conn_opts, db_name); |
| 65 | appendPQExpBufferStr(&conn_opts, " user=" ); |
| 66 | appendConnStrVal(&conn_opts, os_info.user); |
| 67 | appendPQExpBuffer(&conn_opts, " port=%d" , cluster->port); |
| 68 | if (cluster->sockdir) |
| 69 | { |
| 70 | appendPQExpBufferStr(&conn_opts, " host=" ); |
| 71 | appendConnStrVal(&conn_opts, cluster->sockdir); |
| 72 | } |
| 73 | |
| 74 | conn = PQconnectdb(conn_opts.data); |
| 75 | termPQExpBuffer(&conn_opts); |
| 76 | return conn; |
| 77 | } |
| 78 | |
| 79 | |
| 80 | /* |
| 81 | * cluster_conn_opts() |
| 82 | * |
| 83 | * Return standard command-line options for connecting to this cluster when |
| 84 | * using psql, pg_dump, etc. Ideally this would match what get_db_conn() |
| 85 | * sets, but the utilities we need aren't very consistent about the treatment |
| 86 | * of database name options, so we leave that out. |
| 87 | * |
| 88 | * Result is valid until the next call to this function. |
| 89 | */ |
| 90 | char * |
| 91 | cluster_conn_opts(ClusterInfo *cluster) |
| 92 | { |
| 93 | static PQExpBuffer buf; |
| 94 | |
| 95 | if (buf == NULL) |
| 96 | buf = createPQExpBuffer(); |
| 97 | else |
| 98 | resetPQExpBuffer(buf); |
| 99 | |
| 100 | if (cluster->sockdir) |
| 101 | { |
| 102 | appendPQExpBufferStr(buf, "--host " ); |
| 103 | appendShellString(buf, cluster->sockdir); |
| 104 | appendPQExpBufferChar(buf, ' '); |
| 105 | } |
| 106 | appendPQExpBuffer(buf, "--port %d --username " , cluster->port); |
| 107 | appendShellString(buf, os_info.user); |
| 108 | |
| 109 | return buf->data; |
| 110 | } |
| 111 | |
| 112 | |
| 113 | /* |
| 114 | * executeQueryOrDie() |
| 115 | * |
| 116 | * Formats a query string from the given arguments and executes the |
| 117 | * resulting query. If the query fails, this function logs an error |
| 118 | * message and calls exit() to kill the program. |
| 119 | */ |
| 120 | PGresult * |
| 121 | executeQueryOrDie(PGconn *conn, const char *fmt,...) |
| 122 | { |
| 123 | static char query[QUERY_ALLOC]; |
| 124 | va_list args; |
| 125 | PGresult *result; |
| 126 | ExecStatusType status; |
| 127 | |
| 128 | va_start(args, fmt); |
| 129 | vsnprintf(query, sizeof(query), fmt, args); |
| 130 | va_end(args); |
| 131 | |
| 132 | pg_log(PG_VERBOSE, "executing: %s\n" , query); |
| 133 | result = PQexec(conn, query); |
| 134 | status = PQresultStatus(result); |
| 135 | |
| 136 | if ((status != PGRES_TUPLES_OK) && (status != PGRES_COMMAND_OK)) |
| 137 | { |
| 138 | pg_log(PG_REPORT, "SQL command failed\n%s\n%s" , query, |
| 139 | PQerrorMessage(conn)); |
| 140 | PQclear(result); |
| 141 | PQfinish(conn); |
| 142 | printf(_("Failure, exiting\n" )); |
| 143 | exit(1); |
| 144 | } |
| 145 | else |
| 146 | return result; |
| 147 | } |
| 148 | |
| 149 | |
| 150 | /* |
| 151 | * get_major_server_version() |
| 152 | * |
| 153 | * gets the version (in unsigned int form) for the given datadir. Assumes |
| 154 | * that datadir is an absolute path to a valid pgdata directory. The version |
| 155 | * is retrieved by reading the PG_VERSION file. |
| 156 | */ |
| 157 | uint32 |
| 158 | get_major_server_version(ClusterInfo *cluster) |
| 159 | { |
| 160 | FILE *version_fd; |
| 161 | char ver_filename[MAXPGPATH]; |
| 162 | int v1 = 0, |
| 163 | v2 = 0; |
| 164 | |
| 165 | snprintf(ver_filename, sizeof(ver_filename), "%s/PG_VERSION" , |
| 166 | cluster->pgdata); |
| 167 | if ((version_fd = fopen(ver_filename, "r" )) == NULL) |
| 168 | pg_fatal("could not open version file: %s\n" , ver_filename); |
| 169 | |
| 170 | if (fscanf(version_fd, "%63s" , cluster->major_version_str) == 0 || |
| 171 | sscanf(cluster->major_version_str, "%d.%d" , &v1, &v2) < 1) |
| 172 | pg_fatal("could not parse PG_VERSION file from %s\n" , cluster->pgdata); |
| 173 | |
| 174 | fclose(version_fd); |
| 175 | |
| 176 | if (v1 < 10) |
| 177 | { |
| 178 | /* old style, e.g. 9.6.1 */ |
| 179 | return v1 * 10000 + v2 * 100; |
| 180 | } |
| 181 | else |
| 182 | { |
| 183 | /* new style, e.g. 10.1 */ |
| 184 | return v1 * 10000; |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | |
| 189 | static void |
| 190 | stop_postmaster_atexit(void) |
| 191 | { |
| 192 | stop_postmaster(true); |
| 193 | } |
| 194 | |
| 195 | |
| 196 | bool |
| 197 | start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error) |
| 198 | { |
| 199 | char cmd[MAXPGPATH * 4 + 1000]; |
| 200 | PGconn *conn; |
| 201 | bool pg_ctl_return = false; |
| 202 | char socket_string[MAXPGPATH + 200]; |
| 203 | |
| 204 | static bool exit_hook_registered = false; |
| 205 | |
| 206 | if (!exit_hook_registered) |
| 207 | { |
| 208 | atexit(stop_postmaster_atexit); |
| 209 | exit_hook_registered = true; |
| 210 | } |
| 211 | |
| 212 | socket_string[0] = '\0'; |
| 213 | |
| 214 | #ifdef HAVE_UNIX_SOCKETS |
| 215 | /* prevent TCP/IP connections, restrict socket access */ |
| 216 | strcat(socket_string, |
| 217 | " -c listen_addresses='' -c unix_socket_permissions=0700" ); |
| 218 | |
| 219 | /* Have a sockdir? Tell the postmaster. */ |
| 220 | if (cluster->sockdir) |
| 221 | snprintf(socket_string + strlen(socket_string), |
| 222 | sizeof(socket_string) - strlen(socket_string), |
| 223 | " -c %s='%s'" , |
| 224 | (GET_MAJOR_VERSION(cluster->major_version) < 903) ? |
| 225 | "unix_socket_directory" : "unix_socket_directories" , |
| 226 | cluster->sockdir); |
| 227 | #endif |
| 228 | |
| 229 | /* |
| 230 | * Since PG 9.1, we have used -b to disable autovacuum. For earlier |
| 231 | * releases, setting autovacuum=off disables cleanup vacuum and analyze, |
| 232 | * but freeze vacuums can still happen, so we set |
| 233 | * autovacuum_freeze_max_age to its maximum. |
| 234 | * (autovacuum_multixact_freeze_max_age was introduced after 9.1, so there |
| 235 | * is no need to set that.) We assume all datfrozenxid and relfrozenxid |
| 236 | * values are less than a gap of 2000000000 from the current xid counter, |
| 237 | * so autovacuum will not touch them. |
| 238 | * |
| 239 | * Turn off durability requirements to improve object creation speed, and |
| 240 | * we only modify the new cluster, so only use it there. If there is a |
| 241 | * crash, the new cluster has to be recreated anyway. fsync=off is a big |
| 242 | * win on ext4. |
| 243 | */ |
| 244 | snprintf(cmd, sizeof(cmd), |
| 245 | "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d%s%s %s%s\" start" , |
| 246 | cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port, |
| 247 | (cluster->controldata.cat_ver >= |
| 248 | BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? " -b" : |
| 249 | " -c autovacuum=off -c autovacuum_freeze_max_age=2000000000" , |
| 250 | (cluster == &new_cluster) ? |
| 251 | " -c synchronous_commit=off -c fsync=off -c full_page_writes=off" : "" , |
| 252 | cluster->pgopts ? cluster->pgopts : "" , socket_string); |
| 253 | |
| 254 | /* |
| 255 | * Don't throw an error right away, let connecting throw the error because |
| 256 | * it might supply a reason for the failure. |
| 257 | */ |
| 258 | pg_ctl_return = exec_prog(SERVER_START_LOG_FILE, |
| 259 | /* pass both file names if they differ */ |
| 260 | (strcmp(SERVER_LOG_FILE, |
| 261 | SERVER_START_LOG_FILE) != 0) ? |
| 262 | SERVER_LOG_FILE : NULL, |
| 263 | report_and_exit_on_error, false, |
| 264 | "%s" , cmd); |
| 265 | |
| 266 | /* Did it fail and we are just testing if the server could be started? */ |
| 267 | if (!pg_ctl_return && !report_and_exit_on_error) |
| 268 | return false; |
| 269 | |
| 270 | /* |
| 271 | * We set this here to make sure atexit() shuts down the server, but only |
| 272 | * if we started the server successfully. We do it before checking for |
| 273 | * connectivity in case the server started but there is a connectivity |
| 274 | * failure. If pg_ctl did not return success, we will exit below. |
| 275 | * |
| 276 | * Pre-9.1 servers do not have PQping(), so we could be leaving the server |
| 277 | * running if authentication was misconfigured, so someday we might went |
| 278 | * to be more aggressive about doing server shutdowns even if pg_ctl |
| 279 | * fails, but now (2013-08-14) it seems prudent to be cautious. We don't |
| 280 | * want to shutdown a server that might have been accidentally started |
| 281 | * during the upgrade. |
| 282 | */ |
| 283 | if (pg_ctl_return) |
| 284 | os_info.running_cluster = cluster; |
| 285 | |
| 286 | /* |
| 287 | * pg_ctl -w might have failed because the server couldn't be started, or |
| 288 | * there might have been a connection problem in _checking_ if the server |
| 289 | * has started. Therefore, even if pg_ctl failed, we continue and test |
| 290 | * for connectivity in case we get a connection reason for the failure. |
| 291 | */ |
| 292 | if ((conn = get_db_conn(cluster, "template1" )) == NULL || |
| 293 | PQstatus(conn) != CONNECTION_OK) |
| 294 | { |
| 295 | pg_log(PG_REPORT, "\nconnection to database failed: %s" , |
| 296 | PQerrorMessage(conn)); |
| 297 | if (conn) |
| 298 | PQfinish(conn); |
| 299 | if (cluster == &old_cluster) |
| 300 | pg_fatal("could not connect to source postmaster started with the command:\n" |
| 301 | "%s\n" , |
| 302 | cmd); |
| 303 | else |
| 304 | pg_fatal("could not connect to target postmaster started with the command:\n" |
| 305 | "%s\n" , |
| 306 | cmd); |
| 307 | } |
| 308 | PQfinish(conn); |
| 309 | |
| 310 | /* |
| 311 | * If pg_ctl failed, and the connection didn't fail, and |
| 312 | * report_and_exit_on_error is enabled, fail now. This could happen if |
| 313 | * the server was already running. |
| 314 | */ |
| 315 | if (!pg_ctl_return) |
| 316 | { |
| 317 | if (cluster == &old_cluster) |
| 318 | pg_fatal("pg_ctl failed to start the source server, or connection failed\n" ); |
| 319 | else |
| 320 | pg_fatal("pg_ctl failed to start the target server, or connection failed\n" ); |
| 321 | } |
| 322 | |
| 323 | return true; |
| 324 | } |
| 325 | |
| 326 | |
| 327 | void |
| 328 | stop_postmaster(bool in_atexit) |
| 329 | { |
| 330 | ClusterInfo *cluster; |
| 331 | |
| 332 | if (os_info.running_cluster == &old_cluster) |
| 333 | cluster = &old_cluster; |
| 334 | else if (os_info.running_cluster == &new_cluster) |
| 335 | cluster = &new_cluster; |
| 336 | else |
| 337 | return; /* no cluster running */ |
| 338 | |
| 339 | exec_prog(SERVER_STOP_LOG_FILE, NULL, !in_atexit, !in_atexit, |
| 340 | "\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" %s stop" , |
| 341 | cluster->bindir, cluster->pgconfig, |
| 342 | cluster->pgopts ? cluster->pgopts : "" , |
| 343 | in_atexit ? "-m fast" : "-m smart" ); |
| 344 | |
| 345 | os_info.running_cluster = NULL; |
| 346 | } |
| 347 | |
| 348 | |
| 349 | /* |
| 350 | * check_pghost_envvar() |
| 351 | * |
| 352 | * Tests that PGHOST does not point to a non-local server |
| 353 | */ |
| 354 | void |
| 355 | check_pghost_envvar(void) |
| 356 | { |
| 357 | PQconninfoOption *option; |
| 358 | PQconninfoOption *start; |
| 359 | |
| 360 | /* Get valid libpq env vars from the PQconndefaults function */ |
| 361 | |
| 362 | start = PQconndefaults(); |
| 363 | |
| 364 | if (!start) |
| 365 | pg_fatal("out of memory\n" ); |
| 366 | |
| 367 | for (option = start; option->keyword != NULL; option++) |
| 368 | { |
| 369 | if (option->envvar && (strcmp(option->envvar, "PGHOST" ) == 0 || |
| 370 | strcmp(option->envvar, "PGHOSTADDR" ) == 0)) |
| 371 | { |
| 372 | const char *value = getenv(option->envvar); |
| 373 | |
| 374 | if (value && strlen(value) > 0 && |
| 375 | /* check for 'local' host values */ |
| 376 | (strcmp(value, "localhost" ) != 0 && strcmp(value, "127.0.0.1" ) != 0 && |
| 377 | strcmp(value, "::1" ) != 0 && value[0] != '/')) |
| 378 | pg_fatal("libpq environment variable %s has a non-local server value: %s\n" , |
| 379 | option->envvar, value); |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | /* Free the memory that libpq allocated on our behalf */ |
| 384 | PQconninfoFree(start); |
| 385 | } |
| 386 | |