--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
+
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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
+ */
--- /dev/null
+/*
+ * 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
+ */
+