xref: /freebsd/contrib/wpa/src/utils/os_unix.c (revision 0957b409)
1 /*
2  * OS specific functions for UNIX/POSIX systems
3  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include <time.h>
12 #include <sys/wait.h>
13 
14 #ifdef ANDROID
15 #include <sys/capability.h>
16 #include <sys/prctl.h>
17 #include <private/android_filesystem_config.h>
18 #endif /* ANDROID */
19 
20 #ifdef __MACH__
21 #include <CoreServices/CoreServices.h>
22 #include <mach/mach.h>
23 #include <mach/mach_time.h>
24 #endif /* __MACH__ */
25 
26 #include "os.h"
27 #include "common.h"
28 
29 #ifdef WPA_TRACE
30 
31 #include "wpa_debug.h"
32 #include "trace.h"
33 #include "list.h"
34 
35 static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
36 
37 #define ALLOC_MAGIC 0xa84ef1b2
38 #define FREED_MAGIC 0x67fd487a
39 
40 struct os_alloc_trace {
41 	unsigned int magic;
42 	struct dl_list list;
43 	size_t len;
44 	WPA_TRACE_INFO
45 } __attribute__((aligned(16)));
46 
47 #endif /* WPA_TRACE */
48 
49 
50 void os_sleep(os_time_t sec, os_time_t usec)
51 {
52 	if (sec)
53 		sleep(sec);
54 	if (usec)
55 		usleep(usec);
56 }
57 
58 
59 int os_get_time(struct os_time *t)
60 {
61 	int res;
62 	struct timeval tv;
63 	res = gettimeofday(&tv, NULL);
64 	t->sec = tv.tv_sec;
65 	t->usec = tv.tv_usec;
66 	return res;
67 }
68 
69 
70 int os_get_reltime(struct os_reltime *t)
71 {
72 #ifndef __MACH__
73 #if defined(CLOCK_BOOTTIME)
74 	static clockid_t clock_id = CLOCK_BOOTTIME;
75 #elif defined(CLOCK_MONOTONIC)
76 	static clockid_t clock_id = CLOCK_MONOTONIC;
77 #else
78 	static clockid_t clock_id = CLOCK_REALTIME;
79 #endif
80 	struct timespec ts;
81 	int res;
82 
83 	if (TEST_FAIL())
84 		return -1;
85 
86 	while (1) {
87 		res = clock_gettime(clock_id, &ts);
88 		if (res == 0) {
89 			t->sec = ts.tv_sec;
90 			t->usec = ts.tv_nsec / 1000;
91 			return 0;
92 		}
93 		switch (clock_id) {
94 #ifdef CLOCK_BOOTTIME
95 		case CLOCK_BOOTTIME:
96 			clock_id = CLOCK_MONOTONIC;
97 			break;
98 #endif
99 #ifdef CLOCK_MONOTONIC
100 		case CLOCK_MONOTONIC:
101 			clock_id = CLOCK_REALTIME;
102 			break;
103 #endif
104 		case CLOCK_REALTIME:
105 			return -1;
106 		}
107 	}
108 #else /* __MACH__ */
109 	uint64_t abstime, nano;
110 	static mach_timebase_info_data_t info = { 0, 0 };
111 
112 	if (!info.denom) {
113 		if (mach_timebase_info(&info) != KERN_SUCCESS)
114 			return -1;
115 	}
116 
117 	abstime = mach_absolute_time();
118 	nano = (abstime * info.numer) / info.denom;
119 
120 	t->sec = nano / NSEC_PER_SEC;
121 	t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
122 
123 	return 0;
124 #endif /* __MACH__ */
125 }
126 
127 
128 int os_mktime(int year, int month, int day, int hour, int min, int sec,
129 	      os_time_t *t)
130 {
131 	struct tm tm, *tm1;
132 	time_t t_local, t1, t2;
133 	os_time_t tz_offset;
134 
135 	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
136 	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
137 	    sec > 60)
138 		return -1;
139 
140 	memset(&tm, 0, sizeof(tm));
141 	tm.tm_year = year - 1900;
142 	tm.tm_mon = month - 1;
143 	tm.tm_mday = day;
144 	tm.tm_hour = hour;
145 	tm.tm_min = min;
146 	tm.tm_sec = sec;
147 
148 	t_local = mktime(&tm);
149 
150 	/* figure out offset to UTC */
151 	tm1 = localtime(&t_local);
152 	if (tm1) {
153 		t1 = mktime(tm1);
154 		tm1 = gmtime(&t_local);
155 		if (tm1) {
156 			t2 = mktime(tm1);
157 			tz_offset = t2 - t1;
158 		} else
159 			tz_offset = 0;
160 	} else
161 		tz_offset = 0;
162 
163 	*t = (os_time_t) t_local - tz_offset;
164 	return 0;
165 }
166 
167 
168 int os_gmtime(os_time_t t, struct os_tm *tm)
169 {
170 	struct tm *tm2;
171 	time_t t2 = t;
172 
173 	tm2 = gmtime(&t2);
174 	if (tm2 == NULL)
175 		return -1;
176 	tm->sec = tm2->tm_sec;
177 	tm->min = tm2->tm_min;
178 	tm->hour = tm2->tm_hour;
179 	tm->day = tm2->tm_mday;
180 	tm->month = tm2->tm_mon + 1;
181 	tm->year = tm2->tm_year + 1900;
182 	return 0;
183 }
184 
185 
186 #ifdef __APPLE__
187 #include <fcntl.h>
188 static int os_daemon(int nochdir, int noclose)
189 {
190 	int devnull;
191 
192 	if (chdir("/") < 0)
193 		return -1;
194 
195 	devnull = open("/dev/null", O_RDWR);
196 	if (devnull < 0)
197 		return -1;
198 
199 	if (dup2(devnull, STDIN_FILENO) < 0) {
200 		close(devnull);
201 		return -1;
202 	}
203 
204 	if (dup2(devnull, STDOUT_FILENO) < 0) {
205 		close(devnull);
206 		return -1;
207 	}
208 
209 	if (dup2(devnull, STDERR_FILENO) < 0) {
210 		close(devnull);
211 		return -1;
212 	}
213 
214 	return 0;
215 }
216 #else /* __APPLE__ */
217 #define os_daemon daemon
218 #endif /* __APPLE__ */
219 
220 
221 #ifdef __FreeBSD__
222 #include <err.h>
223 #include <libutil.h>
224 #include <stdint.h>
225 #endif /* __FreeBSD__ */
226 
227 int os_daemonize(const char *pid_file)
228 {
229 #if defined(__uClinux__) || defined(__sun__)
230 	return -1;
231 #else /* defined(__uClinux__) || defined(__sun__) */
232 #ifdef __FreeBSD__
233 	pid_t otherpid;
234 	struct pidfh *pfh;
235 
236 	pfh = pidfile_open(pid_file, 0600, &otherpid);
237 	if (pfh == NULL) {
238 		if (errno == EEXIST) {
239 			errx(1, "Daemon already running, pid: %jd.",
240 			    (intmax_t)otherpid);
241 		}
242 		warn("Cannot open or create pidfile.");
243 	}
244 #endif /* __FreeBSD__ */
245 
246 	if (os_daemon(0, 0)) {
247 		perror("daemon");
248 #ifdef __FreeBSD__
249 		pidfile_remove(pfh);
250 #endif /* __FreeBSD__ */
251 		return -1;
252 	}
253 
254 #ifndef __FreeBSD__
255 	if (pid_file) {
256 		FILE *f = fopen(pid_file, "w");
257 		if (f) {
258 			fprintf(f, "%u\n", getpid());
259 			fclose(f);
260 		}
261 	}
262 #else /* __FreeBSD__ */
263 	pidfile_write(pfh);
264 #endif /* __FreeBSD__ */
265 
266 	return -0;
267 #endif /* defined(__uClinux__) || defined(__sun__) */
268 }
269 
270 
271 void os_daemonize_terminate(const char *pid_file)
272 {
273 	if (pid_file)
274 		unlink(pid_file);
275 }
276 
277 
278 int os_get_random(unsigned char *buf, size_t len)
279 {
280 	FILE *f;
281 	size_t rc;
282 
283 	if (TEST_FAIL())
284 		return -1;
285 
286 	f = fopen("/dev/urandom", "rb");
287 	if (f == NULL) {
288 		printf("Could not open /dev/urandom.\n");
289 		return -1;
290 	}
291 
292 	rc = fread(buf, 1, len, f);
293 	fclose(f);
294 
295 	return rc != len ? -1 : 0;
296 }
297 
298 
299 unsigned long os_random(void)
300 {
301 	return random();
302 }
303 
304 
305 char * os_rel2abs_path(const char *rel_path)
306 {
307 	char *buf = NULL, *cwd, *ret;
308 	size_t len = 128, cwd_len, rel_len, ret_len;
309 	int last_errno;
310 
311 	if (!rel_path)
312 		return NULL;
313 
314 	if (rel_path[0] == '/')
315 		return os_strdup(rel_path);
316 
317 	for (;;) {
318 		buf = os_malloc(len);
319 		if (buf == NULL)
320 			return NULL;
321 		cwd = getcwd(buf, len);
322 		if (cwd == NULL) {
323 			last_errno = errno;
324 			os_free(buf);
325 			if (last_errno != ERANGE)
326 				return NULL;
327 			len *= 2;
328 			if (len > 2000)
329 				return NULL;
330 		} else {
331 			buf[len - 1] = '\0';
332 			break;
333 		}
334 	}
335 
336 	cwd_len = os_strlen(cwd);
337 	rel_len = os_strlen(rel_path);
338 	ret_len = cwd_len + 1 + rel_len + 1;
339 	ret = os_malloc(ret_len);
340 	if (ret) {
341 		os_memcpy(ret, cwd, cwd_len);
342 		ret[cwd_len] = '/';
343 		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
344 		ret[ret_len - 1] = '\0';
345 	}
346 	os_free(buf);
347 	return ret;
348 }
349 
350 
351 int os_program_init(void)
352 {
353 #ifdef ANDROID
354 	/*
355 	 * We ignore errors here since errors are normal if we
356 	 * are already running as non-root.
357 	 */
358 #ifdef ANDROID_SETGROUPS_OVERRIDE
359 	gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
360 #else /* ANDROID_SETGROUPS_OVERRIDE */
361 	gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
362 #endif /* ANDROID_SETGROUPS_OVERRIDE */
363 	struct __user_cap_header_struct header;
364 	struct __user_cap_data_struct cap;
365 
366 	setgroups(ARRAY_SIZE(groups), groups);
367 
368 	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
369 
370 	setgid(AID_WIFI);
371 	setuid(AID_WIFI);
372 
373 	header.version = _LINUX_CAPABILITY_VERSION;
374 	header.pid = 0;
375 	cap.effective = cap.permitted =
376 		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
377 	cap.inheritable = 0;
378 	capset(&header, &cap);
379 #endif /* ANDROID */
380 
381 	return 0;
382 }
383 
384 
385 void os_program_deinit(void)
386 {
387 #ifdef WPA_TRACE
388 	struct os_alloc_trace *a;
389 	unsigned long total = 0;
390 	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
391 		total += a->len;
392 		if (a->magic != ALLOC_MAGIC) {
393 			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
394 				   "len %lu",
395 				   a, a->magic, (unsigned long) a->len);
396 			continue;
397 		}
398 		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
399 			   a, (unsigned long) a->len);
400 		wpa_trace_dump("memleak", a);
401 	}
402 	if (total)
403 		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
404 			   (unsigned long) total);
405 	wpa_trace_deinit();
406 #endif /* WPA_TRACE */
407 }
408 
409 
410 int os_setenv(const char *name, const char *value, int overwrite)
411 {
412 	return setenv(name, value, overwrite);
413 }
414 
415 
416 int os_unsetenv(const char *name)
417 {
418 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
419     defined(__OpenBSD__)
420 	unsetenv(name);
421 	return 0;
422 #else
423 	return unsetenv(name);
424 #endif
425 }
426 
427 
428 char * os_readfile(const char *name, size_t *len)
429 {
430 	FILE *f;
431 	char *buf;
432 	long pos;
433 
434 	f = fopen(name, "rb");
435 	if (f == NULL)
436 		return NULL;
437 
438 	if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
439 		fclose(f);
440 		return NULL;
441 	}
442 	*len = pos;
443 	if (fseek(f, 0, SEEK_SET) < 0) {
444 		fclose(f);
445 		return NULL;
446 	}
447 
448 	buf = os_malloc(*len);
449 	if (buf == NULL) {
450 		fclose(f);
451 		return NULL;
452 	}
453 
454 	if (fread(buf, 1, *len, f) != *len) {
455 		fclose(f);
456 		os_free(buf);
457 		return NULL;
458 	}
459 
460 	fclose(f);
461 
462 	return buf;
463 }
464 
465 
466 int os_file_exists(const char *fname)
467 {
468 	return access(fname, F_OK) == 0;
469 }
470 
471 
472 int os_fdatasync(FILE *stream)
473 {
474 	if (!fflush(stream)) {
475 #ifdef __linux__
476 		return fdatasync(fileno(stream));
477 #else /* !__linux__ */
478 #ifdef F_FULLFSYNC
479 		/* OS X does not implement fdatasync(). */
480 		return fcntl(fileno(stream), F_FULLFSYNC);
481 #else /* F_FULLFSYNC */
482 		return fsync(fileno(stream));
483 #endif /* F_FULLFSYNC */
484 #endif /* __linux__ */
485 	}
486 
487 	return -1;
488 }
489 
490 
491 #ifndef WPA_TRACE
492 void * os_zalloc(size_t size)
493 {
494 	return calloc(1, size);
495 }
496 #endif /* WPA_TRACE */
497 
498 
499 size_t os_strlcpy(char *dest, const char *src, size_t siz)
500 {
501 	const char *s = src;
502 	size_t left = siz;
503 
504 	if (left) {
505 		/* Copy string up to the maximum size of the dest buffer */
506 		while (--left != 0) {
507 			if ((*dest++ = *s++) == '\0')
508 				break;
509 		}
510 	}
511 
512 	if (left == 0) {
513 		/* Not enough room for the string; force NUL-termination */
514 		if (siz != 0)
515 			*dest = '\0';
516 		while (*s++)
517 			; /* determine total src string length */
518 	}
519 
520 	return s - src - 1;
521 }
522 
523 
524 int os_memcmp_const(const void *a, const void *b, size_t len)
525 {
526 	const u8 *aa = a;
527 	const u8 *bb = b;
528 	size_t i;
529 	u8 res;
530 
531 	for (res = 0, i = 0; i < len; i++)
532 		res |= aa[i] ^ bb[i];
533 
534 	return res;
535 }
536 
537 
538 void * os_memdup(const void *src, size_t len)
539 {
540 	void *r = os_malloc(len);
541 
542 	if (r)
543 		os_memcpy(r, src, len);
544 	return r;
545 }
546 
547 
548 #ifdef WPA_TRACE
549 
550 #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
551 char wpa_trace_fail_func[256] = { 0 };
552 unsigned int wpa_trace_fail_after;
553 
554 static int testing_fail_alloc(void)
555 {
556 	const char *func[WPA_TRACE_LEN];
557 	size_t i, res, len;
558 	char *pos, *next;
559 	int match;
560 
561 	if (!wpa_trace_fail_after)
562 		return 0;
563 
564 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
565 	i = 0;
566 	if (i < res && os_strcmp(func[i], __func__) == 0)
567 		i++;
568 	if (i < res && os_strcmp(func[i], "os_malloc") == 0)
569 		i++;
570 	if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
571 		i++;
572 	if (i < res && os_strcmp(func[i], "os_calloc") == 0)
573 		i++;
574 	if (i < res && os_strcmp(func[i], "os_realloc") == 0)
575 		i++;
576 	if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
577 		i++;
578 	if (i < res && os_strcmp(func[i], "os_strdup") == 0)
579 		i++;
580 	if (i < res && os_strcmp(func[i], "os_memdup") == 0)
581 		i++;
582 
583 	pos = wpa_trace_fail_func;
584 
585 	match = 0;
586 	while (i < res) {
587 		int allow_skip = 1;
588 		int maybe = 0;
589 
590 		if (*pos == '=') {
591 			allow_skip = 0;
592 			pos++;
593 		} else if (*pos == '?') {
594 			maybe = 1;
595 			pos++;
596 		}
597 		next = os_strchr(pos, ';');
598 		if (next)
599 			len = next - pos;
600 		else
601 			len = os_strlen(pos);
602 		if (os_memcmp(pos, func[i], len) != 0) {
603 			if (maybe && next) {
604 				pos = next + 1;
605 				continue;
606 			}
607 			if (allow_skip) {
608 				i++;
609 				continue;
610 			}
611 			return 0;
612 		}
613 		if (!next) {
614 			match = 1;
615 			break;
616 		}
617 		pos = next + 1;
618 		i++;
619 	}
620 	if (!match)
621 		return 0;
622 
623 	wpa_trace_fail_after--;
624 	if (wpa_trace_fail_after == 0) {
625 		wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
626 			   wpa_trace_fail_func);
627 		for (i = 0; i < res; i++)
628 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
629 				   (int) i, func[i]);
630 		return 1;
631 	}
632 
633 	return 0;
634 }
635 
636 
637 char wpa_trace_test_fail_func[256] = { 0 };
638 unsigned int wpa_trace_test_fail_after;
639 
640 int testing_test_fail(void)
641 {
642 	const char *func[WPA_TRACE_LEN];
643 	size_t i, res, len;
644 	char *pos, *next;
645 	int match;
646 
647 	if (!wpa_trace_test_fail_after)
648 		return 0;
649 
650 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
651 	i = 0;
652 	if (i < res && os_strcmp(func[i], __func__) == 0)
653 		i++;
654 
655 	pos = wpa_trace_test_fail_func;
656 
657 	match = 0;
658 	while (i < res) {
659 		int allow_skip = 1;
660 		int maybe = 0;
661 
662 		if (*pos == '=') {
663 			allow_skip = 0;
664 			pos++;
665 		} else if (*pos == '?') {
666 			maybe = 1;
667 			pos++;
668 		}
669 		next = os_strchr(pos, ';');
670 		if (next)
671 			len = next - pos;
672 		else
673 			len = os_strlen(pos);
674 		if (os_memcmp(pos, func[i], len) != 0) {
675 			if (maybe && next) {
676 				pos = next + 1;
677 				continue;
678 			}
679 			if (allow_skip) {
680 				i++;
681 				continue;
682 			}
683 			return 0;
684 		}
685 		if (!next) {
686 			match = 1;
687 			break;
688 		}
689 		pos = next + 1;
690 		i++;
691 	}
692 	if (!match)
693 		return 0;
694 
695 	wpa_trace_test_fail_after--;
696 	if (wpa_trace_test_fail_after == 0) {
697 		wpa_printf(MSG_INFO, "TESTING: fail at %s",
698 			   wpa_trace_test_fail_func);
699 		for (i = 0; i < res; i++)
700 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
701 				   (int) i, func[i]);
702 		return 1;
703 	}
704 
705 	return 0;
706 }
707 
708 #else
709 
710 static inline int testing_fail_alloc(void)
711 {
712 	return 0;
713 }
714 #endif
715 
716 void * os_malloc(size_t size)
717 {
718 	struct os_alloc_trace *a;
719 
720 	if (testing_fail_alloc())
721 		return NULL;
722 
723 	a = malloc(sizeof(*a) + size);
724 	if (a == NULL)
725 		return NULL;
726 	a->magic = ALLOC_MAGIC;
727 	dl_list_add(&alloc_list, &a->list);
728 	a->len = size;
729 	wpa_trace_record(a);
730 	return a + 1;
731 }
732 
733 
734 void * os_realloc(void *ptr, size_t size)
735 {
736 	struct os_alloc_trace *a;
737 	size_t copy_len;
738 	void *n;
739 
740 	if (ptr == NULL)
741 		return os_malloc(size);
742 
743 	a = (struct os_alloc_trace *) ptr - 1;
744 	if (a->magic != ALLOC_MAGIC) {
745 		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
746 			   a, a->magic,
747 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
748 		wpa_trace_show("Invalid os_realloc() call");
749 		abort();
750 	}
751 	n = os_malloc(size);
752 	if (n == NULL)
753 		return NULL;
754 	copy_len = a->len;
755 	if (copy_len > size)
756 		copy_len = size;
757 	os_memcpy(n, a + 1, copy_len);
758 	os_free(ptr);
759 	return n;
760 }
761 
762 
763 void os_free(void *ptr)
764 {
765 	struct os_alloc_trace *a;
766 
767 	if (ptr == NULL)
768 		return;
769 	a = (struct os_alloc_trace *) ptr - 1;
770 	if (a->magic != ALLOC_MAGIC) {
771 		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
772 			   a, a->magic,
773 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
774 		wpa_trace_show("Invalid os_free() call");
775 		abort();
776 	}
777 	dl_list_del(&a->list);
778 	a->magic = FREED_MAGIC;
779 
780 	wpa_trace_check_ref(ptr);
781 	free(a);
782 }
783 
784 
785 void * os_zalloc(size_t size)
786 {
787 	void *ptr = os_malloc(size);
788 	if (ptr)
789 		os_memset(ptr, 0, size);
790 	return ptr;
791 }
792 
793 
794 char * os_strdup(const char *s)
795 {
796 	size_t len;
797 	char *d;
798 	len = os_strlen(s);
799 	d = os_malloc(len + 1);
800 	if (d == NULL)
801 		return NULL;
802 	os_memcpy(d, s, len);
803 	d[len] = '\0';
804 	return d;
805 }
806 
807 #endif /* WPA_TRACE */
808 
809 
810 int os_exec(const char *program, const char *arg, int wait_completion)
811 {
812 	pid_t pid;
813 	int pid_status;
814 
815 	pid = fork();
816 	if (pid < 0) {
817 		perror("fork");
818 		return -1;
819 	}
820 
821 	if (pid == 0) {
822 		/* run the external command in the child process */
823 		const int MAX_ARG = 30;
824 		char *_program, *_arg, *pos;
825 		char *argv[MAX_ARG + 1];
826 		int i;
827 
828 		_program = os_strdup(program);
829 		_arg = os_strdup(arg);
830 
831 		argv[0] = _program;
832 
833 		i = 1;
834 		pos = _arg;
835 		while (i < MAX_ARG && pos && *pos) {
836 			while (*pos == ' ')
837 				pos++;
838 			if (*pos == '\0')
839 				break;
840 			argv[i++] = pos;
841 			pos = os_strchr(pos, ' ');
842 			if (pos)
843 				*pos++ = '\0';
844 		}
845 		argv[i] = NULL;
846 
847 		execv(program, argv);
848 		perror("execv");
849 		os_free(_program);
850 		os_free(_arg);
851 		exit(0);
852 		return -1;
853 	}
854 
855 	if (wait_completion) {
856 		/* wait for the child process to complete in the parent */
857 		waitpid(pid, &pid_status, 0);
858 	}
859 
860 	return 0;
861 }
862