1/*
2 * OS specific functions for UNIX/POSIX systems
3 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "os.h"
18
19#ifdef WPA_TRACE
20
21#include "common.h"
22#include "list.h"
23#include "wpa_debug.h"
24#include "trace.h"
25
26static struct dl_list alloc_list;
27
28#define ALLOC_MAGIC 0xa84ef1b2
29#define FREED_MAGIC 0x67fd487a
30
31struct os_alloc_trace {
32	unsigned int magic;
33	struct dl_list list;
34	size_t len;
35	WPA_TRACE_INFO
36};
37
38#endif /* WPA_TRACE */
39
40
41void os_sleep(os_time_t sec, os_time_t usec)
42{
43	if (sec)
44		sleep(sec);
45	if (usec)
46		usleep(usec);
47}
48
49
50int os_get_time(struct os_time *t)
51{
52	int res;
53	struct timeval tv;
54	res = gettimeofday(&tv, NULL);
55	t->sec = tv.tv_sec;
56	t->usec = tv.tv_usec;
57	return res;
58}
59
60
61int os_mktime(int year, int month, int day, int hour, int min, int sec,
62	      os_time_t *t)
63{
64	struct tm tm, *tm1;
65	time_t t_local, t1, t2;
66	os_time_t tz_offset;
67
68	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
69	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
70	    sec > 60)
71		return -1;
72
73	memset(&tm, 0, sizeof(tm));
74	tm.tm_year = year - 1900;
75	tm.tm_mon = month - 1;
76	tm.tm_mday = day;
77	tm.tm_hour = hour;
78	tm.tm_min = min;
79	tm.tm_sec = sec;
80
81	t_local = mktime(&tm);
82
83	/* figure out offset to UTC */
84	tm1 = localtime(&t_local);
85	if (tm1) {
86		t1 = mktime(tm1);
87		tm1 = gmtime(&t_local);
88		if (tm1) {
89			t2 = mktime(tm1);
90			tz_offset = t2 - t1;
91		} else
92			tz_offset = 0;
93	} else
94		tz_offset = 0;
95
96	*t = (os_time_t) t_local - tz_offset;
97	return 0;
98}
99
100
101#ifdef __APPLE__
102#include <fcntl.h>
103static int os_daemon(int nochdir, int noclose)
104{
105	int devnull;
106
107	if (chdir("/") < 0)
108		return -1;
109
110	devnull = open("/dev/null", O_RDWR);
111	if (devnull < 0)
112		return -1;
113
114	if (dup2(devnull, STDIN_FILENO) < 0) {
115		close(devnull);
116		return -1;
117	}
118
119	if (dup2(devnull, STDOUT_FILENO) < 0) {
120		close(devnull);
121		return -1;
122	}
123
124	if (dup2(devnull, STDERR_FILENO) < 0) {
125		close(devnull);
126		return -1;
127	}
128
129	return 0;
130}
131#else /* __APPLE__ */
132#define os_daemon daemon
133#endif /* __APPLE__ */
134
135
136int os_daemonize(const char *pid_file)
137{
138#ifdef __uClinux__
139	return -1;
140#else /* __uClinux__ */
141	if (os_daemon(0, 0)) {
142		perror("daemon");
143		return -1;
144	}
145
146	if (pid_file) {
147		FILE *f = fopen(pid_file, "w");
148		if (f) {
149			fprintf(f, "%u\n", getpid());
150			fclose(f);
151		}
152	}
153
154	return -0;
155#endif /* __uClinux__ */
156}
157
158
159void os_daemonize_terminate(const char *pid_file)
160{
161	if (pid_file)
162		unlink(pid_file);
163}
164
165
166int os_get_random(unsigned char *buf, size_t len)
167{
168	FILE *f;
169	size_t rc;
170
171	f = fopen("/dev/urandom", "rb");
172	if (f == NULL) {
173		printf("Could not open /dev/urandom.\n");
174		return -1;
175	}
176
177	rc = fread(buf, 1, len, f);
178	fclose(f);
179
180	return rc != len ? -1 : 0;
181}
182
183
184unsigned long os_random(void)
185{
186	return random();
187}
188
189
190char * os_rel2abs_path(const char *rel_path)
191{
192	char *buf = NULL, *cwd, *ret;
193	size_t len = 128, cwd_len, rel_len, ret_len;
194	int last_errno;
195
196	if (rel_path[0] == '/')
197		return os_strdup(rel_path);
198
199	for (;;) {
200		buf = os_malloc(len);
201		if (buf == NULL)
202			return NULL;
203		cwd = getcwd(buf, len);
204		if (cwd == NULL) {
205			last_errno = errno;
206			os_free(buf);
207			if (last_errno != ERANGE)
208				return NULL;
209			len *= 2;
210			if (len > 2000)
211				return NULL;
212		} else {
213			buf[len - 1] = '\0';
214			break;
215		}
216	}
217
218	cwd_len = os_strlen(cwd);
219	rel_len = os_strlen(rel_path);
220	ret_len = cwd_len + 1 + rel_len + 1;
221	ret = os_malloc(ret_len);
222	if (ret) {
223		os_memcpy(ret, cwd, cwd_len);
224		ret[cwd_len] = '/';
225		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
226		ret[ret_len - 1] = '\0';
227	}
228	os_free(buf);
229	return ret;
230}
231
232
233int os_program_init(void)
234{
235#ifdef WPA_TRACE
236	dl_list_init(&alloc_list);
237#endif /* WPA_TRACE */
238	return 0;
239}
240
241
242void os_program_deinit(void)
243{
244#ifdef WPA_TRACE
245	struct os_alloc_trace *a;
246	unsigned long total = 0;
247	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
248		total += a->len;
249		if (a->magic != ALLOC_MAGIC) {
250			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
251				   "len %lu",
252				   a, a->magic, (unsigned long) a->len);
253			continue;
254		}
255		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
256			   a, (unsigned long) a->len);
257		wpa_trace_dump("memleak", a);
258	}
259	if (total)
260		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
261			   (unsigned long) total);
262#endif /* WPA_TRACE */
263}
264
265
266int os_setenv(const char *name, const char *value, int overwrite)
267{
268	return setenv(name, value, overwrite);
269}
270
271
272int os_unsetenv(const char *name)
273{
274#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
275    defined(__OpenBSD__)
276	unsetenv(name);
277	return 0;
278#else
279	return unsetenv(name);
280#endif
281}
282
283
284char * os_readfile(const char *name, size_t *len)
285{
286	FILE *f;
287	char *buf;
288
289	f = fopen(name, "rb");
290	if (f == NULL)
291		return NULL;
292
293	fseek(f, 0, SEEK_END);
294	*len = ftell(f);
295	fseek(f, 0, SEEK_SET);
296
297	buf = os_malloc(*len);
298	if (buf == NULL) {
299		fclose(f);
300		return NULL;
301	}
302
303	if (fread(buf, 1, *len, f) != *len) {
304		fclose(f);
305		os_free(buf);
306		return NULL;
307	}
308
309	fclose(f);
310
311	return buf;
312}
313
314
315#ifndef WPA_TRACE
316void * os_zalloc(size_t size)
317{
318	return calloc(1, size);
319}
320#endif /* WPA_TRACE */
321
322
323size_t os_strlcpy(char *dest, const char *src, size_t siz)
324{
325	const char *s = src;
326	size_t left = siz;
327
328	if (left) {
329		/* Copy string up to the maximum size of the dest buffer */
330		while (--left != 0) {
331			if ((*dest++ = *s++) == '\0')
332				break;
333		}
334	}
335
336	if (left == 0) {
337		/* Not enough room for the string; force NUL-termination */
338		if (siz != 0)
339			*dest = '\0';
340		while (*s++)
341			; /* determine total src string length */
342	}
343
344	return s - src - 1;
345}
346
347
348#ifdef WPA_TRACE
349
350void * os_malloc(size_t size)
351{
352	struct os_alloc_trace *a;
353	a = malloc(sizeof(*a) + size);
354	if (a == NULL)
355		return NULL;
356	a->magic = ALLOC_MAGIC;
357	dl_list_add(&alloc_list, &a->list);
358	a->len = size;
359	wpa_trace_record(a);
360	return a + 1;
361}
362
363
364void * os_realloc(void *ptr, size_t size)
365{
366	struct os_alloc_trace *a;
367	size_t copy_len;
368	void *n;
369
370	if (ptr == NULL)
371		return os_malloc(size);
372
373	a = (struct os_alloc_trace *) ptr - 1;
374	if (a->magic != ALLOC_MAGIC) {
375		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
376			   a, a->magic,
377			   a->magic == FREED_MAGIC ? " (already freed)" : "");
378		wpa_trace_show("Invalid os_realloc() call");
379		abort();
380	}
381	n = os_malloc(size);
382	if (n == NULL)
383		return NULL;
384	copy_len = a->len;
385	if (copy_len > size)
386		copy_len = size;
387	os_memcpy(n, a + 1, copy_len);
388	os_free(ptr);
389	return n;
390}
391
392
393void os_free(void *ptr)
394{
395	struct os_alloc_trace *a;
396
397	if (ptr == NULL)
398		return;
399	a = (struct os_alloc_trace *) ptr - 1;
400	if (a->magic != ALLOC_MAGIC) {
401		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
402			   a, a->magic,
403			   a->magic == FREED_MAGIC ? " (already freed)" : "");
404		wpa_trace_show("Invalid os_free() call");
405		abort();
406	}
407	dl_list_del(&a->list);
408	a->magic = FREED_MAGIC;
409
410	wpa_trace_check_ref(ptr);
411	free(a);
412}
413
414
415void * os_zalloc(size_t size)
416{
417	void *ptr = os_malloc(size);
418	if (ptr)
419		os_memset(ptr, 0, size);
420	return ptr;
421}
422
423
424char * os_strdup(const char *s)
425{
426	size_t len;
427	char *d;
428	len = os_strlen(s);
429	d = os_malloc(len + 1);
430	if (d == NULL)
431		return NULL;
432	os_memcpy(d, s, len);
433	d[len] = '\0';
434	return d;
435}
436
437#endif /* WPA_TRACE */
438