1/*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * src/bin/pg_basebackup/astreamer_inject.c
9 *-------------------------------------------------------------------------
43 * Create a astreamer that can edit recoverydata into an archive stream.
45 * The input should be a series of typed chunks (not ASTREAMER_UNKNOWN) as
46 * per the conventions described in astreamer.h; the chunks forwarded to
47 * the next astreamer will be similarly typed, but the
48 * ASTREAMER_MEMBER_HEADER chunks may be zero-length in cases where we've
49 * edited the archive stream.
51 * Our goal is to do one of the following three things with the content passed
52 * via recoveryconfcontents: (1) if is_recovery_guc_supported is false, then
53 * put the content into recovery.conf, replacing any existing archive member
54 * by that name; (2) if is_recovery_guc_supported is true and
55 * postgresql.auto.conf exists in the archive, then append the content
56 * provided to the existing file; and (3) if is_recovery_guc_supported is
57 * true but postgresql.auto.conf does not exist in the archive, then create
58 * it with the specified content.
60 * In addition, if is_recovery_guc_supported is true, then we create a
61 * zero-length standby.signal file, dropping any file with that name from
66 bool is_recovery_guc_supported,
78 return &streamer->
base;
82 * Handle each chunk of tar content while injecting recovery configuration.
98 /* Must copy provided data so we have the option to modify it. */
102 * On v12+, skip standby.signal and edit postgresql.auto.conf; on
103 * older versions, skip recovery.conf.
108 (strcmp(member->
pathname,
"standby.signal") == 0);
110 (strcmp(member->
pathname,
"postgresql.auto.conf") == 0);
113 /* Remember we saw it so we don't add it again. */
116 /* Increment length by data to be injected. */
121 * Zap data and len because the archive header is no
122 * longer valid; some subsequent astreamer must regenerate
123 * it if it's necessary.
131 (strcmp(member->
pathname,
"recovery.conf") == 0);
133 /* Do not forward if the file is to be skipped. */
139 /* Do not forward if the file is to be skipped. */
145 /* Do not forward it the file is to be skipped. */
149 /* Append provided content to whatever we already sent. */
161 * If we didn't already find (and thus modify)
162 * postgresql.auto.conf, inject it as an additional archive
167 "postgresql.auto.conf",
171 /* Inject empty standby.signal file. */
173 "standby.signal",
"", 0);
177 /* Inject recovery.conf file with specified contents. */
184 /* Nothing to do here. */
188 /* Shouldn't happen. */
189 pg_fatal(
"unexpected state while injecting recovery settings");
197 * End-of-stream processing for this astreamer.
206 * Free memory associated with this astreamer.
216 * Inject a member into the archive with specified contents.
232 * There seems to be no principled argument for these values, but they are
233 * what PostgreSQL has historically used.
239 * We don't know here how to generate valid member headers and trailers
240 * for the archiving format in use, so if those are needed, some successor
241 * astreamer will have to generate them using the data from 'member'.
static void astreamer_free(astreamer *streamer)
static void astreamer_content(astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
static void astreamer_finalize(astreamer *streamer)
astreamer_archive_context
@ ASTREAMER_MEMBER_HEADER
@ ASTREAMER_MEMBER_CONTENTS
@ ASTREAMER_MEMBER_TRAILER
@ ASTREAMER_ARCHIVE_TRAILER
static void astreamer_recovery_injector_content(astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
astreamer * astreamer_recovery_injector_new(astreamer *next, bool is_recovery_guc_supported, PQExpBuffer recoveryconfcontents)
struct astreamer_recovery_injector astreamer_recovery_injector
static void astreamer_recovery_injector_finalize(astreamer *streamer)
static void astreamer_recovery_injector_free(astreamer *streamer)
static const astreamer_ops astreamer_recovery_injector_ops
void astreamer_inject_file(astreamer *streamer, char *pathname, char *data, int len)
Assert(PointerIsAligned(start, uint64))
void pfree(void *pointer)
void * palloc0(Size size)
static PQExpBuffer recoveryconfcontents
size_t strlcpy(char *dst, const char *src, size_t siz)
char linktarget[MAXPGPATH]
void(* content)(astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
bool found_postgresql_auto_conf
bool is_recovery_guc_supported
bool is_postgresql_auto_conf
PQExpBuffer recoveryconfcontents
const astreamer_ops * bbs_ops