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