Skip to content

Commit 42354b7

Browse files
AndersAstrandjeltz
andcommitted
Use a single argument for archive/restore commands
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 <[email protected]>
1 parent 8d1b4f8 commit 42354b7

File tree

3 files changed

+71
-85
lines changed

3 files changed

+71
-85
lines changed

contrib/pg_tde/src/bin/pg_tde_archive_decrypt.c

Lines changed: 32 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,37 @@ 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" "e.g.\n"
129+
" archive_command='%s %%p \"cp %%%%d /mnt/server/archivedir/%%f\"'\n"
130+
"or\n"
131+
" archive_command='%s %%p \"pgbackrest --stanza=your_stanza archive-push %%%%d\"'\n"
132+
"In these examples %%f and %%p will be replaced as usual by PostgreSQL before\n"
133+
"%s is called.\n\n"), progname, progname, progname);
124134
}
125135

126136
int
127137
main(int argc, char *argv[])
128138
{
129139
const char *progname;
130140
char *sourcepath;
141+
char *command;
131142
char *sep;
132143
char *sourcename;
133144
char tmpdir[MAXPGPATH] = TMPFS_DIRECTORY "/pg_tde_archiveXXXXXX";
134145
char tmppath[MAXPGPATH];
135146
bool issegment;
136-
pid_t child;
137-
int status;
138-
int r;
139147

140148
pg_logging_init(argv[0]);
141149
progname = get_progname(argv[0]);
@@ -154,14 +162,15 @@ main(int argc, char *argv[])
154162
}
155163
}
156164

157-
if (argc < 3)
165+
if (argc != 3)
158166
{
159-
pg_log_error("too few arguments");
167+
pg_log_error("wrong number of arguments, 2 expected");
160168
pg_log_error_detail("Try \"%s --help\" for more information.", progname);
161169
exit(1);
162170
}
163171

164172
sourcepath = argv[1];
173+
command = argv[2];
165174

166175
pg_tde_fe_init("pg_tde");
167176
TDEXLogSmgrInit();
@@ -186,35 +195,19 @@ main(int argc, char *argv[])
186195
s = stpcpy(s, "/");
187196
stpcpy(s, sourcename);
188197

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

193202
write_decrypted_segment(sourcepath, sourcename, tmppath);
194203
}
204+
else
205+
command = replace_percent_placeholders(command,
206+
"ARCHIVE-COMMAND", "d",
207+
sourcepath);
195208

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-
}
209+
if (system(command) != 0)
210+
pg_fatal("ARCHIVE-COMMAND \"%s\" failed: %m", command);
218211

219212
if (issegment)
220213
{

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: 3 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,7 @@
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\"'");
7980
$replica->append_conf('postgresql.conf', "recovery_target_action = promote");
8081
$replica->set_recovery_mode;
8182
$replica->start;

0 commit comments

Comments
 (0)