LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - server.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 145 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 8 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  *      server.c
       3              :  *
       4              :  *      database server functions
       5              :  *
       6              :  *      Copyright (c) 2010-2026, 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            0 : connectToServer(ClusterInfo *cluster, const char *db_name)
      29              : {
      30            0 :         PGconn     *conn = get_db_conn(cluster, db_name);
      31              : 
      32            0 :         if (conn == NULL || PQstatus(conn) != CONNECTION_OK)
      33              :         {
      34            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            0 :         PQclear(executeQueryOrDie(conn, ALWAYS_SECURE_SEARCH_PATH_SQL));
      44              : 
      45            0 :         return conn;
      46            0 : }
      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            0 : get_db_conn(ClusterInfo *cluster, const char *db_name)
      58              : {
      59            0 :         PQExpBufferData conn_opts;
      60            0 :         PGconn     *conn;
      61              : 
      62              :         /* Build connection string with proper quoting */
      63            0 :         initPQExpBuffer(&conn_opts);
      64            0 :         appendPQExpBufferStr(&conn_opts, "dbname=");
      65            0 :         appendConnStrVal(&conn_opts, db_name);
      66            0 :         appendPQExpBufferStr(&conn_opts, " user=");
      67            0 :         appendConnStrVal(&conn_opts, os_info.user);
      68            0 :         appendPQExpBuffer(&conn_opts, " port=%d", cluster->port);
      69            0 :         if (cluster->sockdir)
      70              :         {
      71            0 :                 appendPQExpBufferStr(&conn_opts, " host=");
      72            0 :                 appendConnStrVal(&conn_opts, cluster->sockdir);
      73            0 :         }
      74              : 
      75            0 :         conn = PQconnectdb(conn_opts.data);
      76            0 :         termPQExpBuffer(&conn_opts);
      77            0 :         return conn;
      78            0 : }
      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            0 : cluster_conn_opts(ClusterInfo *cluster)
      93              : {
      94              :         static PQExpBuffer buf;
      95              : 
      96            0 :         if (buf == NULL)
      97            0 :                 buf = createPQExpBuffer();
      98              :         else
      99            0 :                 resetPQExpBuffer(buf);
     100              : 
     101            0 :         if (cluster->sockdir)
     102              :         {
     103            0 :                 appendPQExpBufferStr(buf, "--host ");
     104            0 :                 appendShellString(buf, cluster->sockdir);
     105            0 :                 appendPQExpBufferChar(buf, ' ');
     106            0 :         }
     107            0 :         appendPQExpBuffer(buf, "--port %d --username ", cluster->port);
     108            0 :         appendShellString(buf, os_info.user);
     109              : 
     110            0 :         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            0 : executeQueryOrDie(PGconn *conn, const char *fmt,...)
     123              : {
     124              :         static char query[QUERY_ALLOC];
     125            0 :         va_list         args;
     126            0 :         PGresult   *result;
     127            0 :         ExecStatusType status;
     128              : 
     129            0 :         va_start(args, fmt);
     130            0 :         vsnprintf(query, sizeof(query), fmt, args);
     131            0 :         va_end(args);
     132              : 
     133            0 :         pg_log(PG_VERBOSE, "executing: %s", query);
     134            0 :         result = PQexec(conn, query);
     135            0 :         status = PQresultStatus(result);
     136              : 
     137            0 :         if ((status != PGRES_TUPLES_OK) && (status != PGRES_COMMAND_OK))
     138              :         {
     139            0 :                 pg_log(PG_REPORT, "SQL command failed\n%s\n%s", query,
     140            0 :                            PQerrorMessage(conn));
     141            0 :                 PQclear(result);
     142            0 :                 PQfinish(conn);
     143            0 :                 printf(_("Failure, exiting\n"));
     144            0 :                 exit(1);
     145              :         }
     146              :         else
     147            0 :                 return result;
     148            0 : }
     149              : 
     150              : 
     151              : static void
     152            0 : stop_postmaster_atexit(void)
     153              : {
     154            0 :         stop_postmaster(true);
     155            0 : }
     156              : 
     157              : 
     158              : bool
     159            0 : start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error)
     160              : {
     161            0 :         char            cmd[MAXPGPATH * 4 + 1000];
     162            0 :         PGconn     *conn;
     163            0 :         bool            pg_ctl_return = false;
     164            0 :         char            socket_string[MAXPGPATH + 200];
     165            0 :         PQExpBufferData pgoptions;
     166              : 
     167              :         static bool exit_hook_registered = false;
     168              : 
     169            0 :         if (!exit_hook_registered)
     170              :         {
     171            0 :                 atexit(stop_postmaster_atexit);
     172            0 :                 exit_hook_registered = true;
     173            0 :         }
     174              : 
     175            0 :         socket_string[0] = '\0';
     176              : 
     177              : #if !defined(WIN32)
     178              :         /* prevent TCP/IP connections, restrict socket access */
     179            0 :         strcat(socket_string,
     180              :                    " -c listen_addresses='' -c unix_socket_permissions=0700");
     181              : 
     182              :         /* Have a sockdir?      Tell the postmaster. */
     183            0 :         if (cluster->sockdir)
     184            0 :                 snprintf(socket_string + strlen(socket_string),
     185            0 :                                  sizeof(socket_string) - strlen(socket_string),
     186              :                                  " -c %s='%s'",
     187            0 :                                  (GET_MAJOR_VERSION(cluster->major_version) <= 902) ?
     188              :                                  "unix_socket_directory" : "unix_socket_directories",
     189            0 :                                  cluster->sockdir);
     190              : #endif
     191              : 
     192            0 :         initPQExpBuffer(&pgoptions);
     193              : 
     194              :         /*
     195              :          * Construct a parameter string which is passed to the server process.
     196              :          *
     197              :          * Turn off durability requirements to improve object creation speed, and
     198              :          * we only modify the new cluster, so only use it there.  If there is a
     199              :          * crash, the new cluster has to be recreated anyway.  fsync=off is a big
     200              :          * win on ext4.
     201              :          */
     202            0 :         if (cluster == &new_cluster)
     203            0 :                 appendPQExpBufferStr(&pgoptions, " -c synchronous_commit=off -c fsync=off -c full_page_writes=off");
     204              : 
     205              :         /*
     206              :          * Use -b to disable autovacuum and logical replication launcher
     207              :          * (effective in PG17 or later for the latter).
     208              :          */
     209            0 :         snprintf(cmd, sizeof(cmd),
     210              :                          "\"%s/pg_ctl\" -w -l \"%s/%s\" -D \"%s\" -o \"-p %d -b%s %s%s\" start",
     211            0 :                          cluster->bindir,
     212            0 :                          log_opts.logdir,
     213            0 :                          SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
     214            0 :                          pgoptions.data,
     215            0 :                          cluster->pgopts ? cluster->pgopts : "", socket_string);
     216              : 
     217            0 :         termPQExpBuffer(&pgoptions);
     218              : 
     219              :         /*
     220              :          * Don't throw an error right away, let connecting throw the error because
     221              :          * it might supply a reason for the failure.
     222              :          */
     223            0 :         pg_ctl_return = exec_prog(SERVER_START_LOG_FILE,
     224              :         /* pass both file names if they differ */
     225              :                                                           (strcmp(SERVER_LOG_FILE,
     226              :                                                                           SERVER_START_LOG_FILE) != 0) ?
     227              :                                                           SERVER_LOG_FILE : NULL,
     228            0 :                                                           report_and_exit_on_error, false,
     229            0 :                                                           "%s", cmd);
     230              : 
     231              :         /* Did it fail and we are just testing if the server could be started? */
     232            0 :         if (!pg_ctl_return && !report_and_exit_on_error)
     233            0 :                 return false;
     234              : 
     235              :         /*
     236              :          * We set this here to make sure atexit() shuts down the server, but only
     237              :          * if we started the server successfully.  We do it before checking for
     238              :          * connectivity in case the server started but there is a connectivity
     239              :          * failure.  If pg_ctl did not return success, we will exit below.
     240              :          *
     241              :          * Pre-9.1 servers do not have PQping(), so we could be leaving the server
     242              :          * running if authentication was misconfigured, so someday we might went
     243              :          * to be more aggressive about doing server shutdowns even if pg_ctl
     244              :          * fails, but now (2013-08-14) it seems prudent to be cautious.  We don't
     245              :          * want to shutdown a server that might have been accidentally started
     246              :          * during the upgrade.
     247              :          */
     248            0 :         if (pg_ctl_return)
     249            0 :                 os_info.running_cluster = cluster;
     250              : 
     251              :         /*
     252              :          * pg_ctl -w might have failed because the server couldn't be started, or
     253              :          * there might have been a connection problem in _checking_ if the server
     254              :          * has started.  Therefore, even if pg_ctl failed, we continue and test
     255              :          * for connectivity in case we get a connection reason for the failure.
     256              :          */
     257            0 :         if ((conn = get_db_conn(cluster, "template1")) == NULL ||
     258            0 :                 PQstatus(conn) != CONNECTION_OK)
     259              :         {
     260            0 :                 pg_log(PG_REPORT, "\n%s", PQerrorMessage(conn));
     261            0 :                 if (conn)
     262            0 :                         PQfinish(conn);
     263            0 :                 if (cluster == &old_cluster)
     264            0 :                         pg_fatal("could not connect to source postmaster started with the command:\n"
     265              :                                          "%s",
     266            0 :                                          cmd);
     267              :                 else
     268            0 :                         pg_fatal("could not connect to target postmaster started with the command:\n"
     269              :                                          "%s",
     270            0 :                                          cmd);
     271              :         }
     272            0 :         PQfinish(conn);
     273              : 
     274              :         /*
     275              :          * If pg_ctl failed, and the connection didn't fail, and
     276              :          * report_and_exit_on_error is enabled, fail now.  This could happen if
     277              :          * the server was already running.
     278              :          */
     279            0 :         if (!pg_ctl_return)
     280              :         {
     281            0 :                 if (cluster == &old_cluster)
     282            0 :                         pg_fatal("pg_ctl failed to start the source server, or connection failed");
     283              :                 else
     284            0 :                         pg_fatal("pg_ctl failed to start the target server, or connection failed");
     285              :         }
     286              : 
     287            0 :         return true;
     288            0 : }
     289              : 
     290              : 
     291              : void
     292            0 : stop_postmaster(bool in_atexit)
     293              : {
     294            0 :         ClusterInfo *cluster;
     295              : 
     296            0 :         if (os_info.running_cluster == &old_cluster)
     297            0 :                 cluster = &old_cluster;
     298            0 :         else if (os_info.running_cluster == &new_cluster)
     299            0 :                 cluster = &new_cluster;
     300              :         else
     301            0 :                 return;                                 /* no cluster running */
     302              : 
     303            0 :         exec_prog(SERVER_STOP_LOG_FILE, NULL, !in_atexit, !in_atexit,
     304              :                           "\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" %s stop",
     305            0 :                           cluster->bindir, cluster->pgconfig,
     306            0 :                           cluster->pgopts ? cluster->pgopts : "",
     307            0 :                           in_atexit ? "-m fast" : "-m smart");
     308              : 
     309            0 :         os_info.running_cluster = NULL;
     310            0 : }
     311              : 
     312              : 
     313              : /*
     314              :  * check_pghost_envvar()
     315              :  *
     316              :  * Tests that PGHOST does not point to a non-local server
     317              :  */
     318              : void
     319            0 : check_pghost_envvar(void)
     320              : {
     321            0 :         PQconninfoOption *option;
     322            0 :         PQconninfoOption *start;
     323              : 
     324              :         /* Get valid libpq env vars from the PQconndefaults function */
     325              : 
     326            0 :         start = PQconndefaults();
     327              : 
     328            0 :         if (!start)
     329            0 :                 pg_fatal("out of memory");
     330              : 
     331            0 :         for (option = start; option->keyword != NULL; option++)
     332              :         {
     333            0 :                 if (option->envvar && (strcmp(option->envvar, "PGHOST") == 0 ||
     334            0 :                                                            strcmp(option->envvar, "PGHOSTADDR") == 0))
     335              :                 {
     336            0 :                         const char *value = getenv(option->envvar);
     337              : 
     338            0 :                         if (value && strlen(value) > 0 &&
     339              :                         /* check for 'local' host values */
     340            0 :                                 (strcmp(value, "localhost") != 0 && strcmp(value, "127.0.0.1") != 0 &&
     341            0 :                                  strcmp(value, "::1") != 0 && !is_unixsock_path(value)))
     342            0 :                                 pg_fatal("libpq environment variable %s has a non-local server value: %s",
     343            0 :                                                  option->envvar, value);
     344            0 :                 }
     345            0 :         }
     346              : 
     347              :         /* Free the memory that libpq allocated on our behalf */
     348            0 :         PQconninfoFree(start);
     349            0 : }
        

Generated by: LCOV version 2.3.2-1