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-2013 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 *
debug_alloc(const char * file,int line,size_t size)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 *
debug_newalloc(const char * file,int line,void * old,size_t size)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 *
debug_stralloc(const char * file,int line,const char * str)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 *
internal_vstralloc(const char * file,int line,const char * str,va_list argp)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 *
debug_vstralloc(const char * file,int line,const char * str,...)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 *
debug_newstralloc(const char * file,int line,char * oldstr,const char * newstr)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 *
debug_newvstralloc(const char * file,int line,char * oldstr,const char * newstr,...)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 *
debug_vstrallocf(const char * file,int line,const char * fmt,...)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 *
debug_newvstrallocf(const char * file,int line,char * oldstr,const char * fmt,...)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 *
debug_vstrextend(const char * file,int line,char ** oldstr,...)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 **
safe_env_full(char ** add)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 #ifdef NEED_LD_LIBRARY_PATH_ENV
335 "LD_LIBRARY_PATH",
336 #endif
337 NULL
338 };
339
340 /*
341 * If the initial environment pointer malloc fails, set up to
342 * pass back a pointer to the NULL string pointer at the end of
343 * safe_env_list so our result is always a valid, although possibly
344 * empty, environment list.
345 */
346 #define SAFE_ENV_CNT (size_t)(sizeof(safe_env_list) / sizeof(*safe_env_list))
347 char **envp = safe_env_list + SAFE_ENV_CNT - 1;
348
349 char **p;
350 char **q;
351 char *s;
352 char *v;
353 size_t l1, l2;
354 char **env;
355 int env_cnt;
356 int nadd = 0;
357
358 /* count ADD */
359 for (p = add; p && *p; p++)
360 nadd++;
361
362 if (getuid() == geteuid() && getgid() == getegid()) {
363 env_cnt = 1;
364 for (env = environ; *env != NULL; env++)
365 env_cnt++;
366 if ((q = (char **)malloc((nadd+env_cnt)*SIZEOF(char *))) != NULL) {
367 envp = q;
368 p = envp;
369 /* copy in ADD */
370 for (env = add; env && *env; env++) {
371 *p = *env;
372 p++;
373 }
374 for (env = environ; *env != NULL; env++) {
375 if (strncmp("LANG=", *env, 5) != 0 &&
376 strncmp("LC_", *env, 3) != 0) {
377 *p = stralloc(*env);
378 p++;
379 }
380 }
381 *p = NULL;
382 }
383 return envp;
384 }
385
386 if ((q = (char **)malloc(nadd*sizeof(char *) + SIZEOF(safe_env_list))) != NULL) {
387 envp = q;
388 /* copy in ADD */
389 for (p = add; p && *p; p++) {
390 *q = *p;
391 q++;
392 }
393
394 /* and copy any SAFE_ENV that are already set */
395 for (p = safe_env_list; *p != NULL; p++) {
396 if ((v = getenv(*p)) == NULL) {
397 continue; /* no variable to dup */
398 }
399 l1 = strlen(*p); /* variable name w/o null */
400 l2 = strlen(v) + 1; /* include null byte here */
401 if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
402 break; /* out of memory */
403 }
404 *q++ = s; /* save the new pointer */
405 memcpy(s, *p, l1); /* left hand side */
406 s += l1;
407 *s++ = '=';
408 memcpy(s, v, l2); /* right hand side and null */
409 }
410 *q = NULL; /* terminate the list */
411 }
412 return envp;
413 }
414