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