mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o Populating with stuff from experimental
This commit is contained in:
parent
537d817f8a
commit
df88dece8b
618
lib/config/config.c
Normal file
618
lib/config/config.c
Normal file
@ -0,0 +1,618 @@
|
|||||||
|
/*
|
||||||
|
* tools/lib/lvm_config.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Sistina Software
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This LVM library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This LVM library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this LVM library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changelog
|
||||||
|
*
|
||||||
|
* 17/04/2001 - First version [Joe Thornber]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TOK_INT,
|
||||||
|
TOK_FLOAT,
|
||||||
|
TOK_STRING,
|
||||||
|
TOK_EQ,
|
||||||
|
TOK_SECTION_B,
|
||||||
|
TOK_SECTION_E,
|
||||||
|
TOK_ARRAY_B,
|
||||||
|
TOK_ARRAY_E,
|
||||||
|
TOK_IDENTIFIER,
|
||||||
|
TOK_COMMA,
|
||||||
|
TOK_EOF
|
||||||
|
};
|
||||||
|
|
||||||
|
struct parser {
|
||||||
|
const char *fb, *fe; /* file limits */
|
||||||
|
|
||||||
|
int t; /* token limits and type */
|
||||||
|
const char *tb, *te;
|
||||||
|
|
||||||
|
int fd; /* descriptor for file being parsed */
|
||||||
|
int line; /* line number we are on */
|
||||||
|
|
||||||
|
struct pool *mem;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cs {
|
||||||
|
struct config_file cf;
|
||||||
|
struct pool *mem;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _get_token(struct parser *p);
|
||||||
|
static void _eat_space(struct parser *p);
|
||||||
|
static struct config_node *_file(struct parser *p);
|
||||||
|
static struct config_node *_section(struct parser *p);
|
||||||
|
static struct config_value *_value(struct parser *p);
|
||||||
|
static struct config_value *_type(struct parser *p);
|
||||||
|
static void _parse_error(struct parser *p, const char *file, int line,
|
||||||
|
const char *mess);
|
||||||
|
static int _match_aux(struct parser *p, int t);
|
||||||
|
static struct config_value *_create_value(struct parser *p);
|
||||||
|
static struct config_node *_create_node(struct parser *p);
|
||||||
|
static char *_dup_tok(struct parser *p);
|
||||||
|
static int _tok_match(const char *str, const char *b, const char *e);
|
||||||
|
|
||||||
|
#define MAX_INDENT 32
|
||||||
|
|
||||||
|
#define match(t) do {\
|
||||||
|
if (!_match_aux(p, (t))) {\
|
||||||
|
_parse_error(p, __FILE__, __LINE__, "unexpected token"); \
|
||||||
|
return 0;\
|
||||||
|
} \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public interface
|
||||||
|
*/
|
||||||
|
struct config_file *create_config_file()
|
||||||
|
{
|
||||||
|
struct cs *c;
|
||||||
|
struct pool *mem = create_pool(10 * 1024);
|
||||||
|
|
||||||
|
if (!mem) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(c = pool_alloc(mem, sizeof(*c)))) {
|
||||||
|
stack;
|
||||||
|
destroy_pool(mem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->mem = mem;
|
||||||
|
return &c->cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_config_file(struct config_file *cf)
|
||||||
|
{
|
||||||
|
destroy_pool(((struct cs *) cf)->mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_config(struct config_file *cf, const char *file)
|
||||||
|
{
|
||||||
|
struct cs *c = (struct cs *) cf;
|
||||||
|
struct parser *p;
|
||||||
|
struct stat info;
|
||||||
|
int r = 1, fd;
|
||||||
|
|
||||||
|
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p->mem = c->mem;
|
||||||
|
|
||||||
|
/* memory map the file */
|
||||||
|
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
|
||||||
|
log_sys_err("stat");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = open(file, O_RDONLY)) < 0) {
|
||||||
|
log_sys_err("open");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
if (p->fb == MAP_FAILED) {
|
||||||
|
log_sys_err("mmap");
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p->fe = p->fb + info.st_size;
|
||||||
|
|
||||||
|
/* parse */
|
||||||
|
p->tb = p->te = p->fb;
|
||||||
|
p->line = 1;
|
||||||
|
_get_token(p);
|
||||||
|
if (!(cf->root = _file(p))) {
|
||||||
|
stack;
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unmap the file */
|
||||||
|
if (munmap((char *) p->fb, info.st_size)) {
|
||||||
|
log_sys_err("munmap failed");
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _write_value(FILE *fp, struct config_value *v)
|
||||||
|
{
|
||||||
|
switch (v->type) {
|
||||||
|
case CFG_STRING:
|
||||||
|
fprintf(fp, "\"%s\"", v->v.str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CFG_FLOAT:
|
||||||
|
fprintf(fp, "%f", v->v.r);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CFG_INT:
|
||||||
|
fprintf(fp, "%d", v->v.i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||||
|
{
|
||||||
|
char space[MAX_INDENT + 1];
|
||||||
|
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (i = 0; i < l; i++)
|
||||||
|
space[i] = ' ';
|
||||||
|
space[i] = '\0';
|
||||||
|
|
||||||
|
while (n) {
|
||||||
|
fprintf(fp, "%s%s", space, n->key);
|
||||||
|
if (!n->v) {
|
||||||
|
/* it's a sub section */
|
||||||
|
fprintf(fp, " {\n");
|
||||||
|
_write_config(n->child, fp, level + 1);
|
||||||
|
fprintf(fp, "%s}", space);
|
||||||
|
} else {
|
||||||
|
/* it's a value */
|
||||||
|
struct config_value *v = n->v;
|
||||||
|
fprintf(fp, "=");
|
||||||
|
if (v->next) {
|
||||||
|
fprintf(fp, "[");
|
||||||
|
while (v) {
|
||||||
|
_write_value(fp, v);
|
||||||
|
v = v->next;
|
||||||
|
if (v)
|
||||||
|
fprintf(fp, ", ");
|
||||||
|
}
|
||||||
|
fprintf(fp, "]");
|
||||||
|
} else
|
||||||
|
_write_value(fp, v);
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
n = n->sib;
|
||||||
|
}
|
||||||
|
/* FIXME: add error checking */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_config(struct config_file *cf, const char *file)
|
||||||
|
{
|
||||||
|
int r = 1;
|
||||||
|
FILE *fp = fopen(file, "w");
|
||||||
|
if (!fp) {
|
||||||
|
log_sys_err("open");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_write_config(cf->root, fp, 0)) {
|
||||||
|
stack;
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parser
|
||||||
|
*/
|
||||||
|
static struct config_node *_file(struct parser *p)
|
||||||
|
{
|
||||||
|
struct config_node *root = 0, *n, *l;
|
||||||
|
while (p->t != TOK_EOF) {
|
||||||
|
if (!(n = _section(p))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!root)
|
||||||
|
root = n;
|
||||||
|
else
|
||||||
|
l->sib = n;
|
||||||
|
l = n;
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_node *_section(struct parser *p)
|
||||||
|
{
|
||||||
|
/* IDENTIFIER '{' VALUE* '}' */
|
||||||
|
struct config_node *root, *n, *l;
|
||||||
|
if (!(root = _create_node(p))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(root->key = _dup_tok(p))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (TOK_IDENTIFIER);
|
||||||
|
|
||||||
|
if (p->t == TOK_SECTION_B) {
|
||||||
|
match(TOK_SECTION_B);
|
||||||
|
while (p->t != TOK_SECTION_E) {
|
||||||
|
if (!(n = _section(p))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!root->child)
|
||||||
|
root->child = n;
|
||||||
|
else
|
||||||
|
l->sib = n;
|
||||||
|
l = n;
|
||||||
|
}
|
||||||
|
match(TOK_SECTION_E);
|
||||||
|
} else {
|
||||||
|
match(TOK_EQ);
|
||||||
|
if (!(root->v = _value(p))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_value *_value(struct parser *p)
|
||||||
|
{
|
||||||
|
/* '[' TYPE* ']' | TYPE */
|
||||||
|
struct config_value *h = 0, *l, *ll = 0;
|
||||||
|
if (p->t == TOK_ARRAY_B) {
|
||||||
|
match (TOK_ARRAY_B);
|
||||||
|
while (p->t != TOK_ARRAY_E) {
|
||||||
|
if (!(l = _type(p))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h)
|
||||||
|
h = l;
|
||||||
|
else
|
||||||
|
ll->next = l;
|
||||||
|
ll = l;
|
||||||
|
|
||||||
|
if (p->t == TOK_COMMA)
|
||||||
|
match(TOK_COMMA);
|
||||||
|
}
|
||||||
|
match(TOK_ARRAY_E);
|
||||||
|
} else
|
||||||
|
h = _type(p);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_value *_type(struct parser *p) {
|
||||||
|
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
|
||||||
|
struct config_value *v = _create_value(p);
|
||||||
|
|
||||||
|
switch (p->t) {
|
||||||
|
case TOK_INT:
|
||||||
|
v->type = CFG_INT;
|
||||||
|
v->v.i = strtol(p->tb, 0, 10); /* FIXME: check error */
|
||||||
|
match(TOK_INT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_FLOAT:
|
||||||
|
v->type = CFG_FLOAT;
|
||||||
|
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
|
||||||
|
match(TOK_FLOAT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_STRING:
|
||||||
|
v->type = CFG_STRING;
|
||||||
|
|
||||||
|
p->tb++, p->te--; /* strip "'s */
|
||||||
|
if (!(v->v.str = _dup_tok(p))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p->te++;
|
||||||
|
match(TOK_STRING);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_parse_error(p, __FILE__, __LINE__, "expected a value");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _parse_error(struct parser *p, const char *file, int line,
|
||||||
|
const char *mess)
|
||||||
|
{
|
||||||
|
plog(_LOG_ERR, file, line, "parse error at %d: %s", p->line, mess);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _match_aux(struct parser *p, int t)
|
||||||
|
{
|
||||||
|
if (p->t != t)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_get_token(p);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tokeniser
|
||||||
|
*/
|
||||||
|
static void _get_token(struct parser *p)
|
||||||
|
{
|
||||||
|
p->tb = p->te;
|
||||||
|
_eat_space(p);
|
||||||
|
if (p->tb == p->fe) {
|
||||||
|
p->t = TOK_EOF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->t = TOK_INT; /* fudge so the fall through for
|
||||||
|
floats works */
|
||||||
|
switch (*p->te) {
|
||||||
|
case '{':
|
||||||
|
p->t = TOK_SECTION_B;
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '}':
|
||||||
|
p->t = TOK_SECTION_E;
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
p->t = TOK_ARRAY_B;
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ']':
|
||||||
|
p->t = TOK_ARRAY_E;
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ',':
|
||||||
|
p->t = TOK_COMMA;
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '=':
|
||||||
|
p->t = TOK_EQ;
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
p->t = TOK_STRING;
|
||||||
|
p->te++;
|
||||||
|
while ((p->te != p->fe) && (*p->te != '"')) {
|
||||||
|
if ((*p->te == '\\') && (p->te + 1 != p->fe))
|
||||||
|
p->te++;
|
||||||
|
p->te++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->te != p->fe)
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
p->t = TOK_FLOAT;
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
p->te++;
|
||||||
|
while (p->te != p->fe) {
|
||||||
|
if (*p->te == '.') {
|
||||||
|
if (p->t == TOK_FLOAT)
|
||||||
|
break;
|
||||||
|
p->t = TOK_FLOAT;
|
||||||
|
} else if (!isdigit((int) *p->te))
|
||||||
|
break;
|
||||||
|
p->te++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
p->t = TOK_IDENTIFIER;
|
||||||
|
while ((p->te != p->fe) && !isspace(*p->te) &&
|
||||||
|
(*p->te != '#') && (*p->te != '='))
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _eat_space(struct parser *p)
|
||||||
|
{
|
||||||
|
while (p->tb != p->fe) {
|
||||||
|
if (*p->te == '#') {
|
||||||
|
while ((p->te != p->fe) && (*p->te != '\n'))
|
||||||
|
p->te++;
|
||||||
|
p->line++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isspace(*p->te)) {
|
||||||
|
while ((p->te != p->fe) && isspace(*p->te)) {
|
||||||
|
if (*p->te == '\n')
|
||||||
|
p->line++;
|
||||||
|
p->te++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
p->tb = p->te;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memory management
|
||||||
|
*/
|
||||||
|
static struct config_value *_create_value(struct parser *p)
|
||||||
|
{
|
||||||
|
struct config_value *v = pool_alloc(p->mem, sizeof(*v));
|
||||||
|
memset(v, 0, sizeof(*v));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_node *_create_node(struct parser *p)
|
||||||
|
{
|
||||||
|
struct config_node *n = pool_alloc(p->mem, sizeof(*n));
|
||||||
|
memset(n, 0, sizeof(*n));
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *_dup_tok(struct parser *p)
|
||||||
|
{
|
||||||
|
int len = p->te - p->tb;
|
||||||
|
char *str = pool_alloc(p->mem, len + 1);
|
||||||
|
if (!str) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strncpy(str, p->tb, len);
|
||||||
|
str[len] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* utility functions
|
||||||
|
*/
|
||||||
|
struct config_node *find_config_node(struct config_node *cn,
|
||||||
|
const char *path, char sep)
|
||||||
|
{
|
||||||
|
const char *e;
|
||||||
|
|
||||||
|
while (cn) {
|
||||||
|
/* trim any leading slashes */
|
||||||
|
while (*path && (*path == sep))
|
||||||
|
path++;
|
||||||
|
|
||||||
|
/* find the end of this segment */
|
||||||
|
for (e = path; *e && (*e != sep); e++)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* hunt for the node */
|
||||||
|
while (cn) {
|
||||||
|
if (_tok_match(cn->key, path, e))
|
||||||
|
break;
|
||||||
|
|
||||||
|
cn = cn->sib;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cn && *e)
|
||||||
|
cn = cn->child;
|
||||||
|
else
|
||||||
|
break; /* don't move into the last node */
|
||||||
|
|
||||||
|
path = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
find_config_str(struct config_node *cn,
|
||||||
|
const char *path, char sep, const char *fail)
|
||||||
|
{
|
||||||
|
struct config_node *n = find_config_node(cn, path, sep);
|
||||||
|
|
||||||
|
if (n && n->v->type == CFG_STRING)
|
||||||
|
return n->v->v.str;
|
||||||
|
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_config_int(struct config_node *cn, const char *path,
|
||||||
|
char sep, int fail)
|
||||||
|
{
|
||||||
|
struct config_node *n = find_config_node(cn, path, sep);
|
||||||
|
|
||||||
|
if (n && n->v->type == CFG_INT)
|
||||||
|
return n->v->v.i;
|
||||||
|
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
float find_config_float(struct config_node *cn, const char *path,
|
||||||
|
char sep, float fail)
|
||||||
|
{
|
||||||
|
struct config_node *n = find_config_node(cn, path, sep);
|
||||||
|
|
||||||
|
if (n && n->v->type == CFG_FLOAT)
|
||||||
|
return n->v->v.r;
|
||||||
|
|
||||||
|
return fail;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tok_match(const char *str, const char *b, const char *e)
|
||||||
|
{
|
||||||
|
while (*str && (b != e)) {
|
||||||
|
if (*str++ != *b++)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(*str || (b != e));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
76
lib/config/config.h
Normal file
76
lib/config/config.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* tools/lib/config.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Sistina Software
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This LVM library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This LVM library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this LVM library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LVM_CONFIG_H
|
||||||
|
#define LVM_CONFIG_H
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CFG_STRING,
|
||||||
|
CFG_FLOAT,
|
||||||
|
CFG_INT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_value {
|
||||||
|
int type;
|
||||||
|
union {
|
||||||
|
int i;
|
||||||
|
float r;
|
||||||
|
char *str;
|
||||||
|
} v;
|
||||||
|
struct config_value *next; /* for arrays */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_node {
|
||||||
|
char *key;
|
||||||
|
struct config_node *sib, *child;
|
||||||
|
struct config_value *v;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_file {
|
||||||
|
struct config_node *root;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_file *create_config_file();
|
||||||
|
void destroy_config_file(struct config_file *cf);
|
||||||
|
|
||||||
|
int read_config(struct config_file *cf, const char *file);
|
||||||
|
int write_config(struct config_file *cf, const char *file);
|
||||||
|
|
||||||
|
struct config_node *find_config_node(struct config_node *cn,
|
||||||
|
const char *path, char seperator);
|
||||||
|
|
||||||
|
const char *find_config_str(struct config_node *cn,
|
||||||
|
const char *path, char sep, const char *fail);
|
||||||
|
|
||||||
|
int find_config_int(struct config_node *cn, const char *path,
|
||||||
|
char sep, int fail);
|
||||||
|
|
||||||
|
float find_config_float(struct config_node *cn, const char *path,
|
||||||
|
char sep, float fail);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
152
lib/log/log.c
Normal file
152
lib/log/log.c
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* tools/lib/lvm_log.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Sistina Software
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This LVM library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This LVM library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this LVM library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changelog
|
||||||
|
*
|
||||||
|
* 22/01/2001 - First version (Joe Thornber)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
static FILE *_log = 0;
|
||||||
|
|
||||||
|
static int _verbose_level = 0;
|
||||||
|
static int _test = 0;
|
||||||
|
static int _debug_level = 0;
|
||||||
|
static int _syslog = 0;
|
||||||
|
|
||||||
|
void init_log(FILE *fp) {
|
||||||
|
_log = fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_syslog(int facility) {
|
||||||
|
openlog("lvm", LOG_PID, facility);
|
||||||
|
_syslog = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fin_log() {
|
||||||
|
_log = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fin_syslog() {
|
||||||
|
closelog();
|
||||||
|
_syslog = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_verbose(int level) {
|
||||||
|
_verbose_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_test(int level) {
|
||||||
|
_test = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_mode() {
|
||||||
|
return _test;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_debug(int level) {
|
||||||
|
_debug_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
int debug_level() {
|
||||||
|
return _debug_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_log(int level, const char *file, int line, const char *format, ...) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
switch(level) {
|
||||||
|
case _LOG_DEBUG:
|
||||||
|
if (_verbose_level > 2) {
|
||||||
|
printf(" ");
|
||||||
|
vprintf(format, ap);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _LOG_INFO:
|
||||||
|
if (_verbose_level > 1) {
|
||||||
|
printf(" ");
|
||||||
|
vprintf(format, ap);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case _LOG_NOTICE:
|
||||||
|
if (_verbose_level) {
|
||||||
|
printf(" ");
|
||||||
|
vprintf(format, ap);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case _LOG_WARN:
|
||||||
|
printf(" ");
|
||||||
|
vprintf(format, ap);
|
||||||
|
putchar('\n');
|
||||||
|
break;
|
||||||
|
case _LOG_ERR:
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
vfprintf(stderr, format, ap);
|
||||||
|
fputc('\n',stderr);
|
||||||
|
break;
|
||||||
|
case _LOG_FATAL:
|
||||||
|
vfprintf(stderr, format, ap);
|
||||||
|
fputc('\n',stderr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (level > _debug_level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_log) {
|
||||||
|
fprintf(_log, "%s:%d ", file, line);
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
vfprintf(_log, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
fprintf(_log, "\n");
|
||||||
|
fflush(_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_syslog) {
|
||||||
|
va_start(ap, format);
|
||||||
|
vsyslog(level, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
|
|
97
lib/log/log.h
Normal file
97
lib/log/log.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* tools/lib/lvm_log.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Sistina Software
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This LVM library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This LVM library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this LVM library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changelog
|
||||||
|
*
|
||||||
|
* 22/01/2001 - First version (Joe Thornber)
|
||||||
|
* 25/04/2001 - Remove some spurious ##s that annoyed newer gcc versions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LVM_LOG_H
|
||||||
|
#define LVM_LOG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define _LOG_DEBUG 7
|
||||||
|
#define _LOG_INFO 6
|
||||||
|
#define _LOG_NOTICE 5
|
||||||
|
#define _LOG_WARN 4
|
||||||
|
#define _LOG_ERR 3
|
||||||
|
#define _LOG_FATAL 2
|
||||||
|
|
||||||
|
void init_log(FILE *fp);
|
||||||
|
void fin_log();
|
||||||
|
|
||||||
|
void init_syslog(int facility);
|
||||||
|
void fin_syslog(void);
|
||||||
|
|
||||||
|
void init_verbose(int level);
|
||||||
|
void init_test(int level);
|
||||||
|
void init_debug(int level);
|
||||||
|
|
||||||
|
int test_mode(void);
|
||||||
|
int debug_level(void);
|
||||||
|
|
||||||
|
void print_log(int level, const char *file, int line, const char *format, ...);
|
||||||
|
|
||||||
|
#define plog(l, x...) print_log(l, __FILE__, __LINE__ , ## x)
|
||||||
|
|
||||||
|
#define log_debug(x...) plog(_LOG_DEBUG, x)
|
||||||
|
#define log_info(x...) plog(_LOG_INFO, x)
|
||||||
|
#define log_notice(x...) plog(_LOG_NOTICE, x)
|
||||||
|
#define log_warn(x...) plog(_LOG_WARN, x)
|
||||||
|
#define log_err(x...) plog(_LOG_ERR, x)
|
||||||
|
#define log_fatal(x...) plog(_LOG_FATAL, x)
|
||||||
|
#define log_sys_err(x) log_debug("system call '%s' failed (%s)", \
|
||||||
|
x, strerror(errno))
|
||||||
|
|
||||||
|
#define stack log_debug( "stack trace" )
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros to use for messages:
|
||||||
|
*
|
||||||
|
* log_error - always print to stderr
|
||||||
|
* log_print - always print to stdout
|
||||||
|
* log_verbose - print to stdout if verbose is set (-v)
|
||||||
|
* log_very_verbose - print to stdout if verbose is set twice (-vv)
|
||||||
|
* log_debug - print to stdout if verbose is set three times (-vvv)
|
||||||
|
*
|
||||||
|
* In addition, messages will be logged to file or syslog if they
|
||||||
|
* are more serious than the log level specified with -d.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define log_error(fmt, args...) log_err(fmt , ## args)
|
||||||
|
#define log_print(fmt, args...) log_warn(fmt , ## args)
|
||||||
|
#define log_verbose(fmt, args...) log_notice(fmt , ## args)
|
||||||
|
#define log_very_verbose(fmt, args...) log_info(fmt , ## args)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
214
lib/mm/dbg_malloc.c
Normal file
214
lib/mm/dbg_malloc.c
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* dbg_malloc.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2000, 2001 Sistina Software
|
||||||
|
*
|
||||||
|
* lvm is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* lvm is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU CC; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Changelog
|
||||||
|
*
|
||||||
|
* 9/11/2000 - First version by Joe Thornber
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
*
|
||||||
|
* Thread safety seems to have fallen out, put lock back in.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "dbg_malloc.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
struct memblock {
|
||||||
|
struct memblock *prev, *next; /* All allocated blocks are linked */
|
||||||
|
size_t length; /* Size of the requested block */
|
||||||
|
int id; /* Index of the block */
|
||||||
|
const char *file; /* File that allocated */
|
||||||
|
int line; /* Line that allocated */
|
||||||
|
void *magic; /* Address of this block */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
unsigned int blocks, mblocks;
|
||||||
|
unsigned int bytes, mbytes;
|
||||||
|
|
||||||
|
} _mem_stats = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
static struct memblock *_head = 0;
|
||||||
|
static struct memblock *_tail = 0;
|
||||||
|
|
||||||
|
void *malloc_aux(size_t s, const char *file, int line)
|
||||||
|
{
|
||||||
|
struct memblock *nb;
|
||||||
|
size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
|
||||||
|
|
||||||
|
if (!(nb = malloc(tsize))) {
|
||||||
|
log_error("couldn't allocate any memory, size = %u", s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up the file and line info */
|
||||||
|
nb->file = file;
|
||||||
|
nb->line = line;
|
||||||
|
|
||||||
|
#ifdef BOUNDS_CHECK
|
||||||
|
bounds_check();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* setup fields */
|
||||||
|
nb->magic = nb + 1;
|
||||||
|
nb->length = s;
|
||||||
|
nb->id = ++_mem_stats.blocks;
|
||||||
|
nb->next = 0;
|
||||||
|
nb->prev = _tail;
|
||||||
|
|
||||||
|
/* link to tail of the list */
|
||||||
|
if (!_head)
|
||||||
|
_head = _tail = nb;
|
||||||
|
else {
|
||||||
|
_tail->next = nb;
|
||||||
|
_tail = nb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stomp a pretty pattern across the new memory
|
||||||
|
and fill in the boundary bytes */
|
||||||
|
{
|
||||||
|
char *ptr = (char *) (nb + 1);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < s; i++)
|
||||||
|
*ptr++ = i & 0x1 ? (char) 0xba : (char) 0xbe;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(unsigned long); i++)
|
||||||
|
*ptr++ = (char) nb->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mem_stats.blocks > _mem_stats.mblocks)
|
||||||
|
_mem_stats.mblocks = _mem_stats.blocks;
|
||||||
|
|
||||||
|
_mem_stats.bytes += s;
|
||||||
|
if (_mem_stats.bytes > _mem_stats.mbytes)
|
||||||
|
_mem_stats.mbytes = _mem_stats.bytes;
|
||||||
|
|
||||||
|
return nb + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_aux(void *p)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
int i;
|
||||||
|
struct memblock *mb = ((struct memblock *) p) - 1;
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef BOUNDS_CHECK
|
||||||
|
bounds_check();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
assert(mb->magic == p);
|
||||||
|
|
||||||
|
/* check data at the far boundary */
|
||||||
|
ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
|
||||||
|
for (i = 0; i < sizeof(unsigned long); i++)
|
||||||
|
if(*ptr++ != (char) mb->id)
|
||||||
|
assert(!"Damage at far end of block");
|
||||||
|
|
||||||
|
/* have we freed this before ? */
|
||||||
|
assert(mb->id != 0);
|
||||||
|
mb->id = 0;
|
||||||
|
|
||||||
|
/* stomp a different pattern across the memory */
|
||||||
|
ptr = ((char *) mb) + sizeof(struct memblock);
|
||||||
|
for (i = 0; i < mb->length; i++)
|
||||||
|
*ptr++ = i & 1 ? (char) 0xde : (char) 0xad;
|
||||||
|
|
||||||
|
/* unlink */
|
||||||
|
if (mb->prev)
|
||||||
|
mb->prev->next = mb->next;
|
||||||
|
else
|
||||||
|
_head = mb->next;
|
||||||
|
|
||||||
|
if (mb->next)
|
||||||
|
mb->next->prev = mb->prev;
|
||||||
|
else
|
||||||
|
_tail = mb->prev;
|
||||||
|
|
||||||
|
assert(_mem_stats.blocks);
|
||||||
|
_mem_stats.blocks--;
|
||||||
|
_mem_stats.bytes -= mb->length;
|
||||||
|
|
||||||
|
/* free the memory */
|
||||||
|
free(mb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *realloc_aux(void *p, unsigned int s, const char *file, int line)
|
||||||
|
{
|
||||||
|
void *r;
|
||||||
|
struct memblock *mb = ((struct memblock *) p) - 1;
|
||||||
|
|
||||||
|
r = malloc_aux(s, file, line);
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
memcpy(r, p, mb->length);
|
||||||
|
free_aux(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_MEM
|
||||||
|
int dump_memory(void)
|
||||||
|
{
|
||||||
|
unsigned long tot = 0;
|
||||||
|
struct memblock *mb;
|
||||||
|
if (_head)
|
||||||
|
log_info("you have a memory leak:");
|
||||||
|
|
||||||
|
for (mb = _head; mb; mb = mb->next) {
|
||||||
|
print_log(_LOG_INFO, mb->file, mb->line,
|
||||||
|
"block %d at %p, size %d",
|
||||||
|
mb->id, mb->magic, mb->length);
|
||||||
|
tot += mb->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_head)
|
||||||
|
log_info("%ld bytes leaked in total", tot);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bounds_check(void)
|
||||||
|
{
|
||||||
|
struct memblock *mb = _head;
|
||||||
|
while (mb) {
|
||||||
|
int i;
|
||||||
|
char *ptr = ((char *) (mb + 1)) + mb->length;
|
||||||
|
for (i = 0; i < sizeof(unsigned long); i++)
|
||||||
|
if (*ptr++ != (char) mb->id)
|
||||||
|
assert(!"Memory smash");
|
||||||
|
|
||||||
|
mb = mb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
56
lib/mm/dbg_malloc.h
Normal file
56
lib/mm/dbg_malloc.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* debug.h - what a wonderfully original name for a file.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2000, 2001 Sistina Software
|
||||||
|
*
|
||||||
|
* lvm is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* lvm is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU CC; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Changelog
|
||||||
|
*
|
||||||
|
* 9/11/2000 - First version by Joe Thornber
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DBG_MALLOC_H
|
||||||
|
#define DBG_MALLOC_H
|
||||||
|
|
||||||
|
#ifdef DEBUG_MEM
|
||||||
|
void *malloc_aux(unsigned int s, const char *file, int line);
|
||||||
|
void free_aux(void *p);
|
||||||
|
void *realloc_aux(void *p, unsigned int s, const char *file, int line);
|
||||||
|
int dump_memory(void);
|
||||||
|
void bounds_check(void);
|
||||||
|
|
||||||
|
#define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
|
||||||
|
#define dbg_free(p) free_aux(p)
|
||||||
|
#define dbg_realloc(p, s) realloc_aux(p, s, __FILE__, __LINE__)
|
||||||
|
#else
|
||||||
|
#define dbg_malloc(s) malloc(s)
|
||||||
|
#define dbg_free(p) free(p)
|
||||||
|
#define dbg_realloc(p, s) realloc(p, s)
|
||||||
|
#define dump_memory()
|
||||||
|
#define bounds_check()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
231
lib/mm/pool.c
Normal file
231
lib/mm/pool.c
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* tools/lib/pool.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Sistina Software
|
||||||
|
*
|
||||||
|
* LVM is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* LVM is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LVM; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pool.h"
|
||||||
|
#include "dbg_malloc.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct chunk {
|
||||||
|
char *begin, *end;
|
||||||
|
struct chunk *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pool {
|
||||||
|
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
|
||||||
|
list to stop 'bobbling' */
|
||||||
|
size_t chunk_size;
|
||||||
|
size_t object_len;
|
||||||
|
unsigned object_alignment;
|
||||||
|
};
|
||||||
|
|
||||||
|
void _align_chunk(struct chunk *c, unsigned alignment);
|
||||||
|
struct chunk *_new_chunk(struct pool *p, size_t s);
|
||||||
|
|
||||||
|
/* FIXME: alignment will need to be 4 to work on SUN boxes */
|
||||||
|
#define DEFAULT_ALIGNMENT 4
|
||||||
|
|
||||||
|
struct pool *create_pool(size_t chunk_hint)
|
||||||
|
{
|
||||||
|
size_t new_size = 1024;
|
||||||
|
struct pool *p = dbg_malloc(sizeof(*p));
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
log_err("couldn't create pool");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(p, 0, sizeof(*p));
|
||||||
|
|
||||||
|
/* round chunk_hint up to the next power of 2 */
|
||||||
|
p->chunk_size = chunk_hint + sizeof(struct chunk);
|
||||||
|
while (new_size < p->chunk_size)
|
||||||
|
new_size <<= 1;
|
||||||
|
p->chunk_size = new_size;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_pool(struct pool *p)
|
||||||
|
{
|
||||||
|
struct chunk *c, *pr;
|
||||||
|
dbg_free(p->spare_chunk);
|
||||||
|
c = p->chunk;
|
||||||
|
while (c) {
|
||||||
|
pr = c->prev;
|
||||||
|
dbg_free(c);
|
||||||
|
c = pr;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pool_alloc(struct pool *p, size_t s)
|
||||||
|
{
|
||||||
|
return pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment)
|
||||||
|
{
|
||||||
|
struct chunk *c = p->chunk;
|
||||||
|
void *r;
|
||||||
|
|
||||||
|
/* realign begin */
|
||||||
|
if (c)
|
||||||
|
_align_chunk(c, alignment);
|
||||||
|
|
||||||
|
/* have we got room ? */
|
||||||
|
if(!c || (c->begin > c->end) || (c->end - c->begin < s)) {
|
||||||
|
/* allocate new chunk */
|
||||||
|
int needed = s + alignment + sizeof(struct chunk);
|
||||||
|
c = _new_chunk(p, (needed > p->chunk_size) ?
|
||||||
|
needed : p->chunk_size);
|
||||||
|
_align_chunk(c, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = c->begin;
|
||||||
|
c->begin += s;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pool_free(struct pool *p, void *ptr)
|
||||||
|
{
|
||||||
|
struct chunk *c = p->chunk;
|
||||||
|
|
||||||
|
while (c) {
|
||||||
|
if (((char *) c < (char *) ptr) &&
|
||||||
|
((char *) c->end > (char *) ptr)) {
|
||||||
|
c->begin = ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->spare_chunk)
|
||||||
|
dbg_free(p->spare_chunk);
|
||||||
|
p->spare_chunk = c;
|
||||||
|
c = c->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c)
|
||||||
|
log_warn("pool_free asked to free a pointer "
|
||||||
|
"that wasn't in the pool, doing nothing");
|
||||||
|
else
|
||||||
|
p->chunk = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pool_begin_object(struct pool *p, size_t hint, unsigned align)
|
||||||
|
{
|
||||||
|
struct chunk *c = p->chunk;
|
||||||
|
|
||||||
|
p->object_len = 0;
|
||||||
|
p->object_alignment = align;
|
||||||
|
|
||||||
|
_align_chunk(c, align);
|
||||||
|
if (c->end - c->begin < hint) {
|
||||||
|
/* allocate a new chunk */
|
||||||
|
c = _new_chunk(p,
|
||||||
|
hint > (p->chunk_size - sizeof(struct chunk)) ?
|
||||||
|
hint + sizeof(struct chunk) + align :
|
||||||
|
p->chunk_size);
|
||||||
|
_align_chunk(c, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c->begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pool_grow_object(struct pool *p, unsigned char *buffer, size_t n)
|
||||||
|
{
|
||||||
|
struct chunk *c = p->chunk;
|
||||||
|
|
||||||
|
if (c->end - (c->begin + p->object_len) < n) {
|
||||||
|
/* move into a new chunk */
|
||||||
|
if (p->object_len + n > (p->chunk_size / 2))
|
||||||
|
_new_chunk(p, (p->object_len + n) * 2);
|
||||||
|
else
|
||||||
|
_new_chunk(p, p->chunk_size);
|
||||||
|
|
||||||
|
_align_chunk(p->chunk, p->object_alignment);
|
||||||
|
memcpy(p->chunk->begin, c->begin, p->object_len);
|
||||||
|
c = p->chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(c->begin + p->object_len, buffer, n);
|
||||||
|
p->object_len += n;
|
||||||
|
return c->begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pool_end_object(struct pool *p)
|
||||||
|
{
|
||||||
|
struct chunk *c = p->chunk;
|
||||||
|
void *r = c->begin;
|
||||||
|
c->begin += p->object_len;
|
||||||
|
p->object_len = 0u;
|
||||||
|
p->object_alignment = DEFAULT_ALIGNMENT;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pool_abandon_object(struct pool *p)
|
||||||
|
{
|
||||||
|
p->object_len = 0;
|
||||||
|
p->object_alignment = DEFAULT_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pool_strdup(struct pool *p, const char *str)
|
||||||
|
{
|
||||||
|
char *ret = pool_alloc(p, strlen(str) + 1);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
strcpy(ret, str);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _align_chunk(struct chunk *c, unsigned alignment)
|
||||||
|
{
|
||||||
|
c->begin += alignment - ((unsigned) c->begin & (alignment - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct chunk *_new_chunk(struct pool *p, size_t s)
|
||||||
|
{
|
||||||
|
struct chunk *c;
|
||||||
|
|
||||||
|
if (p->spare_chunk &&
|
||||||
|
((p->spare_chunk->end - (char *) p->spare_chunk) >= s)) {
|
||||||
|
/* reuse old chunk */
|
||||||
|
c = p->spare_chunk;
|
||||||
|
p->spare_chunk = 0;
|
||||||
|
} else {
|
||||||
|
c = dbg_malloc(s);
|
||||||
|
c->end = (char *) c + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->prev = p->chunk;
|
||||||
|
c->begin = (char *) (c + 1);
|
||||||
|
p->chunk = c;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
* vim:ai cin ts=8
|
||||||
|
*/
|
64
lib/mm/pool.h
Normal file
64
lib/mm/pool.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* tools/lib/pool.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Sistina Software
|
||||||
|
*
|
||||||
|
* LVM is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* LVM is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LVM; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POOL_H
|
||||||
|
#define POOL_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct pool;
|
||||||
|
|
||||||
|
/* constructor and destructor */
|
||||||
|
struct pool *create_pool(size_t chunk_hint);
|
||||||
|
void destroy_pool(struct pool *p);
|
||||||
|
|
||||||
|
/* simple allocation/free routines */
|
||||||
|
void *pool_alloc(struct pool *p, size_t s);
|
||||||
|
void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment);
|
||||||
|
void pool_free(struct pool *p, void *ptr);
|
||||||
|
|
||||||
|
/* object building routines */
|
||||||
|
void *pool_begin_object(struct pool *p, size_t hint, unsigned align);
|
||||||
|
void *pool_grow_object(struct pool *p, unsigned char *buffer, size_t n);
|
||||||
|
void *pool_end_object(struct pool *p);
|
||||||
|
void pool_abandon_object(struct pool *p);
|
||||||
|
|
||||||
|
/* utilities */
|
||||||
|
char *pool_strdup(struct pool *p, const char *str);
|
||||||
|
|
||||||
|
static inline void *pool_zalloc(struct pool *p, size_t s) {
|
||||||
|
void *ptr = pool_alloc(p, s);
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
memset(ptr, 0, s);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
* vim:ai cin ts=4
|
||||||
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user