Imported Upstream version 3.2.0
[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 5280 2007-02-13 15:58:56Z martineau $
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
36 #define MIN_ALLOC       64
37
38 static char *internal_vstralloc(const char *, int, const char *, va_list);
39
40 /*
41  * alloc - a wrapper for malloc.
42  */
43 void *
44 debug_alloc(
45     const char *file,
46     int         line,
47     size_t      size)
48 {
49     void *addr;
50
51     addr = (void *)malloc(max(size, 1));
52     if (addr == NULL) {
53         errordump(_("%s@%d: memory allocation failed (%zu bytes requested)"),
54                   file ? file : _("(unknown)"),
55                   file ? line : -1,
56                   size);
57         /*NOTREACHED*/
58     }
59     return addr;
60 }
61
62
63 /*
64  * newalloc - free existing buffer and then alloc a new one.
65  */
66 void *
67 debug_newalloc(
68     const char *file,
69     int         line,
70     void *      old,
71     size_t      size)
72 {
73     char *addr;
74
75     addr = debug_alloc(file, line, size);
76     amfree(old);
77     return addr;
78 }
79
80
81 /*
82  * stralloc - copies the given string into newly allocated memory.
83  *            Just like strdup()!
84  */
85 char *
86 debug_stralloc(
87     const char *file,
88     int         line,
89     const char *str)
90 {
91     char *addr;
92
93     addr = debug_alloc(file, line, strlen(str) + 1);
94     strcpy(addr, str);
95     return (addr);
96 }
97
98 /*
99  * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
100  * allocated memory.
101  *
102  * The MAX_STR_ARGS limit is purely an efficiency issue so we do not have
103  * to scan the strings more than necessary.
104  */
105
106 #define MAX_VSTRALLOC_ARGS      40
107
108 static char *
109 internal_vstralloc(
110     const char *file,
111     int         line,
112     const char *str,
113     va_list argp)
114 {
115     char *next;
116     char *result;
117     int a, b;
118     size_t total_len;
119     const char *arg[MAX_VSTRALLOC_ARGS+1];
120     size_t len[MAX_VSTRALLOC_ARGS+1];
121     size_t l;
122
123     if (str == NULL) {
124         errordump(_("internal_vstralloc: str is NULL"));
125         /*NOTREACHED*/
126     }
127
128     a = 0;
129     arg[a] = str;
130     l = strlen(str);
131     total_len = len[a] = l;
132     a++;
133
134     while ((next = arglist_val(argp, char *)) != NULL) {
135         if ((l = strlen(next)) == 0) {
136             continue;                           /* minor optimisation */
137         }
138         if (a >= MAX_VSTRALLOC_ARGS) {
139             errordump(_("%s@%d: more than %d args to vstralloc"),
140                       file ? file : _("(unknown)"),
141                       file ? line : -1,
142                       MAX_VSTRALLOC_ARGS);
143             /*NOTREACHED*/
144         }
145         arg[a] = next;
146         len[a] = l;
147         total_len += l;
148         a++;
149     }
150
151     result = debug_alloc(file, line, total_len+1);
152
153     next = result;
154     for (b = 0; b < a; b++) {
155         memcpy(next, arg[b], len[b]);
156         next += len[b];
157     }
158     *next = '\0';
159
160     return result;
161 }
162
163
164 /*
165  * vstralloc - copies multiple strings into newly allocated memory.
166  */
167 char *
168 debug_vstralloc(
169     const char *file,
170     int         line,
171     const char *str,
172     ...)
173 {
174     va_list argp;
175     char *result;
176
177     arglist_start(argp, str);
178     result = internal_vstralloc(file, line, str, argp);
179     arglist_end(argp);
180     return result;
181 }
182
183
184 /*
185  * newstralloc - free existing string and then stralloc a new one.
186  */
187 char *
188 debug_newstralloc(
189     const char *file,
190     int         line,
191     char *      oldstr,
192     const char *newstr)
193 {
194     char *addr;
195
196     addr = debug_stralloc(file, line, newstr);
197     amfree(oldstr);
198     return (addr);
199 }
200
201
202 /*
203  * newvstralloc - free existing string and then vstralloc a new one.
204  */
205 char *
206 debug_newvstralloc(
207     const char *file,
208     int         line,
209     char *      oldstr,
210     const char *newstr,
211     ...)
212 {
213     va_list argp;
214     char *result;
215
216     arglist_start(argp, newstr);
217     result = internal_vstralloc(file, line, newstr, argp);
218     arglist_end(argp);
219     amfree(oldstr);
220     return result;
221 }
222
223
224 /*
225  * vstrallocf - copies printf formatted string into newly allocated memory.
226  */
227 char *
228 debug_vstrallocf(
229     const char *file,
230     int         line,
231     const char *fmt,
232     ...)
233 {
234     char *      result;
235     size_t      size;
236     va_list     argp;
237
238
239     result = debug_alloc(file, line, MIN_ALLOC);
240     if (result != NULL) {
241
242         arglist_start(argp, fmt);
243         size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
244         arglist_end(argp);
245
246         if (size >= (size_t)MIN_ALLOC) {
247             amfree(result);
248             result = debug_alloc(file, line, size + 1);
249
250             arglist_start(argp, fmt);
251             (void)g_vsnprintf(result, size + 1, fmt, argp);
252             arglist_end(argp);
253         }
254     }
255
256     return result;
257 }
258
259
260 /*
261  * newvstrallocf - free existing string and then vstrallocf a new one.
262  */
263 char *
264 debug_newvstrallocf(
265     const char *file,
266     int         line,
267     char *      oldstr,
268     const char *fmt,
269     ...)
270 {
271     size_t      size;
272     char *      result;
273     va_list     argp;
274
275     result = debug_alloc(file, line, MIN_ALLOC);
276     if (result != NULL) {
277
278         arglist_start(argp, fmt);
279         size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
280         arglist_end(argp);
281
282         if (size >= MIN_ALLOC) {
283             amfree(result);
284             result = debug_alloc(file, line, size + 1);
285
286             arglist_start(argp, fmt);
287             (void)g_vsnprintf(result, size + 1, fmt, argp);
288             arglist_end(argp);
289         }
290     }
291     amfree(oldstr);
292     return result;
293 }
294
295 /* vstrextend -- Extends the existing string by appending the other 
296  * arguments. */
297 char *
298 debug_vstrextend(
299     const char *file,
300     int         line,
301     char **     oldstr,
302     ...)
303 {
304         char *keep = *oldstr;
305         va_list ap;
306
307         arglist_start(ap, oldstr);
308
309         if (*oldstr == NULL)
310                 *oldstr = "";
311         *oldstr = internal_vstralloc(file, line, *oldstr, ap);
312         amfree(keep);
313
314         arglist_end(ap);
315         return *oldstr;
316 }
317
318 /*
319  * safe_env_full - build a "safe" environment list.
320  */
321 char **
322 safe_env_full(char **add)
323 {
324     static char *safe_env_list[] = {
325         "TZ",
326 #ifdef __CYGWIN__
327         "SYSTEMROOT",
328 #endif
329 #ifdef NEED_PATH_ENV
330         "PATH",
331 #endif
332         "DISPLAY",
333         NULL
334     };
335
336     /*
337      * If the initial environment pointer malloc fails, set up to
338      * pass back a pointer to the NULL string pointer at the end of
339      * safe_env_list so our result is always a valid, although possibly
340      * empty, environment list.
341      */
342 #define SAFE_ENV_CNT    (size_t)(sizeof(safe_env_list) / sizeof(*safe_env_list))
343     char **envp = safe_env_list + SAFE_ENV_CNT - 1;
344
345     char **p;
346     char **q;
347     char *s;
348     char *v;
349     size_t l1, l2;
350     char **env;
351     int    env_cnt;
352     int nadd = 0;
353
354     /* count ADD */
355     for (p = add; p && *p; p++)
356         nadd++;
357
358     if (getuid() == geteuid() && getgid() == getegid()) {
359         env_cnt = 1;
360         for (env = environ; *env != NULL; env++)
361             env_cnt++;
362         if ((q = (char **)malloc((nadd+env_cnt)*SIZEOF(char *))) != NULL) {
363             envp = q;
364             p = envp;
365             /* copy in ADD */
366             for (env = add; env && *env; env++) {
367                 *p = *env;
368                 p++;
369             }
370             for (env = environ; *env != NULL; env++) {
371                 if (strncmp("LANG=", *env, 5) != 0 &&
372                     strncmp("LC_", *env, 3) != 0) {
373                     *p = stralloc(*env);
374                     p++;
375                 }
376             }
377             *p = NULL;
378         }
379         return envp;
380     }
381
382     if ((q = (char **)malloc(nadd*sizeof(char *) + SIZEOF(safe_env_list))) != NULL) {
383         envp = q;
384         /* copy in ADD */
385         for (p = add; p && *p; p++) {
386             *q = *p;
387             q++;
388         }
389
390         /* and copy any SAFE_ENV that are already set */
391         for (p = safe_env_list; *p != NULL; p++) {
392             if ((v = getenv(*p)) == NULL) {
393                 continue;                       /* no variable to dup */
394             }
395             l1 = strlen(*p);                    /* variable name w/o null */
396             l2 = strlen(v) + 1;                 /* include null byte here */
397             if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
398                 break;                          /* out of memory */
399             }
400             *q++ = s;                           /* save the new pointer */
401             memcpy(s, *p, l1);                  /* left hand side */
402             s += l1;
403             *s++ = '=';
404             memcpy(s, v, l2);                   /* right hand side and null */
405         }
406         *q = NULL;                              /* terminate the list */
407     }
408     return envp;
409 }