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