Skip to content

Commit 7a825ad

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 <andreas.karlsson@percona.com>
1 parent 8d1b4f8 commit 7a825ad

File tree

3 files changed

+77
-83
lines changed

3 files changed

+77
-83
lines changed

contrib/pg_tde/src/bin/pg_tde_archive_decrypt.c

Lines changed: 39 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,40 @@ 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, %%d will be replaced with the\n"
126+
" absolute path of the decrypted WAL segment.\n"));
127+
printf(_("\n"));
128+
printf(_("Note that any %%d parameter in ARCHIVE-COMMAND will have to be escaped as\n"
129+
"%%%%d if used as archive_command in postgresql.conf.\n"
130+
"e.g.\n"
131+
" archive_command='%s %%f %%p \"cp %%%%d /mnt/server/archivedir/%%f\"'\n"
132+
"or\n"
133+
" archive_command='%s %%f %%p \"pgbackrest --stanza=your_stanza archive-push %%%%d\"'\n"
134+
"In these examples %%f and %%p will be replaced as usual by PostgreSQL before\n"
135+
"%s is called.\n\n"), progname, progname, progname);
124136
}
125137

126138
int
127139
main(int argc, char *argv[])
128140
{
129141
const char *progname;
130142
char *sourcepath;
143+
char *targetname;
144+
char *command;
131145
char *sep;
132146
char *sourcename;
133147
char tmpdir[MAXPGPATH] = TMPFS_DIRECTORY "/pg_tde_archiveXXXXXX";
134148
char tmppath[MAXPGPATH];
135149
bool issegment;
136-
pid_t child;
137-
int status;
138-
int r;
139150

140151
pg_logging_init(argv[0]);
141152
progname = get_progname(argv[0]);
@@ -154,14 +165,16 @@ main(int argc, char *argv[])
154165
}
155166
}
156167

157-
if (argc < 3)
168+
if (argc != 4)
158169
{
159-
pg_log_error("too few arguments");
170+
pg_log_error("wrong number of arguments, 3 expected");
160171
pg_log_error_detail("Try \"%s --help\" for more information.", progname);
161172
exit(1);
162173
}
163174

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

166179
pg_tde_fe_init("pg_tde");
167180
TDEXLogSmgrInit();
@@ -173,7 +186,7 @@ main(int argc, char *argv[])
173186
else
174187
sourcename = sourcepath;
175188

176-
issegment = is_segment(sourcename);
189+
issegment = is_segment(targetname);
177190

178191
if (issegment)
179192
{
@@ -186,35 +199,19 @@ main(int argc, char *argv[])
186199
s = stpcpy(s, "/");
187200
stpcpy(s, sourcename);
188201

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-
}
202+
command = replace_percent_placeholders(command,
203+
"ARCHIVE-COMMAND", "d",
204+
tmppath);
195205

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

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

219216
if (issegment)
220217
{

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, %%d will be replaced with the\n"
120+
" path where it should write the unencrypted WAL segment\n"));
121+
printf(_("\n"));
122+
printf(_("Note that any %%d parameter in RESTORE-COMMAND will have to be escaped as\n"
123+
"%%%%d if used as restore_command in postgresql.conf.\n"
124+
"e.g.\n"
125+
" restore_command='%s %%f %%p \"cp /mnt/server/archivedir/%%f %%%%d\"'\n"
126+
"or\n"
127+
" restore_command='%s %%f %%p \"pgbackrest --stanza=your_stanza archive-get %%f \\\"%%%%d\\\"\"'\n"
128+
"In these examples %%f and %%p will be replaced as usual by PostgreSQL before\n"
129+
"%s is called.\n\n"), progname, 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", "d",
198+
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", "d",
203+
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 %%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 %f %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)