Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * basebackup_server.c
4 : * store basebackup archives on the server
5 : *
6 : * IDENTIFICATION
7 : * src/backend/backup/basebackup_server.c
8 : *
9 : *-------------------------------------------------------------------------
10 : */
11 : #include "postgres.h"
12 :
13 : #include "access/xact.h"
14 : #include "backup/basebackup.h"
15 : #include "backup/basebackup_sink.h"
16 : #include "catalog/pg_authid.h"
17 : #include "miscadmin.h"
18 : #include "storage/fd.h"
19 : #include "utils/acl.h"
20 : #include "utils/timestamp.h"
21 : #include "utils/wait_event.h"
22 :
23 : typedef struct bbsink_server
24 : {
25 : /* Common information for all types of sink. */
26 : bbsink base;
27 :
28 : /* Directory in which backup is to be stored. */
29 : char *pathname;
30 :
31 : /* Currently open file (or 0 if nothing open). */
32 : File file;
33 :
34 : /* Current file position. */
35 : off_t filepos;
36 : } bbsink_server;
37 :
38 : static void bbsink_server_begin_archive(bbsink *sink,
39 : const char *archive_name);
40 : static void bbsink_server_archive_contents(bbsink *sink, size_t len);
41 : static void bbsink_server_end_archive(bbsink *sink);
42 : static void bbsink_server_begin_manifest(bbsink *sink);
43 : static void bbsink_server_manifest_contents(bbsink *sink, size_t len);
44 : static void bbsink_server_end_manifest(bbsink *sink);
45 :
46 : static const bbsink_ops bbsink_server_ops = {
47 : .begin_backup = bbsink_forward_begin_backup,
48 : .begin_archive = bbsink_server_begin_archive,
49 : .archive_contents = bbsink_server_archive_contents,
50 : .end_archive = bbsink_server_end_archive,
51 : .begin_manifest = bbsink_server_begin_manifest,
52 : .manifest_contents = bbsink_server_manifest_contents,
53 : .end_manifest = bbsink_server_end_manifest,
54 : .end_backup = bbsink_forward_end_backup,
55 : .cleanup = bbsink_forward_cleanup
56 : };
57 :
58 : /*
59 : * Create a new 'server' bbsink.
60 : */
61 : bbsink *
62 8 : bbsink_server_new(bbsink *next, char *pathname)
63 : {
64 8 : bbsink_server *sink = palloc0(sizeof(bbsink_server));
65 :
66 8 : *((const bbsink_ops **) &sink->base.bbs_ops) = &bbsink_server_ops;
67 8 : sink->pathname = pathname;
68 8 : sink->base.bbs_next = next;
69 :
70 : /* Replication permission is not sufficient in this case. */
71 8 : StartTransactionCommand();
72 8 : if (!has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
73 0 : ereport(ERROR,
74 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
75 : errmsg("permission denied to create backup stored on server"),
76 : errdetail("Only roles with privileges of the \"%s\" role may create a backup stored on the server.",
77 : "pg_write_server_files")));
78 8 : CommitTransactionCommand();
79 :
80 : /*
81 : * It's not a good idea to store your backups in the same directory that
82 : * you're backing up. If we allowed a relative path here, that could
83 : * easily happen accidentally, so we don't. The user could still
84 : * accomplish the same thing by including the absolute path to $PGDATA in
85 : * the pathname, but that's likely an intentional bad decision rather than
86 : * an accident.
87 : */
88 8 : if (!is_absolute_path(pathname))
89 0 : ereport(ERROR,
90 : (errcode(ERRCODE_INVALID_NAME),
91 : errmsg("relative path not allowed for backup stored on server")));
92 :
93 8 : switch (pg_check_dir(pathname))
94 : {
95 6 : case 0:
96 :
97 : /*
98 : * Does not exist, so create it using the same permissions we'd
99 : * use for a new subdirectory of the data directory itself.
100 : */
101 6 : if (MakePGDirectory(pathname) < 0)
102 0 : ereport(ERROR,
103 : (errcode_for_file_access(),
104 : errmsg("could not create directory \"%s\": %m", pathname)));
105 6 : break;
106 :
107 2 : case 1:
108 : /* Exists, empty. */
109 2 : break;
110 :
111 0 : case 2:
112 : case 3:
113 : case 4:
114 : /* Exists, not empty. */
115 0 : ereport(ERROR,
116 : (errcode(ERRCODE_DUPLICATE_FILE),
117 : errmsg("directory \"%s\" exists but is not empty",
118 : pathname)));
119 : break;
120 :
121 0 : default:
122 : /* Access problem. */
123 0 : ereport(ERROR,
124 : (errcode_for_file_access(),
125 : errmsg("could not access directory \"%s\": %m",
126 : pathname)));
127 : }
128 :
129 8 : return &sink->base;
130 : }
131 :
132 : /*
133 : * Open the correct output file for this archive.
134 : */
135 : static void
136 8 : bbsink_server_begin_archive(bbsink *sink, const char *archive_name)
137 : {
138 8 : bbsink_server *mysink = (bbsink_server *) sink;
139 : char *filename;
140 :
141 : Assert(mysink->file == 0);
142 : Assert(mysink->filepos == 0);
143 :
144 8 : filename = psprintf("%s/%s", mysink->pathname, archive_name);
145 :
146 8 : mysink->file = PathNameOpenFile(filename,
147 : O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
148 8 : if (mysink->file <= 0)
149 0 : ereport(ERROR,
150 : (errcode_for_file_access(),
151 : errmsg("could not create file \"%s\": %m", filename)));
152 :
153 8 : pfree(filename);
154 :
155 8 : bbsink_forward_begin_archive(sink, archive_name);
156 8 : }
157 :
158 : /*
159 : * Write the data to the output file.
160 : */
161 : static void
162 14282 : bbsink_server_archive_contents(bbsink *sink, size_t len)
163 : {
164 14282 : bbsink_server *mysink = (bbsink_server *) sink;
165 : int nbytes;
166 :
167 14282 : nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
168 : mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);
169 :
170 14282 : if (nbytes != len)
171 : {
172 0 : if (nbytes < 0)
173 0 : ereport(ERROR,
174 : (errcode_for_file_access(),
175 : errmsg("could not write file \"%s\": %m",
176 : FilePathName(mysink->file)),
177 : errhint("Check free disk space.")));
178 : /* short write: complain appropriately */
179 0 : ereport(ERROR,
180 : (errcode(ERRCODE_DISK_FULL),
181 : errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
182 : FilePathName(mysink->file),
183 : nbytes, (int) len, (unsigned) mysink->filepos),
184 : errhint("Check free disk space.")));
185 : }
186 :
187 14282 : mysink->filepos += nbytes;
188 :
189 14282 : bbsink_forward_archive_contents(sink, len);
190 14282 : }
191 :
192 : /*
193 : * fsync and close the current output file.
194 : */
195 : static void
196 8 : bbsink_server_end_archive(bbsink *sink)
197 : {
198 8 : bbsink_server *mysink = (bbsink_server *) sink;
199 :
200 : /*
201 : * We intentionally don't use data_sync_elevel here, because the server
202 : * shouldn't PANIC just because we can't guarantee that the backup has
203 : * been written down to disk. Running recovery won't fix anything in this
204 : * case anyway.
205 : */
206 8 : if (FileSync(mysink->file, WAIT_EVENT_BASEBACKUP_SYNC) < 0)
207 0 : ereport(ERROR,
208 : (errcode_for_file_access(),
209 : errmsg("could not fsync file \"%s\": %m",
210 : FilePathName(mysink->file))));
211 :
212 :
213 : /* We're done with this file now. */
214 8 : FileClose(mysink->file);
215 8 : mysink->file = 0;
216 8 : mysink->filepos = 0;
217 :
218 8 : bbsink_forward_end_archive(sink);
219 8 : }
220 :
221 : /*
222 : * Open the output file to which we will write the manifest.
223 : *
224 : * Just like pg_basebackup, we write the manifest first under a temporary
225 : * name and then rename it into place after fsync. That way, if the manifest
226 : * is there and under the correct name, the user can be sure that the backup
227 : * completed.
228 : */
229 : static void
230 8 : bbsink_server_begin_manifest(bbsink *sink)
231 : {
232 8 : bbsink_server *mysink = (bbsink_server *) sink;
233 : char *tmp_filename;
234 :
235 : Assert(mysink->file == 0);
236 :
237 8 : tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);
238 :
239 8 : mysink->file = PathNameOpenFile(tmp_filename,
240 : O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
241 8 : if (mysink->file <= 0)
242 0 : ereport(ERROR,
243 : (errcode_for_file_access(),
244 : errmsg("could not create file \"%s\": %m", tmp_filename)));
245 :
246 8 : pfree(tmp_filename);
247 :
248 8 : bbsink_forward_begin_manifest(sink);
249 8 : }
250 :
251 : /*
252 : * Each chunk of manifest data is sent using a CopyData message.
253 : */
254 : static void
255 40 : bbsink_server_manifest_contents(bbsink *sink, size_t len)
256 : {
257 40 : bbsink_server *mysink = (bbsink_server *) sink;
258 : int nbytes;
259 :
260 40 : nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
261 : mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);
262 :
263 40 : if (nbytes != len)
264 : {
265 0 : if (nbytes < 0)
266 0 : ereport(ERROR,
267 : (errcode_for_file_access(),
268 : errmsg("could not write file \"%s\": %m",
269 : FilePathName(mysink->file)),
270 : errhint("Check free disk space.")));
271 : /* short write: complain appropriately */
272 0 : ereport(ERROR,
273 : (errcode(ERRCODE_DISK_FULL),
274 : errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
275 : FilePathName(mysink->file),
276 : nbytes, (int) len, (unsigned) mysink->filepos),
277 : errhint("Check free disk space.")));
278 : }
279 :
280 40 : mysink->filepos += nbytes;
281 :
282 40 : bbsink_forward_manifest_contents(sink, len);
283 40 : }
284 :
285 : /*
286 : * fsync the backup manifest, close the file, and then rename it into place.
287 : */
288 : static void
289 8 : bbsink_server_end_manifest(bbsink *sink)
290 : {
291 8 : bbsink_server *mysink = (bbsink_server *) sink;
292 : char *tmp_filename;
293 : char *filename;
294 :
295 : /* We're done with this file now. */
296 8 : FileClose(mysink->file);
297 8 : mysink->file = 0;
298 :
299 : /*
300 : * Rename it into place. This also fsyncs the temporary file, so we don't
301 : * need to do that here. We don't use data_sync_elevel here for the same
302 : * reasons as in bbsink_server_end_archive.
303 : */
304 8 : tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);
305 8 : filename = psprintf("%s/backup_manifest", mysink->pathname);
306 8 : durable_rename(tmp_filename, filename, ERROR);
307 8 : pfree(filename);
308 8 : pfree(tmp_filename);
309 :
310 8 : bbsink_forward_end_manifest(sink);
311 8 : }
|