1/*
2 * wpa_supplicant/hostapd / Internal implementation of OS specific functions
3 * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 *
8 * This file is an example of operating system specific  wrapper functions.
9 * This version implements many of the functions internally, so it can be used
10 * to fill in missing functions from the target system C libraries.
11 *
12 * Some of the functions are using standard C library calls in order to keep
13 * this file in working condition to allow the functions to be tested on a
14 * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for
15 * this file to work correctly. Note that these implementations are only
16 * examples and are not optimized for speed.
17 */
18
19#include "includes.h"
20#include <time.h>
21#include <sys/wait.h>
22
23#undef OS_REJECT_C_LIB_FUNCTIONS
24#include "common.h"
25
26void os_sleep(os_time_t sec, os_time_t usec)
27{
28	if (sec)
29		sleep(sec);
30	if (usec)
31		usleep(usec);
32}
33
34
35int os_get_time(struct os_time *t)
36{
37	int res;
38	struct timeval tv;
39	res = gettimeofday(&tv, NULL);
40	t->sec = tv.tv_sec;
41	t->usec = tv.tv_usec;
42	return res;
43}
44
45
46int os_get_reltime(struct os_reltime *t)
47{
48	int res;
49	struct timeval tv;
50	res = gettimeofday(&tv, NULL);
51	t->sec = tv.tv_sec;
52	t->usec = tv.tv_usec;
53	return res;
54}
55
56
57int os_mktime(int year, int month, int day, int hour, int min, int sec,
58	      os_time_t *t)
59{
60	struct tm tm;
61
62	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
63	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
64	    sec > 60)
65		return -1;
66
67	os_memset(&tm, 0, sizeof(tm));
68	tm.tm_year = year - 1900;
69	tm.tm_mon = month - 1;
70	tm.tm_mday = day;
71	tm.tm_hour = hour;
72	tm.tm_min = min;
73	tm.tm_sec = sec;
74
75	*t = (os_time_t) mktime(&tm);
76	return 0;
77}
78
79
80int os_gmtime(os_time_t t, struct os_tm *tm)
81{
82	struct tm *tm2;
83	time_t t2 = t;
84
85	tm2 = gmtime(&t2);
86	if (tm2 == NULL)
87		return -1;
88	tm->sec = tm2->tm_sec;
89	tm->min = tm2->tm_min;
90	tm->hour = tm2->tm_hour;
91	tm->day = tm2->tm_mday;
92	tm->month = tm2->tm_mon + 1;
93	tm->year = tm2->tm_year + 1900;
94	return 0;
95}
96
97
98int os_daemonize(const char *pid_file)
99{
100	if (daemon(0, 0)) {
101		wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
102		return -1;
103	}
104
105	if (pid_file) {
106		FILE *f = fopen(pid_file, "w");
107		if (f) {
108			fprintf(f, "%u\n", getpid());
109			fclose(f);
110		}
111	}
112
113	return -0;
114}
115
116
117void os_daemonize_terminate(const char *pid_file)
118{
119	if (pid_file)
120		unlink(pid_file);
121}
122
123
124int os_get_random(unsigned char *buf, size_t len)
125{
126#if defined(TEST_FUZZ) || defined(CONFIG_TEST_RANDOM)
127  size_t i;
128
129  for (i = 0; i < len; i++)
130    buf[i] = i & 0xff;
131  return 0;
132#else /* TEST_FUZZ */
133	FILE *f;
134	size_t rc;
135
136	f = fopen("/dev/urandom", "rb");
137	if (f == NULL) {
138		printf("Could not open /dev/urandom.\n");
139		return -1;
140	}
141
142	rc = fread(buf, 1, len, f);
143	fclose(f);
144
145	return rc != len ? -1 : 0;
146#endif
147}
148
149
150unsigned long os_random(void)
151{
152	return random();
153}
154
155
156char * os_rel2abs_path(const char *rel_path)
157{
158	char *buf = NULL, *cwd, *ret;
159	size_t len = 128, cwd_len, rel_len, ret_len;
160
161	if (rel_path[0] == '/')
162		return os_strdup(rel_path);
163
164	for (;;) {
165		buf = os_malloc(len);
166		if (buf == NULL)
167			return NULL;
168		cwd = getcwd(buf, len);
169		if (cwd == NULL) {
170			os_free(buf);
171			if (errno != ERANGE) {
172				return NULL;
173			}
174			len *= 2;
175		} else {
176			break;
177		}
178	}
179
180	cwd_len = os_strlen(cwd);
181	rel_len = os_strlen(rel_path);
182	ret_len = cwd_len + 1 + rel_len + 1;
183	ret = os_malloc(ret_len);
184	if (ret) {
185		os_memcpy(ret, cwd, cwd_len);
186		ret[cwd_len] = '/';
187		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
188		ret[ret_len - 1] = '\0';
189	}
190	os_free(buf);
191	return ret;
192}
193
194
195int os_program_init(void)
196{
197	return 0;
198}
199
200
201void os_program_deinit(void)
202{
203}
204
205
206int os_setenv(const char *name, const char *value, int overwrite)
207{
208	return setenv(name, value, overwrite);
209}
210
211
212int os_unsetenv(const char *name)
213{
214#if defined(__FreeBSD__) || defined(__NetBSD__)
215	unsetenv(name);
216	return 0;
217#else
218	return unsetenv(name);
219#endif
220}
221
222
223char * os_readfile(const char *name, size_t *len)
224{
225	FILE *f;
226	char *buf;
227
228	f = fopen(name, "rb");
229	if (f == NULL)
230		return NULL;
231
232	fseek(f, 0, SEEK_END);
233	*len = ftell(f);
234	fseek(f, 0, SEEK_SET);
235
236	buf = os_malloc(*len);
237	if (buf == NULL) {
238		fclose(f);
239		return NULL;
240	}
241
242	if (fread(buf, 1, *len, f) != *len) {
243		fclose(f);
244		os_free(buf);
245		return NULL;
246	}
247
248	fclose(f);
249
250	return buf;
251}
252
253
254int os_fdatasync(FILE *stream)
255{
256	return 0;
257}
258
259
260void * os_zalloc(size_t size)
261{
262	void *n = os_malloc(size);
263	if (n)
264		os_memset(n, 0, size);
265	return n;
266}
267
268
269void * os_malloc(size_t size)
270{
271	return malloc(size);
272}
273
274
275void * os_realloc(void *ptr, size_t size)
276{
277	return realloc(ptr, size);
278}
279
280
281void os_free(void *ptr)
282{
283	free(ptr);
284}
285
286
287void * os_memcpy(void *dest, const void *src, size_t n)
288{
289	char *d = dest;
290	const char *s = src;
291	while (n--)
292		*d++ = *s++;
293	return dest;
294}
295
296
297void * os_memmove(void *dest, const void *src, size_t n)
298{
299	if (dest < src)
300		os_memcpy(dest, src, n);
301	else {
302		/* overlapping areas */
303		char *d = (char *) dest + n;
304		const char *s = (const char *) src + n;
305		while (n--)
306			*--d = *--s;
307	}
308	return dest;
309}
310
311
312void * os_memset(void *s, int c, size_t n)
313{
314	char *p = s;
315	while (n--)
316		*p++ = c;
317	return s;
318}
319
320
321int os_memcmp(const void *s1, const void *s2, size_t n)
322{
323	const unsigned char *p1 = s1, *p2 = s2;
324
325	if (n == 0)
326		return 0;
327
328	while (*p1 == *p2) {
329		p1++;
330		p2++;
331		n--;
332		if (n == 0)
333			return 0;
334	}
335
336	return *p1 - *p2;
337}
338
339
340char * os_strdup(const char *s)
341{
342	char *res;
343	size_t len;
344	if (s == NULL)
345		return NULL;
346	len = os_strlen(s);
347	res = os_malloc(len + 1);
348	if (res)
349		os_memcpy(res, s, len + 1);
350	return res;
351}
352
353
354size_t os_strlen(const char *s)
355{
356	const char *p = s;
357	while (*p)
358		p++;
359	return p - s;
360}
361
362
363int os_strcasecmp(const char *s1, const char *s2)
364{
365	/*
366	 * Ignoring case is not required for main functionality, so just use
367	 * the case sensitive version of the function.
368	 */
369	return os_strcmp(s1, s2);
370}
371
372
373int os_strncasecmp(const char *s1, const char *s2, size_t n)
374{
375	/*
376	 * Ignoring case is not required for main functionality, so just use
377	 * the case sensitive version of the function.
378	 */
379	return os_strncmp(s1, s2, n);
380}
381
382
383char * os_strchr(const char *s, int c)
384{
385	while (*s) {
386		if (*s == c)
387			return (char *) s;
388		s++;
389	}
390	return NULL;
391}
392
393
394char * os_strrchr(const char *s, int c)
395{
396	const char *p = s;
397	while (*p)
398		p++;
399	p--;
400	while (p >= s) {
401		if (*p == c)
402			return (char *) p;
403		p--;
404	}
405	return NULL;
406}
407
408
409int os_strcmp(const char *s1, const char *s2)
410{
411	while (*s1 == *s2) {
412		if (*s1 == '\0')
413			break;
414		s1++;
415		s2++;
416	}
417
418	return *s1 - *s2;
419}
420
421
422int os_strncmp(const char *s1, const char *s2, size_t n)
423{
424	if (n == 0)
425		return 0;
426
427	while (*s1 == *s2) {
428		if (*s1 == '\0')
429			break;
430		s1++;
431		s2++;
432		n--;
433		if (n == 0)
434			return 0;
435	}
436
437	return *s1 - *s2;
438}
439
440
441size_t os_strlcpy(char *dest, const char *src, size_t siz)
442{
443	const char *s = src;
444	size_t left = siz;
445
446	if (left) {
447		/* Copy string up to the maximum size of the dest buffer */
448		while (--left != 0) {
449			if ((*dest++ = *s++) == '\0')
450				break;
451		}
452	}
453
454	if (left == 0) {
455		/* Not enough room for the string; force NUL-termination */
456		if (siz != 0)
457			*dest = '\0';
458		while (*s++)
459			; /* determine total src string length */
460	}
461
462	return s - src - 1;
463}
464
465
466int os_memcmp_const(const void *a, const void *b, size_t len)
467{
468	const u8 *aa = a;
469	const u8 *bb = b;
470	size_t i;
471	u8 res;
472
473	for (res = 0, i = 0; i < len; i++)
474		res |= aa[i] ^ bb[i];
475
476	return res;
477}
478
479
480char * os_strstr(const char *haystack, const char *needle)
481{
482	size_t len = os_strlen(needle);
483	while (*haystack) {
484		if (os_strncmp(haystack, needle, len) == 0)
485			return (char *) haystack;
486		haystack++;
487	}
488
489	return NULL;
490}
491
492
493int os_snprintf(char *str, size_t size, const char *format, ...)
494{
495	va_list ap;
496	int ret;
497
498	/* See http://www.ijs.si/software/snprintf/ for portable
499	 * implementation of snprintf.
500	 */
501
502	va_start(ap, format);
503	ret = vsnprintf(str, size, format, ap);
504	va_end(ap);
505	if (size > 0)
506		str[size - 1] = '\0';
507	return ret;
508}
509
510
511int os_exec(const char *program, const char *arg, int wait_completion)
512{
513	pid_t pid;
514	int pid_status;
515
516	pid = fork();
517	if (pid < 0) {
518		wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
519		return -1;
520	}
521
522	if (pid == 0) {
523		/* run the external command in the child process */
524		const int MAX_ARG = 30;
525		char *_program, *_arg, *pos;
526		char *argv[MAX_ARG + 1];
527		int i;
528
529		_program = os_strdup(program);
530		_arg = os_strdup(arg);
531
532		argv[0] = _program;
533
534		i = 1;
535		pos = _arg;
536		while (i < MAX_ARG && pos && *pos) {
537			while (*pos == ' ')
538				pos++;
539			if (*pos == '\0')
540				break;
541			argv[i++] = pos;
542			pos = os_strchr(pos, ' ');
543			if (pos)
544				*pos++ = '\0';
545		}
546		argv[i] = NULL;
547
548		execv(program, argv);
549		wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
550		os_free(_program);
551		os_free(_arg);
552		exit(0);
553		return -1;
554	}
555
556	if (wait_completion) {
557		/* wait for the child process to complete in the parent */
558		waitpid(pid, &pid_status, 0);
559	}
560
561	return 0;
562}
563