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