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