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