Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "archiver.h"
18 : : #include "format-text.h"
19 : : #include "lvm-file.h"
20 : : #include "lvm-string.h"
21 : : #include "lvmcache.h"
22 : : #include "toolcontext.h"
23 : : #include "locking.h"
24 : :
25 : : #include <unistd.h>
26 : :
27 : : struct archive_params {
28 : : int enabled;
29 : : char *dir;
30 : : unsigned int keep_days;
31 : : unsigned int keep_number;
32 : : };
33 : :
34 : : struct backup_params {
35 : : int enabled;
36 : : char *dir;
37 : : };
38 : :
39 : 1 : int archive_init(struct cmd_context *cmd, const char *dir,
40 : : unsigned int keep_days, unsigned int keep_min,
41 : : int enabled)
42 : : {
43 [ - + ]: 1 : if (!(cmd->archive_params = dm_pool_zalloc(cmd->libmem,
44 : : sizeof(*cmd->archive_params)))) {
45 : 0 : log_error("archive_params alloc failed");
46 : 0 : return 0;
47 : : }
48 : :
49 : 1 : cmd->archive_params->dir = NULL;
50 : :
51 [ - + ]: 1 : if (!*dir)
52 : 0 : return 1;
53 : :
54 [ - + ]: 1 : if (!(cmd->archive_params->dir = dm_strdup(dir))) {
55 : 0 : log_error("Couldn't copy archive directory name.");
56 : 0 : return 0;
57 : : }
58 : :
59 : 1 : cmd->archive_params->keep_days = keep_days;
60 : 1 : cmd->archive_params->keep_number = keep_min;
61 : 1 : archive_enable(cmd, enabled);
62 : :
63 : 1 : return 1;
64 : : }
65 : :
66 : 1 : void archive_exit(struct cmd_context *cmd)
67 : : {
68 [ - + ]: 1 : if (!cmd->archive_params)
69 : 0 : return;
70 [ + - ]: 1 : if (cmd->archive_params->dir)
71 : 1 : dm_free(cmd->archive_params->dir);
72 : 1 : memset(cmd->archive_params, 0, sizeof(*cmd->archive_params));
73 : : }
74 : :
75 : 3 : void archive_enable(struct cmd_context *cmd, int flag)
76 : : {
77 : 3 : cmd->archive_params->enabled = flag;
78 : 3 : }
79 : :
80 : 0 : static char *_build_desc(struct dm_pool *mem, const char *line, int before)
81 : : {
82 : 0 : size_t len = strlen(line) + 32;
83 : : char *buffer;
84 : :
85 [ # # ]: 0 : if (!(buffer = dm_pool_zalloc(mem, strlen(line) + 32)))
86 : 0 : return_NULL;
87 : :
88 [ # # ][ # # ]: 0 : if (snprintf(buffer, len,
89 : : "Created %s executing '%s'",
90 : : before ? "*before*" : "*after*", line) < 0)
91 : 0 : return_NULL;
92 : :
93 : 0 : return buffer;
94 : : }
95 : :
96 : 0 : static int __archive(struct volume_group *vg)
97 : : {
98 : : char *desc;
99 : :
100 [ # # ]: 0 : if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 1)))
101 : 0 : return_0;
102 : :
103 : 0 : return archive_vg(vg, vg->cmd->archive_params->dir, desc,
104 : 0 : vg->cmd->archive_params->keep_days,
105 : 0 : vg->cmd->archive_params->keep_number);
106 : : }
107 : :
108 : 0 : int archive(struct volume_group *vg)
109 : : {
110 [ # # ][ # # ]: 0 : if (!vg->cmd->archive_params->enabled || !vg->cmd->archive_params->dir)
111 : 0 : return 1;
112 : :
113 [ # # ]: 0 : if (test_mode()) {
114 : 0 : log_verbose("Test mode: Skipping archiving of volume group.");
115 : 0 : return 1;
116 : : }
117 : :
118 [ # # ]: 0 : if (!dm_create_dir(vg->cmd->archive_params->dir))
119 : 0 : return 0;
120 : :
121 : : /* Trap a read-only file system */
122 [ # # # # ]: 0 : if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) &&
123 : 0 : (errno == EROFS))
124 : 0 : return 0;
125 : :
126 : 0 : log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name,
127 : : vg->seqno);
128 [ # # ]: 0 : if (!__archive(vg)) {
129 : 0 : log_error("Volume group \"%s\" metadata archive failed.",
130 : : vg->name);
131 : 0 : return 0;
132 : : }
133 : :
134 : 0 : return 1;
135 : : }
136 : :
137 : 0 : int archive_display(struct cmd_context *cmd, const char *vg_name)
138 : : {
139 : : int r1, r2;
140 : :
141 : 0 : r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
142 : 0 : r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
143 : :
144 [ # # # # ]: 0 : return r1 && r2;
145 : : }
146 : :
147 : 0 : int archive_display_file(struct cmd_context *cmd, const char *file)
148 : : {
149 : : int r;
150 : :
151 : 0 : r = archive_list_file(cmd, file);
152 : :
153 : 0 : return r;
154 : : }
155 : :
156 : 1 : int backup_init(struct cmd_context *cmd, const char *dir,
157 : : int enabled)
158 : : {
159 [ - + ]: 1 : if (!(cmd->backup_params = dm_pool_zalloc(cmd->libmem,
160 : : sizeof(*cmd->backup_params)))) {
161 : 0 : log_error("backup_params alloc failed");
162 : 0 : return 0;
163 : : }
164 : :
165 : 1 : cmd->backup_params->dir = NULL;
166 [ - + ]: 1 : if (!*dir)
167 : 0 : return 1;
168 : :
169 [ - + ]: 1 : if (!(cmd->backup_params->dir = dm_strdup(dir))) {
170 : 0 : log_error("Couldn't copy backup directory name.");
171 : 0 : return 0;
172 : : }
173 : 1 : backup_enable(cmd, enabled);
174 : :
175 : 1 : return 1;
176 : : }
177 : :
178 : 1 : void backup_exit(struct cmd_context *cmd)
179 : : {
180 [ - + ]: 1 : if (!cmd->backup_params)
181 : 0 : return;
182 [ + - ]: 1 : if (cmd->backup_params->dir)
183 : 1 : dm_free(cmd->backup_params->dir);
184 : 1 : memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
185 : : }
186 : :
187 : 3 : void backup_enable(struct cmd_context *cmd, int flag)
188 : : {
189 : 3 : cmd->backup_params->enabled = flag;
190 : 3 : }
191 : :
192 : 0 : static int __backup(struct volume_group *vg)
193 : : {
194 : : char name[PATH_MAX];
195 : : char *desc;
196 : :
197 [ # # ]: 0 : if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0)))
198 : 0 : return_0;
199 : :
200 [ # # ]: 0 : if (dm_snprintf(name, sizeof(name), "%s/%s",
201 : 0 : vg->cmd->backup_params->dir, vg->name) < 0) {
202 : 0 : log_error("Failed to generate volume group metadata backup "
203 : : "filename.");
204 : 0 : return 0;
205 : : }
206 : :
207 : 0 : return backup_to_file(name, desc, vg);
208 : : }
209 : :
210 : 0 : int backup_locally(struct volume_group *vg)
211 : : {
212 [ # # ][ # # ]: 0 : if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
213 : 0 : log_warn("WARNING: This metadata update is NOT backed up");
214 : 0 : return 1;
215 : : }
216 : :
217 [ # # ]: 0 : if (test_mode()) {
218 : 0 : log_verbose("Test mode: Skipping volume group backup.");
219 : 0 : return 1;
220 : : }
221 : :
222 [ # # ]: 0 : if (!dm_create_dir(vg->cmd->backup_params->dir))
223 : 0 : return 0;
224 : :
225 : : /* Trap a read-only file system */
226 [ # # # # ]: 0 : if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) &&
227 : 0 : (errno == EROFS))
228 : 0 : return 0;
229 : :
230 [ # # ]: 0 : if (!__backup(vg)) {
231 : 0 : log_error("Backup of volume group %s metadata failed.",
232 : : vg->name);
233 : 0 : return 0;
234 : : }
235 : :
236 : 0 : return 1;
237 : : }
238 : :
239 : 0 : int backup(struct volume_group *vg)
240 : : {
241 [ # # ]: 0 : if (vg_is_clustered(vg))
242 : 0 : remote_backup_metadata(vg);
243 : :
244 : 0 : return backup_locally(vg);
245 : : }
246 : :
247 : 0 : int backup_remove(struct cmd_context *cmd, const char *vg_name)
248 : : {
249 : : char path[PATH_MAX];
250 : :
251 [ # # ]: 0 : if (dm_snprintf(path, sizeof(path), "%s/%s",
252 : 0 : cmd->backup_params->dir, vg_name) < 0) {
253 : 0 : log_error("Failed to generate backup filename (for removal).");
254 : 0 : return 0;
255 : : }
256 : :
257 : : /*
258 : : * Let this fail silently.
259 : : */
260 : 0 : unlink(path);
261 : 0 : return 1;
262 : : }
263 : :
264 : 0 : struct volume_group *backup_read_vg(struct cmd_context *cmd,
265 : : const char *vg_name, const char *file)
266 : : {
267 : 0 : struct volume_group *vg = NULL;
268 : : struct format_instance *tf;
269 : : struct metadata_area *mda;
270 : : void *context;
271 : :
272 [ # # # # ]: 0 : if (!(context = create_text_context(cmd, file,
273 : : cmd->cmd_line)) ||
274 : 0 : !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
275 : : NULL, context))) {
276 : 0 : log_error("Couldn't create text format object.");
277 : 0 : return NULL;
278 : : }
279 : :
280 [ # # ]: 0 : dm_list_iterate_items(mda, &tf->metadata_areas) {
281 [ # # ]: 0 : if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
282 : 0 : stack;
283 : 0 : break;
284 : : }
285 : :
286 : 0 : tf->fmt->ops->destroy_instance(tf);
287 : 0 : return vg;
288 : : }
289 : :
290 : : /* ORPHAN and VG locks held before calling this */
291 : 0 : int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
292 : : {
293 : : struct pv_list *pvl;
294 : : struct physical_volume *pv;
295 : : struct lvmcache_info *info;
296 : :
297 : : /*
298 : : * FIXME: Check that the PVs referenced in the backup are
299 : : * not members of other existing VGs.
300 : : */
301 : :
302 : : /* Attempt to write out using currently active format */
303 [ # # ]: 0 : if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
304 : : NULL, NULL))) {
305 : 0 : log_error("Failed to allocate format instance");
306 : 0 : return 0;
307 : : }
308 : :
309 : : /* Add any metadata areas on the PVs */
310 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
311 : 0 : pv = pvl->pv;
312 [ # # ]: 0 : if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
313 : 0 : log_error("PV %s missing from cache",
314 : : pv_dev_name(pv));
315 : 0 : return 0;
316 : : }
317 [ # # ]: 0 : if (cmd->fmt != info->fmt) {
318 : 0 : log_error("PV %s is a different format (seqno %s)",
319 : : pv_dev_name(pv), info->fmt->name);
320 : 0 : return 0;
321 : : }
322 [ # # ]: 0 : if (!vg->fid->fmt->ops->
323 : 0 : pv_setup(vg->fid->fmt, UINT64_C(0), 0, 0, 0, 0, 0UL,
324 : 0 : UINT64_C(0), &vg->fid->metadata_areas, pv, vg)) {
325 : 0 : log_error("Format-specific setup for %s failed",
326 : : pv_dev_name(pv));
327 : 0 : return 0;
328 : : }
329 : : }
330 : :
331 [ # # ][ # # ]: 0 : if (!vg_write(vg) || !vg_commit(vg))
332 : 0 : return_0;
333 : :
334 : 0 : return 1;
335 : : }
336 : :
337 : : /* ORPHAN and VG locks held before calling this */
338 : 0 : int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
339 : : const char *file)
340 : : {
341 : : struct volume_group *vg;
342 : 0 : int missing_pvs, r = 0;
343 : :
344 : : /*
345 : : * Read in the volume group from the text file.
346 : : */
347 [ # # ]: 0 : if (!(vg = backup_read_vg(cmd, vg_name, file)))
348 : 0 : return_0;
349 : :
350 : 0 : missing_pvs = vg_missing_pv_count(vg);
351 [ # # ]: 0 : if (missing_pvs == 0)
352 : 0 : r = backup_restore_vg(cmd, vg);
353 : : else
354 : 0 : log_error("Cannot restore Volume Group %s with %i PVs "
355 : : "marked as missing.", vg->name, missing_pvs);
356 : :
357 : 0 : vg_release(vg);
358 : 0 : return r;
359 : : }
360 : :
361 : 0 : int backup_restore(struct cmd_context *cmd, const char *vg_name)
362 : : {
363 : : char path[PATH_MAX];
364 : :
365 [ # # ]: 0 : if (dm_snprintf(path, sizeof(path), "%s/%s",
366 : 0 : cmd->backup_params->dir, vg_name) < 0) {
367 : 0 : log_error("Failed to generate backup filename (for restore).");
368 : 0 : return 0;
369 : : }
370 : :
371 : 0 : return backup_restore_from_file(cmd, vg_name, path);
372 : : }
373 : :
374 : 0 : int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
375 : : {
376 : 0 : int r = 0;
377 : : struct format_instance *tf;
378 : : struct metadata_area *mda;
379 : : void *context;
380 : : struct cmd_context *cmd;
381 : :
382 : 0 : cmd = vg->cmd;
383 : :
384 : 0 : log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
385 : :
386 [ # # # # ]: 0 : if (!(context = create_text_context(cmd, file, desc)) ||
387 : 0 : !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
388 : : NULL, context))) {
389 : 0 : log_error("Couldn't create backup object.");
390 : 0 : return 0;
391 : : }
392 : :
393 : : /* Write and commit the metadata area */
394 [ # # ]: 0 : dm_list_iterate_items(mda, &tf->metadata_areas) {
395 [ # # ]: 0 : if (!(r = mda->ops->vg_write(tf, vg, mda))) {
396 : 0 : stack;
397 : 0 : continue;
398 : : }
399 [ # # # # ]: 0 : if (mda->ops->vg_commit &&
400 : 0 : !(r = mda->ops->vg_commit(tf, vg, mda))) {
401 : 0 : stack;
402 : : }
403 : : }
404 : :
405 : 0 : tf->fmt->ops->destroy_instance(tf);
406 : 0 : return r;
407 : : }
408 : :
409 : : /*
410 : : * Update backup (and archive) if they're out-of-date or don't exist.
411 : : */
412 : 0 : void check_current_backup(struct volume_group *vg)
413 : : {
414 : : char path[PATH_MAX];
415 : : struct volume_group *vg_backup;
416 : : int old_suppress;
417 : :
418 [ # # ]: 0 : if (vg_is_exported(vg))
419 : 0 : return;
420 : :
421 [ # # ]: 0 : if (dm_snprintf(path, sizeof(path), "%s/%s",
422 : 0 : vg->cmd->backup_params->dir, vg->name) < 0) {
423 : 0 : log_debug("Failed to generate backup filename.");
424 : 0 : return;
425 : : }
426 : :
427 : 0 : old_suppress = log_suppress(1);
428 : : /* Up-to-date backup exists? */
429 [ # # # # # : 0 : if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) &&
# ]
430 : 0 : (vg->seqno == vg_backup->seqno) &&
431 : 0 : (id_equal(&vg->id, &vg_backup->id))) {
432 : 0 : log_suppress(old_suppress);
433 : 0 : vg_release(vg_backup);
434 : 0 : return;
435 : : }
436 : 0 : log_suppress(old_suppress);
437 : :
438 [ # # ]: 0 : if (vg_backup) {
439 : 0 : archive(vg_backup);
440 : 0 : vg_release(vg_backup);
441 : : }
442 : 0 : archive(vg);
443 : 0 : backup_locally(vg);
444 : : }
|