]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/utils/os_unix.c
MFV r324714:
[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         wpa_trace_deinit();
403 #endif /* WPA_TRACE */
404 }
405
406
407 int os_setenv(const char *name, const char *value, int overwrite)
408 {
409         return setenv(name, value, overwrite);
410 }
411
412
413 int os_unsetenv(const char *name)
414 {
415 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
416     defined(__OpenBSD__)
417         unsetenv(name);
418         return 0;
419 #else
420         return unsetenv(name);
421 #endif
422 }
423
424
425 char * os_readfile(const char *name, size_t *len)
426 {
427         FILE *f;
428         char *buf;
429         long pos;
430
431         f = fopen(name, "rb");
432         if (f == NULL)
433                 return NULL;
434
435         if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
436                 fclose(f);
437                 return NULL;
438         }
439         *len = pos;
440         if (fseek(f, 0, SEEK_SET) < 0) {
441                 fclose(f);
442                 return NULL;
443         }
444
445         buf = os_malloc(*len);
446         if (buf == NULL) {
447                 fclose(f);
448                 return NULL;
449         }
450
451         if (fread(buf, 1, *len, f) != *len) {
452                 fclose(f);
453                 os_free(buf);
454                 return NULL;
455         }
456
457         fclose(f);
458
459         return buf;
460 }
461
462
463 int os_file_exists(const char *fname)
464 {
465         return access(fname, F_OK) == 0;
466 }
467
468
469 int os_fdatasync(FILE *stream)
470 {
471         if (!fflush(stream)) {
472 #ifdef __linux__
473                 return fdatasync(fileno(stream));
474 #else /* !__linux__ */
475 #ifdef F_FULLFSYNC
476                 /* OS X does not implement fdatasync(). */
477                 return fcntl(fileno(stream), F_FULLFSYNC);
478 #else /* F_FULLFSYNC */
479                 return fsync(fileno(stream));
480 #endif /* F_FULLFSYNC */
481 #endif /* __linux__ */
482         }
483
484         return -1;
485 }
486
487
488 #ifndef WPA_TRACE
489 void * os_zalloc(size_t size)
490 {
491         return calloc(1, size);
492 }
493 #endif /* WPA_TRACE */
494
495
496 size_t os_strlcpy(char *dest, const char *src, size_t siz)
497 {
498         const char *s = src;
499         size_t left = siz;
500
501         if (left) {
502                 /* Copy string up to the maximum size of the dest buffer */
503                 while (--left != 0) {
504                         if ((*dest++ = *s++) == '\0')
505                                 break;
506                 }
507         }
508
509         if (left == 0) {
510                 /* Not enough room for the string; force NUL-termination */
511                 if (siz != 0)
512                         *dest = '\0';
513                 while (*s++)
514                         ; /* determine total src string length */
515         }
516
517         return s - src - 1;
518 }
519
520
521 int os_memcmp_const(const void *a, const void *b, size_t len)
522 {
523         const u8 *aa = a;
524         const u8 *bb = b;
525         size_t i;
526         u8 res;
527
528         for (res = 0, i = 0; i < len; i++)
529                 res |= aa[i] ^ bb[i];
530
531         return res;
532 }
533
534
535 #ifdef WPA_TRACE
536
537 #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
538 char wpa_trace_fail_func[256] = { 0 };
539 unsigned int wpa_trace_fail_after;
540
541 static int testing_fail_alloc(void)
542 {
543         const char *func[WPA_TRACE_LEN];
544         size_t i, res, len;
545         char *pos, *next;
546         int match;
547
548         if (!wpa_trace_fail_after)
549                 return 0;
550
551         res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
552         i = 0;
553         if (i < res && os_strcmp(func[i], __func__) == 0)
554                 i++;
555         if (i < res && os_strcmp(func[i], "os_malloc") == 0)
556                 i++;
557         if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
558                 i++;
559         if (i < res && os_strcmp(func[i], "os_calloc") == 0)
560                 i++;
561         if (i < res && os_strcmp(func[i], "os_realloc") == 0)
562                 i++;
563         if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
564                 i++;
565         if (i < res && os_strcmp(func[i], "os_strdup") == 0)
566                 i++;
567
568         pos = wpa_trace_fail_func;
569
570         match = 0;
571         while (i < res) {
572                 int allow_skip = 1;
573                 int maybe = 0;
574
575                 if (*pos == '=') {
576                         allow_skip = 0;
577                         pos++;
578                 } else if (*pos == '?') {
579                         maybe = 1;
580                         pos++;
581                 }
582                 next = os_strchr(pos, ';');
583                 if (next)
584                         len = next - pos;
585                 else
586                         len = os_strlen(pos);
587                 if (os_memcmp(pos, func[i], len) != 0) {
588                         if (maybe && next) {
589                                 pos = next + 1;
590                                 continue;
591                         }
592                         if (allow_skip) {
593                                 i++;
594                                 continue;
595                         }
596                         return 0;
597                 }
598                 if (!next) {
599                         match = 1;
600                         break;
601                 }
602                 pos = next + 1;
603                 i++;
604         }
605         if (!match)
606                 return 0;
607
608         wpa_trace_fail_after--;
609         if (wpa_trace_fail_after == 0) {
610                 wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
611                            wpa_trace_fail_func);
612                 for (i = 0; i < res; i++)
613                         wpa_printf(MSG_INFO, "backtrace[%d] = %s",
614                                    (int) i, func[i]);
615                 return 1;
616         }
617
618         return 0;
619 }
620
621
622 char wpa_trace_test_fail_func[256] = { 0 };
623 unsigned int wpa_trace_test_fail_after;
624
625 int testing_test_fail(void)
626 {
627         const char *func[WPA_TRACE_LEN];
628         size_t i, res, len;
629         char *pos, *next;
630         int match;
631
632         if (!wpa_trace_test_fail_after)
633                 return 0;
634
635         res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
636         i = 0;
637         if (i < res && os_strcmp(func[i], __func__) == 0)
638                 i++;
639
640         pos = wpa_trace_test_fail_func;
641
642         match = 0;
643         while (i < res) {
644                 int allow_skip = 1;
645                 int maybe = 0;
646
647                 if (*pos == '=') {
648                         allow_skip = 0;
649                         pos++;
650                 } else if (*pos == '?') {
651                         maybe = 1;
652                         pos++;
653                 }
654                 next = os_strchr(pos, ';');
655                 if (next)
656                         len = next - pos;
657                 else
658                         len = os_strlen(pos);
659                 if (os_memcmp(pos, func[i], len) != 0) {
660                         if (maybe && next) {
661                                 pos = next + 1;
662                                 continue;
663                         }
664                         if (allow_skip) {
665                                 i++;
666                                 continue;
667                         }
668                         return 0;
669                 }
670                 if (!next) {
671                         match = 1;
672                         break;
673                 }
674                 pos = next + 1;
675                 i++;
676         }
677         if (!match)
678                 return 0;
679
680         wpa_trace_test_fail_after--;
681         if (wpa_trace_test_fail_after == 0) {
682                 wpa_printf(MSG_INFO, "TESTING: fail at %s",
683                            wpa_trace_test_fail_func);
684                 for (i = 0; i < res; i++)
685                         wpa_printf(MSG_INFO, "backtrace[%d] = %s",
686                                    (int) i, func[i]);
687                 return 1;
688         }
689
690         return 0;
691 }
692
693 #else
694
695 static inline int testing_fail_alloc(void)
696 {
697         return 0;
698 }
699 #endif
700
701 void * os_malloc(size_t size)
702 {
703         struct os_alloc_trace *a;
704
705         if (testing_fail_alloc())
706                 return NULL;
707
708         a = malloc(sizeof(*a) + size);
709         if (a == NULL)
710                 return NULL;
711         a->magic = ALLOC_MAGIC;
712         dl_list_add(&alloc_list, &a->list);
713         a->len = size;
714         wpa_trace_record(a);
715         return a + 1;
716 }
717
718
719 void * os_realloc(void *ptr, size_t size)
720 {
721         struct os_alloc_trace *a;
722         size_t copy_len;
723         void *n;
724
725         if (ptr == NULL)
726                 return os_malloc(size);
727
728         a = (struct os_alloc_trace *) ptr - 1;
729         if (a->magic != ALLOC_MAGIC) {
730                 wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
731                            a, a->magic,
732                            a->magic == FREED_MAGIC ? " (already freed)" : "");
733                 wpa_trace_show("Invalid os_realloc() call");
734                 abort();
735         }
736         n = os_malloc(size);
737         if (n == NULL)
738                 return NULL;
739         copy_len = a->len;
740         if (copy_len > size)
741                 copy_len = size;
742         os_memcpy(n, a + 1, copy_len);
743         os_free(ptr);
744         return n;
745 }
746
747
748 void os_free(void *ptr)
749 {
750         struct os_alloc_trace *a;
751
752         if (ptr == NULL)
753                 return;
754         a = (struct os_alloc_trace *) ptr - 1;
755         if (a->magic != ALLOC_MAGIC) {
756                 wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
757                            a, a->magic,
758                            a->magic == FREED_MAGIC ? " (already freed)" : "");
759                 wpa_trace_show("Invalid os_free() call");
760                 abort();
761         }
762         dl_list_del(&a->list);
763         a->magic = FREED_MAGIC;
764
765         wpa_trace_check_ref(ptr);
766         free(a);
767 }
768
769
770 void * os_zalloc(size_t size)
771 {
772         void *ptr = os_malloc(size);
773         if (ptr)
774                 os_memset(ptr, 0, size);
775         return ptr;
776 }
777
778
779 char * os_strdup(const char *s)
780 {
781         size_t len;
782         char *d;
783         len = os_strlen(s);
784         d = os_malloc(len + 1);
785         if (d == NULL)
786                 return NULL;
787         os_memcpy(d, s, len);
788         d[len] = '\0';
789         return d;
790 }
791
792 #endif /* WPA_TRACE */
793
794
795 int os_exec(const char *program, const char *arg, int wait_completion)
796 {
797         pid_t pid;
798         int pid_status;
799
800         pid = fork();
801         if (pid < 0) {
802                 perror("fork");
803                 return -1;
804         }
805
806         if (pid == 0) {
807                 /* run the external command in the child process */
808                 const int MAX_ARG = 30;
809                 char *_program, *_arg, *pos;
810                 char *argv[MAX_ARG + 1];
811                 int i;
812
813                 _program = os_strdup(program);
814                 _arg = os_strdup(arg);
815
816                 argv[0] = _program;
817
818                 i = 1;
819                 pos = _arg;
820                 while (i < MAX_ARG && pos && *pos) {
821                         while (*pos == ' ')
822                                 pos++;
823                         if (*pos == '\0')
824                                 break;
825                         argv[i++] = pos;
826                         pos = os_strchr(pos, ' ');
827                         if (pos)
828                                 *pos++ = '\0';
829                 }
830                 argv[i] = NULL;
831
832                 execv(program, argv);
833                 perror("execv");
834                 os_free(_program);
835                 os_free(_arg);
836                 exit(0);
837                 return -1;
838         }
839
840         if (wait_completion) {
841                 /* wait for the child process to complete in the parent */
842                 waitpid(pid, &pid_status, 0);
843         }
844
845         return 0;
846 }