]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/wpa/src/utils/os_unix.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 int os_daemonize(const char *pid_file)
157 {
158 #if defined(__uClinux__) || defined(__sun__)
159         return -1;
160 #else /* defined(__uClinux__) || defined(__sun__) */
161         if (os_daemon(0, 0)) {
162                 perror("daemon");
163                 return -1;
164         }
165
166         if (pid_file) {
167                 FILE *f = fopen(pid_file, "w");
168                 if (f) {
169                         fprintf(f, "%u\n", getpid());
170                         fclose(f);
171                 }
172         }
173
174         return -0;
175 #endif /* defined(__uClinux__) || defined(__sun__) */
176 }
177
178
179 void os_daemonize_terminate(const char *pid_file)
180 {
181         if (pid_file)
182                 unlink(pid_file);
183 }
184
185
186 int os_get_random(unsigned char *buf, size_t len)
187 {
188         FILE *f;
189         size_t rc;
190
191         f = fopen("/dev/urandom", "rb");
192         if (f == NULL) {
193                 printf("Could not open /dev/urandom.\n");
194                 return -1;
195         }
196
197         rc = fread(buf, 1, len, f);
198         fclose(f);
199
200         return rc != len ? -1 : 0;
201 }
202
203
204 unsigned long os_random(void)
205 {
206         return random();
207 }
208
209
210 char * os_rel2abs_path(const char *rel_path)
211 {
212         char *buf = NULL, *cwd, *ret;
213         size_t len = 128, cwd_len, rel_len, ret_len;
214         int last_errno;
215
216         if (rel_path[0] == '/')
217                 return os_strdup(rel_path);
218
219         for (;;) {
220                 buf = os_malloc(len);
221                 if (buf == NULL)
222                         return NULL;
223                 cwd = getcwd(buf, len);
224                 if (cwd == NULL) {
225                         last_errno = errno;
226                         os_free(buf);
227                         if (last_errno != ERANGE)
228                                 return NULL;
229                         len *= 2;
230                         if (len > 2000)
231                                 return NULL;
232                 } else {
233                         buf[len - 1] = '\0';
234                         break;
235                 }
236         }
237
238         cwd_len = os_strlen(cwd);
239         rel_len = os_strlen(rel_path);
240         ret_len = cwd_len + 1 + rel_len + 1;
241         ret = os_malloc(ret_len);
242         if (ret) {
243                 os_memcpy(ret, cwd, cwd_len);
244                 ret[cwd_len] = '/';
245                 os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
246                 ret[ret_len - 1] = '\0';
247         }
248         os_free(buf);
249         return ret;
250 }
251
252
253 int os_program_init(void)
254 {
255 #ifdef ANDROID
256         /*
257          * We ignore errors here since errors are normal if we
258          * are already running as non-root.
259          */
260         gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
261         struct __user_cap_header_struct header;
262         struct __user_cap_data_struct cap;
263
264         setgroups(sizeof(groups)/sizeof(groups[0]), groups);
265
266         prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
267
268         setgid(AID_WIFI);
269         setuid(AID_WIFI);
270
271         header.version = _LINUX_CAPABILITY_VERSION;
272         header.pid = 0;
273         cap.effective = cap.permitted =
274                 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
275         cap.inheritable = 0;
276         capset(&header, &cap);
277 #endif /* ANDROID */
278
279 #ifdef WPA_TRACE
280         dl_list_init(&alloc_list);
281 #endif /* WPA_TRACE */
282         return 0;
283 }
284
285
286 void os_program_deinit(void)
287 {
288 #ifdef WPA_TRACE
289         struct os_alloc_trace *a;
290         unsigned long total = 0;
291         dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
292                 total += a->len;
293                 if (a->magic != ALLOC_MAGIC) {
294                         wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
295                                    "len %lu",
296                                    a, a->magic, (unsigned long) a->len);
297                         continue;
298                 }
299                 wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
300                            a, (unsigned long) a->len);
301                 wpa_trace_dump("memleak", a);
302         }
303         if (total)
304                 wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
305                            (unsigned long) total);
306 #endif /* WPA_TRACE */
307 }
308
309
310 int os_setenv(const char *name, const char *value, int overwrite)
311 {
312         return setenv(name, value, overwrite);
313 }
314
315
316 int os_unsetenv(const char *name)
317 {
318 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
319     defined(__OpenBSD__)
320         unsetenv(name);
321         return 0;
322 #else
323         return unsetenv(name);
324 #endif
325 }
326
327
328 char * os_readfile(const char *name, size_t *len)
329 {
330         FILE *f;
331         char *buf;
332         long pos;
333
334         f = fopen(name, "rb");
335         if (f == NULL)
336                 return NULL;
337
338         if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
339                 fclose(f);
340                 return NULL;
341         }
342         *len = pos;
343         if (fseek(f, 0, SEEK_SET) < 0) {
344                 fclose(f);
345                 return NULL;
346         }
347
348         buf = os_malloc(*len);
349         if (buf == NULL) {
350                 fclose(f);
351                 return NULL;
352         }
353
354         if (fread(buf, 1, *len, f) != *len) {
355                 fclose(f);
356                 os_free(buf);
357                 return NULL;
358         }
359
360         fclose(f);
361
362         return buf;
363 }
364
365
366 #ifndef WPA_TRACE
367 void * os_zalloc(size_t size)
368 {
369         return calloc(1, size);
370 }
371 #endif /* WPA_TRACE */
372
373
374 size_t os_strlcpy(char *dest, const char *src, size_t siz)
375 {
376         const char *s = src;
377         size_t left = siz;
378
379         if (left) {
380                 /* Copy string up to the maximum size of the dest buffer */
381                 while (--left != 0) {
382                         if ((*dest++ = *s++) == '\0')
383                                 break;
384                 }
385         }
386
387         if (left == 0) {
388                 /* Not enough room for the string; force NUL-termination */
389                 if (siz != 0)
390                         *dest = '\0';
391                 while (*s++)
392                         ; /* determine total src string length */
393         }
394
395         return s - src - 1;
396 }
397
398
399 #ifdef WPA_TRACE
400
401 void * os_malloc(size_t size)
402 {
403         struct os_alloc_trace *a;
404         a = malloc(sizeof(*a) + size);
405         if (a == NULL)
406                 return NULL;
407         a->magic = ALLOC_MAGIC;
408         dl_list_add(&alloc_list, &a->list);
409         a->len = size;
410         wpa_trace_record(a);
411         return a + 1;
412 }
413
414
415 void * os_realloc(void *ptr, size_t size)
416 {
417         struct os_alloc_trace *a;
418         size_t copy_len;
419         void *n;
420
421         if (ptr == NULL)
422                 return os_malloc(size);
423
424         a = (struct os_alloc_trace *) ptr - 1;
425         if (a->magic != ALLOC_MAGIC) {
426                 wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
427                            a, a->magic,
428                            a->magic == FREED_MAGIC ? " (already freed)" : "");
429                 wpa_trace_show("Invalid os_realloc() call");
430                 abort();
431         }
432         n = os_malloc(size);
433         if (n == NULL)
434                 return NULL;
435         copy_len = a->len;
436         if (copy_len > size)
437                 copy_len = size;
438         os_memcpy(n, a + 1, copy_len);
439         os_free(ptr);
440         return n;
441 }
442
443
444 void os_free(void *ptr)
445 {
446         struct os_alloc_trace *a;
447
448         if (ptr == NULL)
449                 return;
450         a = (struct os_alloc_trace *) ptr - 1;
451         if (a->magic != ALLOC_MAGIC) {
452                 wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
453                            a, a->magic,
454                            a->magic == FREED_MAGIC ? " (already freed)" : "");
455                 wpa_trace_show("Invalid os_free() call");
456                 abort();
457         }
458         dl_list_del(&a->list);
459         a->magic = FREED_MAGIC;
460
461         wpa_trace_check_ref(ptr);
462         free(a);
463 }
464
465
466 void * os_zalloc(size_t size)
467 {
468         void *ptr = os_malloc(size);
469         if (ptr)
470                 os_memset(ptr, 0, size);
471         return ptr;
472 }
473
474
475 char * os_strdup(const char *s)
476 {
477         size_t len;
478         char *d;
479         len = os_strlen(s);
480         d = os_malloc(len + 1);
481         if (d == NULL)
482                 return NULL;
483         os_memcpy(d, s, len);
484         d[len] = '\0';
485         return d;
486 }
487
488 #endif /* WPA_TRACE */