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