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