mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-10 16:58:47 +03:00
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.
This commit is contained in:
parent
af7bbe5a6c
commit
e74999af51
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)))
|
||||
|
38
tools/lvm.c
38
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";
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user