1189251Ssam/*
2189251Ssam * wpa_supplicant/hostapd / Internal implementation of OS specific functions
3189251Ssam * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam *
8189251Ssam * This file is an example of operating system specific  wrapper functions.
9189251Ssam * This version implements many of the functions internally, so it can be used
10189251Ssam * to fill in missing functions from the target system C libraries.
11189251Ssam *
12189251Ssam * Some of the functions are using standard C library calls in order to keep
13189251Ssam * this file in working condition to allow the functions to be tested on a
14189251Ssam * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for
15189251Ssam * this file to work correctly. Note that these implementations are only
16189251Ssam * examples and are not optimized for speed.
17189251Ssam */
18189251Ssam
19189251Ssam#include "includes.h"
20189251Ssam
21189251Ssam#undef OS_REJECT_C_LIB_FUNCTIONS
22189251Ssam#include "os.h"
23189251Ssam
24189251Ssamvoid os_sleep(os_time_t sec, os_time_t usec)
25189251Ssam{
26189251Ssam	if (sec)
27189251Ssam		sleep(sec);
28189251Ssam	if (usec)
29189251Ssam		usleep(usec);
30189251Ssam}
31189251Ssam
32189251Ssam
33189251Ssamint os_get_time(struct os_time *t)
34189251Ssam{
35189251Ssam	int res;
36189251Ssam	struct timeval tv;
37189251Ssam	res = gettimeofday(&tv, NULL);
38189251Ssam	t->sec = tv.tv_sec;
39189251Ssam	t->usec = tv.tv_usec;
40189251Ssam	return res;
41189251Ssam}
42189251Ssam
43189251Ssam
44189251Ssamint os_mktime(int year, int month, int day, int hour, int min, int sec,
45189251Ssam	      os_time_t *t)
46189251Ssam{
47189251Ssam	struct tm tm;
48189251Ssam
49189251Ssam	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
50189251Ssam	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
51189251Ssam	    sec > 60)
52189251Ssam		return -1;
53189251Ssam
54189251Ssam	os_memset(&tm, 0, sizeof(tm));
55189251Ssam	tm.tm_year = year - 1900;
56189251Ssam	tm.tm_mon = month - 1;
57189251Ssam	tm.tm_mday = day;
58189251Ssam	tm.tm_hour = hour;
59189251Ssam	tm.tm_min = min;
60189251Ssam	tm.tm_sec = sec;
61189251Ssam
62189251Ssam	*t = (os_time_t) mktime(&tm);
63189251Ssam	return 0;
64189251Ssam}
65189251Ssam
66189251Ssam
67252726Srpauloint os_gmtime(os_time_t t, struct os_tm *tm)
68252726Srpaulo{
69252726Srpaulo	struct tm *tm2;
70252726Srpaulo	time_t t2 = t;
71252726Srpaulo
72252726Srpaulo	tm2 = gmtime(&t2);
73252726Srpaulo	if (tm2 == NULL)
74252726Srpaulo		return -1;
75252726Srpaulo	tm->sec = tm2->tm_sec;
76252726Srpaulo	tm->min = tm2->tm_min;
77252726Srpaulo	tm->hour = tm2->tm_hour;
78252726Srpaulo	tm->day = tm2->tm_mday;
79252726Srpaulo	tm->month = tm2->tm_mon + 1;
80252726Srpaulo	tm->year = tm2->tm_year + 1900;
81252726Srpaulo	return 0;
82252726Srpaulo}
83252726Srpaulo
84252726Srpaulo
85189251Ssamint os_daemonize(const char *pid_file)
86189251Ssam{
87189251Ssam	if (daemon(0, 0)) {
88189251Ssam		perror("daemon");
89189251Ssam		return -1;
90189251Ssam	}
91189251Ssam
92189251Ssam	if (pid_file) {
93189251Ssam		FILE *f = fopen(pid_file, "w");
94189251Ssam		if (f) {
95189251Ssam			fprintf(f, "%u\n", getpid());
96189251Ssam			fclose(f);
97189251Ssam		}
98189251Ssam	}
99189251Ssam
100189251Ssam	return -0;
101189251Ssam}
102189251Ssam
103189251Ssam
104189251Ssamvoid os_daemonize_terminate(const char *pid_file)
105189251Ssam{
106189251Ssam	if (pid_file)
107189251Ssam		unlink(pid_file);
108189251Ssam}
109189251Ssam
110189251Ssam
111189251Ssamint os_get_random(unsigned char *buf, size_t len)
112189251Ssam{
113189251Ssam	FILE *f;
114189251Ssam	size_t rc;
115189251Ssam
116189251Ssam	f = fopen("/dev/urandom", "rb");
117189251Ssam	if (f == NULL) {
118189251Ssam		printf("Could not open /dev/urandom.\n");
119189251Ssam		return -1;
120189251Ssam	}
121189251Ssam
122189251Ssam	rc = fread(buf, 1, len, f);
123189251Ssam	fclose(f);
124189251Ssam
125189251Ssam	return rc != len ? -1 : 0;
126189251Ssam}
127189251Ssam
128189251Ssam
129189251Ssamunsigned long os_random(void)
130189251Ssam{
131189251Ssam	return random();
132189251Ssam}
133189251Ssam
134189251Ssam
135189251Ssamchar * os_rel2abs_path(const char *rel_path)
136189251Ssam{
137189251Ssam	char *buf = NULL, *cwd, *ret;
138189251Ssam	size_t len = 128, cwd_len, rel_len, ret_len;
139189251Ssam
140189251Ssam	if (rel_path[0] == '/')
141189251Ssam		return os_strdup(rel_path);
142189251Ssam
143189251Ssam	for (;;) {
144189251Ssam		buf = os_malloc(len);
145189251Ssam		if (buf == NULL)
146189251Ssam			return NULL;
147189251Ssam		cwd = getcwd(buf, len);
148189251Ssam		if (cwd == NULL) {
149189251Ssam			os_free(buf);
150189251Ssam			if (errno != ERANGE) {
151189251Ssam				return NULL;
152189251Ssam			}
153189251Ssam			len *= 2;
154189251Ssam		} else {
155189251Ssam			break;
156189251Ssam		}
157189251Ssam	}
158189251Ssam
159189251Ssam	cwd_len = strlen(cwd);
160189251Ssam	rel_len = strlen(rel_path);
161189251Ssam	ret_len = cwd_len + 1 + rel_len + 1;
162189251Ssam	ret = os_malloc(ret_len);
163189251Ssam	if (ret) {
164189251Ssam		os_memcpy(ret, cwd, cwd_len);
165189251Ssam		ret[cwd_len] = '/';
166189251Ssam		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
167189251Ssam		ret[ret_len - 1] = '\0';
168189251Ssam	}
169189251Ssam	os_free(buf);
170189251Ssam	return ret;
171189251Ssam}
172189251Ssam
173189251Ssam
174189251Ssamint os_program_init(void)
175189251Ssam{
176189251Ssam	return 0;
177189251Ssam}
178189251Ssam
179189251Ssam
180189251Ssamvoid os_program_deinit(void)
181189251Ssam{
182189251Ssam}
183189251Ssam
184189251Ssam
185189251Ssamint os_setenv(const char *name, const char *value, int overwrite)
186189251Ssam{
187189251Ssam	return setenv(name, value, overwrite);
188189251Ssam}
189189251Ssam
190189251Ssam
191189251Ssamint os_unsetenv(const char *name)
192189251Ssam{
193189251Ssam#if defined(__FreeBSD__) || defined(__NetBSD__)
194189251Ssam	unsetenv(name);
195189251Ssam	return 0;
196189251Ssam#else
197189251Ssam	return unsetenv(name);
198189251Ssam#endif
199189251Ssam}
200189251Ssam
201189251Ssam
202189251Ssamchar * os_readfile(const char *name, size_t *len)
203189251Ssam{
204189251Ssam	FILE *f;
205189251Ssam	char *buf;
206189251Ssam
207189251Ssam	f = fopen(name, "rb");
208189251Ssam	if (f == NULL)
209189251Ssam		return NULL;
210189251Ssam
211189251Ssam	fseek(f, 0, SEEK_END);
212189251Ssam	*len = ftell(f);
213189251Ssam	fseek(f, 0, SEEK_SET);
214189251Ssam
215189251Ssam	buf = os_malloc(*len);
216189251Ssam	if (buf == NULL) {
217189251Ssam		fclose(f);
218189251Ssam		return NULL;
219189251Ssam	}
220189251Ssam
221214734Srpaulo	if (fread(buf, 1, *len, f) != *len) {
222214734Srpaulo		fclose(f);
223214734Srpaulo		os_free(buf);
224214734Srpaulo		return NULL;
225214734Srpaulo	}
226214734Srpaulo
227189251Ssam	fclose(f);
228189251Ssam
229189251Ssam	return buf;
230189251Ssam}
231189251Ssam
232189251Ssam
233189251Ssamvoid * os_zalloc(size_t size)
234189251Ssam{
235189251Ssam	void *n = os_malloc(size);
236189251Ssam	if (n)
237189251Ssam		os_memset(n, 0, size);
238189251Ssam	return n;
239189251Ssam}
240189251Ssam
241189251Ssam
242189251Ssamvoid * os_malloc(size_t size)
243189251Ssam{
244189251Ssam	return malloc(size);
245189251Ssam}
246189251Ssam
247189251Ssam
248189251Ssamvoid * os_realloc(void *ptr, size_t size)
249189251Ssam{
250189251Ssam	return realloc(ptr, size);
251189251Ssam}
252189251Ssam
253189251Ssam
254189251Ssamvoid os_free(void *ptr)
255189251Ssam{
256189251Ssam	free(ptr);
257189251Ssam}
258189251Ssam
259189251Ssam
260189251Ssamvoid * os_memcpy(void *dest, const void *src, size_t n)
261189251Ssam{
262189251Ssam	char *d = dest;
263189251Ssam	const char *s = src;
264189251Ssam	while (n--)
265189251Ssam		*d++ = *s++;
266189251Ssam	return dest;
267189251Ssam}
268189251Ssam
269189251Ssam
270189251Ssamvoid * os_memmove(void *dest, const void *src, size_t n)
271189251Ssam{
272189251Ssam	if (dest < src)
273189251Ssam		os_memcpy(dest, src, n);
274189251Ssam	else {
275189251Ssam		/* overlapping areas */
276189251Ssam		char *d = (char *) dest + n;
277189251Ssam		const char *s = (const char *) src + n;
278189251Ssam		while (n--)
279189251Ssam			*--d = *--s;
280189251Ssam	}
281189251Ssam	return dest;
282189251Ssam}
283189251Ssam
284189251Ssam
285189251Ssamvoid * os_memset(void *s, int c, size_t n)
286189251Ssam{
287189251Ssam	char *p = s;
288189251Ssam	while (n--)
289189251Ssam		*p++ = c;
290189251Ssam	return s;
291189251Ssam}
292189251Ssam
293189251Ssam
294189251Ssamint os_memcmp(const void *s1, const void *s2, size_t n)
295189251Ssam{
296189251Ssam	const unsigned char *p1 = s1, *p2 = s2;
297189251Ssam
298189251Ssam	if (n == 0)
299189251Ssam		return 0;
300189251Ssam
301189251Ssam	while (*p1 == *p2) {
302189251Ssam		p1++;
303189251Ssam		p2++;
304189251Ssam		n--;
305189251Ssam		if (n == 0)
306189251Ssam			return 0;
307189251Ssam	}
308189251Ssam
309189251Ssam	return *p1 - *p2;
310189251Ssam}
311189251Ssam
312189251Ssam
313189251Ssamchar * os_strdup(const char *s)
314189251Ssam{
315189251Ssam	char *res;
316189251Ssam	size_t len;
317189251Ssam	if (s == NULL)
318189251Ssam		return NULL;
319189251Ssam	len = os_strlen(s);
320189251Ssam	res = os_malloc(len + 1);
321189251Ssam	if (res)
322189251Ssam		os_memcpy(res, s, len + 1);
323189251Ssam	return res;
324189251Ssam}
325189251Ssam
326189251Ssam
327189251Ssamsize_t os_strlen(const char *s)
328189251Ssam{
329189251Ssam	const char *p = s;
330189251Ssam	while (*p)
331189251Ssam		p++;
332189251Ssam	return p - s;
333189251Ssam}
334189251Ssam
335189251Ssam
336189251Ssamint os_strcasecmp(const char *s1, const char *s2)
337189251Ssam{
338189251Ssam	/*
339189251Ssam	 * Ignoring case is not required for main functionality, so just use
340189251Ssam	 * the case sensitive version of the function.
341189251Ssam	 */
342189251Ssam	return os_strcmp(s1, s2);
343189251Ssam}
344189251Ssam
345189251Ssam
346189251Ssamint os_strncasecmp(const char *s1, const char *s2, size_t n)
347189251Ssam{
348189251Ssam	/*
349189251Ssam	 * Ignoring case is not required for main functionality, so just use
350189251Ssam	 * the case sensitive version of the function.
351189251Ssam	 */
352189251Ssam	return os_strncmp(s1, s2, n);
353189251Ssam}
354189251Ssam
355189251Ssam
356189251Ssamchar * os_strchr(const char *s, int c)
357189251Ssam{
358189251Ssam	while (*s) {
359189251Ssam		if (*s == c)
360189251Ssam			return (char *) s;
361189251Ssam		s++;
362189251Ssam	}
363189251Ssam	return NULL;
364189251Ssam}
365189251Ssam
366189251Ssam
367189251Ssamchar * os_strrchr(const char *s, int c)
368189251Ssam{
369189251Ssam	const char *p = s;
370189251Ssam	while (*p)
371189251Ssam		p++;
372189251Ssam	p--;
373189251Ssam	while (p >= s) {
374189251Ssam		if (*p == c)
375189251Ssam			return (char *) p;
376189251Ssam		p--;
377189251Ssam	}
378189251Ssam	return NULL;
379189251Ssam}
380189251Ssam
381189251Ssam
382189251Ssamint os_strcmp(const char *s1, const char *s2)
383189251Ssam{
384189251Ssam	while (*s1 == *s2) {
385189251Ssam		if (*s1 == '\0')
386189251Ssam			break;
387189251Ssam		s1++;
388189251Ssam		s2++;
389189251Ssam	}
390189251Ssam
391189251Ssam	return *s1 - *s2;
392189251Ssam}
393189251Ssam
394189251Ssam
395189251Ssamint os_strncmp(const char *s1, const char *s2, size_t n)
396189251Ssam{
397189251Ssam	if (n == 0)
398189251Ssam		return 0;
399189251Ssam
400189251Ssam	while (*s1 == *s2) {
401189251Ssam		if (*s1 == '\0')
402189251Ssam			break;
403189251Ssam		s1++;
404189251Ssam		s2++;
405189251Ssam		n--;
406189251Ssam		if (n == 0)
407189251Ssam			return 0;
408189251Ssam	}
409189251Ssam
410189251Ssam	return *s1 - *s2;
411189251Ssam}
412189251Ssam
413189251Ssam
414189251Ssamchar * os_strncpy(char *dest, const char *src, size_t n)
415189251Ssam{
416189251Ssam	char *d = dest;
417189251Ssam
418189251Ssam	while (n--) {
419189251Ssam		*d = *src;
420189251Ssam		if (*src == '\0')
421189251Ssam			break;
422189251Ssam		d++;
423189251Ssam		src++;
424189251Ssam	}
425189251Ssam
426189251Ssam	return dest;
427189251Ssam}
428189251Ssam
429189251Ssam
430189251Ssamsize_t os_strlcpy(char *dest, const char *src, size_t siz)
431189251Ssam{
432189251Ssam	const char *s = src;
433189251Ssam	size_t left = siz;
434189251Ssam
435189251Ssam	if (left) {
436189251Ssam		/* Copy string up to the maximum size of the dest buffer */
437189251Ssam		while (--left != 0) {
438189251Ssam			if ((*dest++ = *s++) == '\0')
439189251Ssam				break;
440189251Ssam		}
441189251Ssam	}
442189251Ssam
443189251Ssam	if (left == 0) {
444189251Ssam		/* Not enough room for the string; force NUL-termination */
445189251Ssam		if (siz != 0)
446189251Ssam			*dest = '\0';
447189251Ssam		while (*s++)
448189251Ssam			; /* determine total src string length */
449189251Ssam	}
450189251Ssam
451189251Ssam	return s - src - 1;
452189251Ssam}
453189251Ssam
454189251Ssam
455189251Ssamchar * os_strstr(const char *haystack, const char *needle)
456189251Ssam{
457189251Ssam	size_t len = os_strlen(needle);
458189251Ssam	while (*haystack) {
459189251Ssam		if (os_strncmp(haystack, needle, len) == 0)
460189251Ssam			return (char *) haystack;
461189251Ssam		haystack++;
462189251Ssam	}
463189251Ssam
464189251Ssam	return NULL;
465189251Ssam}
466189251Ssam
467189251Ssam
468189251Ssamint os_snprintf(char *str, size_t size, const char *format, ...)
469189251Ssam{
470189251Ssam	va_list ap;
471189251Ssam	int ret;
472189251Ssam
473189251Ssam	/* See http://www.ijs.si/software/snprintf/ for portable
474189251Ssam	 * implementation of snprintf.
475189251Ssam	 */
476189251Ssam
477189251Ssam	va_start(ap, format);
478189251Ssam	ret = vsnprintf(str, size, format, ap);
479189251Ssam	va_end(ap);
480189251Ssam	if (size > 0)
481189251Ssam		str[size - 1] = '\0';
482189251Ssam	return ret;
483189251Ssam}
484