Skip to content

Commit 81fea7b

Browse files
AndersAstrandjeltz
andcommitted
PG-1862 Use single argument for wrapped command
Use a single argument for the wrapped command in the archivation wrappers. Instead of giving all of the arguments of the command separately and trying to figure out which one should be replaced by the path to the unencrypted WAL segment, we take a single argument and do % parameter replacement similar to what postgres does with archive_command and restore_command. This also mean that we can simplify by using system() instead of exec(). Co-authored-by: Andreas Karlsson <andreas.karlsson@percona.com>
1 parent 8d1b4f8 commit 81fea7b

File tree

3 files changed

+73
-85
lines changed

3 files changed

+73
-85
lines changed

contrib/pg_tde/src/bin/pg_tde_archive_decrypt.c

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
#include "postgres_fe.h"
22

3-
#include <fcntl.h>
4-
#include <sys/wait.h>
5-
#include <unistd.h>
6-
73
#include "access/xlog_internal.h"
84
#include "access/xlog_smgr.h"
95
#include "common/logging.h"
6+
#include "common/percentrepl.h"
107

118
#include "access/pg_tde_fe_init.h"
129
#include "access/pg_tde_xlog_smgr.h"
@@ -116,26 +113,38 @@ write_decrypted_segment(const char *segpath, const char *segname, const char *tm
116113
static void
117114
usage(const char *progname)
118115
{
119-
printf(_("%s wraps an archive command to make it archive unencrypted WAL.\n\n"), progname);
120-
printf(_("Usage:\n %s %%p <archive command>\n\n"), progname);
121-
printf(_("Options:\n"));
122-
printf(_(" -V, --version output version information, then exit\n"));
123-
printf(_(" -?, --help show this help, then exit\n"));
116+
printf(_("%s wraps an archive command to give the command unencrypted WAL.\n\n"), progname);
117+
printf(_("Usage:\n"));
118+
printf(_(" %s [OPTION]\n"), progname);
119+
printf(_(" %s SOURCE-PATH ARCHIVE-COMMAND\n"), progname);
120+
printf(_("\nOptions:\n"));
121+
printf(_(" -V, --version output version information, then exit\n"));
122+
printf(_(" -?, --help show this help, then exit\n"));
123+
printf(_(" SOURCE-PATH path of the source WAL segment to decrypt\n"));
124+
printf(_(" ARCHIVE-COMMAND archive command to wrap, %%d will be replaced with the\n"
125+
" absolute path of the decrypted WAL segment.\n"));
126+
printf(_("\n"));
127+
printf(_("Note that any %%d parameter in ARCHIVE-COMMAND will have to be escaped as\n"
128+
"%%%%d if used as archive_command in postgresql.conf.\n"
129+
"e.g.\n"
130+
" archive_command='%s %%p \"cp %%%%d /mnt/server/archivedir/%%f\"'\n"
131+
"or\n"
132+
" archive_command='%s %%p \"pgbackrest --stanza=your_stanza archive-push %%%%d\"'\n"
133+
"In these examples %%f and %%p will be replaced as usual by PostgreSQL before\n"
134+
"%s is called.\n\n"), progname, progname, progname);
124135
}
125136

126137
int
127138
main(int argc, char *argv[])
128139
{
129140
const char *progname;
130141
char *sourcepath;
142+
char *command;
131143
char *sep;
132144
char *sourcename;
133145
char tmpdir[MAXPGPATH] = TMPFS_DIRECTORY "/pg_tde_archiveXXXXXX";
134146
char tmppath[MAXPGPATH];
135147
bool issegment;
136-
pid_t child;
137-
int status;
138-
int r;
139148

140149
pg_logging_init(argv[0]);
141150
progname = get_progname(argv[0]);
@@ -154,14 +163,15 @@ main(int argc, char *argv[])
154163
}
155164
}
156165

157-
if (argc < 3)
166+
if (argc != 3)
158167
{
159-
pg_log_error("too few arguments");
168+
pg_log_error("wrong number of arguments, 2 expected");
160169
pg_log_error_detail("Try \"%s --help\" for more information.", progname);
161170
exit(1);
162171
}
163172

164173
sourcepath = argv[1];
174+
command = argv[2];
165175

166176
pg_tde_fe_init("pg_tde");
167177
TDEXLogSmgrInit();
@@ -186,35 +196,19 @@ main(int argc, char *argv[])
186196
s = stpcpy(s, "/");
187197
stpcpy(s, sourcename);
188198

189-
for (int i = 2; i < argc; i++)
190-
if (strcmp(sourcepath, argv[i]) == 0)
191-
argv[i] = tmppath;
199+
command = replace_percent_placeholders(command,
200+
"ARCHIVE-COMMAND", "d",
201+
tmppath);
192202

193203
write_decrypted_segment(sourcepath, sourcename, tmppath);
194204
}
205+
else
206+
command = replace_percent_placeholders(command,
207+
"ARCHIVE-COMMAND", "d",
208+
sourcepath);
195209

196-
child = fork();
197-
if (child == 0)
198-
{
199-
if (execvp(argv[2], argv + 2) < 0)
200-
pg_fatal("exec failed: %m");
201-
}
202-
else if (child < 0)
203-
pg_fatal("could not create background process: %m");
204-
205-
r = waitpid(child, &status, 0);
206-
if (r == (pid_t) -1)
207-
pg_fatal("could not wait for child process: %m");
208-
if (r != child)
209-
pg_fatal("child %d died, expected %d", (int) r, (int) child);
210-
if (status != 0)
211-
{
212-
char *reason = wait_result_to_str(status);
213-
214-
pg_fatal("%s", reason);
215-
/* keep lsan happy */
216-
free(reason);
217-
}
210+
if (system(command) != 0)
211+
pg_fatal("ARCHIVE-COMMAND \"%s\" failed: %m", command);
218212

219213
if (issegment)
220214
{

contrib/pg_tde/src/bin/pg_tde_restore_encrypt.c

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
#include "postgres_fe.h"
22

3-
#include <fcntl.h>
4-
#include <sys/wait.h>
5-
#include <unistd.h>
6-
73
#include "access/xlog_internal.h"
84
#include "access/xlog_smgr.h"
95
#include "common/logging.h"
6+
#include "common/percentrepl.h"
107

118
#include "access/pg_tde_fe_init.h"
129
#include "access/pg_tde_xlog_smgr.h"
@@ -110,27 +107,38 @@ write_encrypted_segment(const char *segpath, const char *segname, const char *tm
110107
static void
111108
usage(const char *progname)
112109
{
113-
printf(_("%s wraps a restore command to make it write encrypted WAL to pg_wal.\n\n"), progname);
114-
printf(_("Usage:\n %s %%f %%p <restore command>\n\n"), progname);
115-
printf(_("Options:\n"));
116-
printf(_(" -V, --version output version information, then exit\n"));
117-
printf(_(" -?, --help show this help, then exit\n"));
110+
printf(_("%s wraps a restore command to encrypt its returned WAL.\n\n"), progname);
111+
printf(_("Usage:\n"));
112+
printf(_(" %s [OPTION]\n"), progname);
113+
printf(_(" %s DEST-PATH RESTORE-COMMAND\n"), progname);
114+
printf(_("\nOptions:\n"));
115+
printf(_(" -V, --version output version information, then exit\n"));
116+
printf(_(" -?, --help show this help, then exit\n"));
117+
printf(_(" DEST-PATH path where the encrypted WAL segment should be written\n"));
118+
printf(_(" RESTORE-COMMAND restore command to wrap, %%d will be replaced with the\n"
119+
" path where it should write the unencrypted WAL segment\n"));
120+
printf(_("\n"));
121+
printf(_("Note that any %%d parameter in RESTORE-COMMAND will have to be escaped as\n"
122+
"%%%%d if used as restore_command in postgresql.conf.\n"
123+
"e.g.\n"
124+
" restore_command='%s %%p \"cp /mnt/server/archivedir/%%f %%%%d\"'\n"
125+
"or\n"
126+
" restore_command='%s %%p \"pgbackrest --stanza=your_stanza archive-get %%f \\\"%%%%d\\\"\"'\n"
127+
"In these examples %%f and %%p will be replaced as usual by PostgreSQL before\n"
128+
"%s is called.\n\n"), progname, progname, progname);
118129
}
119130

120131
int
121132
main(int argc, char *argv[])
122133
{
123134
const char *progname;
124-
char *sourcename;
135+
char *command;
125136
char *targetpath;
126137
char *sep;
127138
char *targetname;
128139
char tmpdir[MAXPGPATH] = TMPFS_DIRECTORY "/pg_tde_restoreXXXXXX";
129140
char tmppath[MAXPGPATH];
130141
bool issegment;
131-
pid_t child;
132-
int status;
133-
int r;
134142

135143
pg_logging_init(argv[0]);
136144
progname = get_progname(argv[0]);
@@ -149,15 +157,15 @@ main(int argc, char *argv[])
149157
}
150158
}
151159

152-
if (argc < 4)
160+
if (argc != 3)
153161
{
154-
pg_log_error("too few arguments");
162+
pg_log_error("wrong number of arguments, 2 expected");
155163
pg_log_error_detail("Try \"%s --help\" for more information.", progname);
156164
exit(1);
157165
}
158166

159-
sourcename = argv[1];
160-
targetpath = argv[2];
167+
targetpath = argv[1];
168+
command = argv[2];
161169

162170
pg_tde_fe_init("pg_tde");
163171
TDEXLogSmgrInit();
@@ -169,7 +177,7 @@ main(int argc, char *argv[])
169177
else
170178
targetname = targetpath;
171179

172-
issegment = is_segment(sourcename);
180+
issegment = is_segment(targetname);
173181

174182
if (issegment)
175183
{
@@ -182,37 +190,21 @@ main(int argc, char *argv[])
182190
s = stpcpy(s, "/");
183191
stpcpy(s, targetname);
184192

185-
for (int i = 2; i < argc; i++)
186-
if (strcmp(targetpath, argv[i]) == 0)
187-
argv[i] = tmppath;
188-
}
189-
190-
child = fork();
191-
if (child == 0)
192-
{
193-
if (execvp(argv[3], argv + 3) < 0)
194-
pg_fatal("exec failed: %m");
193+
command = replace_percent_placeholders(command,
194+
"RESTORE-COMMAND", "d",
195+
tmppath);
195196
}
196-
else if (child < 0)
197-
pg_fatal("could not create background process: %m");
198-
199-
r = waitpid(child, &status, 0);
200-
if (r == (pid_t) -1)
201-
pg_fatal("could not wait for child process: %m");
202-
if (r != child)
203-
pg_fatal("child %d died, expected %d", (int) r, (int) child);
204-
if (status != 0)
205-
{
206-
char *reason = wait_result_to_str(status);
197+
else
198+
command = replace_percent_placeholders(command,
199+
"RESTORE-COMMAND", "d",
200+
targetpath);
207201

208-
pg_fatal("%s", reason);
209-
/* keep lsan happy */
210-
free(reason);
211-
}
202+
if (system(command) != 0)
203+
pg_fatal("RESTORE-COMMAND \"%s\" failed: %m", command);
212204

213205
if (issegment)
214206
{
215-
write_encrypted_segment(targetpath, sourcename, tmppath);
207+
write_encrypted_segment(targetpath, targetname, tmppath);
216208

217209
if (unlink(tmppath) < 0)
218210
pg_log_warning("could not remove file \"%s\": %m", tmppath);

contrib/pg_tde/t/wal_archiving.pl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
$primary->append_conf('postgresql.conf', "checkpoint_timeout = 1h");
2222
$primary->append_conf('postgresql.conf', "archive_mode = on");
2323
$primary->append_conf('postgresql.conf',
24-
"archive_command = 'pg_tde_archive_decrypt %p cp %p $archive_dir/%f'");
24+
"archive_command = 'pg_tde_archive_decrypt %p \"cp %%d $archive_dir/%f\"'"
25+
);
2526
$primary->start;
2627

2728
$primary->safe_psql('postgres', "CREATE EXTENSION pg_tde;");
@@ -75,7 +76,8 @@
7576
my $replica = PostgreSQL::Test::Cluster->new('replica');
7677
$replica->init_from_backup($primary, 'backup');
7778
$replica->append_conf('postgresql.conf',
78-
"restore_command = 'pg_tde_restore_encrypt %f %p cp $archive_dir/%f %p'");
79+
"restore_command = 'pg_tde_restore_encrypt %p \"cp $archive_dir/%f %%d\"'"
80+
);
7981
$replica->append_conf('postgresql.conf', "recovery_target_action = promote");
8082
$replica->set_recovery_mode;
8183
$replica->start;

0 commit comments

Comments
 (0)