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