mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o Rename many occurrences of 'backup' to 'archive' to reduce confusion.
o Extract file creation/renaming code into a library and change backup code to use it too. o Support umask. o Bring lvm.conf man page up-to-date.
This commit is contained in:
parent
4bbf2c3418
commit
952d12a5f5
@ -20,6 +20,7 @@
|
|||||||
../lib/mm/dbg_malloc.h
|
../lib/mm/dbg_malloc.h
|
||||||
../lib/mm/pool.h
|
../lib/mm/pool.h
|
||||||
../lib/mm/xlate.h
|
../lib/mm/xlate.h
|
||||||
|
../lib/misc/lvm-file.h
|
||||||
../lib/misc/lvm-string.h
|
../lib/misc/lvm-string.h
|
||||||
../lib/regex/matcher.h
|
../lib/regex/matcher.h
|
||||||
../lib/uuid/uuid.h
|
../lib/uuid/uuid.h
|
||||||
|
@ -29,7 +29,7 @@ SOURCES=\
|
|||||||
format1/import-extents.c \
|
format1/import-extents.c \
|
||||||
format1/layout.c \
|
format1/layout.c \
|
||||||
format1/vg_number.c \
|
format1/vg_number.c \
|
||||||
format_text/backup.c \
|
format_text/archive.c \
|
||||||
format_text/export.c \
|
format_text/export.c \
|
||||||
format_text/flags.c \
|
format_text/flags.c \
|
||||||
format_text/format-text.c \
|
format_text/format-text.c \
|
||||||
@ -40,6 +40,7 @@ SOURCES=\
|
|||||||
metadata/merge.c \
|
metadata/merge.c \
|
||||||
metadata/metadata.c \
|
metadata/metadata.c \
|
||||||
metadata/pv_map.c \
|
metadata/pv_map.c \
|
||||||
|
misc/lvm-file.c \
|
||||||
mm/dbg_malloc.c \
|
mm/dbg_malloc.c \
|
||||||
mm/pool.c \
|
mm/pool.c \
|
||||||
regex/matcher.c \
|
regex/matcher.c \
|
||||||
|
421
lib/format_text/archive.c
Normal file
421
lib/format_text/archive.c
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||||
|
*
|
||||||
|
* This file is released under the LGPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "format-text.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "import-export.h"
|
||||||
|
#include "lvm-string.h"
|
||||||
|
#include "lvm-file.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The format instance is given a directory path upon creation.
|
||||||
|
* Each file in this directory whose name is of the form
|
||||||
|
* '(.*)_[0-9]*.vg' is a config file (see lib/config.[hc]), which
|
||||||
|
* contains a description of a single volume group.
|
||||||
|
*
|
||||||
|
* The prefix ($1 from the above regex) of the config file gives
|
||||||
|
* the volume group name.
|
||||||
|
*
|
||||||
|
* Backup files that have expired will be removed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct archive_c {
|
||||||
|
uint32_t retain_days;
|
||||||
|
uint32_t min_retains;
|
||||||
|
|
||||||
|
char *dir;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An ordered list of previous archives. Each list
|
||||||
|
* entered against the vg name. Most recent first.
|
||||||
|
*/
|
||||||
|
struct hash_table *vg_archives;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scratch pool. Contents of vg_archives come from here.
|
||||||
|
*/
|
||||||
|
struct pool *mem;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A list of these is built up for each volume group. Ordered
|
||||||
|
* with the least recent at the head.
|
||||||
|
*/
|
||||||
|
struct archive_file {
|
||||||
|
struct list list;
|
||||||
|
|
||||||
|
char *path;
|
||||||
|
char *vg;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This format is write only.
|
||||||
|
*/
|
||||||
|
static void _unsupported(const char *cmd)
|
||||||
|
{
|
||||||
|
log_err("The archive format doesn't support '%s'", cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct list *_get_vgs(struct format_instance *fi)
|
||||||
|
{
|
||||||
|
_unsupported("get_vgs");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct list *_get_pvs(struct format_instance *fi)
|
||||||
|
{
|
||||||
|
_unsupported("get_pvs");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct physical_volume *_pv_read(struct format_instance *fi,
|
||||||
|
const char *pv_name)
|
||||||
|
{
|
||||||
|
_unsupported("pv_read");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
|
||||||
|
struct volume_group *vg)
|
||||||
|
{
|
||||||
|
_unsupported("pv_setup");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||||
|
{
|
||||||
|
_unsupported("pv_write");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||||
|
{
|
||||||
|
_unsupported("vg_setup");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct volume_group *_vg_read(struct format_instance *fi,
|
||||||
|
const char *vg_name)
|
||||||
|
{
|
||||||
|
_unsupported("vg_read");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy(struct format_instance *fi)
|
||||||
|
{
|
||||||
|
struct archive_c *bc = (struct archive_c *) fi->private;
|
||||||
|
if (bc->vg_archives)
|
||||||
|
hash_destroy(bc->vg_archives);
|
||||||
|
pool_destroy(bc->mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract vg name and version number from a filename.
|
||||||
|
*/
|
||||||
|
static int _split_vg(const char *filename, char *vg, size_t vg_size,
|
||||||
|
uint32_t *index)
|
||||||
|
{
|
||||||
|
int len, vg_len;
|
||||||
|
char *dot, *underscore;
|
||||||
|
|
||||||
|
len = strlen(filename);
|
||||||
|
if (len < 7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dot = (char *) (filename + len - 3);
|
||||||
|
if (strcmp(".vg", dot))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(underscore = rindex(filename, '_')))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sscanf(underscore + 1, "%u", index) != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
vg_len = underscore - filename;
|
||||||
|
if (vg_len + 1 > vg_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strncpy(vg, filename, vg_len);
|
||||||
|
vg[vg_len] = '\0';
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _insert_file(struct list *head, struct archive_file *b)
|
||||||
|
{
|
||||||
|
struct list *bh;
|
||||||
|
struct archive_file *bf;
|
||||||
|
|
||||||
|
if (list_empty(head)) {
|
||||||
|
list_add(head, &b->list);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* index increases through list */
|
||||||
|
list_iterate (bh, head) {
|
||||||
|
bf = list_item(bh, struct archive_file);
|
||||||
|
|
||||||
|
if (bf->index > b->index) {
|
||||||
|
list_add(&bf->list, &b->list);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_h(&bf->list, &b->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _scan_vg(struct archive_c *bc, const char *file,
|
||||||
|
const char *vg_name, int index)
|
||||||
|
{
|
||||||
|
struct archive_file *b;
|
||||||
|
struct list *files;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do we need to create a new list of archive files for
|
||||||
|
* this vg ?
|
||||||
|
*/
|
||||||
|
if (!(files = hash_lookup(bc->vg_archives, vg_name))) {
|
||||||
|
if (!(files = pool_alloc(bc->mem, sizeof(*files)))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_init(files);
|
||||||
|
if (!hash_insert(bc->vg_archives, vg_name, files)) {
|
||||||
|
log_err("Couldn't insert archive file "
|
||||||
|
"into hash table.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new archive file.
|
||||||
|
*/
|
||||||
|
if (!(b = pool_alloc(bc->mem, sizeof(*b)))) {
|
||||||
|
log_err("Couldn't create new archive file.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->index = index;
|
||||||
|
b->path = (char *)file;
|
||||||
|
b->vg = (char *)vg_name;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert it to the correct part of the list.
|
||||||
|
*/
|
||||||
|
_insert_file(files, b);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *_join(struct pool *mem, const char *dir, const char *name)
|
||||||
|
{
|
||||||
|
if (!pool_begin_object(mem, 32) ||
|
||||||
|
!pool_grow_object(mem, dir, strlen(dir)) ||
|
||||||
|
!pool_grow_object(mem, "/", 1) ||
|
||||||
|
!pool_grow_object(mem, name, strlen(name)) ||
|
||||||
|
!pool_grow_object(mem, "\0", 1)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pool_end_object(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _scan_dir(struct archive_c *bc)
|
||||||
|
{
|
||||||
|
int r = 0, i, count, index;
|
||||||
|
char vg_name[64], *path;
|
||||||
|
struct dirent **dirent;
|
||||||
|
|
||||||
|
if ((count = scandir(bc->dir, &dirent, NULL, alphasort)) < 0) {
|
||||||
|
log_err("Couldn't scan archive directory.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if ((dirent[i]->d_name[0] == '.') ||
|
||||||
|
!_split_vg(dirent[i]->d_name, vg_name,
|
||||||
|
sizeof(vg_name), &index))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(path = _join(bc->mem, bc->dir, dirent[i]->d_name))) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
_scan_vg(bc, path, vg_name, index);
|
||||||
|
}
|
||||||
|
r = 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
free(dirent[i]);
|
||||||
|
free(dirent);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _scan_archives(struct archive_c *bc)
|
||||||
|
{
|
||||||
|
pool_empty(bc->mem);
|
||||||
|
|
||||||
|
if (bc->vg_archives)
|
||||||
|
hash_destroy(bc->vg_archives);
|
||||||
|
|
||||||
|
if (!(bc->vg_archives = hash_create(128))) {
|
||||||
|
log_err("Couldn't create hash table for scanning archives.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_scan_dir(bc)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
|
||||||
|
if (!create_temp_name(bc->dir, temp_file, sizeof(temp_file), &fd)) {
|
||||||
|
log_err("Couldn't create temporary archive name.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fp = fdopen(fd, "w"))) {
|
||||||
|
log_err("Couldn't create FILE object for archive.");
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!text_vg_export(fp, vg)) {
|
||||||
|
stack;
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we want to rename this file to <vg>_index.vg.
|
||||||
|
*/
|
||||||
|
if (!_scan_archives(bc)) {
|
||||||
|
log_err("Couldn't scan the archive directory (%s).", bc->dir);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((last = (struct archive_file *) hash_lookup(bc->vg_archives,
|
||||||
|
vg->name))) {
|
||||||
|
/* move to the last in the list */
|
||||||
|
last = list_item(last->list.p, struct archive_file);
|
||||||
|
index = last->index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
if (lvm_snprintf(archive_name, sizeof(archive_name),
|
||||||
|
"%s/%s_%05d.vg",
|
||||||
|
bc->dir, vg->name, index) < 0) {
|
||||||
|
log_err("archive file name too long.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lvm_rename(temp_file, archive_name)) {
|
||||||
|
r = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void archive_expire(struct format_instance *fi)
|
||||||
|
{
|
||||||
|
/* FIXME: finish */
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct format_handler _archive_handler = {
|
||||||
|
get_vgs: _get_vgs,
|
||||||
|
get_pvs: _get_pvs,
|
||||||
|
pv_read: _pv_read,
|
||||||
|
pv_setup: _pv_setup,
|
||||||
|
pv_write: _pv_write,
|
||||||
|
vg_setup: _vg_setup,
|
||||||
|
vg_read: _vg_read,
|
||||||
|
vg_write: _vg_write,
|
||||||
|
destroy: _destroy
|
||||||
|
};
|
||||||
|
|
||||||
|
struct format_instance *archive_format_create(struct cmd_context *cmd,
|
||||||
|
const char *dir,
|
||||||
|
uint32_t retain_days,
|
||||||
|
uint32_t min_retains)
|
||||||
|
{
|
||||||
|
struct format_instance *fi;
|
||||||
|
struct archive_c *bc = NULL;
|
||||||
|
struct pool *mem = cmd->mem;
|
||||||
|
|
||||||
|
if (!(bc = pool_zalloc(mem, sizeof(*bc)))) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(bc->mem = pool_create(1024))) {
|
||||||
|
stack;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(bc->dir = pool_strdup(mem, dir))) {
|
||||||
|
stack;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
bc->retain_days = retain_days;
|
||||||
|
bc->min_retains = min_retains;
|
||||||
|
|
||||||
|
if (!(fi = pool_alloc(mem, sizeof(*fi)))) {
|
||||||
|
stack;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fi->cmd = cmd;
|
||||||
|
fi->ops = &_archive_handler;
|
||||||
|
fi->private = bc;
|
||||||
|
|
||||||
|
return fi;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
if (bc->mem)
|
||||||
|
pool_destroy(bc->mem);
|
||||||
|
|
||||||
|
pool_free(mem, bc);
|
||||||
|
return NULL;
|
||||||
|
}
|
@ -7,11 +7,17 @@
|
|||||||
#include "format-text.h"
|
#include "format-text.h"
|
||||||
#include "import-export.h"
|
#include "import-export.h"
|
||||||
|
|
||||||
|
#include "lvm-file.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: Currently there can be only one vg per file.
|
* NOTE: Currently there can be only one vg per file.
|
||||||
*/
|
*/
|
||||||
@ -69,25 +75,51 @@ static struct volume_group *_vg_read(struct format_instance *fi,
|
|||||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
int fd;
|
||||||
|
char *slash;
|
||||||
char *file = (char *) fi->private;
|
char *file = (char *) fi->private;
|
||||||
|
char temp_file[PATH_MAX], temp_dir[PATH_MAX];
|
||||||
|
|
||||||
/* FIXME: should be opened exclusively */
|
slash = rindex(file, '/');
|
||||||
if (!(fp = fopen(file, "w"))) {
|
|
||||||
log_sys_error("fopen", file);
|
if (slash == 0)
|
||||||
|
strcpy(temp_dir, ".");
|
||||||
|
else if (slash - file < PATH_MAX) {
|
||||||
|
strncpy(temp_dir, file, slash - file);
|
||||||
|
temp_dir[slash - file] = '\0';
|
||||||
|
} else {
|
||||||
|
log_error("Text format failed to determine directory.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!create_temp_name(temp_dir, temp_file, sizeof(temp_file), &fd)) {
|
||||||
|
log_err("Couldn't create temporary text file name.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fp = fdopen(fd, "w"))) {
|
||||||
|
log_sys_error("fdopen", temp_file);
|
||||||
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text_vg_export(fp, vg)) {
|
if (!text_vg_export(fp, vg)) {
|
||||||
log_error("Failed to write metadata to %s.", file);
|
log_error("Failed to write metadata to %s.", temp_file);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fclose(fp)) {
|
if (fclose(fp)) {
|
||||||
log_sys_error("fclose", file);
|
log_sys_error("fclose", file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rename(temp_file, file)) {
|
||||||
|
log_error("%s: rename to %s failed: %s", temp_file, file,
|
||||||
|
strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,17 +11,18 @@
|
|||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The backup format is used to maintain a set of backup files.
|
* The archive format is used to maintain a set of metadata backup files
|
||||||
* 'retain_days' gives the minimum number of days that a backup must
|
* in an archive directory.
|
||||||
|
* 'retain_days' is the minimum number of days that an archive file must
|
||||||
* be held for.
|
* be held for.
|
||||||
*
|
*
|
||||||
* 'min_backups' is the minimum number of backups required for each volume
|
* 'min_archives' is the minimum number of archives required to be kept
|
||||||
* group.
|
* for each volume group.
|
||||||
*/
|
*/
|
||||||
struct format_instance *backup_format_create(struct cmd_context *cmd,
|
struct format_instance *archive_format_create(struct cmd_context *cmd,
|
||||||
const char *dir,
|
const char *dir,
|
||||||
uint32_t retain_days,
|
uint32_t retain_days,
|
||||||
uint32_t min_backups);
|
uint32_t min_archives);
|
||||||
|
|
||||||
void backup_expire(struct format_instance *fi);
|
void backup_expire(struct format_instance *fi);
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ e.g. backup {
|
|||||||
.br
|
.br
|
||||||
An assignment associates a type with an identifier.
|
An assignment associates a type with an identifier.
|
||||||
.br
|
.br
|
||||||
e.g. max_backups = 42
|
e.g. max_archives = 42
|
||||||
.br
|
.br
|
||||||
.TP
|
.TP
|
||||||
\fBarray = '[' (type ',')* type ']' | '[' ']'\fP
|
\fBarray = '[' (type ',')* type ']' | '[' ']'\fP
|
||||||
@ -109,26 +109,50 @@ is invoked. By default tools append messages to the log file.
|
|||||||
\fBtest\fP \(em If set to 1, run tools in test mode i.e. no metadata
|
\fBtest\fP \(em If set to 1, run tools in test mode i.e. no metadata
|
||||||
gets updated.
|
gets updated.
|
||||||
.TP
|
.TP
|
||||||
\fBbackup\fP \(em Configuration for metadata backups
|
\fBbackup\fP \(em Configuration for metadata backups.
|
||||||
.IP
|
.IP
|
||||||
\fBdir\fP \(em Directory used for automatic metadata backups.
|
\fBarchive_dir\fP \(em Directory used for automatic metadata archives.
|
||||||
|
Backup copies of former metadata for each volume group are archived here.
|
||||||
|
Defaults to "/etc/lvm/archive".
|
||||||
|
.IP
|
||||||
|
\fBbackup_dir\fP \(em Directory used for automatic metadata backups.
|
||||||
|
A single backup copy of the current metadata for each volume group
|
||||||
|
is stored here.
|
||||||
Defaults to "/etc/lvm/backup".
|
Defaults to "/etc/lvm/backup".
|
||||||
.IP
|
.IP
|
||||||
\fBkeep\fP \(em Minimum number of backups to keep.
|
\fBarchive\fP \(em Whether or not tools automatically archive existing
|
||||||
|
metadata into \fBarchive_dir\fP before making changes to it.
|
||||||
|
Default is 1 (automatic archives enabled).
|
||||||
|
Set to 0 to disable.
|
||||||
|
Disabling this might make metadata recovery difficult or impossible
|
||||||
|
if something goes wrong.
|
||||||
|
.IP
|
||||||
|
\fBbackup\fP \(em Whether or not tools make an automatic backup
|
||||||
|
into \fBbackup_dir\fP after changing metadata.
|
||||||
|
Default is 1 (automatic backups enabled). Set to 0 to disable.
|
||||||
|
Disabling this might make metadata recovery difficult or impossible
|
||||||
|
if something goes wrong.
|
||||||
|
.IP
|
||||||
|
\fBretain_min\fP \(em Minimum number of archives to keep.
|
||||||
Defaults to 10.
|
Defaults to 10.
|
||||||
.IP
|
.IP
|
||||||
\fBdays\fP \(em Minimum number of days to keep backup files.
|
\fBretain_days\fP \(em Minimum number of days to keep archive files.
|
||||||
Defaults to 14.
|
Defaults to 30.
|
||||||
.IP
|
|
||||||
\fBauto\fP \(em Whether or not tools make automatic backups after changing
|
|
||||||
metadata. Default is 1 (automatic backups enabled). Set to 0 to disable.
|
|
||||||
.TP
|
.TP
|
||||||
\fBshell\fP \(em LVM2 built-in readline shell settings
|
\fBshell\fP \(em LVM2 built-in readline shell settings
|
||||||
.IP
|
.IP
|
||||||
\fBhistory_size\fP \(em Maximum number of lines of shell history to retain (default 100) in $HOME/.lvm_history
|
\fBhistory_size\fP \(em Maximum number of lines of shell history to retain (default 100) in $HOME/.lvm_history
|
||||||
|
.TP
|
||||||
|
\fBglobal\fP \(em Global settings
|
||||||
|
.IP
|
||||||
|
\fBumask\fP \(em File creation mask for any files and directories created.
|
||||||
|
Interpreted as octal if the first digit is zero.
|
||||||
|
Defaults to 077.
|
||||||
|
Use 022 to allow other users to read the files by default.
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.I /etc/lvm/lvm.conf
|
.I /etc/lvm/lvm.conf
|
||||||
.br
|
.br
|
||||||
.I $HOME/.lvm_history
|
.I $HOME/.lvm_history
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR lvm (8)
|
.BR lvm (8)
|
||||||
|
.BR umask (2)
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
#include "toollib.h"
|
#include "toollib.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
@ -60,7 +61,7 @@ static int __archive(struct volume_group *vg)
|
|||||||
int r;
|
int r;
|
||||||
struct format_instance *archiver;
|
struct format_instance *archiver;
|
||||||
|
|
||||||
if (!(archiver = backup_format_create(vg->cmd,
|
if (!(archiver = archive_format_create(vg->cmd,
|
||||||
_archive_params.dir,
|
_archive_params.dir,
|
||||||
_archive_params.keep_days,
|
_archive_params.keep_days,
|
||||||
_archive_params.keep_number))) {
|
_archive_params.keep_number))) {
|
||||||
|
@ -37,5 +37,6 @@ void backup_exit(void);
|
|||||||
|
|
||||||
void backup_enable(int flag);
|
void backup_enable(int flag);
|
||||||
int backup(struct volume_group *vg);
|
int backup(struct volume_group *vg);
|
||||||
|
int backup_remove(const char *vg_name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -333,6 +333,7 @@ xx(vgcfgbackup,
|
|||||||
"Backup volume group configuration(s)",
|
"Backup volume group configuration(s)",
|
||||||
"vgcfgbackup " "\n"
|
"vgcfgbackup " "\n"
|
||||||
"\t[-d|--debug] " "\n"
|
"\t[-d|--debug] " "\n"
|
||||||
|
"\t[-f|--file filename] " "\n"
|
||||||
"\t[-h|--help] " "\n"
|
"\t[-h|--help] " "\n"
|
||||||
"\t[-v|--verbose]" "\n"
|
"\t[-v|--verbose]" "\n"
|
||||||
"\t[-V|--version] " "\n"
|
"\t[-V|--version] " "\n"
|
||||||
@ -343,7 +344,7 @@ xx(vgcfgrestore,
|
|||||||
"Restore volume group configuration",
|
"Restore volume group configuration",
|
||||||
"vgcfgrestore " "\n"
|
"vgcfgrestore " "\n"
|
||||||
"\t[-d|--debug] " "\n"
|
"\t[-d|--debug] " "\n"
|
||||||
"\t[-f|--file VGConfPath] " "\n"
|
"\t[-f|--file filename] " "\n"
|
||||||
"\t[-l[l]|--list [--list]]" "\n"
|
"\t[-l[l]|--list [--list]]" "\n"
|
||||||
"\t[-n|--name VolumeGroupName] " "\n"
|
"\t[-n|--name VolumeGroupName] " "\n"
|
||||||
"\t[-h|--help]" "\n"
|
"\t[-h|--help]" "\n"
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#define DEFAULT_DEV_DIR "/dev"
|
#define DEFAULT_DEV_DIR "/dev"
|
||||||
|
|
||||||
|
#define DEFAULT_UMASK 0077
|
||||||
|
|
||||||
#ifdef READLINE_SUPPORT
|
#ifdef READLINE_SUPPORT
|
||||||
#define DEFAULT_MAX_HISTORY 100
|
#define DEFAULT_MAX_HISTORY 100
|
||||||
#endif
|
#endif
|
||||||
|
31
tools/lvm.c
31
tools/lvm.c
@ -65,6 +65,8 @@ struct config_info {
|
|||||||
|
|
||||||
int archive; /* should we archive ? */
|
int archive; /* should we archive ? */
|
||||||
int backup; /* should we backup ? */
|
int backup; /* should we backup ? */
|
||||||
|
|
||||||
|
mode_t umask;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct config_info _default_settings;
|
static struct config_info _default_settings;
|
||||||
@ -661,6 +663,15 @@ static void __init_log(struct config_file *cf)
|
|||||||
|
|
||||||
const char *log_file = find_config_str(cf->root, "log/file", '/', 0);
|
const char *log_file = find_config_str(cf->root, "log/file", '/', 0);
|
||||||
|
|
||||||
|
_default_settings.debug =
|
||||||
|
find_config_int(cf->root, "log/level", '/', 0);
|
||||||
|
_default_settings.verbose =
|
||||||
|
find_config_int(cf->root, "log/verbose", '/', 0);
|
||||||
|
_default_settings.test = find_config_int(cf->root, "log/test", '/', 0);
|
||||||
|
|
||||||
|
init_debug(_default_settings.debug);
|
||||||
|
init_verbose(_default_settings.verbose);
|
||||||
|
|
||||||
if (find_config_int(cf->root, "log/overwrite", '/', 0))
|
if (find_config_int(cf->root, "log/overwrite", '/', 0))
|
||||||
open_mode = "w";
|
open_mode = "w";
|
||||||
|
|
||||||
@ -672,13 +683,6 @@ static void __init_log(struct config_file *cf)
|
|||||||
init_log(_log);
|
init_log(_log);
|
||||||
}
|
}
|
||||||
|
|
||||||
_default_settings.debug =
|
|
||||||
find_config_int(cf->root, "log/level", '/', 0);
|
|
||||||
|
|
||||||
_default_settings.verbose =
|
|
||||||
find_config_int(cf->root, "log/verbose", '/', 0);
|
|
||||||
|
|
||||||
_default_settings.test = find_config_int(cf->root, "log/test", '/', 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _init_backup(struct config_file *cf)
|
static int _init_backup(struct config_file *cf)
|
||||||
@ -869,6 +873,7 @@ static int init(void)
|
|||||||
{
|
{
|
||||||
struct stat info;
|
struct stat info;
|
||||||
char config_file[PATH_MAX] = "";
|
char config_file[PATH_MAX] = "";
|
||||||
|
mode_t old_umask;
|
||||||
|
|
||||||
if (!_get_env_vars())
|
if (!_get_env_vars())
|
||||||
return 0;
|
return 0;
|
||||||
@ -890,11 +895,11 @@ static int init(void)
|
|||||||
/* Use LOG_USER for syslog messages by default */
|
/* Use LOG_USER for syslog messages by default */
|
||||||
init_syslog(LOG_USER);
|
init_syslog(LOG_USER);
|
||||||
|
|
||||||
_init_rand();
|
|
||||||
|
|
||||||
/* send log messages to stderr for now */
|
/* send log messages to stderr for now */
|
||||||
init_log(stderr);
|
init_log(stderr);
|
||||||
|
|
||||||
|
_init_rand();
|
||||||
|
|
||||||
if (*_sys_dir && lvm_snprintf(config_file, sizeof(config_file),
|
if (*_sys_dir && lvm_snprintf(config_file, sizeof(config_file),
|
||||||
"%s/lvm.conf", _sys_dir) < 0) {
|
"%s/lvm.conf", _sys_dir) < 0) {
|
||||||
log_error("lvm_sys_dir was too long");
|
log_error("lvm_sys_dir was too long");
|
||||||
@ -912,6 +917,14 @@ static int init(void)
|
|||||||
__init_log(cmd->cf);
|
__init_log(cmd->cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_default_settings.umask = find_config_int(cmd->cf->root,
|
||||||
|
"global/umask", '/',
|
||||||
|
DEFAULT_UMASK);
|
||||||
|
|
||||||
|
if ((old_umask = umask((mode_t)_default_settings.umask)) !=
|
||||||
|
(mode_t)_default_settings.umask)
|
||||||
|
log_verbose("Set umask to %04o", _default_settings.umask);
|
||||||
|
|
||||||
if (lvm_snprintf(_dev_dir, sizeof(_dev_dir), "%s/",
|
if (lvm_snprintf(_dev_dir, sizeof(_dev_dir), "%s/",
|
||||||
find_config_str(cmd->cf->root, "devices/dir",
|
find_config_str(cmd->cf->root, "devices/dir",
|
||||||
'/', DEFAULT_DEV_DIR)) < 0) {
|
'/', DEFAULT_DEV_DIR)) < 0) {
|
||||||
|
@ -17,7 +17,7 @@ int create_dir(const char *dir)
|
|||||||
|
|
||||||
if (stat(dir, &info) < 0 ) {
|
if (stat(dir, &info) < 0 ) {
|
||||||
log_verbose("Creating directory %s", dir);
|
log_verbose("Creating directory %s", dir);
|
||||||
if (!mkdir(dir, S_IRWXU))
|
if (!mkdir(dir, 0777));
|
||||||
return 1;
|
return 1;
|
||||||
log_sys_error("mkdir", dir);
|
log_sys_error("mkdir", dir);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -77,7 +77,7 @@ static int vgremove_single(const char *vg_name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
backup(vg);
|
backup_remove(vg_name);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
log_print("Volume group %s successfully removed", vg_name);
|
log_print("Volume group %s successfully removed", vg_name);
|
||||||
|
Loading…
Reference in New Issue
Block a user