Imported Upstream version 3.2.0
[debian/amanda] / common-src / alloc.c
index 0a0cdef3555f72a6b29d115910fdcd533b0bee06..c470b9d974c33a248edca731b19bce016f8396fe 100644 (file)
@@ -24,7 +24,7 @@
  * file named AUTHORS, in the root directory of this distribution.
  */
 /*
- * $Id: alloc.c,v 1.35 2005/12/21 19:07:49 paddy_s Exp $
+ * $Id: alloc.c 5280 2007-02-13 15:58:56Z martineau $
  *
  * Memory allocators with error handling.  If the allocation fails,
  * errordump() is called, relieving the caller from checking the return
  */
 #include "amanda.h"
 #include "arglist.h"
-#include "queue.h"
 
-static char *internal_vstralloc P((const char *, va_list));
+#define        MIN_ALLOC       64
 
-/*
- *=====================================================================
- * debug_caller_loc -- keep track of all allocation callers
- *
- * const char *debug_caller_loc(const char *file, int line)
- *
- * entry:      file = source file
- *             line = source line
- * exit:       a string like "genversion.c@999"
- *
- * The debug malloc library has a concept of a call stack that can be used
- * to fine tune what was running when a particular allocation was done.
- * We use it to tell who called our various allocation wrappers since
- * it wouldn't do much good to tell us a problem happened because of
- * the malloc call in alloc (they are all from there at some point).
- *
- * But the library expects the string passed to malloc_enter/malloc_leave
- * to be static, so we build a linked list of each one we get (there are
- * not really that many during a given execution).  When we get a repeat
- * we return the previously allocated string.  For a bit of performance,
- * we keep the list in least recently used order, which helps because
- * the calls to us come in pairs (one for malloc_enter and one right
- * after for malloc_leave).
- *=====================================================================
- */
-
-const char *
-debug_caller_loc(file, line)
-    const char *file;
-    int line;
-{
-    struct loc_str {
-       char *str;
-       LIST_ENTRY(loc_str) le;
-    } *ls;
-    static LIST_HEAD(, loc_str) root = LIST_HEAD_INITIALIZER(root);
-    static char loc[256];      /* big enough for filename@lineno */
-    const char *p;
-
-    if ((p = strrchr(file, '/')) != NULL)
-       file = p + 1;                           /* just the last path element */
-
-    snprintf(loc, sizeof(loc), "%s@%d", file, line);
-
-    for (ls = LIST_FIRST(&root); ls != NULL; ls = LIST_NEXT(ls, le)) {
-       if (strcmp(loc, ls->str) == 0) {
-           if (ls != LIST_FIRST(&root)) {
-               /*
-                * This is a repeat and was not at the head of the list.
-                * Unlink it and move it to the front.
-                */
-               LIST_REMOVE(ls, le);
-               LIST_INSERT_HEAD(&root, ls, le);
-           }
-           return (ls->str);
-       }
-    }
-
-    /*
-     * This is a new entry.  Put it at the head of the list.
-     */
-    ls = malloc(sizeof(*ls));
-    if (ls == NULL)
-       return ("??");                  /* not much better than abort */
-    ls->str = malloc(strlen(loc) + 1);
-    if (ls->str == NULL) {
-       free(ls);
-       return ("??");                  /* not much better than abort */
-    }
-    strcpy(ls->str, loc);
-    malloc_mark(ls);
-    malloc_mark(ls->str);
-    LIST_INSERT_HEAD(&root, ls, le);
-    return (ls->str);
-}
-
-/*
- *=====================================================================
- * Save the current source line for vstralloc/newvstralloc.
- *
- * int debug_alloc_push (char *s, int l)
- *
- * entry:      s = source file
- *             l = source line
- * exit:       always zero
- * 
- * See the comments in amanda.h about what this is used for.
- *=====================================================================
- */
-
-#define        DEBUG_ALLOC_SAVE_MAX    10
-
-static struct {
-       char            *file;
-       int             line;
-} debug_alloc_loc_info[DEBUG_ALLOC_SAVE_MAX];
-static int debug_alloc_ptr = 0;
-
-static char            *saved_file;
-static int             saved_line;
-
-int
-debug_alloc_push (s, l)
-    char *s;
-    int l;
-{
-    debug_alloc_loc_info[debug_alloc_ptr].file = s;
-    debug_alloc_loc_info[debug_alloc_ptr].line = l;
-    debug_alloc_ptr = (debug_alloc_ptr + 1) % DEBUG_ALLOC_SAVE_MAX;
-    return 0;
-}
-
-/*
- *=====================================================================
- * Pop the current source line information for vstralloc/newvstralloc.
- *
- * int debug_alloc_pop (void)
- *
- * entry:      none
- * exit:       none
- * 
- * See the comments in amanda.h about what this is used for.
- *=====================================================================
- */
-
-void
-debug_alloc_pop ()
-{
-    debug_alloc_ptr =
-      (debug_alloc_ptr + DEBUG_ALLOC_SAVE_MAX - 1) % DEBUG_ALLOC_SAVE_MAX;
-    saved_file = debug_alloc_loc_info[debug_alloc_ptr].file;
-    saved_line = debug_alloc_loc_info[debug_alloc_ptr].line;
-}
+static char *internal_vstralloc(const char *, int, const char *, va_list);
 
 /*
  * alloc - a wrapper for malloc.
  */
 void *
-debug_alloc(s, l, size)
-    const char *s;
-    int l;
-    size_t size;
+debug_alloc(
+    const char *file,
+    int                line,
+    size_t     size)
 {
     void *addr;
 
-    malloc_enter(debug_caller_loc(s, l));
     addr = (void *)malloc(max(size, 1));
     if (addr == NULL) {
-       errordump("%s@%d: memory allocation failed (%u bytes requested)",
-                 s ? s : "(unknown)",
-                 s ? l : -1,
+       errordump(_("%s@%d: memory allocation failed (%zu bytes requested)"),
+                 file ? file : _("(unknown)"),
+                 file ? line : -1,
                  size);
+       /*NOTREACHED*/
     }
-    malloc_leave(debug_caller_loc(s, l));
     return addr;
 }
 
@@ -198,18 +64,16 @@ debug_alloc(s, l, size)
  * newalloc - free existing buffer and then alloc a new one.
  */
 void *
-debug_newalloc(s, l, old, size)
-    const char *s;
-    int l;
-    void *old;
-    size_t size;
+debug_newalloc(
+    const char *file,
+    int                line,
+    void *     old,
+    size_t     size)
 {
     char *addr;
 
-    malloc_enter(debug_caller_loc(s, l));
-    addr = debug_alloc(s, l, size);
+    addr = debug_alloc(file, line, size);
     amfree(old);
-    malloc_leave(debug_caller_loc(s, l));
     return addr;
 }
 
@@ -219,40 +83,18 @@ debug_newalloc(s, l, old, size)
  *            Just like strdup()!
  */
 char *
-debug_stralloc(s, l, str)
-    const char *s;
-    int l;
-    const char *str;
+debug_stralloc(
+    const char *file,
+    int                line,
+    const char *str)
 {
     char *addr;
 
-    malloc_enter(debug_caller_loc(s, l));
-    addr = debug_alloc(s, l, strlen(str) + 1);
+    addr = debug_alloc(file, line, strlen(str) + 1);
     strcpy(addr, str);
-    malloc_leave(debug_caller_loc(s, l));
     return (addr);
 }
 
-/* vstrextend -- Extends the existing string by appending the other 
- * arguments. */
-arglist_function(char *vstrextend,
-                 char **,
-                 oldstr)
-{
-       char *keep = *oldstr;
-       va_list ap;
-
-       arglist_start(ap, oldstr);
-
-       if (*oldstr == NULL)
-               *oldstr = "";
-       *oldstr = internal_vstralloc(*oldstr, ap);
-        amfree(keep);
-
-       arglist_end(ap);
-        return *oldstr;
-}
-
 /*
  * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
  * allocated memory.
@@ -261,24 +103,26 @@ arglist_function(char *vstrextend,
  * to scan the strings more than necessary.
  */
 
-#define        MAX_VSTRALLOC_ARGS      32
+#define        MAX_VSTRALLOC_ARGS      40
 
 static char *
-internal_vstralloc(str, argp)
-    const char *str;
-    va_list argp;
+internal_vstralloc(
+    const char *file,
+    int                line,
+    const char *str,
+    va_list argp)
 {
     char *next;
     char *result;
-    int a;
+    int a, b;
     size_t total_len;
     const char *arg[MAX_VSTRALLOC_ARGS+1];
     size_t len[MAX_VSTRALLOC_ARGS+1];
     size_t l;
-    const char *s;
 
     if (str == NULL) {
-       return NULL;                            /* probably will not happen */
+       errordump(_("internal_vstralloc: str is NULL"));
+       /*NOTREACHED*/
     }
 
     a = 0;
@@ -292,24 +136,24 @@ internal_vstralloc(str, argp)
            continue;                           /* minor optimisation */
        }
        if (a >= MAX_VSTRALLOC_ARGS) {
-           errordump("%s@%d: more than %d arg%s to vstralloc",
-                     saved_file ? saved_file : "(unknown)",
-                     saved_file ? saved_line : -1,
-                     MAX_VSTRALLOC_ARGS,
-                     (MAX_VSTRALLOC_ARGS == 1) ? "" : "s");
+           errordump(_("%s@%d: more than %d args to vstralloc"),
+                     file ? file : _("(unknown)"),
+                     file ? line : -1,
+                     MAX_VSTRALLOC_ARGS);
+           /*NOTREACHED*/
        }
        arg[a] = next;
        len[a] = l;
        total_len += l;
        a++;
     }
-    arg[a] = NULL;
-    len[a] = 0;
 
-    next = result = debug_alloc(saved_file, saved_line, total_len+1);
-    for (a = 0; (s = arg[a]) != NULL; a++) {
-       memcpy(next, s, len[a]);
-       next += len[a];
+    result = debug_alloc(file, line, total_len+1);
+
+    next = result;
+    for (b = 0; b < a; b++) {
+       memcpy(next, arg[b], len[b]);
+       next += len[b];
     }
     *next = '\0';
 
@@ -320,17 +164,19 @@ internal_vstralloc(str, argp)
 /*
  * vstralloc - copies multiple strings into newly allocated memory.
  */
-arglist_function(char *debug_vstralloc, const char *, str)
+char *
+debug_vstralloc(
+    const char *file,
+    int                line,
+    const char *str,
+    ...)
 {
     va_list argp;
     char *result;
 
-    debug_alloc_pop();
-    malloc_enter(debug_caller_loc(saved_file, saved_line));
     arglist_start(argp, str);
-    result = internal_vstralloc(str, argp);
+    result = internal_vstralloc(file, line, str, argp);
     arglist_end(argp);
-    malloc_leave(debug_caller_loc(saved_file, saved_line));
     return result;
 }
 
@@ -339,18 +185,16 @@ arglist_function(char *debug_vstralloc, const char *, str)
  * newstralloc - free existing string and then stralloc a new one.
  */
 char *
-debug_newstralloc(s, l, oldstr, newstr)
-    const char *s;
-    int l;
-    char *oldstr;
-    const char *newstr;
+debug_newstralloc(
+    const char *file,
+    int                line,
+    char *     oldstr,
+    const char *newstr)
 {
     char *addr;
 
-    malloc_enter(debug_caller_loc(s, l));
-    addr = debug_stralloc(s, l, newstr);
+    addr = debug_stralloc(file, line, newstr);
     amfree(oldstr);
-    malloc_leave(debug_caller_loc(s, l));
     return (addr);
 }
 
@@ -358,31 +202,124 @@ debug_newstralloc(s, l, oldstr, newstr)
 /*
  * newvstralloc - free existing string and then vstralloc a new one.
  */
-arglist_function1(char *debug_newvstralloc,
-                 char *,
-                 oldstr,
-                 const char *,
-                 newstr)
+char *
+debug_newvstralloc(
+    const char *file,
+    int                line,
+    char *     oldstr,
+    const char *newstr,
+    ...)
 {
     va_list argp;
     char *result;
 
-    debug_alloc_pop();
-    malloc_enter(debug_caller_loc(saved_file, saved_line));
     arglist_start(argp, newstr);
-    result = internal_vstralloc(newstr, argp);
+    result = internal_vstralloc(file, line, newstr, argp);
     arglist_end(argp);
     amfree(oldstr);
-    malloc_leave(debug_caller_loc(saved_file, saved_line));
     return result;
 }
 
 
 /*
- * safe_env - build a "safe" environment list.
+ * vstrallocf - copies printf formatted string into newly allocated memory.
+ */
+char *
+debug_vstrallocf(
+    const char *file,
+    int                line,
+    const char *fmt,
+    ...)
+{
+    char *     result;
+    size_t     size;
+    va_list    argp;
+
+
+    result = debug_alloc(file, line, MIN_ALLOC);
+    if (result != NULL) {
+
+       arglist_start(argp, fmt);
+       size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
+       arglist_end(argp);
+
+       if (size >= (size_t)MIN_ALLOC) {
+           amfree(result);
+           result = debug_alloc(file, line, size + 1);
+
+           arglist_start(argp, fmt);
+           (void)g_vsnprintf(result, size + 1, fmt, argp);
+           arglist_end(argp);
+       }
+    }
+
+    return result;
+}
+
+
+/*
+ * newvstrallocf - free existing string and then vstrallocf a new one.
+ */
+char *
+debug_newvstrallocf(
+    const char *file,
+    int                line,
+    char *     oldstr,
+    const char *fmt,
+    ...)
+{
+    size_t     size;
+    char *     result;
+    va_list    argp;
+
+    result = debug_alloc(file, line, MIN_ALLOC);
+    if (result != NULL) {
+
+       arglist_start(argp, fmt);
+       size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
+       arglist_end(argp);
+
+       if (size >= MIN_ALLOC) {
+           amfree(result);
+           result = debug_alloc(file, line, size + 1);
+
+           arglist_start(argp, fmt);
+           (void)g_vsnprintf(result, size + 1, fmt, argp);
+           arglist_end(argp);
+       }
+    }
+    amfree(oldstr);
+    return result;
+}
+
+/* vstrextend -- Extends the existing string by appending the other 
+ * arguments. */
+char *
+debug_vstrextend(
+    const char *file,
+    int                line,
+    char **    oldstr,
+    ...)
+{
+       char *keep = *oldstr;
+       va_list ap;
+
+       arglist_start(ap, oldstr);
+
+       if (*oldstr == NULL)
+               *oldstr = "";
+       *oldstr = internal_vstralloc(file, line, *oldstr, ap);
+        amfree(keep);
+
+       arglist_end(ap);
+        return *oldstr;
+}
+
+/*
+ * safe_env_full - build a "safe" environment list.
  */
 char **
-safe_env()
+safe_env_full(char **add)
 {
     static char *safe_env_list[] = {
        "TZ",
@@ -402,7 +339,7 @@ safe_env()
      * safe_env_list so our result is always a valid, although possibly
      * empty, environment list.
      */
-#define SAFE_ENV_CNT   (sizeof(safe_env_list) / sizeof(*safe_env_list))
+#define SAFE_ENV_CNT   (size_t)(sizeof(safe_env_list) / sizeof(*safe_env_list))
     char **envp = safe_env_list + SAFE_ENV_CNT - 1;
 
     char **p;
@@ -410,9 +347,47 @@ safe_env()
     char *s;
     char *v;
     size_t l1, l2;
+    char **env;
+    int    env_cnt;
+    int nadd = 0;
+
+    /* count ADD */
+    for (p = add; p && *p; p++)
+       nadd++;
+
+    if (getuid() == geteuid() && getgid() == getegid()) {
+       env_cnt = 1;
+       for (env = environ; *env != NULL; env++)
+           env_cnt++;
+       if ((q = (char **)malloc((nadd+env_cnt)*SIZEOF(char *))) != NULL) {
+           envp = q;
+           p = envp;
+           /* copy in ADD */
+           for (env = add; env && *env; env++) {
+               *p = *env;
+               p++;
+           }
+           for (env = environ; *env != NULL; env++) {
+               if (strncmp("LANG=", *env, 5) != 0 &&
+                   strncmp("LC_", *env, 3) != 0) {
+                   *p = stralloc(*env);
+                   p++;
+               }
+           }
+           *p = NULL;
+       }
+       return envp;
+    }
 
-    if ((q = (char **)malloc(sizeof(safe_env_list))) != NULL) {
+    if ((q = (char **)malloc(nadd*sizeof(char *) + SIZEOF(safe_env_list))) != NULL) {
        envp = q;
+       /* copy in ADD */
+       for (p = add; p && *p; p++) {
+           *q = *p;
+           q++;
+       }
+
+       /* and copy any SAFE_ENV that are already set */
        for (p = safe_env_list; *p != NULL; p++) {
            if ((v = getenv(*p)) == NULL) {
                continue;                       /* no variable to dup */
@@ -432,70 +407,3 @@ safe_env()
     }
     return envp;
 }
-
-/*
- * amtable_alloc -- (re)allocate enough space for some number of elements.
- *
- * input:      table -- pointer to pointer to table
- *             current -- pointer to current number of elements
- *             elsize -- size of a table element
- *             count -- desired number of elements
- *             bump -- round up factor
- *             init_func -- optional element initialization function
- * output:     table -- possibly adjusted to point to new table area
- *             current -- possibly adjusted to new number of elements
- */
-
-int
-debug_amtable_alloc(s, l, table, current, elsize, count, bump, init_func)
-    const char *s;
-    int l;
-    void **table;
-    int *current;
-    size_t elsize;
-    int count;
-    int bump;
-    void (*init_func)(void *);
-{
-    void *table_new;
-    int table_count_new;
-    int i;
-
-    if (count >= *current) {
-       table_count_new = ((count + bump) / bump) * bump;
-       table_new = debug_alloc(s, l, table_count_new * elsize);
-       if (0 != *table) {
-           memcpy(table_new, *table, *current * elsize);
-           free(*table);
-       }
-       *table = table_new;
-       memset(((char *)*table) + *current * elsize,
-              0,
-              (table_count_new - *current) * elsize);
-       if (init_func != NULL) {
-           for (i = *current; i < table_count_new; i++) {
-               (*init_func)(((char *)*table) + i * elsize);
-           }
-       }
-       *current = table_count_new;
-    }
-    return 0;
-}
-
-/*
- * amtable_free -- release a table.
- *
- * input:      table -- pointer to pointer to table
- *             current -- pointer to current number of elements
- * output:     table -- possibly adjusted to point to new table area
- *             current -- possibly adjusted to new number of elements
- */
-
-void
-amtable_free(table, current)
-    void **table;
-    int *current;
-{
-    amfree(*table);
-    *current = 0;
-}