]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/utils/os_unix.c
Update libc++ to 3.8.0. Excerpted list of fixes (with upstream revision
[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 #include <sys/wait.h>
13
14 #ifdef ANDROID
15 #include <sys/capability.h>
16 #include <sys/prctl.h>
17 #include <private/android_filesystem_config.h>
18 #endif /* ANDROID */
19
20 #ifdef __MACH__
21 #include <CoreServices/CoreServices.h>
22 #include <mach/mach.h>
23 #include <mach/mach_time.h>
24 #endif /* __MACH__ */
25
26 #include "os.h"
27 #include "common.h"
28
29 #ifdef WPA_TRACE
30
31 #include "wpa_debug.h"
32 #include "trace.h"
33 #include "list.h"
34
35 static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
36
37 #define ALLOC_MAGIC 0xa84ef1b2
38 #define FREED_MAGIC 0x67fd487a
39
40 struct os_alloc_trace {
41         unsigned int magic;
42         struct dl_list list;
43         size_t len;
44         WPA_TRACE_INFO
45 } __attribute__((aligned(16)));
46
47 #endif /* WPA_TRACE */
48
49
50 void os_sleep(os_time_t sec, os_time_t usec)
51 {
52         if (sec)
53                 sleep(sec);
54         if (usec)
55                 usleep(usec);
56 }
57
58
59 int os_get_time(struct os_time *t)
60 {
61         int res;
62         struct timeval tv;
63         res = gettimeofday(&tv, NULL);
64         t->sec = tv.tv_sec;
65         t->usec = tv.tv_usec;
66         return res;
67 }
68
69
70 int os_get_reltime(struct os_reltime *t)
71 {
72 #ifndef __MACH__
73 #if defined(CLOCK_BOOTTIME)
74         static clockid_t clock_id = CLOCK_BOOTTIME;
75 #elif defined(CLOCK_MONOTONIC)
76         static clockid_t clock_id = CLOCK_MONOTONIC;
77 #else
78         static clockid_t clock_id = CLOCK_REALTIME;
79 #endif
80         struct timespec ts;
81         int res;
82
83         while (1) {
84                 res = clock_gettime(clock_id, &ts);
85                 if (res == 0) {
86                         t->sec = ts.tv_sec;
87                         t->usec = ts.tv_nsec / 1000;
88                         return 0;
89                 }
90                 switch (clock_id) {
91 #ifdef CLOCK_BOOTTIME
92                 case CLOCK_BOOTTIME:
93                         clock_id = CLOCK_MONOTONIC;
94                         break;
95 #endif
96 #ifdef CLOCK_MONOTONIC
97                 case CLOCK_MONOTONIC:
98                         clock_id = CLOCK_REALTIME;
99                         break;
100 #endif
101                 case CLOCK_REALTIME:
102                         return -1;
103                 }
104         }
105 #else /* __MACH__ */
106         uint64_t abstime, nano;
107         static mach_timebase_info_data_t info = { 0, 0 };
108
109         if (!info.denom) {
110                 if (mach_timebase_info(&info) != KERN_SUCCESS)
111                         return -1;
112         }
113
114         abstime = mach_absolute_time();
115         nano = (abstime * info.numer) / info.denom;
116
117         t->sec = nano / NSEC_PER_SEC;
118         t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
119
120         return 0;
121 #endif /* __MACH__ */
122 }
123
124
125 int os_mktime(int year, int month, int day, int hour, int min, int sec,
126               os_time_t *t)
127 {
128         struct tm tm, *tm1;
129         time_t t_local, t1, t2;
130         os_time_t tz_offset;
131
132         if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
133             hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
134             sec > 60)
135                 return -1;
136
137         memset(&tm, 0, sizeof(tm));
138         tm.tm_year = year - 1900;
139         tm.tm_mon = month - 1;
140         tm.tm_mday = day;
141         tm.tm_hour = hour;
142         tm.tm_min = min;
143         tm.tm_sec = sec;
144
145         t_local = mktime(&tm);
146
147         /* figure out offset to UTC */
148         tm1 = localtime(&t_local);
149         if (tm1) {
150                 t1 = mktime(tm1);
151                 tm1 = gmtime(&t_local);
152                 if (tm1) {
153                         t2 = mktime(tm1);
154                         tz_offset = t2 - t1;
155                 } else
156                         tz_offset = 0;
157         } else
158                 tz_offset = 0;
159
160         *t = (os_time_t) t_local - tz_offset;
161         return 0;
162 }
163
164
165 int os_gmtime(os_time_t t, struct os_tm *tm)
166 {
167         struct tm *tm2;
168         time_t t2 = t;
169
170         tm2 = gmtime(&t2);
171         if (tm2 == NULL)
172                 return -1;
173         tm->sec = tm2->tm_sec;
174         tm->min = tm2->tm_min;
175         tm->hour = tm2->tm_hour;
176         tm->day = tm2->tm_mday;
177         tm->month = tm2->tm_mon + 1;
178         tm->year = tm2->tm_year + 1900;
179         return 0;
180 }
181
182
183 #ifdef __APPLE__
184 #include <fcntl.h>
185 static int os_daemon(int nochdir, int noclose)
186 {
187         int devnull;
188
189         if (chdir("/") < 0)
190                 return -1;
191
192         devnull = open("/dev/null", O_RDWR);
193         if (devnull < 0)
194                 return -1;
195
196         if (dup2(devnull, STDIN_FILENO) < 0) {
197                 close(devnull);
198                 return -1;
199         }
200
201         if (dup2(devnull, STDOUT_FILENO) < 0) {
202                 close(devnull);
203                 return -1;
204         }
205
206         if (dup2(devnull, STDERR_FILENO) < 0) {
207                 close(devnull);
208                 return -1;
209         }
210
211         return 0;
212 }
213 #else /* __APPLE__ */
214 #define os_daemon daemon
215 #endif /* __APPLE__ */
216
217
218 #ifdef __FreeBSD__
219 #include <err.h>
220 #include <libutil.h>
221 #include <stdint.h>
222 #endif /* __FreeBSD__ */
223
224 int os_daemonize(const char *pid_file)
225 {
226 #if defined(__uClinux__) || defined(__sun__)
227         return -1;
228 #else /* defined(__uClinux__) || defined(__sun__) */
229 #ifdef __FreeBSD__
230         pid_t otherpid;
231         struct pidfh *pfh;
232
233         pfh = pidfile_open(pid_file, 0600, &otherpid);
234         if (pfh == NULL) {
235                 if (errno == EEXIST) {
236                         errx(1, "Daemon already running, pid: %jd.",
237                             (intmax_t)otherpid);
238                 }
239                 warn("Cannot open or create pidfile.");
240         }
241 #endif /* __FreeBSD__ */
242
243         if (os_daemon(0, 0)) {
244                 perror("daemon");
245 #ifdef __FreeBSD__
246                 pidfile_remove(pfh);
247 #endif /* __FreeBSD__ */
248                 return -1;
249         }
250
251 #ifndef __FreeBSD__
252         if (pid_file) {
253                 FILE *f = fopen(pid_file, "w");
254                 if (f) {
255                         fprintf(f, "%u\n", getpid());
256                         fclose(f);
257                 }
258         }
259 #else /* __FreeBSD__ */
260         pidfile_write(pfh);
261 #endif /* __FreeBSD__ */
262
263         return -0;
264 #endif /* defined(__uClinux__) || defined(__sun__) */
265 }
266
267
268 void os_daemonize_terminate(const char *pid_file)
269 {
270         if (pid_file)
271                 unlink(pid_file);
272 }
273
274
275 int os_get_random(unsigned char *buf, size_t len)
276 {
277         FILE *f;
278         size_t rc;
279
280         if (TEST_FAIL())
281                 return -1;
282
283         f = fopen("/dev/urandom", "rb");
284         if (f == NULL) {
285                 printf("Could not open /dev/urandom.\n");
286                 return -1;
287         }
288
289         rc = fread(buf, 1, len, f);
290         fclose(f);
291
292         return rc != len ? -1 : 0;
293 }
294
295
296 unsigned long os_random(void)
297 {
298         return random();
299 }
300
301
302 char * os_rel2abs_path(const char *rel_path)
303 {
304         char *buf = NULL, *cwd, *ret;
305         size_t len = 128, cwd_len, rel_len, ret_len;
306         int last_errno;
307
308         if (!rel_path)
309                 return NULL;
310
311         if (rel_path[0] == '/')
312                 return os_strdup(rel_path);
313
314         for (;;) {
315                 buf = os_malloc(len);
316                 if (buf == NULL)
317                         return NULL;
318                 cwd = getcwd(buf, len);
319                 if (cwd == NULL) {
320                         last_errno = errno;
321                         os_free(buf);
322                         if (last_errno != ERANGE)
323                                 return NULL;
324                         len *= 2;
325                         if (len > 2000)
326                                 return NULL;
327                 } else {
328                         buf[len - 1] = '\0';
329                         break;
330                 }
331         }
332
333         cwd_len = os_strlen(cwd);
334         rel_len = os_strlen(rel_path);
335         ret_len = cwd_len + 1 + rel_len + 1;
336         ret = os_malloc(ret_len);
337         if (ret) {
338                 os_memcpy(ret, cwd, cwd_len);
339                 ret[cwd_len] = '/';
340                 os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
341                 ret[ret_len - 1] = '\0';
342         }
343         os_free(buf);
344         return ret;
345 }
346
347
348 int os_program_init(void)
349 {
350 #ifdef ANDROID
351         /*
352          * We ignore errors here since errors are normal if we
353          * are already running as non-root.
354          */
355 #ifdef ANDROID_SETGROUPS_OVERRIDE
356         gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
357 #else /* ANDROID_SETGROUPS_OVERRIDE */
358         gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
359 #endif /* ANDROID_SETGROUPS_OVERRIDE */
360         struct __user_cap_header_struct header;
361         struct __user_cap_data_struct cap;
362
363         setgroups(ARRAY_SIZE(groups), groups);
364
365         prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
366
367         setgid(AID_WIFI);
368         setuid(AID_WIFI);
369
370         header.version = _LINUX_CAPABILITY_VERSION;
371         header.pid = 0;
372         cap.effective = cap.permitted =
373                 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
374         cap.inheritable = 0;
375         capset(&header, &cap);
376 #endif /* ANDROID */
377
378         return 0;
379 }
380
381
382 void os_program_deinit(void)
383 {
384 #ifdef WPA_TRACE
385         struct os_alloc_trace *a;
386         unsigned long total = 0;
387         dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
388                 total += a->len;
389                 if (a->magic != ALLOC_MAGIC) {
390                         wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
391                                    "len %lu",
392                                    a, a->magic, (unsigned long) a->len);
393                         continue;
394                 }
395                 wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
396                            a, (unsigned long) a->len);
397                 wpa_trace_dump("memleak", a);
398         }
399         if (total)
400                 wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
401                            (unsigned long) total);
402 #endif /* WPA_TRACE */
403 }
404
405
406 int os_setenv(const char *name, const char *value, int overwrite)
407 {
408         return setenv(name, value, overwrite);
409 }
410
411
412 int os_unsetenv(const char *name)
413 {
414 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
415     defined(__OpenBSD__)
416         unsetenv(name);
417         return 0;
418 #else
419         return unsetenv(name);
420 #endif
421 }
422
423
424 char * os_readfile(const char *name, size_t *len)
425 {
426         FILE *f;
427         char *buf;
428         long pos;
429
430         f = fopen(name, "rb");
431         if (f == NULL)
432                 return NULL;
433
434         if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
435                 fclose(f);
436                 return NULL;
437         }
438         *len = pos;
439         if (fseek(f, 0, SEEK_SET) < 0) {
440                 fclose(f);
441                 return NULL;
442         }
443
444         buf = os_malloc(*len);
445         if (buf == NULL) {
446                 fclose(f);
447                 return NULL;
448         }
449
450         if (fread(buf, 1, *len, f) != *len) {
451                 fclose(f);
452                 os_free(buf);
453                 return NULL;
454         }
455
456         fclose(f);
457
458         return buf;
459 }
460
461
462 int os_file_exists(const char *fname)
463 {
464         FILE *f = fopen(fname, "rb");
465         if (f == NULL)
466                 return 0;
467         fclose(f);
468         return 1;
469 }
470
471
472 int os_fdatasync(FILE *stream)
473 {
474         if (!fflush(stream)) {
475 #ifdef __linux__
476                 return fdatasync(fileno(stream));
477 #else /* !__linux__ */
478 #ifdef F_FULLFSYNC
479                 /* OS X does not implement fdatasync(). */
480                 return fcntl(fileno(stream), F_FULLFSYNC);
481 #else /* F_FULLFSYNC */
482                 return fsync(fileno(stream));
483 #endif /* F_FULLFSYNC */
484 #endif /* __linux__ */
485         }
486
487         return -1;
488 }
489
490
491 #ifndef WPA_TRACE
492 void * os_zalloc(size_t size)
493 {
494         return calloc(1, size);
495 }
496 #endif /* WPA_TRACE */
497
498
499 size_t os_strlcpy(char *dest, const char *src, size_t siz)
500 {
501         const char *s = src;
502         size_t left = siz;
503
504         if (left) {
505                 /* Copy string up to the maximum size of the dest buffer */
506                 while (--left != 0) {
507                         if ((*dest++ = *s++) == '\0')
508                                 break;
509                 }
510         }
511
512         if (left == 0) {
513                 /* Not enough room for the string; force NUL-termination */
514                 if (siz != 0)
515                         *dest = '\0';
516                 while (*s++)
517                         ; /* determine total src string length */
518         }
519
520         return s - src - 1;
521 }
522
523
524 int os_memcmp_const(const void *a, const void *b, size_t len)
525 {
526         const u8 *aa = a;
527         const u8 *bb = b;
528         size_t i;
529         u8 res;
530
531         for (res = 0, i = 0; i < len; i++)
532                 res |= aa[i] ^ bb[i];
533
534         return res;
535 }
536
537
538 #ifdef WPA_TRACE
539
540 #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
541 char wpa_trace_fail_func[256] = { 0 };
542 unsigned int wpa_trace_fail_after;
543
544 static int testing_fail_alloc(void)
545 {
546         const char *func[WPA_TRACE_LEN];
547         size_t i, res, len;
548         char *pos, *next;
549         int match;
550
551         if (!wpa_trace_fail_after)
552                 return 0;
553
554         res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
555         i = 0;
556         if (i < res && os_strcmp(func[i], __func__) == 0)
557                 i++;
558         if (i < res && os_strcmp(func[i], "os_malloc") == 0)
559                 i++;
560         if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
561                 i++;
562         if (i < res && os_strcmp(func[i], "os_calloc") == 0)
563                 i++;
564         if (i < res && os_strcmp(func[i], "os_realloc") == 0)
565                 i++;
566         if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
567                 i++;
568         if (i < res && os_strcmp(func[i], "os_strdup") == 0)
569                 i++;
570
571         pos = wpa_trace_fail_func;
572
573         match = 0;
574         while (i < res) {
575                 int allow_skip = 1;
576                 int maybe = 0;
577
578                 if (*pos == '=') {
579                         allow_skip = 0;
580                         pos++;
581                 } else if (*pos == '?') {
582                         maybe = 1;
583                         pos++;
584                 }
585                 next = os_strchr(pos, ';');
586                 if (next)
587                         len = next - pos;
588                 else
589                         len = os_strlen(pos);
590                 if (os_memcmp(pos, func[i], len) != 0) {
591                         if (maybe && next) {
592                                 pos = next + 1;
593                                 continue;
594                         }
595                         if (allow_skip) {
596                                 i++;
597                                 continue;
598                         }
599                         return 0;
600                 }
601                 if (!next) {
602                         match = 1;
603                         break;
604                 }
605                 pos = next + 1;
606                 i++;
607         }
608         if (!match)
609                 return 0;
610
611         wpa_trace_fail_after--;
612         if (wpa_trace_fail_after == 0) {
613                 wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
614                            wpa_trace_fail_func);
615                 for (i = 0; i < res; i++)
616                         wpa_printf(MSG_INFO, "backtrace[%d] = %s",
617                                    (int) i, func[i]);
618                 return 1;
619         }
620
621         return 0;
622 }
623
624
625 char wpa_trace_test_fail_func[256] = { 0 };
626 unsigned int wpa_trace_test_fail_after;
627
628 int testing_test_fail(void)
629 {
630         const char *func[WPA_TRACE_LEN];
631         size_t i, res, len;
632         char *pos, *next;
633         int match;
634
635         if (!wpa_trace_test_fail_after)
636                 return 0;
637
638         res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
639         i = 0;
640         if (i < res && os_strcmp(func[i], __func__) == 0)
641                 i++;
642
643         pos = wpa_trace_test_fail_func;
644
645         match = 0;
646         while (i < res) {
647                 int allow_skip = 1;
648                 int maybe = 0;
649
650                 if (*pos == '=') {
651                         allow_skip = 0;
652                         pos++;
653                 } else if (*pos == '?') {
654                         maybe = 1;
655                         pos++;
656                 }
657                 next = os_strchr(pos, ';');
658                 if (next)
659                         len = next - pos;
660                 else
661                         len = os_strlen(pos);
662                 if (os_memcmp(pos, func[i], len) != 0) {
663                         if (maybe && next) {
664                                 pos = next + 1;
665                                 continue;
666                         }
667                         if (allow_skip) {
668                                 i++;
669                                 continue;
670                         }
671                         return 0;
672                 }
673                 if (!next) {
674                         match = 1;
675                         break;
676                 }
677                 pos = next + 1;
678                 i++;
679         }
680         if (!match)
681                 return 0;
682
683         wpa_trace_test_fail_after--;
684         if (wpa_trace_test_fail_after == 0) {
685                 wpa_printf(MSG_INFO, "TESTING: fail at %s",
686                            wpa_trace_test_fail_func);
687                 for (i = 0; i < res; i++)
688                         wpa_printf(MSG_INFO, "backtrace[%d] = %s",
689                                    (int) i, func[i]);
690                 return 1;
691         }
692
693         return 0;
694 }
695
696 #else
697
698 static inline int testing_fail_alloc(void)
699 {
700         return 0;
701 }
702 #endif
703
704 void * os_malloc(size_t size)
705 {
706         struct os_alloc_trace *a;
707
708         if (testing_fail_alloc())
709                 return NULL;
710
711         a = malloc(sizeof(*a) + size);
712         if (a == NULL)
713                 return NULL;
714         a->magic = ALLOC_MAGIC;
715         dl_list_add(&alloc_list, &a->list);
716         a->len = size;
717         wpa_trace_record(a);
718         return a + 1;
719 }
720
721
722 void * os_realloc(void *ptr, size_t size)
723 {
724         struct os_alloc_trace *a;
725         size_t copy_len;
726         void *n;
727
728         if (ptr == NULL)
729                 return os_malloc(size);
730
731         a = (struct os_alloc_trace *) ptr - 1;
732         if (a->magic != ALLOC_MAGIC) {
733                 wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
734                            a, a->magic,
735                            a->magic == FREED_MAGIC ? " (already freed)" : "");
736                 wpa_trace_show("Invalid os_realloc() call");
737                 abort();
738         }
739         n = os_malloc(size);
740         if (n == NULL)
741                 return NULL;
742         copy_len = a->len;
743         if (copy_len > size)
744                 copy_len = size;
745         os_memcpy(n, a + 1, copy_len);
746         os_free(ptr);
747         return n;
748 }
749
750
751 void os_free(void *ptr)
752 {
753         struct os_alloc_trace *a;
754
755         if (ptr == NULL)
756                 return;
757         a = (struct os_alloc_trace *) ptr - 1;
758         if (a->magic != ALLOC_MAGIC) {
759                 wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
760                            a, a->magic,
761                            a->magic == FREED_MAGIC ? " (already freed)" : "");
762                 wpa_trace_show("Invalid os_free() call");
763                 abort();
764         }
765         dl_list_del(&a->list);
766         a->magic = FREED_MAGIC;
767
768         wpa_trace_check_ref(ptr);
769         free(a);
770 }
771
772
773 void * os_zalloc(size_t size)
774 {
775         void *ptr = os_malloc(size);
776         if (ptr)
777                 os_memset(ptr, 0, size);
778         return ptr;
779 }
780
781
782 char * os_strdup(const char *s)
783 {
784         size_t len;
785         char *d;
786         len = os_strlen(s);
787         d = os_malloc(len + 1);
788         if (d == NULL)
789                 return NULL;
790         os_memcpy(d, s, len);
791         d[len] = '\0';
792         return d;
793 }
794
795 #endif /* WPA_TRACE */
796
797
798 int os_exec(const char *program, const char *arg, int wait_completion)
799 {
800         pid_t pid;
801         int pid_status;
802
803         pid = fork();
804         if (pid < 0) {
805                 perror("fork");
806                 return -1;
807         }
808
809         if (pid == 0) {
810                 /* run the external command in the child process */
811                 const int MAX_ARG = 30;
812                 char *_program, *_arg, *pos;
813                 char *argv[MAX_ARG + 1];
814                 int i;
815
816                 _program = os_strdup(program);
817                 _arg = os_strdup(arg);
818
819                 argv[0] = _program;
820
821                 i = 1;
822                 pos = _arg;
823                 while (i < MAX_ARG && pos && *pos) {
824                         while (*pos == ' ')
825                                 pos++;
826                         if (*pos == '\0')
827                                 break;
828                         argv[i++] = pos;
829                         pos = os_strchr(pos, ' ');
830                         if (pos)
831                                 *pos++ = '\0';
832                 }
833                 argv[i] = NULL;
834
835                 execv(program, argv);
836                 perror("execv");
837                 os_free(_program);
838                 os_free(_arg);
839                 exit(0);
840                 return -1;
841         }
842
843         if (wait_completion) {
844                 /* wait for the child process to complete in the parent */
845                 waitpid(pid, &pid_status, 0);
846         }
847
848         return 0;
849 }