PostgreSQL Source Code  git master
recovery_gen.c
Go to the documentation of this file.
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  */
24 {
25  PQconninfoOption *connOptions;
26  PQExpBufferData conninfo_buf;
27  char *escaped;
28  PQExpBuffer contents;
29 
30  Assert(pgconn != NULL);
31 
32  contents = createPQExpBuffer();
33  if (!contents)
34  {
35  pg_log_error("out of memory");
36  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  */
44  appendPQExpBufferStr(contents, "standby_mode = 'on'\n");
45 
46  connOptions = PQconninfo(pgconn);
47  if (connOptions == NULL)
48  {
49  pg_log_error("out of memory");
50  exit(1);
51  }
52 
53  initPQExpBuffer(&conninfo_buf);
54  for (PQconninfoOption *opt = connOptions; opt && opt->keyword; opt++)
55  {
56  /* Omit empty settings and those libpqwalreceiver overrides. */
57  if (strcmp(opt->keyword, "replication") == 0 ||
58  strcmp(opt->keyword, "dbname") == 0 ||
59  strcmp(opt->keyword, "fallback_application_name") == 0 ||
60  (opt->val == NULL) ||
61  (opt->val != NULL && opt->val[0] == '\0'))
62  continue;
63 
64  /* Separate key-value pairs with spaces */
65  if (conninfo_buf.len != 0)
66  appendPQExpBufferChar(&conninfo_buf, ' ');
67 
68  /*
69  * Write "keyword=value" pieces, the value string is escaped and/or
70  * quoted if necessary.
71  */
72  appendPQExpBuffer(&conninfo_buf, "%s=", opt->keyword);
73  appendConnStrVal(&conninfo_buf, opt->val);
74  }
75  if (PQExpBufferDataBroken(conninfo_buf))
76  {
77  pg_log_error("out of memory");
78  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  escaped = escape_quotes(conninfo_buf.data);
87  termPQExpBuffer(&conninfo_buf);
88  appendPQExpBuffer(contents, "primary_conninfo = '%s'\n", escaped);
89  free(escaped);
90 
91  if (replication_slot)
92  {
93  /* unescaped: ReplicationSlotValidateName allows [a-z0-9_] only */
94  appendPQExpBuffer(contents, "primary_slot_name = '%s'\n",
95  replication_slot);
96  }
97 
98  if (PQExpBufferBroken(contents))
99  {
100  pg_log_error("out of memory");
101  exit(1);
102  }
103 
104  PQconninfoFree(connOptions);
105 
106  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 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  use_recovery_conf =
127 
128  snprintf(filename, MAXPGPATH, "%s/%s", target_dir,
129  use_recovery_conf ? "recovery.conf" : "postgresql.auto.conf");
130 
131  cf = fopen(filename, use_recovery_conf ? "a" : "w");
132  if (cf == NULL)
133  {
134  pg_log_error("could not open file \"%s\": %m", filename);
135  exit(1);
136  }
137 
138  if (fwrite(contents->data, contents->len, 1, cf) != 1)
139  {
140  pg_log_error("could not write to file \"%s\": %m", filename);
141  exit(1);
142  }
143 
144  fclose(cf);
145 
146  if (!use_recovery_conf)
147  {
148  snprintf(filename, MAXPGPATH, "%s/%s", target_dir, "standby.signal");
149  cf = fopen(filename, "w");
150  if (cf == NULL)
151  {
152  pg_log_error("could not create file \"%s\": %m", filename);
153  exit(1);
154  }
155 
156  fclose(cf);
157  }
158 }
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 escape_quotes(const char *src)
166 {
167  char *result = escape_single_quotes_ascii(src);
168 
169  if (!result)
170  {
171  pg_log_error("out of memory");
172  exit(1);
173  }
174  return result;
175 }
static char * escape_quotes(const char *src)
Definition: recovery_gen.c:165
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:79
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
void WriteRecoveryConfig(PGconn *pgconn, char *target_dir, PQExpBuffer contents)
Definition: recovery_gen.c:117
void appendConnStrVal(PQExpBuffer buf, const char *str)
Definition: string_utils.c:545
#define MINIMUM_VERSION_FOR_RECOVERY_GUC
Definition: recovery_gen.h:21
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6607
char * escape_single_quotes_ascii(const char *src)
Definition: quotes.c:33
#define MAXPGPATH
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
void PQconninfoFree(PQconninfoOption *connOptions)
Definition: fe-connect.c:6449
PQconninfoOption * PQconninfo(PGconn *conn)
Definition: fe-connect.c:6408
PQExpBuffer GenerateRecoveryConfig(PGconn *pgconn, char *replication_slot)
Definition: recovery_gen.c:23
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:74
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
#define free(a)
Definition: header.h:65
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
#define Assert(condition)
Definition: c.h:733
#define PQExpBufferBroken(str)
Definition: pqexpbuffer.h:59
static char * filename
Definition: pg_dumpall.c:90
static char * replication_slot
Definition: pg_basebackup.c:99
#define snprintf
Definition: port.h:192
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92