Skip to content

Commit f508287

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(). We also clean up usage instructions and make the two wrappers more symmetrical by requiring the same parameters. Co-authored-by: Andreas Karlsson <[email protected]>
1 parent db41dae commit f508287

File tree

3 files changed

+76
-83
lines changed

3 files changed

+76
-83
lines changed

contrib/pg_tde/src/bin/pg_tde_archive_decrypt.c

Lines changed: 38 additions & 42 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,39 @@ 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 DEST-NAME 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(_(" DEST-NAME name of the WAL file to send to archive\n"));
124+
printf(_(" SOURCE-PATH path of the source WAL segment to decrypt\n"));
125+
printf(_(" ARCHIVE-COMMAND archive command to wrap, %%p will be replaced with the\n"
126+
" absolute path of the decrypted WAL segment, %%f with the name\n"));
127+
printf(_("\n"));
128+
printf(_("Note that any %%f or %%p parameter in ARCHIVE-COMMAND will have to be escaped\n"
129+
"as %%%%f or %%%%p respectively if used as archive_command in postgresql.conf.\n"
130+
"e.g.\n"
131+
" archive_command='%s %%f %%p \"cp %%%%p /mnt/server/archivedir/%%%%f\"'\n"
132+
"or\n"
133+
" archive_command='%s %%f %%p \"pgbackrest --stanza=your_stanza archive-push %%%%p\"'\n"
134+
"\n"), progname, progname);
124135
}
125136

126137
int
127138
main(int argc, char *argv[])
128139
{
129140
const char *progname;
141+
char *targetname;
130142
char *sourcepath;
143+
char *command;
131144
char *sep;
132145
char *sourcename;
133146
char tmpdir[MAXPGPATH] = TMPFS_DIRECTORY "/pg_tde_archiveXXXXXX";
134147
char tmppath[MAXPGPATH];
135148
bool issegment;
136-
pid_t child;
137-
int status;
138-
int r;
139149

140150
pg_logging_init(argv[0]);
141151
progname = get_progname(argv[0]);
@@ -154,14 +164,16 @@ main(int argc, char *argv[])
154164
}
155165
}
156166

157-
if (argc < 3)
167+
if (argc != 4)
158168
{
159-
pg_log_error("too few arguments");
169+
pg_log_error("wrong number of arguments, 3 expected");
160170
pg_log_error_detail("Try \"%s --help\" for more information.", progname);
161171
exit(1);
162172
}
163173

164-
sourcepath = argv[1];
174+
targetname = argv[1];
175+
sourcepath = argv[2];
176+
command = argv[3];
165177

166178
pg_tde_fe_init("pg_tde");
167179
TDEXLogSmgrInit();
@@ -173,7 +185,7 @@ main(int argc, char *argv[])
173185
else
174186
sourcename = sourcepath;
175187

176-
issegment = is_segment(sourcename);
188+
issegment = is_segment(targetname);
177189

178190
if (issegment)
179191
{
@@ -186,35 +198,19 @@ main(int argc, char *argv[])
186198
s = stpcpy(s, "/");
187199
stpcpy(s, sourcename);
188200

189-
for (int i = 2; i < argc; i++)
190-
if (strcmp(sourcepath, argv[i]) == 0)
191-
argv[i] = tmppath;
192-
193-
write_decrypted_segment(sourcepath, sourcename, tmppath);
194-
}
201+
command = replace_percent_placeholders(command,
202+
"ARCHIVE-COMMAND", "fp",
203+
targetname, tmppath);
195204

196-
child = fork();
197-
if (child == 0)
198-
{
199-
if (execvp(argv[2], argv + 2) < 0)
200-
pg_fatal("exec failed: %m");
205+
write_decrypted_segment(sourcepath, targetname, tmppath);
201206
}
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);
207+
else
208+
command = replace_percent_placeholders(command,
209+
"ARCHIVE-COMMAND", "fp",
210+
targetname, sourcepath);
213211

214-
pg_fatal("%s", reason);
215-
/* keep lsan happy */
216-
free(reason);
217-
}
212+
if (system(command) != 0)
213+
pg_fatal("ARCHIVE-COMMAND \"%s\" failed: %m", command);
218214

219215
if (issegment)
220216
{

contrib/pg_tde/src/bin/pg_tde_restore_encrypt.c

Lines changed: 34 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"
@@ -110,11 +107,26 @@ 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 SOURCE-NAME 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(_(" SOURCE-NAME name of the WAL file to retrieve from archive\n"));
118+
printf(_(" DEST-PATH path where the encrypted WAL segment should be written\n"));
119+
printf(_(" RESTORE-COMMAND restore command to wrap, %%p will be replaced with the path\n"
120+
" where it should write the unencrypted WAL segment, %%f with\n"
121+
" the WAL segment's name\n"));
122+
printf(_("\n"));
123+
printf(_("Note that any %%f or %%p parameter in RESTORE-COMMAND will have to be escaped\n"
124+
"as %%%%f or %%%%p respectively if used as restore_command in postgresql.conf.\n"
125+
"e.g.\n"
126+
" restore_command='%s %%f %%p \"cp /mnt/server/archivedir/%%%%f %%%%p\"'\n"
127+
"or\n"
128+
" restore_command='%s %%f %%p \"pgbackrest --stanza=your_stanza archive-get %%%%f \\\"%%%%p\\\"\"'\n"
129+
"\n"), progname, progname);
118130
}
119131

120132
int
@@ -123,14 +135,12 @@ main(int argc, char *argv[])
123135
const char *progname;
124136
char *sourcename;
125137
char *targetpath;
138+
char *command;
126139
char *sep;
127140
char *targetname;
128141
char tmpdir[MAXPGPATH] = TMPFS_DIRECTORY "/pg_tde_restoreXXXXXX";
129142
char tmppath[MAXPGPATH];
130143
bool issegment;
131-
pid_t child;
132-
int status;
133-
int r;
134144

135145
pg_logging_init(argv[0]);
136146
progname = get_progname(argv[0]);
@@ -149,15 +159,16 @@ main(int argc, char *argv[])
149159
}
150160
}
151161

152-
if (argc < 4)
162+
if (argc != 4)
153163
{
154-
pg_log_error("too few arguments");
164+
pg_log_error("wrong number of arguments, 3 expected");
155165
pg_log_error_detail("Try \"%s --help\" for more information.", progname);
156166
exit(1);
157167
}
158168

159169
sourcename = argv[1];
160170
targetpath = argv[2];
171+
command = argv[3];
161172

162173
pg_tde_fe_init("pg_tde");
163174
TDEXLogSmgrInit();
@@ -182,33 +193,17 @@ main(int argc, char *argv[])
182193
s = stpcpy(s, "/");
183194
stpcpy(s, targetname);
184195

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");
196+
command = replace_percent_placeholders(command,
197+
"RESTORE-COMMAND", "fp",
198+
sourcename, tmppath);
195199
}
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);
200+
else
201+
command = replace_percent_placeholders(command,
202+
"RESTORE-COMMAND", "fp",
203+
sourcename, targetpath);
207204

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

213208
if (issegment)
214209
{

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 %f %p \"cp %%p $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 %f %p \"cp $archive_dir/%%f %%p\"'"
80+
);
7981
$replica->append_conf('postgresql.conf', "recovery_target_action = promote");
8082
$replica->set_recovery_mode;
8183
$replica->start;

0 commit comments

Comments
 (0)