LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - server.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 79.6 % 113 90
Test Date: 2026-07-16 11:17:59 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 59.5 % 74 44

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

Generated by: LCOV version 2.0-1