xref: /freebsd/contrib/wpa/src/utils/os_unix.c (revision 85732ac8bccbc0adcf5a261ea1ffec8ca7b3a92d)
139beb93cSSam Leffler /*
2e28a4053SRui Paulo  * OS specific functions for UNIX/POSIX systems
3e28a4053SRui Paulo  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
11f05cddf9SRui Paulo #include <time.h>
125b9c547cSRui Paulo #include <sys/wait.h>
13f05cddf9SRui Paulo 
14f05cddf9SRui Paulo #ifdef ANDROID
155b9c547cSRui Paulo #include <sys/capability.h>
165b9c547cSRui Paulo #include <sys/prctl.h>
17f05cddf9SRui Paulo #include <private/android_filesystem_config.h>
18f05cddf9SRui Paulo #endif /* ANDROID */
19f05cddf9SRui Paulo 
20325151a3SRui Paulo #ifdef __MACH__
21325151a3SRui Paulo #include <CoreServices/CoreServices.h>
22325151a3SRui Paulo #include <mach/mach.h>
23325151a3SRui Paulo #include <mach/mach_time.h>
24325151a3SRui Paulo #endif /* __MACH__ */
25325151a3SRui Paulo 
2639beb93cSSam Leffler #include "os.h"
275b9c547cSRui Paulo #include "common.h"
2839beb93cSSam Leffler 
29e28a4053SRui Paulo #ifdef WPA_TRACE
30e28a4053SRui Paulo 
31e28a4053SRui Paulo #include "wpa_debug.h"
32e28a4053SRui Paulo #include "trace.h"
33f05cddf9SRui Paulo #include "list.h"
34e28a4053SRui Paulo 
355b9c547cSRui Paulo static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
36e28a4053SRui Paulo 
37e28a4053SRui Paulo #define ALLOC_MAGIC 0xa84ef1b2
38e28a4053SRui Paulo #define FREED_MAGIC 0x67fd487a
39e28a4053SRui Paulo 
40e28a4053SRui Paulo struct os_alloc_trace {
41e28a4053SRui Paulo 	unsigned int magic;
42e28a4053SRui Paulo 	struct dl_list list;
43e28a4053SRui Paulo 	size_t len;
44e28a4053SRui Paulo 	WPA_TRACE_INFO
45325151a3SRui Paulo } __attribute__((aligned(16)));
46e28a4053SRui Paulo 
47e28a4053SRui Paulo #endif /* WPA_TRACE */
48e28a4053SRui Paulo 
49e28a4053SRui Paulo 
5039beb93cSSam Leffler void os_sleep(os_time_t sec, os_time_t usec)
5139beb93cSSam Leffler {
5239beb93cSSam Leffler 	if (sec)
5339beb93cSSam Leffler 		sleep(sec);
5439beb93cSSam Leffler 	if (usec)
5539beb93cSSam Leffler 		usleep(usec);
5639beb93cSSam Leffler }
5739beb93cSSam Leffler 
5839beb93cSSam Leffler 
5939beb93cSSam Leffler int os_get_time(struct os_time *t)
6039beb93cSSam Leffler {
6139beb93cSSam Leffler 	int res;
6239beb93cSSam Leffler 	struct timeval tv;
6339beb93cSSam Leffler 	res = gettimeofday(&tv, NULL);
6439beb93cSSam Leffler 	t->sec = tv.tv_sec;
6539beb93cSSam Leffler 	t->usec = tv.tv_usec;
6639beb93cSSam Leffler 	return res;
6739beb93cSSam Leffler }
6839beb93cSSam Leffler 
6939beb93cSSam Leffler 
705b9c547cSRui Paulo int os_get_reltime(struct os_reltime *t)
715b9c547cSRui Paulo {
72325151a3SRui Paulo #ifndef __MACH__
735b9c547cSRui Paulo #if defined(CLOCK_BOOTTIME)
745b9c547cSRui Paulo 	static clockid_t clock_id = CLOCK_BOOTTIME;
755b9c547cSRui Paulo #elif defined(CLOCK_MONOTONIC)
765b9c547cSRui Paulo 	static clockid_t clock_id = CLOCK_MONOTONIC;
775b9c547cSRui Paulo #else
785b9c547cSRui Paulo 	static clockid_t clock_id = CLOCK_REALTIME;
795b9c547cSRui Paulo #endif
805b9c547cSRui Paulo 	struct timespec ts;
815b9c547cSRui Paulo 	int res;
825b9c547cSRui Paulo 
83*85732ac8SCy Schubert 	if (TEST_FAIL())
84*85732ac8SCy Schubert 		return -1;
85*85732ac8SCy Schubert 
865b9c547cSRui Paulo 	while (1) {
875b9c547cSRui Paulo 		res = clock_gettime(clock_id, &ts);
885b9c547cSRui Paulo 		if (res == 0) {
895b9c547cSRui Paulo 			t->sec = ts.tv_sec;
905b9c547cSRui Paulo 			t->usec = ts.tv_nsec / 1000;
915b9c547cSRui Paulo 			return 0;
925b9c547cSRui Paulo 		}
935b9c547cSRui Paulo 		switch (clock_id) {
945b9c547cSRui Paulo #ifdef CLOCK_BOOTTIME
955b9c547cSRui Paulo 		case CLOCK_BOOTTIME:
965b9c547cSRui Paulo 			clock_id = CLOCK_MONOTONIC;
975b9c547cSRui Paulo 			break;
985b9c547cSRui Paulo #endif
995b9c547cSRui Paulo #ifdef CLOCK_MONOTONIC
1005b9c547cSRui Paulo 		case CLOCK_MONOTONIC:
1015b9c547cSRui Paulo 			clock_id = CLOCK_REALTIME;
1025b9c547cSRui Paulo 			break;
1035b9c547cSRui Paulo #endif
1045b9c547cSRui Paulo 		case CLOCK_REALTIME:
1055b9c547cSRui Paulo 			return -1;
1065b9c547cSRui Paulo 		}
1075b9c547cSRui Paulo 	}
108325151a3SRui Paulo #else /* __MACH__ */
109325151a3SRui Paulo 	uint64_t abstime, nano;
110325151a3SRui Paulo 	static mach_timebase_info_data_t info = { 0, 0 };
111325151a3SRui Paulo 
112325151a3SRui Paulo 	if (!info.denom) {
113325151a3SRui Paulo 		if (mach_timebase_info(&info) != KERN_SUCCESS)
114325151a3SRui Paulo 			return -1;
115325151a3SRui Paulo 	}
116325151a3SRui Paulo 
117325151a3SRui Paulo 	abstime = mach_absolute_time();
118325151a3SRui Paulo 	nano = (abstime * info.numer) / info.denom;
119325151a3SRui Paulo 
120325151a3SRui Paulo 	t->sec = nano / NSEC_PER_SEC;
121325151a3SRui Paulo 	t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
122325151a3SRui Paulo 
123325151a3SRui Paulo 	return 0;
124325151a3SRui Paulo #endif /* __MACH__ */
1255b9c547cSRui Paulo }
1265b9c547cSRui Paulo 
1275b9c547cSRui Paulo 
12839beb93cSSam Leffler int os_mktime(int year, int month, int day, int hour, int min, int sec,
12939beb93cSSam Leffler 	      os_time_t *t)
13039beb93cSSam Leffler {
13139beb93cSSam Leffler 	struct tm tm, *tm1;
13239beb93cSSam Leffler 	time_t t_local, t1, t2;
13339beb93cSSam Leffler 	os_time_t tz_offset;
13439beb93cSSam Leffler 
13539beb93cSSam Leffler 	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
13639beb93cSSam Leffler 	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
13739beb93cSSam Leffler 	    sec > 60)
13839beb93cSSam Leffler 		return -1;
13939beb93cSSam Leffler 
14039beb93cSSam Leffler 	memset(&tm, 0, sizeof(tm));
14139beb93cSSam Leffler 	tm.tm_year = year - 1900;
14239beb93cSSam Leffler 	tm.tm_mon = month - 1;
14339beb93cSSam Leffler 	tm.tm_mday = day;
14439beb93cSSam Leffler 	tm.tm_hour = hour;
14539beb93cSSam Leffler 	tm.tm_min = min;
14639beb93cSSam Leffler 	tm.tm_sec = sec;
14739beb93cSSam Leffler 
14839beb93cSSam Leffler 	t_local = mktime(&tm);
14939beb93cSSam Leffler 
15039beb93cSSam Leffler 	/* figure out offset to UTC */
15139beb93cSSam Leffler 	tm1 = localtime(&t_local);
15239beb93cSSam Leffler 	if (tm1) {
15339beb93cSSam Leffler 		t1 = mktime(tm1);
15439beb93cSSam Leffler 		tm1 = gmtime(&t_local);
15539beb93cSSam Leffler 		if (tm1) {
15639beb93cSSam Leffler 			t2 = mktime(tm1);
15739beb93cSSam Leffler 			tz_offset = t2 - t1;
15839beb93cSSam Leffler 		} else
15939beb93cSSam Leffler 			tz_offset = 0;
16039beb93cSSam Leffler 	} else
16139beb93cSSam Leffler 		tz_offset = 0;
16239beb93cSSam Leffler 
16339beb93cSSam Leffler 	*t = (os_time_t) t_local - tz_offset;
16439beb93cSSam Leffler 	return 0;
16539beb93cSSam Leffler }
16639beb93cSSam Leffler 
16739beb93cSSam Leffler 
168f05cddf9SRui Paulo int os_gmtime(os_time_t t, struct os_tm *tm)
169f05cddf9SRui Paulo {
170f05cddf9SRui Paulo 	struct tm *tm2;
171f05cddf9SRui Paulo 	time_t t2 = t;
172f05cddf9SRui Paulo 
173f05cddf9SRui Paulo 	tm2 = gmtime(&t2);
174f05cddf9SRui Paulo 	if (tm2 == NULL)
175f05cddf9SRui Paulo 		return -1;
176f05cddf9SRui Paulo 	tm->sec = tm2->tm_sec;
177f05cddf9SRui Paulo 	tm->min = tm2->tm_min;
178f05cddf9SRui Paulo 	tm->hour = tm2->tm_hour;
179f05cddf9SRui Paulo 	tm->day = tm2->tm_mday;
180f05cddf9SRui Paulo 	tm->month = tm2->tm_mon + 1;
181f05cddf9SRui Paulo 	tm->year = tm2->tm_year + 1900;
182f05cddf9SRui Paulo 	return 0;
183f05cddf9SRui Paulo }
184f05cddf9SRui Paulo 
185f05cddf9SRui Paulo 
18639beb93cSSam Leffler #ifdef __APPLE__
18739beb93cSSam Leffler #include <fcntl.h>
18839beb93cSSam Leffler static int os_daemon(int nochdir, int noclose)
18939beb93cSSam Leffler {
19039beb93cSSam Leffler 	int devnull;
19139beb93cSSam Leffler 
19239beb93cSSam Leffler 	if (chdir("/") < 0)
19339beb93cSSam Leffler 		return -1;
19439beb93cSSam Leffler 
19539beb93cSSam Leffler 	devnull = open("/dev/null", O_RDWR);
19639beb93cSSam Leffler 	if (devnull < 0)
19739beb93cSSam Leffler 		return -1;
19839beb93cSSam Leffler 
19939beb93cSSam Leffler 	if (dup2(devnull, STDIN_FILENO) < 0) {
20039beb93cSSam Leffler 		close(devnull);
20139beb93cSSam Leffler 		return -1;
20239beb93cSSam Leffler 	}
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 	if (dup2(devnull, STDOUT_FILENO) < 0) {
20539beb93cSSam Leffler 		close(devnull);
20639beb93cSSam Leffler 		return -1;
20739beb93cSSam Leffler 	}
20839beb93cSSam Leffler 
20939beb93cSSam Leffler 	if (dup2(devnull, STDERR_FILENO) < 0) {
21039beb93cSSam Leffler 		close(devnull);
21139beb93cSSam Leffler 		return -1;
21239beb93cSSam Leffler 	}
21339beb93cSSam Leffler 
21439beb93cSSam Leffler 	return 0;
21539beb93cSSam Leffler }
21639beb93cSSam Leffler #else /* __APPLE__ */
21739beb93cSSam Leffler #define os_daemon daemon
21839beb93cSSam Leffler #endif /* __APPLE__ */
21939beb93cSSam Leffler 
22039beb93cSSam Leffler 
221a061720cSJohn-Mark Gurney #ifdef __FreeBSD__
222a061720cSJohn-Mark Gurney #include <err.h>
223a061720cSJohn-Mark Gurney #include <libutil.h>
224a061720cSJohn-Mark Gurney #include <stdint.h>
225a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
226a061720cSJohn-Mark Gurney 
22739beb93cSSam Leffler int os_daemonize(const char *pid_file)
22839beb93cSSam Leffler {
229f05cddf9SRui Paulo #if defined(__uClinux__) || defined(__sun__)
23039beb93cSSam Leffler 	return -1;
231f05cddf9SRui Paulo #else /* defined(__uClinux__) || defined(__sun__) */
232a061720cSJohn-Mark Gurney #ifdef __FreeBSD__
233a061720cSJohn-Mark Gurney 	pid_t otherpid;
234a061720cSJohn-Mark Gurney 	struct pidfh *pfh;
235a061720cSJohn-Mark Gurney 
236a061720cSJohn-Mark Gurney 	pfh = pidfile_open(pid_file, 0600, &otherpid);
237a061720cSJohn-Mark Gurney 	if (pfh == NULL) {
238a061720cSJohn-Mark Gurney 		if (errno == EEXIST) {
239a061720cSJohn-Mark Gurney 			errx(1, "Daemon already running, pid: %jd.",
240a061720cSJohn-Mark Gurney 			    (intmax_t)otherpid);
241a061720cSJohn-Mark Gurney 		}
242a061720cSJohn-Mark Gurney 		warn("Cannot open or create pidfile.");
243a061720cSJohn-Mark Gurney 	}
244a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
245a061720cSJohn-Mark Gurney 
24639beb93cSSam Leffler 	if (os_daemon(0, 0)) {
24739beb93cSSam Leffler 		perror("daemon");
248a061720cSJohn-Mark Gurney #ifdef __FreeBSD__
249a061720cSJohn-Mark Gurney 		pidfile_remove(pfh);
250a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
25139beb93cSSam Leffler 		return -1;
25239beb93cSSam Leffler 	}
25339beb93cSSam Leffler 
254a061720cSJohn-Mark Gurney #ifndef __FreeBSD__
25539beb93cSSam Leffler 	if (pid_file) {
25639beb93cSSam Leffler 		FILE *f = fopen(pid_file, "w");
25739beb93cSSam Leffler 		if (f) {
25839beb93cSSam Leffler 			fprintf(f, "%u\n", getpid());
25939beb93cSSam Leffler 			fclose(f);
26039beb93cSSam Leffler 		}
26139beb93cSSam Leffler 	}
262a061720cSJohn-Mark Gurney #else /* __FreeBSD__ */
263a061720cSJohn-Mark Gurney 	pidfile_write(pfh);
264a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
26539beb93cSSam Leffler 
26639beb93cSSam Leffler 	return -0;
267f05cddf9SRui Paulo #endif /* defined(__uClinux__) || defined(__sun__) */
26839beb93cSSam Leffler }
26939beb93cSSam Leffler 
27039beb93cSSam Leffler 
27139beb93cSSam Leffler void os_daemonize_terminate(const char *pid_file)
27239beb93cSSam Leffler {
27339beb93cSSam Leffler 	if (pid_file)
27439beb93cSSam Leffler 		unlink(pid_file);
27539beb93cSSam Leffler }
27639beb93cSSam Leffler 
27739beb93cSSam Leffler 
27839beb93cSSam Leffler int os_get_random(unsigned char *buf, size_t len)
27939beb93cSSam Leffler {
28039beb93cSSam Leffler 	FILE *f;
28139beb93cSSam Leffler 	size_t rc;
28239beb93cSSam Leffler 
283325151a3SRui Paulo 	if (TEST_FAIL())
284325151a3SRui Paulo 		return -1;
285325151a3SRui Paulo 
28639beb93cSSam Leffler 	f = fopen("/dev/urandom", "rb");
28739beb93cSSam Leffler 	if (f == NULL) {
28839beb93cSSam Leffler 		printf("Could not open /dev/urandom.\n");
28939beb93cSSam Leffler 		return -1;
29039beb93cSSam Leffler 	}
29139beb93cSSam Leffler 
29239beb93cSSam Leffler 	rc = fread(buf, 1, len, f);
29339beb93cSSam Leffler 	fclose(f);
29439beb93cSSam Leffler 
29539beb93cSSam Leffler 	return rc != len ? -1 : 0;
29639beb93cSSam Leffler }
29739beb93cSSam Leffler 
29839beb93cSSam Leffler 
29939beb93cSSam Leffler unsigned long os_random(void)
30039beb93cSSam Leffler {
30139beb93cSSam Leffler 	return random();
30239beb93cSSam Leffler }
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 
30539beb93cSSam Leffler char * os_rel2abs_path(const char *rel_path)
30639beb93cSSam Leffler {
30739beb93cSSam Leffler 	char *buf = NULL, *cwd, *ret;
30839beb93cSSam Leffler 	size_t len = 128, cwd_len, rel_len, ret_len;
30939beb93cSSam Leffler 	int last_errno;
31039beb93cSSam Leffler 
3115b9c547cSRui Paulo 	if (!rel_path)
3125b9c547cSRui Paulo 		return NULL;
3135b9c547cSRui Paulo 
31439beb93cSSam Leffler 	if (rel_path[0] == '/')
315e28a4053SRui Paulo 		return os_strdup(rel_path);
31639beb93cSSam Leffler 
31739beb93cSSam Leffler 	for (;;) {
318e28a4053SRui Paulo 		buf = os_malloc(len);
31939beb93cSSam Leffler 		if (buf == NULL)
32039beb93cSSam Leffler 			return NULL;
32139beb93cSSam Leffler 		cwd = getcwd(buf, len);
32239beb93cSSam Leffler 		if (cwd == NULL) {
32339beb93cSSam Leffler 			last_errno = errno;
324e28a4053SRui Paulo 			os_free(buf);
32539beb93cSSam Leffler 			if (last_errno != ERANGE)
32639beb93cSSam Leffler 				return NULL;
32739beb93cSSam Leffler 			len *= 2;
32839beb93cSSam Leffler 			if (len > 2000)
32939beb93cSSam Leffler 				return NULL;
33039beb93cSSam Leffler 		} else {
33139beb93cSSam Leffler 			buf[len - 1] = '\0';
33239beb93cSSam Leffler 			break;
33339beb93cSSam Leffler 		}
33439beb93cSSam Leffler 	}
33539beb93cSSam Leffler 
336e28a4053SRui Paulo 	cwd_len = os_strlen(cwd);
337e28a4053SRui Paulo 	rel_len = os_strlen(rel_path);
33839beb93cSSam Leffler 	ret_len = cwd_len + 1 + rel_len + 1;
339e28a4053SRui Paulo 	ret = os_malloc(ret_len);
34039beb93cSSam Leffler 	if (ret) {
341e28a4053SRui Paulo 		os_memcpy(ret, cwd, cwd_len);
34239beb93cSSam Leffler 		ret[cwd_len] = '/';
343e28a4053SRui Paulo 		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
34439beb93cSSam Leffler 		ret[ret_len - 1] = '\0';
34539beb93cSSam Leffler 	}
346e28a4053SRui Paulo 	os_free(buf);
34739beb93cSSam Leffler 	return ret;
34839beb93cSSam Leffler }
34939beb93cSSam Leffler 
35039beb93cSSam Leffler 
35139beb93cSSam Leffler int os_program_init(void)
35239beb93cSSam Leffler {
353f05cddf9SRui Paulo #ifdef ANDROID
354f05cddf9SRui Paulo 	/*
355f05cddf9SRui Paulo 	 * We ignore errors here since errors are normal if we
356f05cddf9SRui Paulo 	 * are already running as non-root.
357f05cddf9SRui Paulo 	 */
3585b9c547cSRui Paulo #ifdef ANDROID_SETGROUPS_OVERRIDE
3595b9c547cSRui Paulo 	gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
3605b9c547cSRui Paulo #else /* ANDROID_SETGROUPS_OVERRIDE */
361f05cddf9SRui Paulo 	gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
3625b9c547cSRui Paulo #endif /* ANDROID_SETGROUPS_OVERRIDE */
363f05cddf9SRui Paulo 	struct __user_cap_header_struct header;
364f05cddf9SRui Paulo 	struct __user_cap_data_struct cap;
365f05cddf9SRui Paulo 
3665b9c547cSRui Paulo 	setgroups(ARRAY_SIZE(groups), groups);
367f05cddf9SRui Paulo 
368f05cddf9SRui Paulo 	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
369f05cddf9SRui Paulo 
370f05cddf9SRui Paulo 	setgid(AID_WIFI);
371f05cddf9SRui Paulo 	setuid(AID_WIFI);
372f05cddf9SRui Paulo 
373f05cddf9SRui Paulo 	header.version = _LINUX_CAPABILITY_VERSION;
374f05cddf9SRui Paulo 	header.pid = 0;
375f05cddf9SRui Paulo 	cap.effective = cap.permitted =
376f05cddf9SRui Paulo 		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
377f05cddf9SRui Paulo 	cap.inheritable = 0;
378f05cddf9SRui Paulo 	capset(&header, &cap);
379f05cddf9SRui Paulo #endif /* ANDROID */
380f05cddf9SRui Paulo 
38139beb93cSSam Leffler 	return 0;
38239beb93cSSam Leffler }
38339beb93cSSam Leffler 
38439beb93cSSam Leffler 
38539beb93cSSam Leffler void os_program_deinit(void)
38639beb93cSSam Leffler {
387e28a4053SRui Paulo #ifdef WPA_TRACE
388e28a4053SRui Paulo 	struct os_alloc_trace *a;
389e28a4053SRui Paulo 	unsigned long total = 0;
390e28a4053SRui Paulo 	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
391e28a4053SRui Paulo 		total += a->len;
392e28a4053SRui Paulo 		if (a->magic != ALLOC_MAGIC) {
393e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
394e28a4053SRui Paulo 				   "len %lu",
395e28a4053SRui Paulo 				   a, a->magic, (unsigned long) a->len);
396e28a4053SRui Paulo 			continue;
397e28a4053SRui Paulo 		}
398e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
399e28a4053SRui Paulo 			   a, (unsigned long) a->len);
400e28a4053SRui Paulo 		wpa_trace_dump("memleak", a);
401e28a4053SRui Paulo 	}
402e28a4053SRui Paulo 	if (total)
403e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
404e28a4053SRui Paulo 			   (unsigned long) total);
405780fb4a2SCy Schubert 	wpa_trace_deinit();
406e28a4053SRui Paulo #endif /* WPA_TRACE */
40739beb93cSSam Leffler }
40839beb93cSSam Leffler 
40939beb93cSSam Leffler 
41039beb93cSSam Leffler int os_setenv(const char *name, const char *value, int overwrite)
41139beb93cSSam Leffler {
41239beb93cSSam Leffler 	return setenv(name, value, overwrite);
41339beb93cSSam Leffler }
41439beb93cSSam Leffler 
41539beb93cSSam Leffler 
41639beb93cSSam Leffler int os_unsetenv(const char *name)
41739beb93cSSam Leffler {
4183157ba21SRui Paulo #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
4193157ba21SRui Paulo     defined(__OpenBSD__)
42039beb93cSSam Leffler 	unsetenv(name);
42139beb93cSSam Leffler 	return 0;
42239beb93cSSam Leffler #else
42339beb93cSSam Leffler 	return unsetenv(name);
42439beb93cSSam Leffler #endif
42539beb93cSSam Leffler }
42639beb93cSSam Leffler 
42739beb93cSSam Leffler 
42839beb93cSSam Leffler char * os_readfile(const char *name, size_t *len)
42939beb93cSSam Leffler {
43039beb93cSSam Leffler 	FILE *f;
43139beb93cSSam Leffler 	char *buf;
432f05cddf9SRui Paulo 	long pos;
43339beb93cSSam Leffler 
43439beb93cSSam Leffler 	f = fopen(name, "rb");
43539beb93cSSam Leffler 	if (f == NULL)
43639beb93cSSam Leffler 		return NULL;
43739beb93cSSam Leffler 
438f05cddf9SRui Paulo 	if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
439f05cddf9SRui Paulo 		fclose(f);
440f05cddf9SRui Paulo 		return NULL;
441f05cddf9SRui Paulo 	}
442f05cddf9SRui Paulo 	*len = pos;
443f05cddf9SRui Paulo 	if (fseek(f, 0, SEEK_SET) < 0) {
444f05cddf9SRui Paulo 		fclose(f);
445f05cddf9SRui Paulo 		return NULL;
446f05cddf9SRui Paulo 	}
44739beb93cSSam Leffler 
448e28a4053SRui Paulo 	buf = os_malloc(*len);
44939beb93cSSam Leffler 	if (buf == NULL) {
45039beb93cSSam Leffler 		fclose(f);
45139beb93cSSam Leffler 		return NULL;
45239beb93cSSam Leffler 	}
45339beb93cSSam Leffler 
45439beb93cSSam Leffler 	if (fread(buf, 1, *len, f) != *len) {
45539beb93cSSam Leffler 		fclose(f);
456e28a4053SRui Paulo 		os_free(buf);
45739beb93cSSam Leffler 		return NULL;
45839beb93cSSam Leffler 	}
45939beb93cSSam Leffler 
46039beb93cSSam Leffler 	fclose(f);
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 	return buf;
46339beb93cSSam Leffler }
46439beb93cSSam Leffler 
46539beb93cSSam Leffler 
4665b9c547cSRui Paulo int os_file_exists(const char *fname)
4675b9c547cSRui Paulo {
468780fb4a2SCy Schubert 	return access(fname, F_OK) == 0;
4695b9c547cSRui Paulo }
4705b9c547cSRui Paulo 
4715b9c547cSRui Paulo 
472325151a3SRui Paulo int os_fdatasync(FILE *stream)
473325151a3SRui Paulo {
474325151a3SRui Paulo 	if (!fflush(stream)) {
475325151a3SRui Paulo #ifdef __linux__
476325151a3SRui Paulo 		return fdatasync(fileno(stream));
477325151a3SRui Paulo #else /* !__linux__ */
478325151a3SRui Paulo #ifdef F_FULLFSYNC
479325151a3SRui Paulo 		/* OS X does not implement fdatasync(). */
480325151a3SRui Paulo 		return fcntl(fileno(stream), F_FULLFSYNC);
481325151a3SRui Paulo #else /* F_FULLFSYNC */
482325151a3SRui Paulo 		return fsync(fileno(stream));
483325151a3SRui Paulo #endif /* F_FULLFSYNC */
484325151a3SRui Paulo #endif /* __linux__ */
485325151a3SRui Paulo 	}
486325151a3SRui Paulo 
487325151a3SRui Paulo 	return -1;
488325151a3SRui Paulo }
489325151a3SRui Paulo 
490325151a3SRui Paulo 
491e28a4053SRui Paulo #ifndef WPA_TRACE
49239beb93cSSam Leffler void * os_zalloc(size_t size)
49339beb93cSSam Leffler {
49439beb93cSSam Leffler 	return calloc(1, size);
49539beb93cSSam Leffler }
496e28a4053SRui Paulo #endif /* WPA_TRACE */
49739beb93cSSam Leffler 
49839beb93cSSam Leffler 
49939beb93cSSam Leffler size_t os_strlcpy(char *dest, const char *src, size_t siz)
50039beb93cSSam Leffler {
50139beb93cSSam Leffler 	const char *s = src;
50239beb93cSSam Leffler 	size_t left = siz;
50339beb93cSSam Leffler 
50439beb93cSSam Leffler 	if (left) {
50539beb93cSSam Leffler 		/* Copy string up to the maximum size of the dest buffer */
50639beb93cSSam Leffler 		while (--left != 0) {
50739beb93cSSam Leffler 			if ((*dest++ = *s++) == '\0')
50839beb93cSSam Leffler 				break;
50939beb93cSSam Leffler 		}
51039beb93cSSam Leffler 	}
51139beb93cSSam Leffler 
51239beb93cSSam Leffler 	if (left == 0) {
51339beb93cSSam Leffler 		/* Not enough room for the string; force NUL-termination */
51439beb93cSSam Leffler 		if (siz != 0)
51539beb93cSSam Leffler 			*dest = '\0';
51639beb93cSSam Leffler 		while (*s++)
51739beb93cSSam Leffler 			; /* determine total src string length */
51839beb93cSSam Leffler 	}
51939beb93cSSam Leffler 
52039beb93cSSam Leffler 	return s - src - 1;
52139beb93cSSam Leffler }
522e28a4053SRui Paulo 
523e28a4053SRui Paulo 
5245b9c547cSRui Paulo int os_memcmp_const(const void *a, const void *b, size_t len)
5255b9c547cSRui Paulo {
5265b9c547cSRui Paulo 	const u8 *aa = a;
5275b9c547cSRui Paulo 	const u8 *bb = b;
5285b9c547cSRui Paulo 	size_t i;
5295b9c547cSRui Paulo 	u8 res;
5305b9c547cSRui Paulo 
5315b9c547cSRui Paulo 	for (res = 0, i = 0; i < len; i++)
5325b9c547cSRui Paulo 		res |= aa[i] ^ bb[i];
5335b9c547cSRui Paulo 
5345b9c547cSRui Paulo 	return res;
5355b9c547cSRui Paulo }
5365b9c547cSRui Paulo 
5375b9c547cSRui Paulo 
538*85732ac8SCy Schubert void * os_memdup(const void *src, size_t len)
539*85732ac8SCy Schubert {
540*85732ac8SCy Schubert 	void *r = os_malloc(len);
541*85732ac8SCy Schubert 
542*85732ac8SCy Schubert 	if (r)
543*85732ac8SCy Schubert 		os_memcpy(r, src, len);
544*85732ac8SCy Schubert 	return r;
545*85732ac8SCy Schubert }
546*85732ac8SCy Schubert 
547*85732ac8SCy Schubert 
548e28a4053SRui Paulo #ifdef WPA_TRACE
549e28a4053SRui Paulo 
5505b9c547cSRui Paulo #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
5515b9c547cSRui Paulo char wpa_trace_fail_func[256] = { 0 };
5525b9c547cSRui Paulo unsigned int wpa_trace_fail_after;
5535b9c547cSRui Paulo 
5545b9c547cSRui Paulo static int testing_fail_alloc(void)
5555b9c547cSRui Paulo {
5565b9c547cSRui Paulo 	const char *func[WPA_TRACE_LEN];
5575b9c547cSRui Paulo 	size_t i, res, len;
5585b9c547cSRui Paulo 	char *pos, *next;
5595b9c547cSRui Paulo 	int match;
5605b9c547cSRui Paulo 
5615b9c547cSRui Paulo 	if (!wpa_trace_fail_after)
5625b9c547cSRui Paulo 		return 0;
5635b9c547cSRui Paulo 
5645b9c547cSRui Paulo 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
5655b9c547cSRui Paulo 	i = 0;
5665b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], __func__) == 0)
5675b9c547cSRui Paulo 		i++;
5685b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_malloc") == 0)
5695b9c547cSRui Paulo 		i++;
5705b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
5715b9c547cSRui Paulo 		i++;
5725b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_calloc") == 0)
5735b9c547cSRui Paulo 		i++;
5745b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_realloc") == 0)
5755b9c547cSRui Paulo 		i++;
5765b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
5775b9c547cSRui Paulo 		i++;
5785b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_strdup") == 0)
5795b9c547cSRui Paulo 		i++;
580*85732ac8SCy Schubert 	if (i < res && os_strcmp(func[i], "os_memdup") == 0)
581*85732ac8SCy Schubert 		i++;
5825b9c547cSRui Paulo 
5835b9c547cSRui Paulo 	pos = wpa_trace_fail_func;
5845b9c547cSRui Paulo 
5855b9c547cSRui Paulo 	match = 0;
5865b9c547cSRui Paulo 	while (i < res) {
5875b9c547cSRui Paulo 		int allow_skip = 1;
5885b9c547cSRui Paulo 		int maybe = 0;
5895b9c547cSRui Paulo 
5905b9c547cSRui Paulo 		if (*pos == '=') {
5915b9c547cSRui Paulo 			allow_skip = 0;
5925b9c547cSRui Paulo 			pos++;
5935b9c547cSRui Paulo 		} else if (*pos == '?') {
5945b9c547cSRui Paulo 			maybe = 1;
5955b9c547cSRui Paulo 			pos++;
5965b9c547cSRui Paulo 		}
5975b9c547cSRui Paulo 		next = os_strchr(pos, ';');
5985b9c547cSRui Paulo 		if (next)
5995b9c547cSRui Paulo 			len = next - pos;
6005b9c547cSRui Paulo 		else
6015b9c547cSRui Paulo 			len = os_strlen(pos);
6025b9c547cSRui Paulo 		if (os_memcmp(pos, func[i], len) != 0) {
6035b9c547cSRui Paulo 			if (maybe && next) {
6045b9c547cSRui Paulo 				pos = next + 1;
6055b9c547cSRui Paulo 				continue;
6065b9c547cSRui Paulo 			}
6075b9c547cSRui Paulo 			if (allow_skip) {
6085b9c547cSRui Paulo 				i++;
6095b9c547cSRui Paulo 				continue;
6105b9c547cSRui Paulo 			}
6115b9c547cSRui Paulo 			return 0;
6125b9c547cSRui Paulo 		}
6135b9c547cSRui Paulo 		if (!next) {
6145b9c547cSRui Paulo 			match = 1;
6155b9c547cSRui Paulo 			break;
6165b9c547cSRui Paulo 		}
6175b9c547cSRui Paulo 		pos = next + 1;
6185b9c547cSRui Paulo 		i++;
6195b9c547cSRui Paulo 	}
6205b9c547cSRui Paulo 	if (!match)
6215b9c547cSRui Paulo 		return 0;
6225b9c547cSRui Paulo 
6235b9c547cSRui Paulo 	wpa_trace_fail_after--;
6245b9c547cSRui Paulo 	if (wpa_trace_fail_after == 0) {
6255b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
6265b9c547cSRui Paulo 			   wpa_trace_fail_func);
6275b9c547cSRui Paulo 		for (i = 0; i < res; i++)
6285b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
6295b9c547cSRui Paulo 				   (int) i, func[i]);
6305b9c547cSRui Paulo 		return 1;
6315b9c547cSRui Paulo 	}
6325b9c547cSRui Paulo 
6335b9c547cSRui Paulo 	return 0;
6345b9c547cSRui Paulo }
6355b9c547cSRui Paulo 
636325151a3SRui Paulo 
637325151a3SRui Paulo char wpa_trace_test_fail_func[256] = { 0 };
638325151a3SRui Paulo unsigned int wpa_trace_test_fail_after;
639325151a3SRui Paulo 
640325151a3SRui Paulo int testing_test_fail(void)
641325151a3SRui Paulo {
642325151a3SRui Paulo 	const char *func[WPA_TRACE_LEN];
643325151a3SRui Paulo 	size_t i, res, len;
644325151a3SRui Paulo 	char *pos, *next;
645325151a3SRui Paulo 	int match;
646325151a3SRui Paulo 
647325151a3SRui Paulo 	if (!wpa_trace_test_fail_after)
648325151a3SRui Paulo 		return 0;
649325151a3SRui Paulo 
650325151a3SRui Paulo 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
651325151a3SRui Paulo 	i = 0;
652325151a3SRui Paulo 	if (i < res && os_strcmp(func[i], __func__) == 0)
653325151a3SRui Paulo 		i++;
654325151a3SRui Paulo 
655325151a3SRui Paulo 	pos = wpa_trace_test_fail_func;
656325151a3SRui Paulo 
657325151a3SRui Paulo 	match = 0;
658325151a3SRui Paulo 	while (i < res) {
659325151a3SRui Paulo 		int allow_skip = 1;
660325151a3SRui Paulo 		int maybe = 0;
661325151a3SRui Paulo 
662325151a3SRui Paulo 		if (*pos == '=') {
663325151a3SRui Paulo 			allow_skip = 0;
664325151a3SRui Paulo 			pos++;
665325151a3SRui Paulo 		} else if (*pos == '?') {
666325151a3SRui Paulo 			maybe = 1;
667325151a3SRui Paulo 			pos++;
668325151a3SRui Paulo 		}
669325151a3SRui Paulo 		next = os_strchr(pos, ';');
670325151a3SRui Paulo 		if (next)
671325151a3SRui Paulo 			len = next - pos;
672325151a3SRui Paulo 		else
673325151a3SRui Paulo 			len = os_strlen(pos);
674325151a3SRui Paulo 		if (os_memcmp(pos, func[i], len) != 0) {
675325151a3SRui Paulo 			if (maybe && next) {
676325151a3SRui Paulo 				pos = next + 1;
677325151a3SRui Paulo 				continue;
678325151a3SRui Paulo 			}
679325151a3SRui Paulo 			if (allow_skip) {
680325151a3SRui Paulo 				i++;
681325151a3SRui Paulo 				continue;
682325151a3SRui Paulo 			}
683325151a3SRui Paulo 			return 0;
684325151a3SRui Paulo 		}
685325151a3SRui Paulo 		if (!next) {
686325151a3SRui Paulo 			match = 1;
687325151a3SRui Paulo 			break;
688325151a3SRui Paulo 		}
689325151a3SRui Paulo 		pos = next + 1;
690325151a3SRui Paulo 		i++;
691325151a3SRui Paulo 	}
692325151a3SRui Paulo 	if (!match)
693325151a3SRui Paulo 		return 0;
694325151a3SRui Paulo 
695325151a3SRui Paulo 	wpa_trace_test_fail_after--;
696325151a3SRui Paulo 	if (wpa_trace_test_fail_after == 0) {
697325151a3SRui Paulo 		wpa_printf(MSG_INFO, "TESTING: fail at %s",
698325151a3SRui Paulo 			   wpa_trace_test_fail_func);
699325151a3SRui Paulo 		for (i = 0; i < res; i++)
700325151a3SRui Paulo 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
701325151a3SRui Paulo 				   (int) i, func[i]);
702325151a3SRui Paulo 		return 1;
703325151a3SRui Paulo 	}
704325151a3SRui Paulo 
705325151a3SRui Paulo 	return 0;
706325151a3SRui Paulo }
707325151a3SRui Paulo 
7085b9c547cSRui Paulo #else
7095b9c547cSRui Paulo 
7105b9c547cSRui Paulo static inline int testing_fail_alloc(void)
7115b9c547cSRui Paulo {
7125b9c547cSRui Paulo 	return 0;
7135b9c547cSRui Paulo }
7145b9c547cSRui Paulo #endif
7155b9c547cSRui Paulo 
716e28a4053SRui Paulo void * os_malloc(size_t size)
717e28a4053SRui Paulo {
718e28a4053SRui Paulo 	struct os_alloc_trace *a;
7195b9c547cSRui Paulo 
7205b9c547cSRui Paulo 	if (testing_fail_alloc())
7215b9c547cSRui Paulo 		return NULL;
7225b9c547cSRui Paulo 
723e28a4053SRui Paulo 	a = malloc(sizeof(*a) + size);
724e28a4053SRui Paulo 	if (a == NULL)
725e28a4053SRui Paulo 		return NULL;
726e28a4053SRui Paulo 	a->magic = ALLOC_MAGIC;
727e28a4053SRui Paulo 	dl_list_add(&alloc_list, &a->list);
728e28a4053SRui Paulo 	a->len = size;
729e28a4053SRui Paulo 	wpa_trace_record(a);
730e28a4053SRui Paulo 	return a + 1;
731e28a4053SRui Paulo }
732e28a4053SRui Paulo 
733e28a4053SRui Paulo 
734e28a4053SRui Paulo void * os_realloc(void *ptr, size_t size)
735e28a4053SRui Paulo {
736e28a4053SRui Paulo 	struct os_alloc_trace *a;
737e28a4053SRui Paulo 	size_t copy_len;
738e28a4053SRui Paulo 	void *n;
739e28a4053SRui Paulo 
740e28a4053SRui Paulo 	if (ptr == NULL)
741e28a4053SRui Paulo 		return os_malloc(size);
742e28a4053SRui Paulo 
743e28a4053SRui Paulo 	a = (struct os_alloc_trace *) ptr - 1;
744e28a4053SRui Paulo 	if (a->magic != ALLOC_MAGIC) {
745e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
746e28a4053SRui Paulo 			   a, a->magic,
747e28a4053SRui Paulo 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
748e28a4053SRui Paulo 		wpa_trace_show("Invalid os_realloc() call");
749e28a4053SRui Paulo 		abort();
750e28a4053SRui Paulo 	}
751e28a4053SRui Paulo 	n = os_malloc(size);
752e28a4053SRui Paulo 	if (n == NULL)
753e28a4053SRui Paulo 		return NULL;
754e28a4053SRui Paulo 	copy_len = a->len;
755e28a4053SRui Paulo 	if (copy_len > size)
756e28a4053SRui Paulo 		copy_len = size;
757e28a4053SRui Paulo 	os_memcpy(n, a + 1, copy_len);
758e28a4053SRui Paulo 	os_free(ptr);
759e28a4053SRui Paulo 	return n;
760e28a4053SRui Paulo }
761e28a4053SRui Paulo 
762e28a4053SRui Paulo 
763e28a4053SRui Paulo void os_free(void *ptr)
764e28a4053SRui Paulo {
765e28a4053SRui Paulo 	struct os_alloc_trace *a;
766e28a4053SRui Paulo 
767e28a4053SRui Paulo 	if (ptr == NULL)
768e28a4053SRui Paulo 		return;
769e28a4053SRui Paulo 	a = (struct os_alloc_trace *) ptr - 1;
770e28a4053SRui Paulo 	if (a->magic != ALLOC_MAGIC) {
771e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
772e28a4053SRui Paulo 			   a, a->magic,
773e28a4053SRui Paulo 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
774e28a4053SRui Paulo 		wpa_trace_show("Invalid os_free() call");
775e28a4053SRui Paulo 		abort();
776e28a4053SRui Paulo 	}
777e28a4053SRui Paulo 	dl_list_del(&a->list);
778e28a4053SRui Paulo 	a->magic = FREED_MAGIC;
779e28a4053SRui Paulo 
780e28a4053SRui Paulo 	wpa_trace_check_ref(ptr);
781e28a4053SRui Paulo 	free(a);
782e28a4053SRui Paulo }
783e28a4053SRui Paulo 
784e28a4053SRui Paulo 
785e28a4053SRui Paulo void * os_zalloc(size_t size)
786e28a4053SRui Paulo {
787e28a4053SRui Paulo 	void *ptr = os_malloc(size);
788e28a4053SRui Paulo 	if (ptr)
789e28a4053SRui Paulo 		os_memset(ptr, 0, size);
790e28a4053SRui Paulo 	return ptr;
791e28a4053SRui Paulo }
792e28a4053SRui Paulo 
793e28a4053SRui Paulo 
794e28a4053SRui Paulo char * os_strdup(const char *s)
795e28a4053SRui Paulo {
796e28a4053SRui Paulo 	size_t len;
797e28a4053SRui Paulo 	char *d;
798e28a4053SRui Paulo 	len = os_strlen(s);
799e28a4053SRui Paulo 	d = os_malloc(len + 1);
800e28a4053SRui Paulo 	if (d == NULL)
801e28a4053SRui Paulo 		return NULL;
802e28a4053SRui Paulo 	os_memcpy(d, s, len);
803e28a4053SRui Paulo 	d[len] = '\0';
804e28a4053SRui Paulo 	return d;
805e28a4053SRui Paulo }
806e28a4053SRui Paulo 
807e28a4053SRui Paulo #endif /* WPA_TRACE */
8085b9c547cSRui Paulo 
8095b9c547cSRui Paulo 
8105b9c547cSRui Paulo int os_exec(const char *program, const char *arg, int wait_completion)
8115b9c547cSRui Paulo {
8125b9c547cSRui Paulo 	pid_t pid;
8135b9c547cSRui Paulo 	int pid_status;
8145b9c547cSRui Paulo 
8155b9c547cSRui Paulo 	pid = fork();
8165b9c547cSRui Paulo 	if (pid < 0) {
8175b9c547cSRui Paulo 		perror("fork");
8185b9c547cSRui Paulo 		return -1;
8195b9c547cSRui Paulo 	}
8205b9c547cSRui Paulo 
8215b9c547cSRui Paulo 	if (pid == 0) {
8225b9c547cSRui Paulo 		/* run the external command in the child process */
8235b9c547cSRui Paulo 		const int MAX_ARG = 30;
8245b9c547cSRui Paulo 		char *_program, *_arg, *pos;
8255b9c547cSRui Paulo 		char *argv[MAX_ARG + 1];
8265b9c547cSRui Paulo 		int i;
8275b9c547cSRui Paulo 
8285b9c547cSRui Paulo 		_program = os_strdup(program);
8295b9c547cSRui Paulo 		_arg = os_strdup(arg);
8305b9c547cSRui Paulo 
8315b9c547cSRui Paulo 		argv[0] = _program;
8325b9c547cSRui Paulo 
8335b9c547cSRui Paulo 		i = 1;
8345b9c547cSRui Paulo 		pos = _arg;
8355b9c547cSRui Paulo 		while (i < MAX_ARG && pos && *pos) {
8365b9c547cSRui Paulo 			while (*pos == ' ')
8375b9c547cSRui Paulo 				pos++;
8385b9c547cSRui Paulo 			if (*pos == '\0')
8395b9c547cSRui Paulo 				break;
8405b9c547cSRui Paulo 			argv[i++] = pos;
8415b9c547cSRui Paulo 			pos = os_strchr(pos, ' ');
8425b9c547cSRui Paulo 			if (pos)
8435b9c547cSRui Paulo 				*pos++ = '\0';
8445b9c547cSRui Paulo 		}
8455b9c547cSRui Paulo 		argv[i] = NULL;
8465b9c547cSRui Paulo 
8475b9c547cSRui Paulo 		execv(program, argv);
8485b9c547cSRui Paulo 		perror("execv");
8495b9c547cSRui Paulo 		os_free(_program);
8505b9c547cSRui Paulo 		os_free(_arg);
8515b9c547cSRui Paulo 		exit(0);
8525b9c547cSRui Paulo 		return -1;
8535b9c547cSRui Paulo 	}
8545b9c547cSRui Paulo 
8555b9c547cSRui Paulo 	if (wait_completion) {
8565b9c547cSRui Paulo 		/* wait for the child process to complete in the parent */
8575b9c547cSRui Paulo 		waitpid(pid, &pid_status, 0);
8585b9c547cSRui Paulo 	}
8595b9c547cSRui Paulo 
8605b9c547cSRui Paulo 	return 0;
8615b9c547cSRui Paulo }
862