From e74999af5187b9f3cfcbb9fb260e99cdd3d7a269 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Fri, 8 Feb 2002 11:13:47 +0000 Subject: [PATCH] o Add cmd_line field to struct cmd_context o Text format now has a description and time field at the top level. o archiving and backup set the description appropriately. eg, for an archive: description = "Created *before* executing 'lvextend test_vg/lvol0 -l +1'." creation_time = 1013166332 for a backup: description = "Created *after* executing 'lvextend test_vg/lvol0 -l +1'." creation_time = 1013166332 This is preparing the way for a simple vgcfgundo command. --- lib/format_text/archive.c | 21 +++++++++++---- lib/format_text/export.c | 13 +++++++--- lib/format_text/format-text.c | 44 ++++++++++++++++++++++---------- lib/format_text/format-text.h | 22 ++++++++-------- lib/format_text/import-export.h | 2 +- lib/metadata/metadata.h | 3 ++- tools/archive.c | 45 ++++++++++++++++++++++++++++----- tools/lvm.c | 38 +++++++++++++++++++++++++++- tools/vgcfgbackup.c | 3 ++- 9 files changed, 147 insertions(+), 44 deletions(-) diff --git a/lib/format_text/archive.c b/lib/format_text/archive.c index 8404ec4cb..ce25ffd4a 100644 --- a/lib/format_text/archive.c +++ b/lib/format_text/archive.c @@ -39,6 +39,7 @@ struct archive_c { uint32_t min_retains; char *dir; + char *desc; /* * An ordered list of previous archives. Each list @@ -296,9 +297,10 @@ static int _scan_archives(struct archive_c *bc) static int _vg_write(struct format_instance *fi, struct volume_group *vg) { + struct archive_c *bc = (struct archive_c *) fi->private; + int r = 0, i, fd; unsigned int index = 0; - struct archive_c *bc = (struct archive_c *) fi->private; struct archive_file *last; FILE *fp = NULL; char temp_file[PATH_MAX], archive_name[PATH_MAX]; @@ -314,7 +316,7 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg) return 0; } - if (!text_vg_export(fp, vg)) { + if (!text_vg_export(fp, vg, bc->desc)) { stack; fclose(fp); return 0; @@ -374,10 +376,14 @@ static struct format_handler _archive_handler = { destroy: _destroy }; +/* + * FIXME: format_instances shouldn't be allocated from the pool. + */ struct format_instance *archive_format_create(struct cmd_context *cmd, - const char *dir, - uint32_t retain_days, - uint32_t min_retains) + const char *dir, + uint32_t retain_days, + uint32_t min_retains, + const char *desc) { struct format_instance *fi; struct archive_c *bc = NULL; @@ -398,6 +404,11 @@ struct format_instance *archive_format_create(struct cmd_context *cmd, goto bad; } + if (!(bc->desc = pool_strdup(mem, desc))) { + stack; + goto bad; + } + bc->retain_days = retain_days; bc->min_retains = min_retains; diff --git a/lib/format_text/export.c b/lib/format_text/export.c index 343f0964d..c3e3ec859 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -172,7 +172,8 @@ static void _out(struct formatter *f, const char *fmt, ...) va_end(ap); } -static int _print_header(struct formatter *f, struct volume_group *vg) +static int _print_header(struct formatter *f, + struct volume_group *vg, const char *desc) { time_t t; @@ -181,6 +182,10 @@ static int _print_header(struct formatter *f, struct volume_group *vg) _out(f, "# This file was originally generated by the LVM2 library\n" "# Generated: %s\n", ctime(&t)); + + _out(f, "description = \"%s\"", desc); + _out(f, "creation_time = %lu\n", t); + return 1; } @@ -217,7 +222,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg) static inline const char * _get_pv_name(struct formatter *f, struct physical_volume *pv) { - return (pv) ? (const char *) + return (pv) ? (const char *) hash_lookup(f->pv_names, dev_name(pv->dev)) : "Missing"; } @@ -431,7 +436,7 @@ static int _build_pv_names(struct formatter *f, return 0; } -int text_vg_export(FILE *fp, struct volume_group *vg) +int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc) { int r = 0; struct formatter *f; @@ -452,7 +457,7 @@ int text_vg_export(FILE *fp, struct volume_group *vg) #define fail do {stack; goto out;} while(0) - if (!_print_header(f, vg)) + if (!_print_header(f, vg, desc)) fail; _out(f, "%s {", vg->name); diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index 0da845f43..351be046e 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -25,6 +25,7 @@ struct text_c { char *path; + char *desc; struct uuid_map *um; }; @@ -130,7 +131,7 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg) return 0; } - if (!text_vg_export(fp, vg)) { + if (!text_vg_export(fp, vg, tc->desc)) { log_error("Failed to write metadata to %s.", temp_file); fclose(fp); return 0; @@ -173,33 +174,35 @@ static struct format_handler _text_handler = { struct format_instance *text_format_create(struct cmd_context *cmd, const char *file, - struct uuid_map *um) + struct uuid_map *um, + const char *desc) { - const char *no_alloc = "Couldn't allocate text format object."; - struct format_instance *fi; - char *path; + char *path, *d; struct text_c *tc; if (!(fi = dbg_malloc(sizeof(*fi)))) { - log_err(no_alloc); - return NULL; + stack; + goto no_mem; } if (!(path = dbg_strdup(file))) { - dbg_free(fi); - log_err(no_alloc); - return NULL; + stack; + goto no_mem; + } + + if (!(d = dbg_strdup(desc))) { + stack; + goto no_mem; } if (!(tc = dbg_malloc(sizeof(*tc)))) { - dbg_free(fi); - dbg_free(path); - log_err(no_alloc); - return NULL; + stack; + goto no_mem; } tc->path = path; + tc->desc = d; tc->um = um; fi->cmd = cmd; @@ -207,4 +210,17 @@ struct format_instance *text_format_create(struct cmd_context *cmd, fi->private = tc; return fi; + + no_mem: + if (fi) + dbg_free(fi); + + if (path) + dbg_free(path); + + if (d) + dbg_free(path); + + log_err("Couldn't allocate text format object."); + return NULL; } diff --git a/lib/format_text/format-text.h b/lib/format_text/format-text.h index 1deca4618..9817f4c67 100644 --- a/lib/format_text/format-text.h +++ b/lib/format_text/format-text.h @@ -12,18 +12,17 @@ #include "uuid-map.h" /* - * The archive format is used to maintain a set of metadata backup files - * in an archive directory. - * 'retain_days' is the minimum number of days that an archive file must - * be held for. - * - * 'min_archives' is the minimum number of archives required to be kept - * for each volume group. + * The archive format is used to maintain a set of metadata + * backup files in an archive directory. 'retain_days' is the + * minimum number of days that an archive file must be held for. + * 'min_archives' is the minimum number of archives required to + * be kept for each volume group. */ struct format_instance *archive_format_create(struct cmd_context *cmd, - const char *dir, - uint32_t retain_days, - uint32_t min_archives); + const char *dir, + uint32_t retain_days, + uint32_t min_archives, + const char *desc); void backup_expire(struct format_instance *fi); @@ -32,6 +31,7 @@ void backup_expire(struct format_instance *fi); */ struct format_instance *text_format_create(struct cmd_context *cmd, const char *file, - struct uuid_map *um); + struct uuid_map *um, + const char *desc); #endif diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h index d33e68ca6..015995a01 100644 --- a/lib/format_text/import-export.h +++ b/lib/format_text/import-export.h @@ -24,7 +24,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size); int read_flags(uint32_t *status, int type, struct config_value *cv); -int text_vg_export(FILE *fp, struct volume_group *vg); +int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc); struct volume_group *text_vg_import(struct cmd_context *cmd, const char *file, struct uuid_map *um); diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index ed2be736a..04f6aa0fe 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -148,6 +148,7 @@ struct cmd_context { struct pool *mem; /* misc. vars needed by format handler */ + char *cmd_line; char *dev_dir; struct dev_filter *filter; struct config_file *cf; @@ -267,7 +268,7 @@ struct logical_volume *lv_create(struct format_instance *fi, struct volume_group *vg, struct list *acceptable_pvs); -int lv_reduce(struct format_instance *fi, +int lv_reduce(struct format_instance *fi, struct logical_volume *lv, uint32_t extents); int lv_extend(struct format_instance *fi, diff --git a/tools/archive.c b/tools/archive.c index 7f84506eb..c248a3ef8 100644 --- a/tools/archive.c +++ b/tools/archive.c @@ -59,15 +59,42 @@ void archive_enable(int flag) _archive_params.enabled = flag; } +static char *_build_desc(struct pool *mem, const char *line, int before) +{ + size_t len = strlen(line) + 32; + char *buffer; + + if (!(buffer = pool_zalloc(mem, strlen(line) + 32))) { + stack; + return NULL; + } + + if (snprintf(buffer, len, + "Created %s executing '%s'", + before ? "*before*" : "*after*", line) < 0) { + stack; + return NULL; + } + + return buffer; +} + static int __archive(struct volume_group *vg) { int r; struct format_instance *archiver; + char *desc; + + if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 1))) { + stack; + return 0; + } if (!(archiver = archive_format_create(vg->cmd, - _archive_params.dir, - _archive_params.keep_days, - _archive_params.keep_number))) { + _archive_params.dir, + _archive_params.keep_days, + _archive_params.keep_number, + desc))) { log_error("Couldn't create archiver object."); return 0; } @@ -141,6 +168,12 @@ static int __backup(struct volume_group *vg) int r; struct format_instance *tf; char name[PATH_MAX]; + char *desc; + + if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) { + stack; + return 0; + } if (lvm_snprintf(name, sizeof(name), "%s/%s", _backup_params.dir, vg->name) < 0) { @@ -151,7 +184,7 @@ static int __backup(struct volume_group *vg) log_verbose("Creating volume group backup \"%s\"", name); - if (!(tf = text_format_create(vg->cmd, name, the_um))) { + if (!(tf = text_format_create(vg->cmd, name, the_um, desc))) { stack; return 0; } @@ -207,9 +240,9 @@ static struct volume_group *_read_vg(struct cmd_context *cmd, struct volume_group *vg; struct format_instance *tf; - if (!(tf = text_format_create(cmd, file, the_um))) { + if (!(tf = text_format_create(cmd, file, the_um, cmd->cmd_line))) { log_error("Couldn't create text format object."); - return 0; + return NULL; } if (!(vg = tf->ops->vg_read(tf, vg_name))) diff --git a/tools/lvm.c b/tools/lvm.c index 3d84cab3e..c2f6f70f7 100644 --- a/tools/lvm.c +++ b/tools/lvm.c @@ -684,10 +684,46 @@ static void _use_settings(struct config_info *settings) backup_enable(settings->backup); } +static char *_copy_command_line(struct pool *mem, int argc, char **argv) +{ + int i; + + /* + * Build up the complete command line, used as a + * description for backups. + */ + if (!pool_begin_object(cmd->mem, 128)) + goto bad; + + for (i = 0; i < argc; i++) { + if (!pool_grow_object(cmd->mem, argv[i], strlen(argv[i]))) + goto bad; + + if (i < (argc - 1)) + if (!pool_grow_object(cmd->mem, " ", 1)); + } + + /* + * Terminate. + */ + if (!pool_grow_object(mem, "\0", 1)) + goto bad; + + return pool_end_object(mem); + + bad: + log_err("Couldn't copy command line."); + pool_abandon_object(mem); + return NULL; +} + static int run_command(int argc, char **argv) { int ret = 0; + if (!(cmd->cmd_line = _copy_command_line(cmd->mem, argc, argv))) + return ECMD_FAILED; + if (!(the_command = find_command(argv[0]))) return ENO_SUCH_CMD; @@ -787,7 +823,7 @@ static void __init_log(struct config_file *cf) init_cmd_name(find_config_int(cf->root, "log/command_names", '/', 0)); - _default_settings.test = find_config_int(cf->root, "global/test", + _default_settings.test = find_config_int(cf->root, "global/test", '/', 0); if (find_config_int(cf->root, "log/overwrite", '/', 0)) open_mode = "w"; diff --git a/tools/vgcfgbackup.c b/tools/vgcfgbackup.c index 949c96ec1..17e378837 100644 --- a/tools/vgcfgbackup.c +++ b/tools/vgcfgbackup.c @@ -13,7 +13,8 @@ static int _backup_to_file(const char *file, struct volume_group *vg) int r; struct format_instance *tf; - if (!(tf = text_format_create(vg->cmd, file, the_um))) { + if (!(tf = text_format_create(vg->cmd, file, the_um, + vg->cmd->cmd_line))) { log_error("Couldn't create backup object."); return 0; } -- 2.43.5