PostgreSQL Source Code git master
Loading...
Searching...
No Matches
basebackup_to_shell.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "backup/basebackup_target.h"
#include "common/percentrepl.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/guc.h"
Include dependency graph for basebackup_to_shell.c:

Go to the source code of this file.

Data Structures

struct  bbsink_shell
 

Typedefs

typedef struct bbsink_shell bbsink_shell
 

Functions

 PG_MODULE_MAGIC_EXT (.name="basebackup_to_shell",.version=PG_VERSION)
 
static voidshell_check_detail (char *target, char *target_detail)
 
static bbsinkshell_get_sink (bbsink *next_sink, void *detail_arg)
 
static void bbsink_shell_begin_archive (bbsink *sink, const char *archive_name)
 
static void bbsink_shell_archive_contents (bbsink *sink, size_t len)
 
static void bbsink_shell_end_archive (bbsink *sink)
 
static void bbsink_shell_begin_manifest (bbsink *sink)
 
static void bbsink_shell_manifest_contents (bbsink *sink, size_t len)
 
static void bbsink_shell_end_manifest (bbsink *sink)
 
void _PG_init (void)
 
static charshell_construct_command (const char *base_command, const char *filename, const char *target_detail)
 
static void shell_finish_command (bbsink_shell *sink)
 
static void shell_run_command (bbsink_shell *sink, const char *filename)
 
static void shell_send_data (bbsink_shell *sink, size_t len)
 

Variables

static const bbsink_ops bbsink_shell_ops
 
static charshell_command = ""
 
static charshell_required_role = ""
 

Typedef Documentation

◆ bbsink_shell

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 71 of file basebackup_to_shell.c.

72{
73 DefineCustomStringVariable("basebackup_to_shell.command",
74 "Shell command to be executed for each backup file.",
75 NULL,
77 "",
79 0,
80 NULL, NULL, NULL);
81
82 DefineCustomStringVariable("basebackup_to_shell.required_role",
83 "Backup user must be a member of this role to use shell backup target.",
84 NULL,
86 "",
88 0,
89 NULL, NULL, NULL);
90
91 MarkGUCPrefixReserved("basebackup_to_shell");
92
94}
void BaseBackupAddTarget(char *name, void *(*check_detail)(char *, char *), bbsink *(*get_sink)(bbsink *, void *))
static void * shell_check_detail(char *target, char *target_detail)
static char * shell_required_role
static bbsink * shell_get_sink(bbsink *next_sink, void *detail_arg)
static char * shell_command
void DefineCustomStringVariable(const char *name, const char *short_desc, const char *long_desc, char **valueAddr, const char *bootValue, GucContext context, int flags, GucStringCheckHook check_hook, GucStringAssignHook assign_hook, GucShowHook show_hook)
Definition guc.c:5091
void MarkGUCPrefixReserved(const char *className)
Definition guc.c:5148
@ PGC_SIGHUP
Definition guc.h:75
static int fb(int x)

References BaseBackupAddTarget(), DefineCustomStringVariable(), fb(), MarkGUCPrefixReserved(), PGC_SIGHUP, shell_check_detail(), shell_command, shell_get_sink(), and shell_required_role.

◆ bbsink_shell_archive_contents()

static void bbsink_shell_archive_contents ( bbsink sink,
size_t  len 
)
static

Definition at line 322 of file basebackup_to_shell.c.

323{
325
328}
void bbsink_forward_archive_contents(bbsink *sink, size_t len)
static void shell_send_data(bbsink_shell *sink, size_t len)
const void size_t len

References bbsink_forward_archive_contents(), fb(), len, and shell_send_data().

◆ bbsink_shell_begin_archive()

static void bbsink_shell_begin_archive ( bbsink sink,
const char archive_name 
)
static

Definition at line 310 of file basebackup_to_shell.c.

311{
313
314 shell_run_command(mysink, archive_name);
315 bbsink_forward_begin_archive(sink, archive_name);
316}
void bbsink_forward_begin_archive(bbsink *sink, const char *archive_name)
static void shell_run_command(bbsink_shell *sink, const char *filename)

References bbsink_forward_begin_archive(), fb(), and shell_run_command().

◆ bbsink_shell_begin_manifest()

static void bbsink_shell_begin_manifest ( bbsink sink)
static

Definition at line 346 of file basebackup_to_shell.c.

347{
349
350 shell_run_command(mysink, "backup_manifest");
352}
void bbsink_forward_begin_manifest(bbsink *sink)

References bbsink_forward_begin_manifest(), fb(), and shell_run_command().

◆ bbsink_shell_end_archive()

static void bbsink_shell_end_archive ( bbsink sink)
static

Definition at line 334 of file basebackup_to_shell.c.

335{
337
340}
void bbsink_forward_end_archive(bbsink *sink)
static void shell_finish_command(bbsink_shell *sink)

References bbsink_forward_end_archive(), fb(), and shell_finish_command().

◆ bbsink_shell_end_manifest()

static void bbsink_shell_end_manifest ( bbsink sink)
static

Definition at line 370 of file basebackup_to_shell.c.

371{
373
376}
void bbsink_forward_end_manifest(bbsink *sink)

References bbsink_forward_end_manifest(), fb(), and shell_finish_command().

◆ bbsink_shell_manifest_contents()

static void bbsink_shell_manifest_contents ( bbsink sink,
size_t  len 
)
static

Definition at line 358 of file basebackup_to_shell.c.

359{
361
364}
void bbsink_forward_manifest_contents(bbsink *sink, size_t len)

References bbsink_forward_manifest_contents(), fb(), len, and shell_send_data().

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "basebackup_to_shell",
version = PG_VERSION 
)

◆ shell_check_detail()

static void * shell_check_detail ( char target,
char target_detail 
)
static

Definition at line 102 of file basebackup_to_shell.c.

103{
104 if (shell_required_role[0] != '\0')
105 {
106 Oid roleid;
107
109 roleid = get_role_oid(shell_required_role, true);
110 if (!has_privs_of_role(GetUserId(), roleid))
113 errmsg("permission denied to use basebackup_to_shell")));
115 }
116
117 return target_detail;
118}
bool has_privs_of_role(Oid member, Oid role)
Definition acl.c:5284
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition acl.c:5552
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
Oid GetUserId(void)
Definition miscinit.c:469
unsigned int Oid
void StartTransactionCommand(void)
Definition xact.c:3080
void CommitTransactionCommand(void)
Definition xact.c:3178

References CommitTransactionCommand(), ereport, errcode(), errmsg(), ERROR, fb(), get_role_oid(), GetUserId(), has_privs_of_role(), shell_required_role, and StartTransactionCommand().

Referenced by _PG_init().

◆ shell_construct_command()

static char * shell_construct_command ( const char base_command,
const char filename,
const char target_detail 
)
static

Definition at line 212 of file basebackup_to_shell.c.

214{
215 return replace_percent_placeholders(base_command, "basebackup_to_shell.command",
216 "df", target_detail, filename);
217}
char * replace_percent_placeholders(const char *instr, const char *param_name, const char *letters,...)
Definition percentrepl.c:59
static char * filename
Definition pg_dumpall.c:120

References fb(), filename, and replace_percent_placeholders().

Referenced by shell_run_command().

◆ shell_finish_command()

static void shell_finish_command ( bbsink_shell sink)
static

Definition at line 223 of file basebackup_to_shell.c.

224{
225 int pclose_rc;
226
227 /* There should be a command running. */
228 Assert(sink->current_command != NULL);
229 Assert(sink->pipe != NULL);
230
231 /* Close down the pipe we opened. */
233 if (pclose_rc == -1)
236 errmsg("could not close pipe to external command: %m")));
237 else if (pclose_rc != 0)
238 {
241 errmsg("shell command \"%s\" failed",
242 sink->current_command),
244 }
245
246 /* Clean up. */
247 sink->pipe = NULL;
248 pfree(sink->current_command);
249 sink->current_command = NULL;
250}
#define Assert(condition)
Definition c.h:873
int errdetail_internal(const char *fmt,...)
Definition elog.c:1243
int errcode_for_file_access(void)
Definition elog.c:886
int ClosePipeStream(FILE *file)
Definition fd.c:3035
void pfree(void *pointer)
Definition mcxt.c:1616
char * wait_result_to_str(int exitstatus)
Definition wait_error.c:33

References Assert, ClosePipeStream(), ereport, errcode(), errcode_for_file_access(), errdetail_internal(), errmsg(), ERROR, fb(), pfree(), and wait_result_to_str().

Referenced by bbsink_shell_end_archive(), bbsink_shell_end_manifest(), and shell_send_data().

◆ shell_get_sink()

static bbsink * shell_get_sink ( bbsink next_sink,
void detail_arg 
)
static

Definition at line 127 of file basebackup_to_shell.c.

128{
130 bool has_detail_escape = false;
131 char *c;
132
133 /*
134 * Set up the bbsink.
135 *
136 * We remember the current value of basebackup_to_shell.shell_command to
137 * be certain that it can't change under us during the backup.
138 */
140 *((const bbsink_ops **) &sink->base.bbs_ops) = &bbsink_shell_ops;
141 sink->base.bbs_next = next_sink;
142 sink->target_detail = detail_arg;
143 sink->shell_command = pstrdup(shell_command);
144
145 /* Reject an empty shell command. */
146 if (sink->shell_command[0] == '\0')
149 errmsg("shell command for backup is not configured"));
150
151 /* Determine whether the shell command we're using contains %d. */
152 for (c = sink->shell_command; *c != '\0'; ++c)
153 {
154 if (c[0] == '%' && c[1] != '\0')
155 {
156 if (c[1] == 'd')
157 has_detail_escape = true;
158 ++c;
159 }
160 }
161
162 /* There should be a target detail if %d was used, and not otherwise. */
163 if (has_detail_escape && sink->target_detail == NULL)
166 errmsg("a target detail is required because the configured command includes %%d"),
167 errhint("Try \"pg_basebackup --target shell:DETAIL ...\"")));
168 else if (!has_detail_escape && sink->target_detail != NULL)
171 errmsg("a target detail is not permitted because the configured command does not include %%d")));
172
173 /*
174 * Since we're passing the string provided by the user to popen(), it will
175 * be interpreted by the shell, which is a potential security
176 * vulnerability, since the user invoking this module is not necessarily a
177 * superuser. To stay out of trouble, we must disallow any shell
178 * metacharacters here; to be conservative and keep things simple, we
179 * allow only alphanumerics.
180 */
181 if (sink->target_detail != NULL)
182 {
183 char *d;
184 bool scary = false;
185
186 for (d = sink->target_detail; *d != '\0'; ++d)
187 {
188 if (*d >= 'a' && *d <= 'z')
189 continue;
190 if (*d >= 'A' && *d <= 'Z')
191 continue;
192 if (*d >= '0' && *d <= '9')
193 continue;
194 scary = true;
195 break;
196 }
197
198 if (scary)
201 errmsg("target detail must contain only alphanumeric characters"));
202 }
203
204 return &sink->base;
205}
static const bbsink_ops bbsink_shell_ops
int errhint(const char *fmt,...)
Definition elog.c:1330
#define palloc0_object(type)
Definition fe_memutils.h:75
char * pstrdup(const char *in)
Definition mcxt.c:1781
char * c

References bbsink_shell_ops, ereport, errcode(), errhint(), errmsg(), ERROR, fb(), palloc0_object, pstrdup(), and shell_command.

Referenced by _PG_init().

◆ shell_run_command()

static void shell_run_command ( bbsink_shell sink,
const char filename 
)
static

Definition at line 256 of file basebackup_to_shell.c.

257{
258 /* There should not be anything already running. */
259 Assert(sink->current_command == NULL);
260 Assert(sink->pipe == NULL);
261
262 /* Construct a suitable command. */
263 sink->current_command = shell_construct_command(sink->shell_command,
264 filename,
265 sink->target_detail);
266
267 /* Run it. */
268 sink->pipe = OpenPipeStream(sink->current_command, PG_BINARY_W);
269 if (sink->pipe == NULL)
272 errmsg("could not execute command \"%s\": %m",
273 sink->current_command)));
274}
static char * shell_construct_command(const char *base_command, const char *filename, const char *target_detail)
#define PG_BINARY_W
Definition c.h:1290
FILE * OpenPipeStream(const char *command, const char *mode)
Definition fd.c:2727

References Assert, ereport, errcode_for_file_access(), errmsg(), ERROR, fb(), filename, OpenPipeStream(), PG_BINARY_W, and shell_construct_command().

Referenced by bbsink_shell_begin_archive(), and bbsink_shell_begin_manifest().

◆ shell_send_data()

static void shell_send_data ( bbsink_shell sink,
size_t  len 
)
static

Definition at line 280 of file basebackup_to_shell.c.

281{
282 /* There should be a command running. */
283 Assert(sink->current_command != NULL);
284 Assert(sink->pipe != NULL);
285
286 /* Try to write the data. */
287 if (fwrite(sink->base.bbs_buffer, len, 1, sink->pipe) != 1 ||
288 ferror(sink->pipe))
289 {
290 if (errno == EPIPE)
291 {
292 /*
293 * The error we're about to throw would shut down the command
294 * anyway, but we may get a more meaningful error message by doing
295 * this. If not, we'll fall through to the generic error below.
296 */
298 errno = EPIPE;
299 }
302 errmsg("could not write to shell backup program: %m")));
303 }
304}

References Assert, ereport, errcode_for_file_access(), errmsg(), ERROR, fb(), len, and shell_finish_command().

Referenced by bbsink_shell_archive_contents(), and bbsink_shell_manifest_contents().

Variable Documentation

◆ bbsink_shell_ops

const bbsink_ops bbsink_shell_ops
static
Initial value:
= {
.begin_backup = bbsink_forward_begin_backup,
.begin_archive = bbsink_shell_begin_archive,
.archive_contents = bbsink_shell_archive_contents,
.end_archive = bbsink_shell_end_archive,
.begin_manifest = bbsink_shell_begin_manifest,
.manifest_contents = bbsink_shell_manifest_contents,
.end_manifest = bbsink_shell_end_manifest,
}
void bbsink_forward_begin_backup(bbsink *sink)
void bbsink_forward_end_backup(bbsink *sink, XLogRecPtr endptr, TimeLineID endtli)
void bbsink_forward_cleanup(bbsink *sink)
static void bbsink_shell_begin_manifest(bbsink *sink)
static void bbsink_shell_end_manifest(bbsink *sink)
static void bbsink_shell_end_archive(bbsink *sink)
static void bbsink_shell_begin_archive(bbsink *sink, const char *archive_name)
static void bbsink_shell_archive_contents(bbsink *sink, size_t len)
static void bbsink_shell_manifest_contents(bbsink *sink, size_t len)

Definition at line 55 of file basebackup_to_shell.c.

55 {
56 .begin_backup = bbsink_forward_begin_backup,
57 .begin_archive = bbsink_shell_begin_archive,
58 .archive_contents = bbsink_shell_archive_contents,
59 .end_archive = bbsink_shell_end_archive,
60 .begin_manifest = bbsink_shell_begin_manifest,
61 .manifest_contents = bbsink_shell_manifest_contents,
62 .end_manifest = bbsink_shell_end_manifest,
63 .end_backup = bbsink_forward_end_backup,
64 .cleanup = bbsink_forward_cleanup
65};

Referenced by shell_get_sink().

◆ shell_command

char* shell_command = ""
static

Definition at line 67 of file basebackup_to_shell.c.

Referenced by _PG_init(), and shell_get_sink().

◆ shell_required_role

char* shell_required_role = ""
static

Definition at line 68 of file basebackup_to_shell.c.

Referenced by _PG_init(), and shell_check_detail().