PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/pg_upgrade/server.c

https://github.com/bbt123/postgres
C | 348 lines | 195 code | 57 blank | 96 comment | 48 complexity | 764018d6ef23aead762d23bfa6f41f07 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*
  2. * server.c
  3. *
  4. * database server functions
  5. *
  6. * Copyright (c) 2010-2014, PostgreSQL Global Development Group
  7. * contrib/pg_upgrade/server.c
  8. */
  9. #include "postgres_fe.h"
  10. #include "pg_upgrade.h"
  11. static PGconn *get_db_conn(ClusterInfo *cluster, const char *db_name);
  12. /*
  13. * connectToServer()
  14. *
  15. * Connects to the desired database on the designated server.
  16. * If the connection attempt fails, this function logs an error
  17. * message and calls exit() to kill the program.
  18. */
  19. PGconn *
  20. connectToServer(ClusterInfo *cluster, const char *db_name)
  21. {
  22. PGconn *conn = get_db_conn(cluster, db_name);
  23. if (conn == NULL || PQstatus(conn) != CONNECTION_OK)
  24. {
  25. pg_log(PG_REPORT, "connection to database failed: %s\n",
  26. PQerrorMessage(conn));
  27. if (conn)
  28. PQfinish(conn);
  29. printf("Failure, exiting\n");
  30. exit(1);
  31. }
  32. return conn;
  33. }
  34. /*
  35. * get_db_conn()
  36. *
  37. * get database connection, using named database + standard params for cluster
  38. */
  39. static PGconn *
  40. get_db_conn(ClusterInfo *cluster, const char *db_name)
  41. {
  42. char conn_opts[2 * NAMEDATALEN + MAXPGPATH + 100];
  43. if (cluster->sockdir)
  44. snprintf(conn_opts, sizeof(conn_opts),
  45. "dbname = '%s' user = '%s' host = '%s' port = %d",
  46. db_name, os_info.user, cluster->sockdir, cluster->port);
  47. else
  48. snprintf(conn_opts, sizeof(conn_opts),
  49. "dbname = '%s' user = '%s' port = %d",
  50. db_name, os_info.user, cluster->port);
  51. return PQconnectdb(conn_opts);
  52. }
  53. /*
  54. * cluster_conn_opts()
  55. *
  56. * Return standard command-line options for connecting to this cluster when
  57. * using psql, pg_dump, etc. Ideally this would match what get_db_conn()
  58. * sets, but the utilities we need aren't very consistent about the treatment
  59. * of database name options, so we leave that out.
  60. *
  61. * Note result is in static storage, so use it right away.
  62. */
  63. char *
  64. cluster_conn_opts(ClusterInfo *cluster)
  65. {
  66. static char conn_opts[MAXPGPATH + NAMEDATALEN + 100];
  67. if (cluster->sockdir)
  68. snprintf(conn_opts, sizeof(conn_opts),
  69. "--host \"%s\" --port %d --username \"%s\"",
  70. cluster->sockdir, cluster->port, os_info.user);
  71. else
  72. snprintf(conn_opts, sizeof(conn_opts),
  73. "--port %d --username \"%s\"",
  74. cluster->port, os_info.user);
  75. return conn_opts;
  76. }
  77. /*
  78. * executeQueryOrDie()
  79. *
  80. * Formats a query string from the given arguments and executes the
  81. * resulting query. If the query fails, this function logs an error
  82. * message and calls exit() to kill the program.
  83. */
  84. PGresult *
  85. executeQueryOrDie(PGconn *conn, const char *fmt,...)
  86. {
  87. static char command[8192];
  88. va_list args;
  89. PGresult *result;
  90. ExecStatusType status;
  91. va_start(args, fmt);
  92. vsnprintf(command, sizeof(command), fmt, args);
  93. va_end(args);
  94. pg_log(PG_VERBOSE, "executing: %s\n", command);
  95. result = PQexec(conn, command);
  96. status = PQresultStatus(result);
  97. if ((status != PGRES_TUPLES_OK) && (status != PGRES_COMMAND_OK))
  98. {
  99. pg_log(PG_REPORT, "SQL command failed\n%s\n%s\n", command,
  100. PQerrorMessage(conn));
  101. PQclear(result);
  102. PQfinish(conn);
  103. printf("Failure, exiting\n");
  104. exit(1);
  105. }
  106. else
  107. return result;
  108. }
  109. /*
  110. * get_major_server_version()
  111. *
  112. * gets the version (in unsigned int form) for the given datadir. Assumes
  113. * that datadir is an absolute path to a valid pgdata directory. The version
  114. * is retrieved by reading the PG_VERSION file.
  115. */
  116. uint32
  117. get_major_server_version(ClusterInfo *cluster)
  118. {
  119. FILE *version_fd;
  120. char ver_filename[MAXPGPATH];
  121. int integer_version = 0;
  122. int fractional_version = 0;
  123. snprintf(ver_filename, sizeof(ver_filename), "%s/PG_VERSION",
  124. cluster->pgdata);
  125. if ((version_fd = fopen(ver_filename, "r")) == NULL)
  126. pg_fatal("could not open version file: %s\n", ver_filename);
  127. if (fscanf(version_fd, "%63s", cluster->major_version_str) == 0 ||
  128. sscanf(cluster->major_version_str, "%d.%d", &integer_version,
  129. &fractional_version) != 2)
  130. pg_fatal("could not get version from %s\n", cluster->pgdata);
  131. fclose(version_fd);
  132. return (100 * integer_version + fractional_version) * 100;
  133. }
  134. static void
  135. stop_postmaster_atexit(void)
  136. {
  137. stop_postmaster(true);
  138. }
  139. bool
  140. start_postmaster(ClusterInfo *cluster, bool throw_error)
  141. {
  142. char cmd[MAXPGPATH * 4 + 1000];
  143. PGconn *conn;
  144. bool exit_hook_registered = false;
  145. bool pg_ctl_return = false;
  146. char socket_string[MAXPGPATH + 200];
  147. if (!exit_hook_registered)
  148. {
  149. atexit(stop_postmaster_atexit);
  150. exit_hook_registered = true;
  151. }
  152. socket_string[0] = '\0';
  153. #ifdef HAVE_UNIX_SOCKETS
  154. /* prevent TCP/IP connections, restrict socket access */
  155. strcat(socket_string,
  156. " -c listen_addresses='' -c unix_socket_permissions=0700");
  157. /* Have a sockdir? Tell the postmaster. */
  158. if (cluster->sockdir)
  159. snprintf(socket_string + strlen(socket_string),
  160. sizeof(socket_string) - strlen(socket_string),
  161. " -c %s='%s'",
  162. (GET_MAJOR_VERSION(cluster->major_version) < 903) ?
  163. "unix_socket_directory" : "unix_socket_directories",
  164. cluster->sockdir);
  165. #endif
  166. /*
  167. * Using autovacuum=off disables cleanup vacuum and analyze, but freeze
  168. * vacuums can still happen, so we set autovacuum_freeze_max_age to its
  169. * maximum. We assume all datfrozenxid and relfrozen values are less than
  170. * a gap of 2000000000 from the current xid counter, so autovacuum will
  171. * not touch them.
  172. *
  173. * Turn off durability requirements to improve object creation speed, and
  174. * we only modify the new cluster, so only use it there. If there is a
  175. * crash, the new cluster has to be recreated anyway. fsync=off is a big
  176. * win on ext4.
  177. */
  178. snprintf(cmd, sizeof(cmd),
  179. "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d%s%s %s%s\" start",
  180. cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, 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. (cluster == &new_cluster) ?
  185. " -c synchronous_commit=off -c fsync=off -c full_page_writes=off" : "",
  186. cluster->pgopts ? cluster->pgopts : "", socket_string);
  187. /*
  188. * Don't throw an error right away, let connecting throw the error because
  189. * it might supply a reason for the failure.
  190. */
  191. pg_ctl_return = exec_prog(SERVER_START_LOG_FILE,
  192. /* pass both file names if they differ */
  193. (strcmp(SERVER_LOG_FILE,
  194. SERVER_START_LOG_FILE) != 0) ?
  195. SERVER_LOG_FILE : NULL,
  196. false,
  197. "%s", cmd);
  198. /* Did it fail and we are just testing if the server could be started? */
  199. if (!pg_ctl_return && !throw_error)
  200. return false;
  201. /*
  202. * We set this here to make sure atexit() shuts down the server, but only
  203. * if we started the server successfully. We do it before checking for
  204. * connectivity in case the server started but there is a connectivity
  205. * failure. If pg_ctl did not return success, we will exit below.
  206. *
  207. * Pre-9.1 servers do not have PQping(), so we could be leaving the server
  208. * running if authentication was misconfigured, so someday we might went
  209. * to be more aggressive about doing server shutdowns even if pg_ctl
  210. * fails, but now (2013-08-14) it seems prudent to be cautious. We don't
  211. * want to shutdown a server that might have been accidentally started
  212. * during the upgrade.
  213. */
  214. if (pg_ctl_return)
  215. os_info.running_cluster = cluster;
  216. /*
  217. * pg_ctl -w might have failed because the server couldn't be started, or
  218. * there might have been a connection problem in _checking_ if the server
  219. * has started. Therefore, even if pg_ctl failed, we continue and test
  220. * for connectivity in case we get a connection reason for the failure.
  221. */
  222. if ((conn = get_db_conn(cluster, "template1")) == NULL ||
  223. PQstatus(conn) != CONNECTION_OK)
  224. {
  225. pg_log(PG_REPORT, "\nconnection to database failed: %s\n",
  226. PQerrorMessage(conn));
  227. if (conn)
  228. PQfinish(conn);
  229. pg_fatal("could not connect to %s postmaster started with the command:\n"
  230. "%s\n",
  231. CLUSTER_NAME(cluster), cmd);
  232. }
  233. PQfinish(conn);
  234. /*
  235. * If pg_ctl failed, and the connection didn't fail, and throw_error is
  236. * enabled, fail now. This could happen if the server was already
  237. * running.
  238. */
  239. if (!pg_ctl_return)
  240. pg_fatal("pg_ctl failed to start the %s server, or connection failed\n",
  241. CLUSTER_NAME(cluster));
  242. return true;
  243. }
  244. void
  245. stop_postmaster(bool fast)
  246. {
  247. ClusterInfo *cluster;
  248. if (os_info.running_cluster == &old_cluster)
  249. cluster = &old_cluster;
  250. else if (os_info.running_cluster == &new_cluster)
  251. cluster = &new_cluster;
  252. else
  253. return; /* no cluster running */
  254. exec_prog(SERVER_STOP_LOG_FILE, NULL, !fast,
  255. "\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" %s stop",
  256. cluster->bindir, cluster->pgconfig,
  257. cluster->pgopts ? cluster->pgopts : "",
  258. fast ? "-m fast" : "");
  259. os_info.running_cluster = NULL;
  260. }
  261. /*
  262. * check_pghost_envvar()
  263. *
  264. * Tests that PGHOST does not point to a non-local server
  265. */
  266. void
  267. check_pghost_envvar(void)
  268. {
  269. PQconninfoOption *option;
  270. PQconninfoOption *start;
  271. /* Get valid libpq env vars from the PQconndefaults function */
  272. start = PQconndefaults();
  273. if (!start)
  274. pg_fatal("out of memory\n");
  275. for (option = start; option->keyword != NULL; option++)
  276. {
  277. if (option->envvar && (strcmp(option->envvar, "PGHOST") == 0 ||
  278. strcmp(option->envvar, "PGHOSTADDR") == 0))
  279. {
  280. const char *value = getenv(option->envvar);
  281. if (value && strlen(value) > 0 &&
  282. /* check for 'local' host values */
  283. (strcmp(value, "localhost") != 0 && strcmp(value, "127.0.0.1") != 0 &&
  284. strcmp(value, "::1") != 0 && value[0] != '/'))
  285. pg_fatal("libpq environment variable %s has a non-local server value: %s\n",
  286. option->envvar, value);
  287. }
  288. }
  289. /* Free the memory that libpq allocated on our behalf */
  290. PQconninfoFree(start);
  291. }