1189251Ssam/*
2214734Srpaulo * OS specific functions for UNIX/POSIX systems
3214734Srpaulo * Copyright (c) 2005-2009, 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
15189251Ssam#include "includes.h"
16189251Ssam
17189251Ssam#include "os.h"
18189251Ssam
19214734Srpaulo#ifdef WPA_TRACE
20214734Srpaulo
21214734Srpaulo#include "common.h"
22214734Srpaulo#include "list.h"
23214734Srpaulo#include "wpa_debug.h"
24214734Srpaulo#include "trace.h"
25214734Srpaulo
26214734Srpaulostatic struct dl_list alloc_list;
27214734Srpaulo
28214734Srpaulo#define ALLOC_MAGIC 0xa84ef1b2
29214734Srpaulo#define FREED_MAGIC 0x67fd487a
30214734Srpaulo
31214734Srpaulostruct os_alloc_trace {
32214734Srpaulo	unsigned int magic;
33214734Srpaulo	struct dl_list list;
34214734Srpaulo	size_t len;
35214734Srpaulo	WPA_TRACE_INFO
36214734Srpaulo};
37214734Srpaulo
38214734Srpaulo#endif /* WPA_TRACE */
39214734Srpaulo
40214734Srpaulo
41189251Ssamvoid os_sleep(os_time_t sec, os_time_t usec)
42189251Ssam{
43189251Ssam	if (sec)
44189251Ssam		sleep(sec);
45189251Ssam	if (usec)
46189251Ssam		usleep(usec);
47189251Ssam}
48189251Ssam
49189251Ssam
50189251Ssamint os_get_time(struct os_time *t)
51189251Ssam{
52189251Ssam	int res;
53189251Ssam	struct timeval tv;
54189251Ssam	res = gettimeofday(&tv, NULL);
55189251Ssam	t->sec = tv.tv_sec;
56189251Ssam	t->usec = tv.tv_usec;
57189251Ssam	return res;
58189251Ssam}
59189251Ssam
60189251Ssam
61189251Ssamint os_mktime(int year, int month, int day, int hour, int min, int sec,
62189251Ssam	      os_time_t *t)
63189251Ssam{
64189251Ssam	struct tm tm, *tm1;
65189251Ssam	time_t t_local, t1, t2;
66189251Ssam	os_time_t tz_offset;
67189251Ssam
68189251Ssam	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
69189251Ssam	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
70189251Ssam	    sec > 60)
71189251Ssam		return -1;
72189251Ssam
73189251Ssam	memset(&tm, 0, sizeof(tm));
74189251Ssam	tm.tm_year = year - 1900;
75189251Ssam	tm.tm_mon = month - 1;
76189251Ssam	tm.tm_mday = day;
77189251Ssam	tm.tm_hour = hour;
78189251Ssam	tm.tm_min = min;
79189251Ssam	tm.tm_sec = sec;
80189251Ssam
81189251Ssam	t_local = mktime(&tm);
82189251Ssam
83189251Ssam	/* figure out offset to UTC */
84189251Ssam	tm1 = localtime(&t_local);
85189251Ssam	if (tm1) {
86189251Ssam		t1 = mktime(tm1);
87189251Ssam		tm1 = gmtime(&t_local);
88189251Ssam		if (tm1) {
89189251Ssam			t2 = mktime(tm1);
90189251Ssam			tz_offset = t2 - t1;
91189251Ssam		} else
92189251Ssam			tz_offset = 0;
93189251Ssam	} else
94189251Ssam		tz_offset = 0;
95189251Ssam
96189251Ssam	*t = (os_time_t) t_local - tz_offset;
97189251Ssam	return 0;
98189251Ssam}
99189251Ssam
100189251Ssam
101189251Ssam#ifdef __APPLE__
102189251Ssam#include <fcntl.h>
103189251Ssamstatic int os_daemon(int nochdir, int noclose)
104189251Ssam{
105189251Ssam	int devnull;
106189251Ssam
107189251Ssam	if (chdir("/") < 0)
108189251Ssam		return -1;
109189251Ssam
110189251Ssam	devnull = open("/dev/null", O_RDWR);
111189251Ssam	if (devnull < 0)
112189251Ssam		return -1;
113189251Ssam
114189251Ssam	if (dup2(devnull, STDIN_FILENO) < 0) {
115189251Ssam		close(devnull);
116189251Ssam		return -1;
117189251Ssam	}
118189251Ssam
119189251Ssam	if (dup2(devnull, STDOUT_FILENO) < 0) {
120189251Ssam		close(devnull);
121189251Ssam		return -1;
122189251Ssam	}
123189251Ssam
124189251Ssam	if (dup2(devnull, STDERR_FILENO) < 0) {
125189251Ssam		close(devnull);
126189251Ssam		return -1;
127189251Ssam	}
128189251Ssam
129189251Ssam	return 0;
130189251Ssam}
131189251Ssam#else /* __APPLE__ */
132189251Ssam#define os_daemon daemon
133189251Ssam#endif /* __APPLE__ */
134189251Ssam
135189251Ssam
136189251Ssamint os_daemonize(const char *pid_file)
137189251Ssam{
138189251Ssam#ifdef __uClinux__
139189251Ssam	return -1;
140189251Ssam#else /* __uClinux__ */
141189251Ssam	if (os_daemon(0, 0)) {
142189251Ssam		perror("daemon");
143189251Ssam		return -1;
144189251Ssam	}
145189251Ssam
146189251Ssam	if (pid_file) {
147189251Ssam		FILE *f = fopen(pid_file, "w");
148189251Ssam		if (f) {
149189251Ssam			fprintf(f, "%u\n", getpid());
150189251Ssam			fclose(f);
151189251Ssam		}
152189251Ssam	}
153189251Ssam
154189251Ssam	return -0;
155189251Ssam#endif /* __uClinux__ */
156189251Ssam}
157189251Ssam
158189251Ssam
159189251Ssamvoid os_daemonize_terminate(const char *pid_file)
160189251Ssam{
161189251Ssam	if (pid_file)
162189251Ssam		unlink(pid_file);
163189251Ssam}
164189251Ssam
165189251Ssam
166189251Ssamint os_get_random(unsigned char *buf, size_t len)
167189251Ssam{
168189251Ssam	FILE *f;
169189251Ssam	size_t rc;
170189251Ssam
171189251Ssam	f = fopen("/dev/urandom", "rb");
172189251Ssam	if (f == NULL) {
173189251Ssam		printf("Could not open /dev/urandom.\n");
174189251Ssam		return -1;
175189251Ssam	}
176189251Ssam
177189251Ssam	rc = fread(buf, 1, len, f);
178189251Ssam	fclose(f);
179189251Ssam
180189251Ssam	return rc != len ? -1 : 0;
181189251Ssam}
182189251Ssam
183189251Ssam
184189251Ssamunsigned long os_random(void)
185189251Ssam{
186189251Ssam	return random();
187189251Ssam}
188189251Ssam
189189251Ssam
190189251Ssamchar * os_rel2abs_path(const char *rel_path)
191189251Ssam{
192189251Ssam	char *buf = NULL, *cwd, *ret;
193189251Ssam	size_t len = 128, cwd_len, rel_len, ret_len;
194189251Ssam	int last_errno;
195189251Ssam
196189251Ssam	if (rel_path[0] == '/')
197214734Srpaulo		return os_strdup(rel_path);
198189251Ssam
199189251Ssam	for (;;) {
200214734Srpaulo		buf = os_malloc(len);
201189251Ssam		if (buf == NULL)
202189251Ssam			return NULL;
203189251Ssam		cwd = getcwd(buf, len);
204189251Ssam		if (cwd == NULL) {
205189251Ssam			last_errno = errno;
206214734Srpaulo			os_free(buf);
207189251Ssam			if (last_errno != ERANGE)
208189251Ssam				return NULL;
209189251Ssam			len *= 2;
210189251Ssam			if (len > 2000)
211189251Ssam				return NULL;
212189251Ssam		} else {
213189251Ssam			buf[len - 1] = '\0';
214189251Ssam			break;
215189251Ssam		}
216189251Ssam	}
217189251Ssam
218214734Srpaulo	cwd_len = os_strlen(cwd);
219214734Srpaulo	rel_len = os_strlen(rel_path);
220189251Ssam	ret_len = cwd_len + 1 + rel_len + 1;
221214734Srpaulo	ret = os_malloc(ret_len);
222189251Ssam	if (ret) {
223214734Srpaulo		os_memcpy(ret, cwd, cwd_len);
224189251Ssam		ret[cwd_len] = '/';
225214734Srpaulo		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
226189251Ssam		ret[ret_len - 1] = '\0';
227189251Ssam	}
228214734Srpaulo	os_free(buf);
229189251Ssam	return ret;
230189251Ssam}
231189251Ssam
232189251Ssam
233189251Ssamint os_program_init(void)
234189251Ssam{
235214734Srpaulo#ifdef WPA_TRACE
236214734Srpaulo	dl_list_init(&alloc_list);
237214734Srpaulo#endif /* WPA_TRACE */
238189251Ssam	return 0;
239189251Ssam}
240189251Ssam
241189251Ssam
242189251Ssamvoid os_program_deinit(void)
243189251Ssam{
244214734Srpaulo#ifdef WPA_TRACE
245214734Srpaulo	struct os_alloc_trace *a;
246214734Srpaulo	unsigned long total = 0;
247214734Srpaulo	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
248214734Srpaulo		total += a->len;
249214734Srpaulo		if (a->magic != ALLOC_MAGIC) {
250214734Srpaulo			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
251214734Srpaulo				   "len %lu",
252214734Srpaulo				   a, a->magic, (unsigned long) a->len);
253214734Srpaulo			continue;
254214734Srpaulo		}
255214734Srpaulo		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
256214734Srpaulo			   a, (unsigned long) a->len);
257214734Srpaulo		wpa_trace_dump("memleak", a);
258214734Srpaulo	}
259214734Srpaulo	if (total)
260214734Srpaulo		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
261214734Srpaulo			   (unsigned long) total);
262214734Srpaulo#endif /* WPA_TRACE */
263189251Ssam}
264189251Ssam
265189251Ssam
266189251Ssamint os_setenv(const char *name, const char *value, int overwrite)
267189251Ssam{
268189251Ssam	return setenv(name, value, overwrite);
269189251Ssam}
270189251Ssam
271189251Ssam
272189251Ssamint os_unsetenv(const char *name)
273189251Ssam{
274209158Srpaulo#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
275209158Srpaulo    defined(__OpenBSD__)
276189251Ssam	unsetenv(name);
277189251Ssam	return 0;
278189251Ssam#else
279189251Ssam	return unsetenv(name);
280189251Ssam#endif
281189251Ssam}
282189251Ssam
283189251Ssam
284189251Ssamchar * os_readfile(const char *name, size_t *len)
285189251Ssam{
286189251Ssam	FILE *f;
287189251Ssam	char *buf;
288189251Ssam
289189251Ssam	f = fopen(name, "rb");
290189251Ssam	if (f == NULL)
291189251Ssam		return NULL;
292189251Ssam
293189251Ssam	fseek(f, 0, SEEK_END);
294189251Ssam	*len = ftell(f);
295189251Ssam	fseek(f, 0, SEEK_SET);
296189251Ssam
297214734Srpaulo	buf = os_malloc(*len);
298189251Ssam	if (buf == NULL) {
299189251Ssam		fclose(f);
300189251Ssam		return NULL;
301189251Ssam	}
302189251Ssam
303189251Ssam	if (fread(buf, 1, *len, f) != *len) {
304189251Ssam		fclose(f);
305214734Srpaulo		os_free(buf);
306189251Ssam		return NULL;
307189251Ssam	}
308189251Ssam
309189251Ssam	fclose(f);
310189251Ssam
311189251Ssam	return buf;
312189251Ssam}
313189251Ssam
314189251Ssam
315214734Srpaulo#ifndef WPA_TRACE
316189251Ssamvoid * os_zalloc(size_t size)
317189251Ssam{
318189251Ssam	return calloc(1, size);
319189251Ssam}
320214734Srpaulo#endif /* WPA_TRACE */
321189251Ssam
322189251Ssam
323189251Ssamsize_t os_strlcpy(char *dest, const char *src, size_t siz)
324189251Ssam{
325189251Ssam	const char *s = src;
326189251Ssam	size_t left = siz;
327189251Ssam
328189251Ssam	if (left) {
329189251Ssam		/* Copy string up to the maximum size of the dest buffer */
330189251Ssam		while (--left != 0) {
331189251Ssam			if ((*dest++ = *s++) == '\0')
332189251Ssam				break;
333189251Ssam		}
334189251Ssam	}
335189251Ssam
336189251Ssam	if (left == 0) {
337189251Ssam		/* Not enough room for the string; force NUL-termination */
338189251Ssam		if (siz != 0)
339189251Ssam			*dest = '\0';
340189251Ssam		while (*s++)
341189251Ssam			; /* determine total src string length */
342189251Ssam	}
343189251Ssam
344189251Ssam	return s - src - 1;
345189251Ssam}
346214734Srpaulo
347214734Srpaulo
348214734Srpaulo#ifdef WPA_TRACE
349214734Srpaulo
350214734Srpaulovoid * os_malloc(size_t size)
351214734Srpaulo{
352214734Srpaulo	struct os_alloc_trace *a;
353214734Srpaulo	a = malloc(sizeof(*a) + size);
354214734Srpaulo	if (a == NULL)
355214734Srpaulo		return NULL;
356214734Srpaulo	a->magic = ALLOC_MAGIC;
357214734Srpaulo	dl_list_add(&alloc_list, &a->list);
358214734Srpaulo	a->len = size;
359214734Srpaulo	wpa_trace_record(a);
360214734Srpaulo	return a + 1;
361214734Srpaulo}
362214734Srpaulo
363214734Srpaulo
364214734Srpaulovoid * os_realloc(void *ptr, size_t size)
365214734Srpaulo{
366214734Srpaulo	struct os_alloc_trace *a;
367214734Srpaulo	size_t copy_len;
368214734Srpaulo	void *n;
369214734Srpaulo
370214734Srpaulo	if (ptr == NULL)
371214734Srpaulo		return os_malloc(size);
372214734Srpaulo
373214734Srpaulo	a = (struct os_alloc_trace *) ptr - 1;
374214734Srpaulo	if (a->magic != ALLOC_MAGIC) {
375214734Srpaulo		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
376214734Srpaulo			   a, a->magic,
377214734Srpaulo			   a->magic == FREED_MAGIC ? " (already freed)" : "");
378214734Srpaulo		wpa_trace_show("Invalid os_realloc() call");
379214734Srpaulo		abort();
380214734Srpaulo	}
381214734Srpaulo	n = os_malloc(size);
382214734Srpaulo	if (n == NULL)
383214734Srpaulo		return NULL;
384214734Srpaulo	copy_len = a->len;
385214734Srpaulo	if (copy_len > size)
386214734Srpaulo		copy_len = size;
387214734Srpaulo	os_memcpy(n, a + 1, copy_len);
388214734Srpaulo	os_free(ptr);
389214734Srpaulo	return n;
390214734Srpaulo}
391214734Srpaulo
392214734Srpaulo
393214734Srpaulovoid os_free(void *ptr)
394214734Srpaulo{
395214734Srpaulo	struct os_alloc_trace *a;
396214734Srpaulo
397214734Srpaulo	if (ptr == NULL)
398214734Srpaulo		return;
399214734Srpaulo	a = (struct os_alloc_trace *) ptr - 1;
400214734Srpaulo	if (a->magic != ALLOC_MAGIC) {
401214734Srpaulo		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
402214734Srpaulo			   a, a->magic,
403214734Srpaulo			   a->magic == FREED_MAGIC ? " (already freed)" : "");
404214734Srpaulo		wpa_trace_show("Invalid os_free() call");
405214734Srpaulo		abort();
406214734Srpaulo	}
407214734Srpaulo	dl_list_del(&a->list);
408214734Srpaulo	a->magic = FREED_MAGIC;
409214734Srpaulo
410214734Srpaulo	wpa_trace_check_ref(ptr);
411214734Srpaulo	free(a);
412214734Srpaulo}
413214734Srpaulo
414214734Srpaulo
415214734Srpaulovoid * os_zalloc(size_t size)
416214734Srpaulo{
417214734Srpaulo	void *ptr = os_malloc(size);
418214734Srpaulo	if (ptr)
419214734Srpaulo		os_memset(ptr, 0, size);
420214734Srpaulo	return ptr;
421214734Srpaulo}
422214734Srpaulo
423214734Srpaulo
424214734Srpaulochar * os_strdup(const char *s)
425214734Srpaulo{
426214734Srpaulo	size_t len;
427214734Srpaulo	char *d;
428214734Srpaulo	len = os_strlen(s);
429214734Srpaulo	d = os_malloc(len + 1);
430214734Srpaulo	if (d == NULL)
431214734Srpaulo		return NULL;
432214734Srpaulo	os_memcpy(d, s, len);
433214734Srpaulo	d[len] = '\0';
434214734Srpaulo	return d;
435214734Srpaulo}
436214734Srpaulo
437214734Srpaulo#endif /* WPA_TRACE */
438