mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o Split import-export.c into two files.
This commit is contained in:
parent
a76318a698
commit
d96dea9abf
454
lib/format_text/export.c
Normal file
454
lib/format_text/export.c
Normal file
@ -0,0 +1,454 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "text-rep.h"
|
||||
#include "metadata.h"
|
||||
#include "log.h"
|
||||
#include "hash.h"
|
||||
#include "pool.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/*
|
||||
* The first half of this file deals with
|
||||
* exporting the vg, ie. writing it to a file.
|
||||
*/
|
||||
struct formatter {
|
||||
struct pool *mem; /* pv names allocated from here */
|
||||
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
|
||||
|
||||
FILE *fp; /* where we're writing to */
|
||||
int indent; /* current level of indentation */
|
||||
};
|
||||
|
||||
#define MAX_INDENT 5
|
||||
static void _inc_indent(struct formatter *f)
|
||||
{
|
||||
if (++f->indent > MAX_INDENT)
|
||||
f->indent = MAX_INDENT;
|
||||
}
|
||||
|
||||
static void _dec_indent(struct formatter *f)
|
||||
{
|
||||
if (--f->indent) {
|
||||
log_debug("Indenting seems to have messed up\n");
|
||||
f->indent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Newline function for prettier layout.
|
||||
*/
|
||||
static void _nl(struct formatter *f)
|
||||
{
|
||||
fprintf(f->fp, "\n");
|
||||
}
|
||||
|
||||
#define COMMENT_TAB 6
|
||||
static void _out_with_comment(struct formatter *f, const char *comment,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
int i;
|
||||
char white_space[MAX_INDENT + 1];
|
||||
|
||||
for (i = 0; i < f->indent; i++)
|
||||
white_space[i] = '\t';
|
||||
white_space[i] = '\0';
|
||||
fprintf(f->fp, white_space);
|
||||
|
||||
i = vfprintf(f->fp, fmt, ap);
|
||||
|
||||
if (comment) {
|
||||
/*
|
||||
* line comments up if possible.
|
||||
*/
|
||||
i += 8 * f->indent;
|
||||
i /= 8;
|
||||
i++;
|
||||
|
||||
do
|
||||
fputc('\t', f->fp);
|
||||
|
||||
while (++i < COMMENT_TAB);
|
||||
|
||||
fprintf(f->fp, comment);
|
||||
}
|
||||
fputc('\n', f->fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Formats a string, converting a size specified
|
||||
* in 512-byte sectors to a more human readable
|
||||
* form (eg, megabytes). We may want to lift this
|
||||
* for other code to use.
|
||||
*/
|
||||
static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
{
|
||||
static char *_units = [
|
||||
"Kilobytes",
|
||||
"Megabytes",
|
||||
"Gigabytes",
|
||||
"Terrabytes",
|
||||
NULL
|
||||
];
|
||||
|
||||
int i;
|
||||
double d = (double) sectors;
|
||||
|
||||
/* to convert to K */
|
||||
d /= 2.0;
|
||||
|
||||
for (i = 0; (d > 1024.0) && _units[i]; i++)
|
||||
d /= 1024.0;
|
||||
|
||||
/* FIXME: arrange so this doesn't print a
|
||||
* decimal point unless we have a
|
||||
* fractional part. */
|
||||
return snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends a comment giving a size in more easily
|
||||
* readable form (eg, 4M instead of 8096).
|
||||
*/
|
||||
static void _out_size(struct formatter *f, uint64_t size,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
char buffer[64];
|
||||
va_list ap;
|
||||
|
||||
_sectors_to_units(size, buffer, sizeof(buffer));
|
||||
|
||||
va_start(ap, fmt);
|
||||
_out_with_comment(f, buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends a comment indicating that the line is
|
||||
* only a hint.
|
||||
*/
|
||||
static void _out_hint(struct formatter *f, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_out_with_comment(f, "# Hint only", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* The normal output function.
|
||||
*/
|
||||
static void _out(struct formatter *f, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_out_with_comment(f, NULL, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static int _print_header(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
_out(f,
|
||||
"# This file was originally generated by the LVM2 library\n"
|
||||
"# It is inadvisable for people to edit this by hand unless\n"
|
||||
"# they *really* know what they're doing.\n"
|
||||
"# Generated: %s\n", ctime(time(NULL)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
if (!id_write_format(&vg.uuid, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "id = \"%s\"", buffer);
|
||||
_nl(f);
|
||||
|
||||
if (!_print_flags(vg->status, _vg_flags, buffer, size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "status = %s");
|
||||
_nl(f);
|
||||
|
||||
_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size);
|
||||
_nl(f);
|
||||
|
||||
_out(f, "max_lv = %u", vg->max_lv);
|
||||
_out(f, "max_pv = %u", vg->max_pv);
|
||||
_nl(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the pv%d name from the formatters hash
|
||||
* table.
|
||||
*/
|
||||
static inline const char *
|
||||
_get_pv_name(struct formatter *f, struct physical_volume *pv)
|
||||
{
|
||||
return (const char *) hash_lookup(f->pv_names, dev_name(pv));
|
||||
}
|
||||
|
||||
static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list pvh;
|
||||
struct physical_volume *pv;
|
||||
char buffer[256];
|
||||
const char *name;
|
||||
|
||||
_out(f, "physical_volumes {");
|
||||
_nl(f);
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate (pvh, &vg->pvs) {
|
||||
|
||||
if (!(name = _get_pv_name(f, pv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "%s {", name);
|
||||
_inc_indent(f);
|
||||
|
||||
pv = &list_item(pvh, struct pv_list)->pv;
|
||||
|
||||
if (!id_write_format(&pv->uuid, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "tid = \"%s\"", buffer);
|
||||
_out_hint(f, "device = %s", dev_name(pv->dev));
|
||||
_nl(f);
|
||||
|
||||
if (!print_flags(pv->status, _pv_flags,
|
||||
buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "status = %s", buffer);
|
||||
_out(f, "pe_start = %u", pv->pe_start);
|
||||
_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||
"pe_count = %u", pv->pe_count);
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
_nl(f);
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
int count, struct stripe_segment *seg, int last)
|
||||
{
|
||||
int s;
|
||||
const char *name;
|
||||
|
||||
_out(f, "segment%u {", count);
|
||||
_inc_indent(f);
|
||||
|
||||
_out(f, "start_entent = %u", seg->le);
|
||||
_out_size(f, seg->len * vg->extent_size, "extent_count = %u", seg->len);
|
||||
_out(f, "stripes = %u", seg->stripes);
|
||||
|
||||
if (seg->stripes > 1)
|
||||
_out_size(f, "stripe_size = %u", seg->stripe_size);
|
||||
|
||||
_nl(f);
|
||||
_out(f, "areas = [");
|
||||
_inc_indent(f);
|
||||
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
if (!(name = _get_pv_name(f, seg->areas[s].pv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "\"%s\", %u%s", name, seg->area[s].pe,
|
||||
last ? "" : ",");
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "]");
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh, *segh;
|
||||
struct logical_volume *lv;
|
||||
struct stripe_segment *seg;
|
||||
char buffer[256];
|
||||
int seg_count = 1;
|
||||
|
||||
_out(f, "logical_volumes {");
|
||||
_nl(f);
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate (lvh, &vg->lvs) {
|
||||
lv = &list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
_out(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
if (!_print_flags(lv->status, _lv_flags,
|
||||
buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "read_ahead = %u", lv->read_ahead);
|
||||
_nl(f);
|
||||
|
||||
_out(f, "segment_count = %u", _count_segments(lv));
|
||||
_nl(f);
|
||||
|
||||
list_iterate (segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
if (!_print_segment(f, seg_count++, seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_out(f, "}");
|
||||
_dec_indent(f);
|
||||
}
|
||||
|
||||
_out(f, "}");
|
||||
_nl(f);
|
||||
_dec_indent(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the text format we refer to pv's as 'pv1',
|
||||
* 'pv2' etc. This function builds a hash table
|
||||
* to enable a quick lookup from device -> name.
|
||||
*/
|
||||
static int _build_pv_names(struct formatter *f,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
int count = 0;
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
char buffer[32], *name;
|
||||
|
||||
if (!(f->mem = pool_create(512))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f->pv_names = hash_create(128))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_iterate (pvh, &vg->pvs) {
|
||||
pv = &list_item(pvh, struct pv_list)->pv;
|
||||
|
||||
if (snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(name = pool_strdup(f->mem, buffer))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!hash_insert(f->pv_names, dev_name(pv->dev), buffer)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
if (f->mem)
|
||||
pool_destroy(f->mem);
|
||||
|
||||
if (f->pv_names)
|
||||
hash_destroy(f->pv_names);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int text_vg_export(FILE *fp, struct volume_group *vg)
|
||||
{
|
||||
int r = 0;
|
||||
struct formatter *f;
|
||||
|
||||
if (!f = dbg_malloc(sizeof(*f))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(f, 0, sizeof(*f));
|
||||
f->fp = fp;
|
||||
f->indent = 0;
|
||||
|
||||
if (!_build_pv_names(f, vg)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define fail do {stack; goto out;} while(0)
|
||||
|
||||
if (!_print_header(f, vg))
|
||||
fail;
|
||||
|
||||
_out(f, "%s {", vg->name);
|
||||
_inc_indent(f):
|
||||
|
||||
if (!_print_vg(f, vg))
|
||||
fail;
|
||||
|
||||
if (!_print_pvs(f, vg))
|
||||
fail;
|
||||
|
||||
if (!_print_lvs(f, vg))
|
||||
fail;
|
||||
|
||||
#undef fail
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (f->mem)
|
||||
pool_destroy(f->mem);
|
||||
|
||||
if (f->pv_names)
|
||||
hash_destroy(f->pv_names);
|
||||
|
||||
dbg_free(f):
|
||||
return r;
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "text-rep.h"
|
||||
#include "metadata.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct flag {
|
||||
int mask;
|
||||
char *description;
|
||||
};
|
||||
|
||||
static struct flag _vg_flags[] = {
|
||||
{ACTIVE, "ACTIVE"},
|
||||
{EXPORTED_VG, "EXPORTED"},
|
||||
{EXTENDABLE_VG, "EXTENDABLE"},
|
||||
{CLUSTERED, "CLUSTERED"},
|
||||
{SHARED, "SHARED"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static struct flag _pv_flags[] = {
|
||||
{ACTIVE, "ACTIVE"},
|
||||
{ALLOCATED_PV, "ALLOCATED"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static struct flag _lv_flags[] = {
|
||||
{ACTIVE, "ACTIVE"},
|
||||
{READ, "READ"},
|
||||
{WRITE, "WRITE"},
|
||||
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
|
||||
{ALLOC_STRICT, "ALLOC_STRICT"},
|
||||
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
|
||||
{SNAPSHOT, "SNASHOT"},
|
||||
{SNAPSHOT_ORG, "SNAPSHOT_ORIGIN"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static void _print_flags(uint32_t status, struct flag *flags, FILE *fp)
|
||||
{
|
||||
int f, first = 1;
|
||||
|
||||
fprintf(fp, "[");
|
||||
for (f = 0; flags[f].mask; f++) {
|
||||
if (status & flags[f].mask) {
|
||||
if (!first)
|
||||
fprintf(fp, ", ");
|
||||
else
|
||||
first = 0;
|
||||
|
||||
fprintf(fp, "\"%s\"", flags[f].name);
|
||||
status &= ~flags[f].mask;
|
||||
}
|
||||
}
|
||||
fprintf(fp, "]");
|
||||
|
||||
if (status)
|
||||
/* FIXME: agk is this the correct log level ? */
|
||||
log_print("Not all flags were successfully exported, "
|
||||
"possible bug.");
|
||||
}
|
||||
|
||||
static int _print_header(FILE *fp, struct volume_group *vg)
|
||||
{
|
||||
fprintf(fp, "# This file was generated by the LVM2 library\n"
|
||||
"# %s\n\n", ctime(time(NULL)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_vg(FILE *fp, struct volume_group *vg)
|
||||
{
|
||||
fprintf(fp, "volume_group {\n");
|
||||
|
||||
fprintf(fp, "\tid = ");
|
||||
_print_uuid(&vg.uuid);
|
||||
fprintf(fp, "\n\tname = \"%s\"\n", vg->name);
|
||||
|
||||
fprintf(fp, "\tstatus = ");
|
||||
_print_flags(fp, vg->status, _vg_flags);
|
||||
|
||||
fprintf(fp, "\n\textent_size = %u", vg->extent_size);
|
||||
_print_size_comment(fp, vg->extent_size);
|
||||
|
||||
fprintf(fp, "\tmax_lv = %u\n", vg->max_lv);
|
||||
fprintf(fp, "\tmax_pv = %u\n", vg->max_pv);
|
||||
fprintf(fp, "}\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_pvs(FILE *fp, struct volume_group *vg)
|
||||
{
|
||||
struct list pvh;
|
||||
struct physical_volume *pv;
|
||||
int count;
|
||||
|
||||
fprintf(fp, "physical_volumes {\n\n");
|
||||
|
||||
list_iterate (pvh, &vg->pvs) {
|
||||
fprintf(fp, "\tpv%d {\n", count++);
|
||||
pv = &list_item(pvh, struct pv_list)->pv;
|
||||
fprintf(fp, "\t\tid = ");
|
||||
_print_uuid(fp, &pv->uuid);
|
||||
fprintf(fp, "\n\t\tdevice = %s\t# Hint only\n\n",
|
||||
dev_name(pv->dev));
|
||||
|
||||
fprintf(fp, "\t\tstatus = ");
|
||||
_print_flags(fp, pv->status, _pv_flags);
|
||||
|
||||
fprintf(fp, "\n\n\t\tpe_start = %u\n");
|
||||
fprintf(fp, "\t\tpe_count = %u", pv->pe_count);
|
||||
_print_size_comment(fp, pe_count * vg->extent_size);
|
||||
_fprintf(fp, "\n\t}\n")
|
||||
}
|
||||
|
||||
fprintf(fp, "}\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_lvs(FILE *fp, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
|
||||
fprintf(fp, "logical_volumes {\n");
|
||||
|
||||
list_iterate (lvh, &vg->lvs) {
|
||||
lv = &list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
|
||||
}
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import(struct pool *mem, struct config_file *cf)
|
||||
{
|
||||
log_err("text_vg_import not implemented yet.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int text_vg_export(FILE *fp, struct volume_group *vg)
|
||||
{
|
||||
#define fail do {stack; return 0;} while(0)
|
||||
|
||||
if (!_print_header(fp, vg))
|
||||
fail;
|
||||
|
||||
if (!_print_vg(fp, vg))
|
||||
fail;
|
||||
|
||||
if (!_print_pvs(fp, vg))
|
||||
fail;
|
||||
|
||||
if (!_print_lvs(fp, vg))
|
||||
fail;
|
||||
|
||||
#undef fail
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -7,7 +7,19 @@
|
||||
#ifndef _LVM_TEXT_IMPORT_EXPORT_H
|
||||
#define _LVM_TEXT_IMPORT_EXPORT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
enum {
|
||||
VG_FLAGS,
|
||||
PV_FLAGS,
|
||||
LV_FLAGS
|
||||
};
|
||||
|
||||
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);
|
||||
struct volume_group *text_vg_import(struct pool *mem, struct config_file *cf);
|
||||
struct config_file *text_vg_export(struct pool *mem, struct volume_group *vg);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user