LCOV - differential code coverage report
Current view: top level - src/bin/pg_upgrade - server.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 79.3 % 121 96 6 19 1 95 6 1
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 9 9 4 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a