/*
* Amanda, The Advanced Maryland Automatic Network Disk Archiver
- * Copyright (c) 1991-1998 University of Maryland at College Park
+ * Copyright (c) 1991-1999 University of Maryland at College Park
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: alloc.c,v 1.17.2.1.4.3.2.3 2002/10/27 14:31:18 martinea 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"
-/*
- *=====================================================================
- * debug_caller_loc -- keep track of all allocation callers
- *
- * char *debug_caller_loc(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).
- *=====================================================================
- */
-
-char *
-debug_caller_loc(file, line)
- char *file;
- int line;
-{
- struct loc_str {
- char *str;
- struct loc_str *next;
- };
- static struct loc_str *root = NULL;
- struct loc_str *ls, *ls_last;
- int len;
- int size;
- char *p;
- static char *loc = NULL;
- static int loc_size = 0;
-
- if ((p = strrchr(file, '/')) == NULL) {
- p = file; /* keep the whole name */
- } else {
- p++; /* just the last path element */
- }
-
- len = strlen (p);
- size = len + 1 + NUM_STR_SIZE + 1;
- if (size > loc_size) {
- size = ((size + 64 - 1) / 64) * 64; /* might as well get a bunch */
- /*
- * We should free the previous loc area, but we have marked it
- * as a non-leak and the library considers it an error to free
- * such an area, so we just ignore it. We probably grabbed
- * enough the first time that this will not even happen.
- */
- loc = malloc (size);
- if (loc == NULL) {
- return "??"; /* not much better than abort */
- }
- malloc_mark (loc);
- loc_size = size;
- }
-
- strcpy (loc, p);
- ap_snprintf(loc + len, 1 + NUM_STR_SIZE, "@%d", line);
-
- for (ls_last = NULL, ls = root; ls != NULL; ls_last = ls, ls = ls->next) {
- if (strcmp (loc, ls->str) == 0) {
- break;
- }
- }
-
- if (ls == NULL) {
- /*
- * 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 */
- }
- malloc_mark (ls);
- size = strlen (loc) + 1;
- ls->str = malloc (size);
- if (ls->str == NULL) {
- free (ls);
- return "??"; /* not much better than abort */
- }
- malloc_mark (ls->str);
- strcpy (ls->str, loc);
- ls->next = root;
- root = ls;
- } else if (ls_last != NULL) {
- /*
- * This is a repeat and was not at the head of the list.
- * Unlink it and move it to the front.
- */
- ls_last->next = ls->next;
- ls->next = root;
- root = ls;
- } else {
- /*
- * This is a repeat but was already at the head of the list,
- * so nothing else needs to be done.
- */
- }
- 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.
- *=====================================================================
- */
+#define MIN_ALLOC 64
-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)
- 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,
+ if (addr == NULL) {
+ 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;
}
* newalloc - free existing buffer and then alloc a new one.
*/
void *
-debug_newalloc(s, l, old, size)
- 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;
}
* Just like strdup()!
*/
char *
-debug_stralloc(s, l, str)
- 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;
+ return (addr);
}
-
/*
* internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
* allocated memory.
* 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;
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';
/*
* 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;
}
* newstralloc - free existing string and then stralloc a new one.
*/
char *
-debug_newstralloc(s, l, oldstr, newstr)
- 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;
+ return (addr);
}
/*
* 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;
}
/*
- * sbuf_man - static buffer manager.
- *
- * Manage a bunch of static buffer pointers.
+ * vstrallocf - copies printf formatted string into newly allocated memory.
*/
-void *sbuf_man(e_bufs, ptr)
- void *e_bufs; /* XXX - I dont think this is right */
- void *ptr;
+char *
+debug_vstrallocf(
+ const char *file,
+ int line,
+ const char *fmt,
+ ...)
{
- SBUF2_DEF(1) *bufs;
- int slot;
+ char * result;
+ size_t size;
+ va_list argp;
+
- bufs = e_bufs;
+ result = debug_alloc(file, line, MIN_ALLOC);
+ if (result != NULL) {
- /* try and trap bugs */
- assert(bufs->magic == SBUF_MAGIC);
- assert(bufs->max > 0);
+ arglist_start(argp, fmt);
+ size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
+ arglist_end(argp);
- /* initialise first time through */
- if(bufs->cur == -1)
- for(slot=0; slot < bufs->max; slot++) {
- bufs->bufp[slot] = (void *)0;
- }
+ 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;
- /* calculate the next slot */
- slot = bufs->cur + 1;
- if (slot >= bufs->max) slot = 0;
+ result = debug_alloc(file, line, MIN_ALLOC);
+ if (result != NULL) {
- /* free the previous inhabitant */
- if(bufs->bufp[slot] != (void *)0) free(bufs->bufp[slot]);
+ arglist_start(argp, fmt);
+ size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
+ arglist_end(argp);
- /* store the new one */
- bufs->bufp[slot] = ptr;
- bufs->cur = slot;
+ if (size >= MIN_ALLOC) {
+ amfree(result);
+ result = debug_alloc(file, line, size + 1);
- return ptr;
+ 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 - build a "safe" environment list.
+ * safe_env_full - build a "safe" environment list.
*/
char **
-safe_env()
+safe_env_full(char **add)
{
static char *safe_env_list[] = {
"TZ",
+#ifdef __CYGWIN__
+ "SYSTEMROOT",
+#endif
#ifdef NEED_PATH_ENV
"PATH",
#endif
+ "DISPLAY",
NULL
};
* 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;
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 */
}
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)
- 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;
-}