0a0cdef3555f72a6b29d115910fdcd533b0bee06
[debian/amanda] / common-src / alloc.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1999 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: alloc.c,v 1.35 2005/12/21 19:07:49 paddy_s Exp $
28  *
29  * Memory allocators with error handling.  If the allocation fails,
30  * errordump() is called, relieving the caller from checking the return
31  * code
32  */
33 #include "amanda.h"
34 #include "arglist.h"
35 #include "queue.h"
36
37 static char *internal_vstralloc P((const char *, va_list));
38
39 /*
40  *=====================================================================
41  * debug_caller_loc -- keep track of all allocation callers
42  *
43  * const char *debug_caller_loc(const char *file, int line)
44  *
45  * entry:       file = source file
46  *              line = source line
47  * exit:        a string like "genversion.c@999"
48  *
49  * The debug malloc library has a concept of a call stack that can be used
50  * to fine tune what was running when a particular allocation was done.
51  * We use it to tell who called our various allocation wrappers since
52  * it wouldn't do much good to tell us a problem happened because of
53  * the malloc call in alloc (they are all from there at some point).
54  *
55  * But the library expects the string passed to malloc_enter/malloc_leave
56  * to be static, so we build a linked list of each one we get (there are
57  * not really that many during a given execution).  When we get a repeat
58  * we return the previously allocated string.  For a bit of performance,
59  * we keep the list in least recently used order, which helps because
60  * the calls to us come in pairs (one for malloc_enter and one right
61  * after for malloc_leave).
62  *=====================================================================
63  */
64
65 const char *
66 debug_caller_loc(file, line)
67     const char *file;
68     int line;
69 {
70     struct loc_str {
71         char *str;
72         LIST_ENTRY(loc_str) le;
73     } *ls;
74     static LIST_HEAD(, loc_str) root = LIST_HEAD_INITIALIZER(root);
75     static char loc[256];       /* big enough for filename@lineno */
76     const char *p;
77
78     if ((p = strrchr(file, '/')) != NULL)
79         file = p + 1;                           /* just the last path element */
80
81     snprintf(loc, sizeof(loc), "%s@%d", file, line);
82
83     for (ls = LIST_FIRST(&root); ls != NULL; ls = LIST_NEXT(ls, le)) {
84         if (strcmp(loc, ls->str) == 0) {
85             if (ls != LIST_FIRST(&root)) {
86                 /*
87                  * This is a repeat and was not at the head of the list.
88                  * Unlink it and move it to the front.
89                  */
90                 LIST_REMOVE(ls, le);
91                 LIST_INSERT_HEAD(&root, ls, le);
92             }
93             return (ls->str);
94         }
95     }
96
97     /*
98      * This is a new entry.  Put it at the head of the list.
99      */
100     ls = malloc(sizeof(*ls));
101     if (ls == NULL)
102         return ("??");                  /* not much better than abort */
103     ls->str = malloc(strlen(loc) + 1);
104     if (ls->str == NULL) {
105         free(ls);
106         return ("??");                  /* not much better than abort */
107     }
108     strcpy(ls->str, loc);
109     malloc_mark(ls);
110     malloc_mark(ls->str);
111     LIST_INSERT_HEAD(&root, ls, le);
112     return (ls->str);
113 }
114
115 /*
116  *=====================================================================
117  * Save the current source line for vstralloc/newvstralloc.
118  *
119  * int debug_alloc_push (char *s, int l)
120  *
121  * entry:       s = source file
122  *              l = source line
123  * exit:        always zero
124  * 
125  * See the comments in amanda.h about what this is used for.
126  *=====================================================================
127  */
128
129 #define DEBUG_ALLOC_SAVE_MAX    10
130
131 static struct {
132         char            *file;
133         int             line;
134 } debug_alloc_loc_info[DEBUG_ALLOC_SAVE_MAX];
135 static int debug_alloc_ptr = 0;
136
137 static char             *saved_file;
138 static int              saved_line;
139
140 int
141 debug_alloc_push (s, l)
142     char *s;
143     int l;
144 {
145     debug_alloc_loc_info[debug_alloc_ptr].file = s;
146     debug_alloc_loc_info[debug_alloc_ptr].line = l;
147     debug_alloc_ptr = (debug_alloc_ptr + 1) % DEBUG_ALLOC_SAVE_MAX;
148     return 0;
149 }
150
151 /*
152  *=====================================================================
153  * Pop the current source line information for vstralloc/newvstralloc.
154  *
155  * int debug_alloc_pop (void)
156  *
157  * entry:       none
158  * exit:        none
159  * 
160  * See the comments in amanda.h about what this is used for.
161  *=====================================================================
162  */
163
164 void
165 debug_alloc_pop ()
166 {
167     debug_alloc_ptr =
168       (debug_alloc_ptr + DEBUG_ALLOC_SAVE_MAX - 1) % DEBUG_ALLOC_SAVE_MAX;
169     saved_file = debug_alloc_loc_info[debug_alloc_ptr].file;
170     saved_line = debug_alloc_loc_info[debug_alloc_ptr].line;
171 }
172
173 /*
174  * alloc - a wrapper for malloc.
175  */
176 void *
177 debug_alloc(s, l, size)
178     const char *s;
179     int l;
180     size_t size;
181 {
182     void *addr;
183
184     malloc_enter(debug_caller_loc(s, l));
185     addr = (void *)malloc(max(size, 1));
186     if (addr == NULL) {
187         errordump("%s@%d: memory allocation failed (%u bytes requested)",
188                   s ? s : "(unknown)",
189                   s ? l : -1,
190                   size);
191     }
192     malloc_leave(debug_caller_loc(s, l));
193     return addr;
194 }
195
196
197 /*
198  * newalloc - free existing buffer and then alloc a new one.
199  */
200 void *
201 debug_newalloc(s, l, old, size)
202     const char *s;
203     int l;
204     void *old;
205     size_t size;
206 {
207     char *addr;
208
209     malloc_enter(debug_caller_loc(s, l));
210     addr = debug_alloc(s, l, size);
211     amfree(old);
212     malloc_leave(debug_caller_loc(s, l));
213     return addr;
214 }
215
216
217 /*
218  * stralloc - copies the given string into newly allocated memory.
219  *            Just like strdup()!
220  */
221 char *
222 debug_stralloc(s, l, str)
223     const char *s;
224     int l;
225     const char *str;
226 {
227     char *addr;
228
229     malloc_enter(debug_caller_loc(s, l));
230     addr = debug_alloc(s, l, strlen(str) + 1);
231     strcpy(addr, str);
232     malloc_leave(debug_caller_loc(s, l));
233     return (addr);
234 }
235
236 /* vstrextend -- Extends the existing string by appending the other 
237  * arguments. */
238 arglist_function(char *vstrextend,
239                   char **,
240                  oldstr)
241 {
242         char *keep = *oldstr;
243         va_list ap;
244
245         arglist_start(ap, oldstr);
246
247         if (*oldstr == NULL)
248                 *oldstr = "";
249         *oldstr = internal_vstralloc(*oldstr, ap);
250         amfree(keep);
251
252         arglist_end(ap);
253         return *oldstr;
254 }
255
256 /*
257  * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
258  * allocated memory.
259  *
260  * The MAX_STR_ARGS limit is purely an efficiency issue so we do not have
261  * to scan the strings more than necessary.
262  */
263
264 #define MAX_VSTRALLOC_ARGS      32
265
266 static char *
267 internal_vstralloc(str, argp)
268     const char *str;
269     va_list argp;
270 {
271     char *next;
272     char *result;
273     int a;
274     size_t total_len;
275     const char *arg[MAX_VSTRALLOC_ARGS+1];
276     size_t len[MAX_VSTRALLOC_ARGS+1];
277     size_t l;
278     const char *s;
279
280     if (str == NULL) {
281         return NULL;                            /* probably will not happen */
282     }
283
284     a = 0;
285     arg[a] = str;
286     l = strlen(str);
287     total_len = len[a] = l;
288     a++;
289
290     while ((next = arglist_val(argp, char *)) != NULL) {
291         if ((l = strlen(next)) == 0) {
292             continue;                           /* minor optimisation */
293         }
294         if (a >= MAX_VSTRALLOC_ARGS) {
295             errordump("%s@%d: more than %d arg%s to vstralloc",
296                       saved_file ? saved_file : "(unknown)",
297                       saved_file ? saved_line : -1,
298                       MAX_VSTRALLOC_ARGS,
299                       (MAX_VSTRALLOC_ARGS == 1) ? "" : "s");
300         }
301         arg[a] = next;
302         len[a] = l;
303         total_len += l;
304         a++;
305     }
306     arg[a] = NULL;
307     len[a] = 0;
308
309     next = result = debug_alloc(saved_file, saved_line, total_len+1);
310     for (a = 0; (s = arg[a]) != NULL; a++) {
311         memcpy(next, s, len[a]);
312         next += len[a];
313     }
314     *next = '\0';
315
316     return result;
317 }
318
319
320 /*
321  * vstralloc - copies multiple strings into newly allocated memory.
322  */
323 arglist_function(char *debug_vstralloc, const char *, str)
324 {
325     va_list argp;
326     char *result;
327
328     debug_alloc_pop();
329     malloc_enter(debug_caller_loc(saved_file, saved_line));
330     arglist_start(argp, str);
331     result = internal_vstralloc(str, argp);
332     arglist_end(argp);
333     malloc_leave(debug_caller_loc(saved_file, saved_line));
334     return result;
335 }
336
337
338 /*
339  * newstralloc - free existing string and then stralloc a new one.
340  */
341 char *
342 debug_newstralloc(s, l, oldstr, newstr)
343     const char *s;
344     int l;
345     char *oldstr;
346     const char *newstr;
347 {
348     char *addr;
349
350     malloc_enter(debug_caller_loc(s, l));
351     addr = debug_stralloc(s, l, newstr);
352     amfree(oldstr);
353     malloc_leave(debug_caller_loc(s, l));
354     return (addr);
355 }
356
357
358 /*
359  * newvstralloc - free existing string and then vstralloc a new one.
360  */
361 arglist_function1(char *debug_newvstralloc,
362                   char *,
363                   oldstr,
364                   const char *,
365                   newstr)
366 {
367     va_list argp;
368     char *result;
369
370     debug_alloc_pop();
371     malloc_enter(debug_caller_loc(saved_file, saved_line));
372     arglist_start(argp, newstr);
373     result = internal_vstralloc(newstr, argp);
374     arglist_end(argp);
375     amfree(oldstr);
376     malloc_leave(debug_caller_loc(saved_file, saved_line));
377     return result;
378 }
379
380
381 /*
382  * safe_env - build a "safe" environment list.
383  */
384 char **
385 safe_env()
386 {
387     static char *safe_env_list[] = {
388         "TZ",
389 #ifdef __CYGWIN__
390         "SYSTEMROOT",
391 #endif
392 #ifdef NEED_PATH_ENV
393         "PATH",
394 #endif
395         "DISPLAY",
396         NULL
397     };
398
399     /*
400      * If the initial environment pointer malloc fails, set up to
401      * pass back a pointer to the NULL string pointer at the end of
402      * safe_env_list so our result is always a valid, although possibly
403      * empty, environment list.
404      */
405 #define SAFE_ENV_CNT    (sizeof(safe_env_list) / sizeof(*safe_env_list))
406     char **envp = safe_env_list + SAFE_ENV_CNT - 1;
407
408     char **p;
409     char **q;
410     char *s;
411     char *v;
412     size_t l1, l2;
413
414     if ((q = (char **)malloc(sizeof(safe_env_list))) != NULL) {
415         envp = q;
416         for (p = safe_env_list; *p != NULL; p++) {
417             if ((v = getenv(*p)) == NULL) {
418                 continue;                       /* no variable to dup */
419             }
420             l1 = strlen(*p);                    /* variable name w/o null */
421             l2 = strlen(v) + 1;                 /* include null byte here */
422             if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
423                 break;                          /* out of memory */
424             }
425             *q++ = s;                           /* save the new pointer */
426             memcpy(s, *p, l1);                  /* left hand side */
427             s += l1;
428             *s++ = '=';
429             memcpy(s, v, l2);                   /* right hand side and null */
430         }
431         *q = NULL;                              /* terminate the list */
432     }
433     return envp;
434 }
435
436 /*
437  * amtable_alloc -- (re)allocate enough space for some number of elements.
438  *
439  * input:       table -- pointer to pointer to table
440  *              current -- pointer to current number of elements
441  *              elsize -- size of a table element
442  *              count -- desired number of elements
443  *              bump -- round up factor
444  *              init_func -- optional element initialization function
445  * output:      table -- possibly adjusted to point to new table area
446  *              current -- possibly adjusted to new number of elements
447  */
448
449 int
450 debug_amtable_alloc(s, l, table, current, elsize, count, bump, init_func)
451     const char *s;
452     int l;
453     void **table;
454     int *current;
455     size_t elsize;
456     int count;
457     int bump;
458     void (*init_func)(void *);
459 {
460     void *table_new;
461     int table_count_new;
462     int i;
463
464     if (count >= *current) {
465         table_count_new = ((count + bump) / bump) * bump;
466         table_new = debug_alloc(s, l, table_count_new * elsize);
467         if (0 != *table) {
468             memcpy(table_new, *table, *current * elsize);
469             free(*table);
470         }
471         *table = table_new;
472         memset(((char *)*table) + *current * elsize,
473                0,
474                (table_count_new - *current) * elsize);
475         if (init_func != NULL) {
476             for (i = *current; i < table_count_new; i++) {
477                 (*init_func)(((char *)*table) + i * elsize);
478             }
479         }
480         *current = table_count_new;
481     }
482     return 0;
483 }
484
485 /*
486  * amtable_free -- release a table.
487  *
488  * input:       table -- pointer to pointer to table
489  *              current -- pointer to current number of elements
490  * output:      table -- possibly adjusted to point to new table area
491  *              current -- possibly adjusted to new number of elements
492  */
493
494 void
495 amtable_free(table, current)
496     void **table;
497     int *current;
498 {
499     amfree(*table);
500     *current = 0;
501 }