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