xref: /freebsd/contrib/wpa/src/utils/os_unix.c (revision 6472ac3d8a86336899b6cfb789a4cd9897e3fab5)
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 
26 static struct dl_list alloc_list;
27 
28 #define ALLOC_MAGIC 0xa84ef1b2
29 #define FREED_MAGIC 0x67fd487a
30 
31 struct 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 
41 void 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 
50 int 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 
61 int 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>
103 static 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 
136 int 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 
159 void os_daemonize_terminate(const char *pid_file)
160 {
161 	if (pid_file)
162 		unlink(pid_file);
163 }
164 
165 
166 int 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 
184 unsigned long os_random(void)
185 {
186 	return random();
187 }
188 
189 
190 char * 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 
233 int 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 
242 void 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 
266 int os_setenv(const char *name, const char *value, int overwrite)
267 {
268 	return setenv(name, value, overwrite);
269 }
270 
271 
272 int 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 
284 char * 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
316 void * os_zalloc(size_t size)
317 {
318 	return calloc(1, size);
319 }
320 #endif /* WPA_TRACE */
321 
322 
323 size_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 
350 void * 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 
364 void * 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 
393 void 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 
415 void * 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 
424 char * 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