LCOV - code coverage report
Current view: top level - src/fe_utils - recovery_gen.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 46 63 73.0 %
Date: 2019-11-15 22:06:47 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * recovery_gen.c
       4             :  *      Generator for recovery configuration
       5             :  *
       6             :  * Portions Copyright (c) 2011-2019, PostgreSQL Global Development Group
       7             :  *
       8             :  *-------------------------------------------------------------------------
       9             :  */
      10             : #include "postgres_fe.h"
      11             : 
      12             : #include "common/logging.h"
      13             : #include "fe_utils/recovery_gen.h"
      14             : #include "fe_utils/string_utils.h"
      15             : 
      16             : static char *escape_quotes(const char *src);
      17             : 
      18             : /*
      19             :  * Write recovery configuration contents into a fresh PQExpBuffer, and
      20             :  * return it.
      21             :  */
      22             : PQExpBuffer
      23          12 : GenerateRecoveryConfig(PGconn *pgconn, char *replication_slot)
      24             : {
      25             :     PQconninfoOption *connOptions;
      26             :     PQExpBufferData conninfo_buf;
      27             :     char       *escaped;
      28             :     PQExpBuffer contents;
      29             : 
      30             :     Assert(pgconn != NULL);
      31             : 
      32          12 :     contents = createPQExpBuffer();
      33          12 :     if (!contents)
      34             :     {
      35           0 :         pg_log_error("out of memory");
      36           0 :         exit(1);
      37             :     }
      38             : 
      39             :     /*
      40             :      * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
      41             :      * standby.signal to trigger a standby state at recovery.
      42             :      */
      43          12 :     if (PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
      44           0 :         appendPQExpBufferStr(contents, "standby_mode = 'on'\n");
      45             : 
      46          12 :     connOptions = PQconninfo(pgconn);
      47          12 :     if (connOptions == NULL)
      48             :     {
      49           0 :         pg_log_error("out of memory");
      50           0 :         exit(1);
      51             :     }
      52             : 
      53          12 :     initPQExpBuffer(&conninfo_buf);
      54         384 :     for (PQconninfoOption *opt = connOptions; opt && opt->keyword; opt++)
      55             :     {
      56             :         /* Omit empty settings and those libpqwalreceiver overrides. */
      57         732 :         if (strcmp(opt->keyword, "replication") == 0 ||
      58         708 :             strcmp(opt->keyword, "dbname") == 0 ||
      59         684 :             strcmp(opt->keyword, "fallback_application_name") == 0 ||
      60         480 :             (opt->val == NULL) ||
      61         288 :             (opt->val != NULL && opt->val[0] == '\0'))
      62         252 :             continue;
      63             : 
      64             :         /* Separate key-value pairs with spaces */
      65         120 :         if (conninfo_buf.len != 0)
      66         108 :             appendPQExpBufferChar(&conninfo_buf, ' ');
      67             : 
      68             :         /*
      69             :          * Write "keyword=value" pieces, the value string is escaped and/or
      70             :          * quoted if necessary.
      71             :          */
      72         120 :         appendPQExpBuffer(&conninfo_buf, "%s=", opt->keyword);
      73         120 :         appendConnStrVal(&conninfo_buf, opt->val);
      74             :     }
      75          12 :     if (PQExpBufferDataBroken(conninfo_buf))
      76             :     {
      77           0 :         pg_log_error("out of memory");
      78           0 :         exit(1);
      79             :     }
      80             : 
      81             :     /*
      82             :      * Escape the connection string, so that it can be put in the config file.
      83             :      * Note that this is different from the escaping of individual connection
      84             :      * options above!
      85             :      */
      86          12 :     escaped = escape_quotes(conninfo_buf.data);
      87          12 :     termPQExpBuffer(&conninfo_buf);
      88          12 :     appendPQExpBuffer(contents, "primary_conninfo = '%s'\n", escaped);
      89          12 :     free(escaped);
      90             : 
      91          12 :     if (replication_slot)
      92             :     {
      93             :         /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
      94           2 :         appendPQExpBuffer(contents, "primary_slot_name = '%s'\n",
      95             :                           replication_slot);
      96             :     }
      97             : 
      98          12 :     if (PQExpBufferBroken(contents))
      99             :     {
     100           0 :         pg_log_error("out of memory");
     101           0 :         exit(1);
     102             :     }
     103             : 
     104          12 :     PQconninfoFree(connOptions);
     105             : 
     106          12 :     return contents;
     107             : }
     108             : 
     109             : /*
     110             :  * Write the configuration file in the directory specified in target_dir,
     111             :  * with the contents already collected in memory appended.  Then write
     112             :  * the signal file into the target_dir.  If the server does not support
     113             :  * recovery parameters as GUCs, the signal file is not necessary, and
     114             :  * configuration is written to recovery.conf.
     115             :  */
     116             : void
     117          12 : WriteRecoveryConfig(PGconn *pgconn, char *target_dir, PQExpBuffer contents)
     118             : {
     119             :     char        filename[MAXPGPATH];
     120             :     FILE       *cf;
     121             :     bool        use_recovery_conf;
     122             : 
     123             :     Assert(pgconn != NULL);
     124             : 
     125          12 :     use_recovery_conf =
     126          12 :         PQserverVersion(pgconn) < MINIMUM_VERSION_FOR_RECOVERY_GUC;
     127             : 
     128          12 :     snprintf(filename, MAXPGPATH, "%s/%s", target_dir,
     129             :              use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf");
     130             : 
     131          12 :     cf = fopen(filename, use_recovery_conf ? "a" : "w");
     132          12 :     if (cf == NULL)
     133             :     {
     134           0 :         pg_log_error("could not open file \"%s\": %m", filename);
     135           0 :         exit(1);
     136             :     }
     137             : 
     138          12 :     if (fwrite(contents->data, contents->len, 1, cf) != 1)
     139             :     {
     140           0 :         pg_log_error("could not write to file \"%s\": %m", filename);
     141           0 :         exit(1);
     142             :     }
     143             : 
     144          12 :     fclose(cf);
     145             : 
     146          12 :     if (!use_recovery_conf)
     147             :     {
     148          12 :         snprintf(filename, MAXPGPATH, "%s/%s", target_dir, "standby.signal");
     149          12 :         cf = fopen(filename, "w");
     150          12 :         if (cf == NULL)
     151             :         {
     152           0 :             pg_log_error("could not create file \"%s\": %m", filename);
     153           0 :             exit(1);
     154             :         }
     155             : 
     156          12 :         fclose(cf);
     157             :     }
     158          12 : }
     159             : 
     160             : /*
     161             :  * Escape a string so that it can be used as a value in a key-value pair
     162             :  * a configuration file.
     163             :  */
     164             : static char *
     165          12 : escape_quotes(const char *src)
     166             : {
     167          12 :     char       *result = escape_single_quotes_ascii(src);
     168             : 
     169          12 :     if (!result)
     170             :     {
     171           0 :         pg_log_error("out of memory");
     172           0 :         exit(1);
     173             :     }
     174          12 :     return result;
     175             : }

Generated by: LCOV version 1.13