]> sourceware.org Git - lvm2.git/commitdiff
o Populating with stuff from experimental
authorJoe Thornber <thornber@redhat.com>
Tue, 21 Aug 2001 12:56:08 +0000 (12:56 +0000)
committerJoe Thornber <thornber@redhat.com>
Tue, 21 Aug 2001 12:56:08 +0000 (12:56 +0000)
lib/config/config.c [new file with mode: 0644]
lib/config/config.h [new file with mode: 0644]
lib/log/log.c [new file with mode: 0644]
lib/log/log.h [new file with mode: 0644]
lib/mm/dbg_malloc.c [new file with mode: 0644]
lib/mm/dbg_malloc.h [new file with mode: 0644]
lib/mm/pool.c [new file with mode: 0644]
lib/mm/pool.h [new file with mode: 0644]

diff --git a/lib/config/config.c b/lib/config/config.c
new file mode 100644 (file)
index 0000000..5eb250f
--- /dev/null
@@ -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:
+ */
diff --git a/lib/config/config.h b/lib/config/config.h
new file mode 100644 (file)
index 0000000..7b8c40f
--- /dev/null
@@ -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:
+ */
diff --git a/lib/log/log.c b/lib/log/log.c
new file mode 100644 (file)
index 0000000..6f54eba
--- /dev/null
@@ -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:
+ */
+
diff --git a/lib/log/log.h b/lib/log/log.h
new file mode 100644 (file)
index 0000000..07396a1
--- /dev/null
@@ -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:
+ */
diff --git a/lib/mm/dbg_malloc.c b/lib/mm/dbg_malloc.c
new file mode 100644 (file)
index 0000000..e15256a
--- /dev/null
@@ -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:
+ */
diff --git a/lib/mm/dbg_malloc.h b/lib/mm/dbg_malloc.h
new file mode 100644 (file)
index 0000000..3dbc251
--- /dev/null
@@ -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:
+ */
diff --git a/lib/mm/pool.c b/lib/mm/pool.c
new file mode 100644 (file)
index 0000000..2df9b95
--- /dev/null
@@ -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
+ */
diff --git a/lib/mm/pool.h b/lib/mm/pool.h
new file mode 100644 (file)
index 0000000..89b6438
--- /dev/null
@@ -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
+ */
+
This page took 0.067433 seconds and 5 git commands to generate.