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