Home | History | Annotate | Download | only in utils
      1 /*
      2  * OS specific functions for UNIX/POSIX systems
      3  * Copyright (c) 2005-2019, 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 #ifdef TEST_FUZZ
    256 	size_t i;
    257 
    258 	for (i = 0; i < len; i++)
    259 		buf[i] = i & 0xff;
    260 	return 0;
    261 #else /* TEST_FUZZ */
    262 	FILE *f;
    263 	size_t rc;
    264 
    265 	if (TEST_FAIL())
    266 		return -1;
    267 
    268 	f = fopen("/dev/urandom", "rb");
    269 	if (f == NULL) {
    270 		printf("Could not open /dev/urandom.\n");
    271 		return -1;
    272 	}
    273 
    274 	rc = fread(buf, 1, len, f);
    275 	fclose(f);
    276 
    277 	return rc != len ? -1 : 0;
    278 #endif /* TEST_FUZZ */
    279 }
    280 
    281 
    282 unsigned long os_random(void)
    283 {
    284 	return random();
    285 }
    286 
    287 
    288 char * os_rel2abs_path(const char *rel_path)
    289 {
    290 	char *buf = NULL, *cwd, *ret;
    291 	size_t len = 128, cwd_len, rel_len, ret_len;
    292 	int last_errno;
    293 
    294 	if (!rel_path)
    295 		return NULL;
    296 
    297 	if (rel_path[0] == '/')
    298 		return os_strdup(rel_path);
    299 
    300 	for (;;) {
    301 		buf = os_malloc(len);
    302 		if (buf == NULL)
    303 			return NULL;
    304 		cwd = getcwd(buf, len);
    305 		if (cwd == NULL) {
    306 			last_errno = errno;
    307 			os_free(buf);
    308 			if (last_errno != ERANGE)
    309 				return NULL;
    310 			len *= 2;
    311 			if (len > 2000)
    312 				return NULL;
    313 		} else {
    314 			buf[len - 1] = '\0';
    315 			break;
    316 		}
    317 	}
    318 
    319 	cwd_len = os_strlen(cwd);
    320 	rel_len = os_strlen(rel_path);
    321 	ret_len = cwd_len + 1 + rel_len + 1;
    322 	ret = os_malloc(ret_len);
    323 	if (ret) {
    324 		os_memcpy(ret, cwd, cwd_len);
    325 		ret[cwd_len] = '/';
    326 		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
    327 		ret[ret_len - 1] = '\0';
    328 	}
    329 	os_free(buf);
    330 	return ret;
    331 }
    332 
    333 
    334 int os_program_init(void)
    335 {
    336 #ifdef ANDROID
    337 	struct __user_cap_header_struct header;
    338 	struct __user_cap_data_struct cap;
    339 	struct group *grp = getgrnam("wifi");
    340 	gid_t gid_wifi = grp ? grp->gr_gid : 0;
    341 	struct passwd *pwd = getpwnam("wifi");
    342 	uid_t uid_wifi = pwd ? pwd->pw_uid : 0;
    343 
    344 	/*
    345 	 * We ignore errors here since errors are normal if we
    346 	 * are already running as non-root.
    347 	 */
    348 #ifdef ANDROID_SETGROUPS_OVERRIDE
    349 	gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
    350 
    351 	if (!gid_wifi || !uid_wifi) return -1;
    352 	setgroups(ARRAY_SIZE(groups), groups);
    353 #else /* ANDROID_SETGROUPS_OVERRIDE */
    354 	gid_t groups[4];
    355 	int group_idx = 0;
    356 
    357 	if (!gid_wifi || !uid_wifi) return -1;
    358 	groups[group_idx] = gid_wifi;
    359 
    360 	grp = getgrnam("inet");
    361 	groups[++group_idx] = grp ? grp->gr_gid : 0;
    362 	if (!groups[group_idx]) return -1;
    363 
    364 	grp = getgrnam("keystore");
    365 	groups[++group_idx] = grp ? grp->gr_gid : 0;
    366 	if (!groups[group_idx]) return -1;
    367 
    368 	grp = getgrnam("log");
    369 	groups[++group_idx] = grp ? grp->gr_gid : 0;
    370 	if (!groups[group_idx]) group_idx--;
    371 
    372 	setgroups(group_idx + 1, groups);
    373 #endif /* ANDROID_SETGROUPS_OVERRIDE */
    374 
    375 	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
    376 
    377 	setgid(gid_wifi);
    378 	setuid(uid_wifi);
    379 
    380 	header.version = _LINUX_CAPABILITY_VERSION;
    381 	header.pid = 0;
    382 	cap.effective = cap.permitted =
    383 		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
    384 	cap.inheritable = 0;
    385 	capset(&header, &cap);
    386 #endif /* ANDROID */
    387 
    388 	return 0;
    389 }
    390 
    391 
    392 void os_program_deinit(void)
    393 {
    394 #ifdef WPA_TRACE
    395 	struct os_alloc_trace *a;
    396 	unsigned long total = 0;
    397 	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
    398 		total += a->len;
    399 		if (a->magic != ALLOC_MAGIC) {
    400 			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
    401 				   "len %lu",
    402 				   a, a->magic, (unsigned long) a->len);
    403 			continue;
    404 		}
    405 		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
    406 			   a, (unsigned long) a->len);
    407 		wpa_trace_dump("memleak", a);
    408 	}
    409 	if (total)
    410 		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
    411 			   (unsigned long) total);
    412 	wpa_trace_deinit();
    413 #endif /* WPA_TRACE */
    414 }
    415 
    416 
    417 int os_setenv(const char *name, const char *value, int overwrite)
    418 {
    419 	return setenv(name, value, overwrite);
    420 }
    421 
    422 
    423 int os_unsetenv(const char *name)
    424 {
    425 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
    426     defined(__OpenBSD__)
    427 	unsetenv(name);
    428 	return 0;
    429 #else
    430 	return unsetenv(name);
    431 #endif
    432 }
    433 
    434 
    435 char * os_readfile(const char *name, size_t *len)
    436 {
    437 	FILE *f;
    438 	char *buf;
    439 	long pos;
    440 
    441 	f = fopen(name, "rb");
    442 	if (f == NULL)
    443 		return NULL;
    444 
    445 	if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
    446 		fclose(f);
    447 		return NULL;
    448 	}
    449 	*len = pos;
    450 	if (fseek(f, 0, SEEK_SET) < 0) {
    451 		fclose(f);
    452 		return NULL;
    453 	}
    454 
    455 	buf = os_malloc(*len);
    456 	if (buf == NULL) {
    457 		fclose(f);
    458 		return NULL;
    459 	}
    460 
    461 	if (fread(buf, 1, *len, f) != *len) {
    462 		fclose(f);
    463 		os_free(buf);
    464 		return NULL;
    465 	}
    466 
    467 	fclose(f);
    468 
    469 	return buf;
    470 }
    471 
    472 
    473 int os_file_exists(const char *fname)
    474 {
    475 	return access(fname, F_OK) == 0;
    476 }
    477 
    478 
    479 int os_fdatasync(FILE *stream)
    480 {
    481 	if (!fflush(stream)) {
    482 #ifdef __linux__
    483 		return fdatasync(fileno(stream));
    484 #else /* !__linux__ */
    485 #ifdef F_FULLFSYNC
    486 		/* OS X does not implement fdatasync(). */
    487 		return fcntl(fileno(stream), F_FULLFSYNC);
    488 #else /* F_FULLFSYNC */
    489 		return fsync(fileno(stream));
    490 #endif /* F_FULLFSYNC */
    491 #endif /* __linux__ */
    492 	}
    493 
    494 	return -1;
    495 }
    496 
    497 
    498 #ifndef WPA_TRACE
    499 void * os_zalloc(size_t size)
    500 {
    501 	return calloc(1, size);
    502 }
    503 #endif /* WPA_TRACE */
    504 
    505 
    506 size_t os_strlcpy(char *dest, const char *src, size_t siz)
    507 {
    508 	const char *s = src;
    509 	size_t left = siz;
    510 
    511 	if (left) {
    512 		/* Copy string up to the maximum size of the dest buffer */
    513 		while (--left != 0) {
    514 			if ((*dest++ = *s++) == '\0')
    515 				break;
    516 		}
    517 	}
    518 
    519 	if (left == 0) {
    520 		/* Not enough room for the string; force NUL-termination */
    521 		if (siz != 0)
    522 			*dest = '\0';
    523 		while (*s++)
    524 			; /* determine total src string length */
    525 	}
    526 
    527 	return s - src - 1;
    528 }
    529 
    530 
    531 int os_memcmp_const(const void *a, const void *b, size_t len)
    532 {
    533 	const u8 *aa = a;
    534 	const u8 *bb = b;
    535 	size_t i;
    536 	u8 res;
    537 
    538 	for (res = 0, i = 0; i < len; i++)
    539 		res |= aa[i] ^ bb[i];
    540 
    541 	return res;
    542 }
    543 
    544 
    545 void * os_memdup(const void *src, size_t len)
    546 {
    547 	void *r = os_malloc(len);
    548 
    549 	if (r && src)
    550 		os_memcpy(r, src, len);
    551 	return r;
    552 }
    553 
    554 
    555 #ifdef WPA_TRACE
    556 
    557 #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
    558 char wpa_trace_fail_func[256] = { 0 };
    559 unsigned int wpa_trace_fail_after;
    560 
    561 static int testing_fail_alloc(void)
    562 {
    563 	const char *func[WPA_TRACE_LEN];
    564 	size_t i, res, len;
    565 	char *pos, *next;
    566 	int match;
    567 
    568 	if (!wpa_trace_fail_after)
    569 		return 0;
    570 
    571 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
    572 	i = 0;
    573 	if (i < res && os_strcmp(func[i], __func__) == 0)
    574 		i++;
    575 	if (i < res && os_strcmp(func[i], "os_malloc") == 0)
    576 		i++;
    577 	if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
    578 		i++;
    579 	if (i < res && os_strcmp(func[i], "os_calloc") == 0)
    580 		i++;
    581 	if (i < res && os_strcmp(func[i], "os_realloc") == 0)
    582 		i++;
    583 	if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
    584 		i++;
    585 	if (i < res && os_strcmp(func[i], "os_strdup") == 0)
    586 		i++;
    587 	if (i < res && os_strcmp(func[i], "os_memdup") == 0)
    588 		i++;
    589 
    590 	pos = wpa_trace_fail_func;
    591 
    592 	match = 0;
    593 	while (i < res) {
    594 		int allow_skip = 1;
    595 		int maybe = 0;
    596 
    597 		if (*pos == '=') {
    598 			allow_skip = 0;
    599 			pos++;
    600 		} else if (*pos == '?') {
    601 			maybe = 1;
    602 			pos++;
    603 		}
    604 		next = os_strchr(pos, ';');
    605 		if (next)
    606 			len = next - pos;
    607 		else
    608 			len = os_strlen(pos);
    609 		if (os_memcmp(pos, func[i], len) != 0) {
    610 			if (maybe && next) {
    611 				pos = next + 1;
    612 				continue;
    613 			}
    614 			if (allow_skip) {
    615 				i++;
    616 				continue;
    617 			}
    618 			return 0;
    619 		}
    620 		if (!next) {
    621 			match = 1;
    622 			break;
    623 		}
    624 		pos = next + 1;
    625 		i++;
    626 	}
    627 	if (!match)
    628 		return 0;
    629 
    630 	wpa_trace_fail_after--;
    631 	if (wpa_trace_fail_after == 0) {
    632 		wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
    633 			   wpa_trace_fail_func);
    634 		for (i = 0; i < res; i++)
    635 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
    636 				   (int) i, func[i]);
    637 		return 1;
    638 	}
    639 
    640 	return 0;
    641 }
    642 
    643 
    644 char wpa_trace_test_fail_func[256] = { 0 };
    645 unsigned int wpa_trace_test_fail_after;
    646 
    647 int testing_test_fail(void)
    648 {
    649 	const char *func[WPA_TRACE_LEN];
    650 	size_t i, res, len;
    651 	char *pos, *next;
    652 	int match;
    653 
    654 	if (!wpa_trace_test_fail_after)
    655 		return 0;
    656 
    657 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
    658 	i = 0;
    659 	if (i < res && os_strcmp(func[i], __func__) == 0)
    660 		i++;
    661 
    662 	pos = wpa_trace_test_fail_func;
    663 
    664 	match = 0;
    665 	while (i < res) {
    666 		int allow_skip = 1;
    667 		int maybe = 0;
    668 
    669 		if (*pos == '=') {
    670 			allow_skip = 0;
    671 			pos++;
    672 		} else if (*pos == '?') {
    673 			maybe = 1;
    674 			pos++;
    675 		}
    676 		next = os_strchr(pos, ';');
    677 		if (next)
    678 			len = next - pos;
    679 		else
    680 			len = os_strlen(pos);
    681 		if (os_memcmp(pos, func[i], len) != 0) {
    682 			if (maybe && next) {
    683 				pos = next + 1;
    684 				continue;
    685 			}
    686 			if (allow_skip) {
    687 				i++;
    688 				continue;
    689 			}
    690 			return 0;
    691 		}
    692 		if (!next) {
    693 			match = 1;
    694 			break;
    695 		}
    696 		pos = next + 1;
    697 		i++;
    698 	}
    699 	if (!match)
    700 		return 0;
    701 
    702 	wpa_trace_test_fail_after--;
    703 	if (wpa_trace_test_fail_after == 0) {
    704 		wpa_printf(MSG_INFO, "TESTING: fail at %s",
    705 			   wpa_trace_test_fail_func);
    706 		for (i = 0; i < res; i++)
    707 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
    708 				   (int) i, func[i]);
    709 		return 1;
    710 	}
    711 
    712 	return 0;
    713 }
    714 
    715 #else
    716 
    717 static inline int testing_fail_alloc(void)
    718 {
    719 	return 0;
    720 }
    721 #endif
    722 
    723 void * os_malloc(size_t size)
    724 {
    725 	struct os_alloc_trace *a;
    726 
    727 	if (testing_fail_alloc())
    728 		return NULL;
    729 
    730 	a = malloc(sizeof(*a) + size);
    731 	if (a == NULL)
    732 		return NULL;
    733 	a->magic = ALLOC_MAGIC;
    734 	dl_list_add(&alloc_list, &a->list);
    735 	a->len = size;
    736 	wpa_trace_record(a);
    737 	return a + 1;
    738 }
    739 
    740 
    741 void * os_realloc(void *ptr, size_t size)
    742 {
    743 	struct os_alloc_trace *a;
    744 	size_t copy_len;
    745 	void *n;
    746 
    747 	if (ptr == NULL)
    748 		return os_malloc(size);
    749 
    750 	a = (struct os_alloc_trace *) ptr - 1;
    751 	if (a->magic != ALLOC_MAGIC) {
    752 		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
    753 			   a, a->magic,
    754 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
    755 		wpa_trace_show("Invalid os_realloc() call");
    756 		abort();
    757 	}
    758 	n = os_malloc(size);
    759 	if (n == NULL)
    760 		return NULL;
    761 	copy_len = a->len;
    762 	if (copy_len > size)
    763 		copy_len = size;
    764 	os_memcpy(n, a + 1, copy_len);
    765 	os_free(ptr);
    766 	return n;
    767 }
    768 
    769 
    770 void os_free(void *ptr)
    771 {
    772 	struct os_alloc_trace *a;
    773 
    774 	if (ptr == NULL)
    775 		return;
    776 	a = (struct os_alloc_trace *) ptr - 1;
    777 	if (a->magic != ALLOC_MAGIC) {
    778 		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
    779 			   a, a->magic,
    780 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
    781 		wpa_trace_show("Invalid os_free() call");
    782 		abort();
    783 	}
    784 	dl_list_del(&a->list);
    785 	a->magic = FREED_MAGIC;
    786 
    787 	wpa_trace_check_ref(ptr);
    788 	free(a);
    789 }
    790 
    791 
    792 void * os_zalloc(size_t size)
    793 {
    794 	void *ptr = os_malloc(size);
    795 	if (ptr)
    796 		os_memset(ptr, 0, size);
    797 	return ptr;
    798 }
    799 
    800 
    801 char * os_strdup(const char *s)
    802 {
    803 	size_t len;
    804 	char *d;
    805 	len = os_strlen(s);
    806 	d = os_malloc(len + 1);
    807 	if (d == NULL)
    808 		return NULL;
    809 	os_memcpy(d, s, len);
    810 	d[len] = '\0';
    811 	return d;
    812 }
    813 
    814 #endif /* WPA_TRACE */
    815 
    816 
    817 int os_exec(const char *program, const char *arg, int wait_completion)
    818 {
    819 	pid_t pid;
    820 	int pid_status;
    821 
    822 	pid = fork();
    823 	if (pid < 0) {
    824 		perror("fork");
    825 		return -1;
    826 	}
    827 
    828 	if (pid == 0) {
    829 		/* run the external command in the child process */
    830 		const int MAX_ARG = 30;
    831 		char *_program, *_arg, *pos;
    832 		char *argv[MAX_ARG + 1];
    833 		int i;
    834 
    835 		_program = os_strdup(program);
    836 		_arg = os_strdup(arg);
    837 
    838 		argv[0] = _program;
    839 
    840 		i = 1;
    841 		pos = _arg;
    842 		while (i < MAX_ARG && pos && *pos) {
    843 			while (*pos == ' ')
    844 				pos++;
    845 			if (*pos == '\0')
    846 				break;
    847 			argv[i++] = pos;
    848 			pos = os_strchr(pos, ' ');
    849 			if (pos)
    850 				*pos++ = '\0';
    851 		}
    852 		argv[i] = NULL;
    853 
    854 		execv(program, argv);
    855 		perror("execv");
    856 		os_free(_program);
    857 		os_free(_arg);
    858 		exit(0);
    859 		return -1;
    860 	}
    861 
    862 	if (wait_completion) {
    863 		/* wait for the child process to complete in the parent */
    864 		waitpid(pid, &pid_status, 0);
    865 	}
    866 
    867 	return 0;
    868 }
    869