Home | History | Annotate | Line # | Download | only in format_text
archiver.c revision 1.1.1.3
      1 /*	$NetBSD: archiver.c,v 1.1.1.3 2009/12/02 00:26:29 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 	if (!dm_create_dir(vg->cmd->archive_params->dir))
    121 		return 0;
    122 
    123 	/* Trap a read-only file system */
    124 	if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) &&
    125 	     (errno == EROFS))
    126 		return 0;
    127 
    128 	log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name,
    129 		    vg->seqno);
    130 	if (!__archive(vg)) {
    131 		log_error("Volume group \"%s\" metadata archive failed.",
    132 			  vg->name);
    133 		return 0;
    134 	}
    135 
    136 	return 1;
    137 }
    138 
    139 int archive_display(struct cmd_context *cmd, const char *vg_name)
    140 {
    141 	int r1, r2;
    142 
    143 	r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
    144 	r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
    145 
    146 	return r1 && r2;
    147 }
    148 
    149 int archive_display_file(struct cmd_context *cmd, const char *file)
    150 {
    151 	int r;
    152 
    153 	r = archive_list_file(cmd, file);
    154 
    155 	return r;
    156 }
    157 
    158 int backup_init(struct cmd_context *cmd, const char *dir,
    159 		int enabled)
    160 {
    161 	if (!(cmd->backup_params = dm_pool_zalloc(cmd->libmem,
    162 					       sizeof(*cmd->backup_params)))) {
    163 		log_error("backup_params alloc failed");
    164 		return 0;
    165 	}
    166 
    167 	cmd->backup_params->dir = NULL;
    168 	if (!*dir)
    169 		return 1;
    170 
    171 	if (!(cmd->backup_params->dir = dm_strdup(dir))) {
    172 		log_error("Couldn't copy backup directory name.");
    173 		return 0;
    174 	}
    175 	backup_enable(cmd, enabled);
    176 
    177 	return 1;
    178 }
    179 
    180 void backup_exit(struct cmd_context *cmd)
    181 {
    182 	if (!cmd->backup_params)
    183 		return;
    184 	if (cmd->backup_params->dir)
    185 		dm_free(cmd->backup_params->dir);
    186 	memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
    187 }
    188 
    189 void backup_enable(struct cmd_context *cmd, int flag)
    190 {
    191 	cmd->backup_params->enabled = flag;
    192 }
    193 
    194 static int __backup(struct volume_group *vg)
    195 {
    196 	char name[PATH_MAX];
    197 	char *desc;
    198 
    199 	if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0)))
    200 		return_0;
    201 
    202 	if (dm_snprintf(name, sizeof(name), "%s/%s",
    203 			 vg->cmd->backup_params->dir, vg->name) < 0) {
    204 		log_error("Failed to generate volume group metadata backup "
    205 			  "filename.");
    206 		return 0;
    207 	}
    208 
    209 	return backup_to_file(name, desc, vg);
    210 }
    211 
    212 int backup_locally(struct volume_group *vg)
    213 {
    214 	if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
    215 		log_warn("WARNING: This metadata update is NOT backed up");
    216 		return 1;
    217 	}
    218 
    219 	if (test_mode()) {
    220 		log_verbose("Test mode: Skipping volume group backup.");
    221 		return 1;
    222 	}
    223 
    224 	if (!dm_create_dir(vg->cmd->backup_params->dir))
    225 		return 0;
    226 
    227 	/* Trap a read-only file system */
    228 	if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) &&
    229 	    (errno == EROFS))
    230 		return 0;
    231 
    232 	if (!__backup(vg)) {
    233 		log_error("Backup of volume group %s metadata failed.",
    234 			  vg->name);
    235 		return 0;
    236 	}
    237 
    238 	return 1;
    239 }
    240 
    241 int backup(struct volume_group *vg)
    242 {
    243 	if (vg_is_clustered(vg))
    244 		remote_backup_metadata(vg);
    245 
    246 	return backup_locally(vg);
    247 }
    248 
    249 int backup_remove(struct cmd_context *cmd, const char *vg_name)
    250 {
    251 	char path[PATH_MAX];
    252 
    253 	if (dm_snprintf(path, sizeof(path), "%s/%s",
    254 			 cmd->backup_params->dir, vg_name) < 0) {
    255 		log_error("Failed to generate backup filename (for removal).");
    256 		return 0;
    257 	}
    258 
    259 	/*
    260 	 * Let this fail silently.
    261 	 */
    262 	unlink(path);
    263 	return 1;
    264 }
    265 
    266 struct volume_group *backup_read_vg(struct cmd_context *cmd,
    267 				    const char *vg_name, const char *file)
    268 {
    269 	struct volume_group *vg = NULL;
    270 	struct format_instance *tf;
    271 	struct metadata_area *mda;
    272 	void *context;
    273 
    274 	if (!(context = create_text_context(cmd, file,
    275 					    cmd->cmd_line)) ||
    276 	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
    277 							 NULL, context))) {
    278 		log_error("Couldn't create text format object.");
    279 		return NULL;
    280 	}
    281 
    282 	dm_list_iterate_items(mda, &tf->metadata_areas) {
    283 		if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
    284 			stack;
    285 		break;
    286 	}
    287 
    288 	tf->fmt->ops->destroy_instance(tf);
    289 	return vg;
    290 }
    291 
    292 /* ORPHAN and VG locks held before calling this */
    293 int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
    294 {
    295 	struct pv_list *pvl;
    296 	struct physical_volume *pv;
    297 	struct lvmcache_info *info;
    298 
    299 	/*
    300 	 * FIXME: Check that the PVs referenced in the backup are
    301 	 * not members of other existing VGs.
    302 	 */
    303 
    304 	/* Attempt to write out using currently active format */
    305 	if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
    306 						       NULL, NULL))) {
    307 		log_error("Failed to allocate format instance");
    308 		return 0;
    309 	}
    310 
    311 	/* Add any metadata areas on the PVs */
    312 	dm_list_iterate_items(pvl, &vg->pvs) {
    313 		pv = pvl->pv;
    314 		if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
    315 			log_error("PV %s missing from cache",
    316 				  pv_dev_name(pv));
    317 			return 0;
    318 		}
    319 		if (cmd->fmt != info->fmt) {
    320 			log_error("PV %s is a different format (seqno %s)",
    321 				  pv_dev_name(pv), info->fmt->name);
    322 			return 0;
    323 		}
    324 		if (!vg->fid->fmt->ops->
    325 		    pv_setup(vg->fid->fmt, UINT64_C(0), 0, 0, 0, 0, 0UL,
    326 			     UINT64_C(0), &vg->fid->metadata_areas, pv, vg)) {
    327 			log_error("Format-specific setup for %s failed",
    328 				  pv_dev_name(pv));
    329 			return 0;
    330 		}
    331 	}
    332 
    333 	if (!vg_write(vg) || !vg_commit(vg))
    334 		return_0;
    335 
    336 	return 1;
    337 }
    338 
    339 /* ORPHAN and VG locks held before calling this */
    340 int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
    341 			     const char *file)
    342 {
    343 	struct volume_group *vg;
    344 	int missing_pvs, r = 0;
    345 
    346 	/*
    347 	 * Read in the volume group from the text file.
    348 	 */
    349 	if (!(vg = backup_read_vg(cmd, vg_name, file)))
    350 		return_0;
    351 
    352 	missing_pvs = vg_missing_pv_count(vg);
    353 	if (missing_pvs == 0)
    354 		r = backup_restore_vg(cmd, vg);
    355 	else
    356 		log_error("Cannot restore Volume Group %s with %i PVs "
    357 			  "marked as missing.", vg->name, missing_pvs);
    358 
    359 	vg_release(vg);
    360 	return r;
    361 }
    362 
    363 int backup_restore(struct cmd_context *cmd, const char *vg_name)
    364 {
    365 	char path[PATH_MAX];
    366 
    367 	if (dm_snprintf(path, sizeof(path), "%s/%s",
    368 			 cmd->backup_params->dir, vg_name) < 0) {
    369 		log_error("Failed to generate backup filename (for restore).");
    370 		return 0;
    371 	}
    372 
    373 	return backup_restore_from_file(cmd, vg_name, path);
    374 }
    375 
    376 int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
    377 {
    378 	int r = 0;
    379 	struct format_instance *tf;
    380 	struct metadata_area *mda;
    381 	void *context;
    382 	struct cmd_context *cmd;
    383 
    384 	cmd = vg->cmd;
    385 
    386 	log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
    387 
    388 	if (!(context = create_text_context(cmd, file, desc)) ||
    389 	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
    390 							 NULL, context))) {
    391 		log_error("Couldn't create backup object.");
    392 		return 0;
    393 	}
    394 
    395 	/* Write and commit the metadata area */
    396 	dm_list_iterate_items(mda, &tf->metadata_areas) {
    397 		if (!(r = mda->ops->vg_write(tf, vg, mda))) {
    398 			stack;
    399 			continue;
    400 		}
    401 		if (mda->ops->vg_commit &&
    402 		    !(r = mda->ops->vg_commit(tf, vg, mda))) {
    403 			stack;
    404 		}
    405 	}
    406 
    407 	tf->fmt->ops->destroy_instance(tf);
    408 	return r;
    409 }
    410 
    411 /*
    412  * Update backup (and archive) if they're out-of-date or don't exist.
    413  */
    414 void check_current_backup(struct volume_group *vg)
    415 {
    416 	char path[PATH_MAX];
    417 	struct volume_group *vg_backup;
    418 	int old_suppress;
    419 
    420 	if (vg_is_exported(vg))
    421 		return;
    422 
    423 	if (dm_snprintf(path, sizeof(path), "%s/%s",
    424 			 vg->cmd->backup_params->dir, vg->name) < 0) {
    425 		log_debug("Failed to generate backup filename.");
    426 		return;
    427 	}
    428 
    429 	old_suppress = log_suppress(1);
    430 	/* Up-to-date backup exists? */
    431 	if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) &&
    432 	    (vg->seqno == vg_backup->seqno) &&
    433 	    (id_equal(&vg->id, &vg_backup->id))) {
    434 		log_suppress(old_suppress);
    435 		vg_release(vg_backup);
    436 		return;
    437 	}
    438 	log_suppress(old_suppress);
    439 
    440 	if (vg_backup) {
    441 		archive(vg_backup);
    442 		vg_release(vg_backup);
    443 	}
    444 	archive(vg);
    445 	backup_locally(vg);
    446 }
    447