Skip to content

Commit 9a29e91

Browse files
committed
[Issue #221] WIP
1 parent 6d98d46 commit 9a29e91

File tree

7 files changed

+153
-30
lines changed

7 files changed

+153
-30
lines changed

Diff for: src/catalog.c

+7
Original file line numberDiff line numberDiff line change
@@ -2012,6 +2012,13 @@ readBackupControlFile(const char *path)
20122012
return NULL;
20132013
}
20142014

2015+
if (parsed_options == -1)
2016+
{
2017+
elog(WARNING, "Failed to parse control file \"%s\"", path);
2018+
pgBackupFree(backup);
2019+
return NULL;
2020+
}
2021+
20152022
if (backup->start_time == 0)
20162023
{
20172024
elog(WARNING, "Invalid ID/start-time, control file \"%s\" is corrupted", path);

Diff for: src/configure.c

+7
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,13 @@ readInstanceConfigFile(const char *instance_name)
621621
return NULL;
622622
}
623623

624+
if (parsed_options == -1)
625+
{
626+
elog(WARNING, "Failed to parse control file \"%s\"", path);
627+
pfree(instance);
628+
return NULL;
629+
}
630+
624631
if (log_level_console)
625632
instance->logger.log_level_console = parse_log_level(log_level_console);
626633

Diff for: src/pg_probackup.h

+3
Original file line numberDiff line numberDiff line change
@@ -1044,4 +1044,7 @@ extern void get_header_errormsg(Page page, char **errormsg);
10441044
extern void get_checksum_errormsg(Page page, char **errormsg,
10451045
BlockNumber absolute_blkno);
10461046

1047+
extern char *escape_single_quotes(const char *src);
1048+
extern char *escapeConnectionParameter(const char *src);
1049+
10471050
#endif /* PG_PROBACKUP_H */

Diff for: src/restore.c

+23-2
Original file line numberDiff line numberDiff line change
@@ -1069,16 +1069,37 @@ create_recovery_conf(time_t backup_id,
10691069

10701070
if (params->restore_as_replica)
10711071
{
1072+
char *primary_conninfo = NULL;
1073+
char *escaped = NULL;
1074+
char *connstr = NULL;
10721075
fio_fprintf(fp, "\n## standby settings\n");
10731076
/* standby_mode was removed in PG12 */
10741077
#if PG_VERSION_NUM < 120000
10751078
fio_fprintf(fp, "standby_mode = 'on'\n");
10761079
#endif
10771080

10781081
if (params->primary_conninfo)
1079-
fio_fprintf(fp, "primary_conninfo = '%s'\n", params->primary_conninfo);
1082+
{
1083+
// fio_fprintf(fp, "primary_conninfo = '%s'\n", params->primary_conninfo);
1084+
primary_conninfo = escape_single_quotes(params->primary_conninfo);
1085+
}
10801086
else if (backup->primary_conninfo)
1081-
fio_fprintf(fp, "primary_conninfo = '%s'\n", backup->primary_conninfo);
1087+
{
1088+
// fio_fprintf(fp, "primary_conninfo = '%s'\n", backup->primary_conninfo);
1089+
primary_conninfo = escape_single_quotes(backup->primary_conninfo);
1090+
}
1091+
1092+
escaped = escapeConnectionParameter(primary_conninfo);
1093+
connstr = escape_single_quotes(escaped);
1094+
1095+
// pg_free(escaped);
1096+
// pg_free(connstr);
1097+
1098+
fio_fprintf(fp, "primary_conninfo = '%s'\n", connstr);
1099+
pg_free(primary_conninfo);
1100+
pg_free(escaped);
1101+
pg_free(connstr);
1102+
10821103

10831104
if (params->primary_slot_name != NULL)
10841105
fio_fprintf(fp, "primary_slot_name = '%s'\n", params->primary_slot_name);

Diff for: src/show.c

+8
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,17 @@ print_backup_json_object(PQExpBuffer buf, pgBackup *backup)
420420
}
421421

422422
if (backup->primary_conninfo)
423+
{
424+
// char *escaped = escapeConnectionParameter(backup->primary_conninfo);
425+
// char *connstr = escape_single_quotes(escaped);
426+
423427
json_add_value(buf, "primary_conninfo", backup->primary_conninfo,
424428
json_level, true);
425429

430+
// pg_free(escaped);
431+
// pg_free(connstr);
432+
}
433+
426434
if (backup->external_dir_str)
427435
json_add_value(buf, "external-dirs", backup->external_dir_str,
428436
json_level, true);

Diff for: src/utils/configuration.c

+52-22
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ skip_space(const char *str, const char *line)
302302
return str;
303303
}
304304

305+
/*
306+
* TODO:
307+
* user provides: -U "Mr. Mac'Nuggets"
308+
* to recovery.conf in primary_conninfo must be saved: user=''Mr. Mac\\''Nuggets''
309+
*/
305310
static const char *
306311
get_next_token(const char *src, char *dst, const char *line)
307312
{
@@ -313,22 +318,27 @@ get_next_token(const char *src, char *dst, const char *line)
313318
return NULL;
314319

315320
/* parse quoted string */
316-
if (*s == '\'')
321+
if (*s == '\'' || *s == '"')
317322
{
318323
s++;
319324
for (i = 0, j = 0; s[i] != '\0'; i++)
320325
{
321-
if (s[i] == '\'')
326+
/* If the current token is a single quote or a double quote and
327+
* the next token is string terminator, then there is no point in going futher
328+
*/
329+
if ((s[i] == '\'' || s[i] == '"') &&
330+
s[i+1] == '\0')
322331
{
323332
i++;
324-
/* doubled quote becomes just one quote */
325-
if (s[i] == '\'')
326-
dst[j] = s[i];
327-
else
328-
break;
333+
break;
329334
}
330-
else
331-
dst[j] = s[i];
335+
336+
/* doubled quote becomes just one quote */
337+
if (s[i] == '\'' && s[i+1] == '\'')
338+
i++;
339+
340+
/* simple token */
341+
dst[j] = s[i];
332342
j++;
333343
}
334344
}
@@ -342,7 +352,13 @@ get_next_token(const char *src, char *dst, const char *line)
342352
return s + i;
343353
}
344354

345-
static bool
355+
/* Return codes:
356+
* 0 - PARSED pair
357+
* 1 - SKIP
358+
* 2 - ERROR
359+
*/
360+
361+
static int
346362
parse_pair(const char buffer[], char key[], char value[])
347363
{
348364
const char *start;
@@ -355,16 +371,20 @@ parse_pair(const char buffer[], char key[], char value[])
355371
*/
356372
start = buffer;
357373
if ((start = skip_space(start, buffer)) == NULL)
358-
return false;
374+
return 1;
359375

360376
end = start + strcspn(start, "=# \n\r\t\v");
361377

362378
/* skip blank buffer */
363379
if (end - start <= 0)
364380
{
365381
if (*start == '=')
366-
elog(ERROR, "Syntax error in \"%s\"", buffer);
367-
return false;
382+
{
383+
elog(WARNING, "Syntax error in \"%s\"", buffer);
384+
return 2;
385+
}
386+
387+
return 1;
368388
}
369389

370390
/* key found */
@@ -373,12 +393,12 @@ parse_pair(const char buffer[], char key[], char value[])
373393

374394
/* find key and value split char */
375395
if ((start = skip_space(end, buffer)) == NULL)
376-
return false;
396+
return 1;
377397

378398
if (*start != '=')
379399
{
380-
elog(ERROR, "Syntax error in \"%s\"", buffer);
381-
return false;
400+
elog(WARNING, "Syntax error in \"%s\"", buffer);
401+
return 2;
382402
}
383403

384404
start++;
@@ -387,18 +407,18 @@ parse_pair(const char buffer[], char key[], char value[])
387407
* parse value
388408
*/
389409
if ((end = get_next_token(start, value, buffer)) == NULL)
390-
return false;
410+
return 1;
391411

392412
if ((start = skip_space(end, buffer)) == NULL)
393-
return false;
413+
return 1;
394414

395415
if (*start != '\0' && *start != '#')
396416
{
397-
elog(ERROR, "Syntax error in \"%s\"", buffer);
398-
return false;
417+
elog(WARNING, "Syntax error in \"%s\"", buffer);
418+
return 2;
399419
}
400420

401-
return true;
421+
return 0;
402422
}
403423

404424
/*
@@ -484,6 +504,8 @@ config_get_opt(int argc, char **argv, ConfigOption cmd_options[],
484504
/*
485505
* Get configuration from configuration file.
486506
* Return number of parsed options.
507+
*
508+
* -1 means that error was encountered
487509
*/
488510
int
489511
config_read_opt(const char *path, ConfigOption options[], int elevel,
@@ -503,12 +525,15 @@ config_read_opt(const char *path, ConfigOption options[], int elevel,
503525

504526
while (fgets(buf, lengthof(buf), fp))
505527
{
528+
int rc;
506529
size_t i;
507530

508531
for (i = strlen(buf); i > 0 && IsSpace(buf[i - 1]); i--)
509532
buf[i - 1] = '\0';
510533

511-
if (parse_pair(buf, key, value))
534+
rc = parse_pair(buf, key, value);
535+
536+
if (rc == 0)
512537
{
513538
for (i = 0; options[i].type; i++)
514539
{
@@ -531,6 +556,11 @@ config_read_opt(const char *path, ConfigOption options[], int elevel,
531556
if (strict && !options[i].type)
532557
elog(elevel, "Invalid option \"%s\" in file \"%s\"", key, path);
533558
}
559+
else if (rc == 2)
560+
{
561+
elog(elevel, "Failed to parse string \"%s\" in file \"%s\"", buf, path);
562+
return -1;
563+
}
534564
}
535565

536566
if (ferror(fp))

Diff for: src/utils/pgut.c

+53-6
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ prompt_for_password(const char *username)
101101
*
102102
* The returned string is malloc'd. Return NULL on out-of-memory.
103103
*/
104-
static char *
104+
char *
105105
escapeConnectionParameter(const char *src)
106106
{
107107
bool need_quotes = false;
@@ -156,6 +156,47 @@ escapeConnectionParameter(const char *src)
156156
return dstbuf;
157157
}
158158

159+
/*
160+
* Escape (by doubling) any single quotes or backslashes in given string
161+
*
162+
* Note: this is used to process postgresql.conf entries and to quote
163+
* string literals in pg_basebackup for creating recovery.conf.
164+
* Since postgresql.conf strings are defined to treat backslashes as escapes,
165+
* we have to double backslashes here.
166+
*
167+
* Since this function is only used for parsing or creating configuration
168+
* files, we do not care about encoding considerations.
169+
*
170+
* Returns a malloced() string that it's the responsibility of the caller
171+
* to free.
172+
*/
173+
char *
174+
escape_single_quotes(const char *src)
175+
{
176+
int len = strlen(src),
177+
i,
178+
j;
179+
char *result = malloc(len * 2 + 1);
180+
181+
if (!result)
182+
return NULL;
183+
184+
for (i = 0, j = 0; i < len; i++)
185+
{
186+
// if (SQL_STR_DOUBLE(src[i], true))
187+
// result[j++] = src[i];
188+
if (src[i] == '\'')
189+
result[j++] = src[i];
190+
else if (src[i] == '\\')
191+
result[j++] = src[i];
192+
193+
result[j++] = src[i];
194+
// result[j++] = src[i];
195+
}
196+
result[j] = '\0';
197+
return result;
198+
}
199+
159200
/* Construct a connection string for possible future use in recovery.conf */
160201
char *
161202
pgut_get_conninfo_string(PGconn *conn)
@@ -165,7 +206,7 @@ pgut_get_conninfo_string(PGconn *conn)
165206
PQExpBuffer buf = createPQExpBuffer();
166207
char *connstr;
167208
bool firstkeyword = true;
168-
char *escaped;
209+
char *escaped = NULL;
169210

170211
connOptions = PQconninfo(conn);
171212
if (connOptions == NULL)
@@ -198,12 +239,18 @@ pgut_get_conninfo_string(PGconn *conn)
198239

199240
firstkeyword = false;
200241

201-
escaped = escapeConnectionParameter(option->val);
202-
appendPQExpBuffer(buf, "%s=%s", option->keyword, escaped);
203-
free(escaped);
242+
// escaped = escapeConnectionParameter(option->val);
243+
appendPQExpBuffer(buf, "%s=%s", option->keyword, option->val);
244+
pg_free(escaped);
204245
}
205246

206-
connstr = pg_strdup(buf->data);
247+
// elog(INFO, "CONNSTR: %s", buf->data);
248+
// connstr = escape_single_quotes(buf->data);
249+
250+
connstr = pgut_strdup(buf->data);
251+
252+
elog(INFO, "CONNSTR2: %s", connstr);
253+
207254
destroyPQExpBuffer(buf);
208255
return connstr;
209256
}

0 commit comments

Comments
 (0)