diff options
Diffstat (limited to 'src/utils/os_unix.c')
-rw-r--r-- | src/utils/os_unix.c | 232 |
1 files changed, 224 insertions, 8 deletions
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 23a93becea43..e0c1125d5305 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -9,23 +9,24 @@ #include "includes.h" #include <time.h> +#include <sys/wait.h> #ifdef ANDROID -#include <linux/capability.h> -#include <linux/prctl.h> +#include <sys/capability.h> +#include <sys/prctl.h> #include <private/android_filesystem_config.h> #endif /* ANDROID */ #include "os.h" +#include "common.h" #ifdef WPA_TRACE -#include "common.h" #include "wpa_debug.h" #include "trace.h" #include "list.h" -static struct dl_list alloc_list; +static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list); #define ALLOC_MAGIC 0xa84ef1b2 #define FREED_MAGIC 0x67fd487a @@ -60,6 +61,43 @@ int os_get_time(struct os_time *t) } +int os_get_reltime(struct os_reltime *t) +{ +#if defined(CLOCK_BOOTTIME) + static clockid_t clock_id = CLOCK_BOOTTIME; +#elif defined(CLOCK_MONOTONIC) + static clockid_t clock_id = CLOCK_MONOTONIC; +#else + static clockid_t clock_id = CLOCK_REALTIME; +#endif + struct timespec ts; + int res; + + while (1) { + res = clock_gettime(clock_id, &ts); + if (res == 0) { + t->sec = ts.tv_sec; + t->usec = ts.tv_nsec / 1000; + return 0; + } + switch (clock_id) { +#ifdef CLOCK_BOOTTIME + case CLOCK_BOOTTIME: + clock_id = CLOCK_MONOTONIC; + break; +#endif +#ifdef CLOCK_MONOTONIC + case CLOCK_MONOTONIC: + clock_id = CLOCK_REALTIME; + break; +#endif + case CLOCK_REALTIME: + return -1; + } + } +} + + int os_mktime(int year, int month, int day, int hour, int min, int sec, os_time_t *t) { @@ -213,6 +251,9 @@ char * os_rel2abs_path(const char *rel_path) size_t len = 128, cwd_len, rel_len, ret_len; int last_errno; + if (!rel_path) + return NULL; + if (rel_path[0] == '/') return os_strdup(rel_path); @@ -257,11 +298,15 @@ int os_program_init(void) * We ignore errors here since errors are normal if we * are already running as non-root. */ +#ifdef ANDROID_SETGROUPS_OVERRIDE + gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; +#else /* ANDROID_SETGROUPS_OVERRIDE */ gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; +#endif /* ANDROID_SETGROUPS_OVERRIDE */ struct __user_cap_header_struct header; struct __user_cap_data_struct cap; - setgroups(sizeof(groups)/sizeof(groups[0]), groups); + setgroups(ARRAY_SIZE(groups), groups); prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); @@ -276,9 +321,6 @@ int os_program_init(void) capset(&header, &cap); #endif /* ANDROID */ -#ifdef WPA_TRACE - dl_list_init(&alloc_list); -#endif /* WPA_TRACE */ return 0; } @@ -363,6 +405,16 @@ char * os_readfile(const char *name, size_t *len) } +int os_file_exists(const char *fname) +{ + FILE *f = fopen(fname, "rb"); + if (f == NULL) + return 0; + fclose(f); + return 1; +} + + #ifndef WPA_TRACE void * os_zalloc(size_t size) { @@ -396,11 +448,121 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz) } +int os_memcmp_const(const void *a, const void *b, size_t len) +{ + const u8 *aa = a; + const u8 *bb = b; + size_t i; + u8 res; + + for (res = 0, i = 0; i < len; i++) + res |= aa[i] ^ bb[i]; + + return res; +} + + #ifdef WPA_TRACE +#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) +char wpa_trace_fail_func[256] = { 0 }; +unsigned int wpa_trace_fail_after; + +static int testing_fail_alloc(void) +{ + const char *func[WPA_TRACE_LEN]; + size_t i, res, len; + char *pos, *next; + int match; + + if (!wpa_trace_fail_after) + return 0; + + res = wpa_trace_calling_func(func, WPA_TRACE_LEN); + i = 0; + if (i < res && os_strcmp(func[i], __func__) == 0) + i++; + if (i < res && os_strcmp(func[i], "os_malloc") == 0) + i++; + if (i < res && os_strcmp(func[i], "os_zalloc") == 0) + i++; + if (i < res && os_strcmp(func[i], "os_calloc") == 0) + i++; + if (i < res && os_strcmp(func[i], "os_realloc") == 0) + i++; + if (i < res && os_strcmp(func[i], "os_realloc_array") == 0) + i++; + if (i < res && os_strcmp(func[i], "os_strdup") == 0) + i++; + + pos = wpa_trace_fail_func; + + match = 0; + while (i < res) { + int allow_skip = 1; + int maybe = 0; + + if (*pos == '=') { + allow_skip = 0; + pos++; + } else if (*pos == '?') { + maybe = 1; + pos++; + } + next = os_strchr(pos, ';'); + if (next) + len = next - pos; + else + len = os_strlen(pos); + if (os_memcmp(pos, func[i], len) != 0) { + if (maybe && next) { + pos = next + 1; + continue; + } + if (allow_skip) { + i++; + continue; + } + return 0; + } + if (!next) { + match = 1; + break; + } + pos = next + 1; + i++; + } + if (!match) + return 0; + + wpa_trace_fail_after--; + if (wpa_trace_fail_after == 0) { + wpa_printf(MSG_INFO, "TESTING: fail allocation at %s", + wpa_trace_fail_func); + for (i = 0; i < res; i++) + wpa_printf(MSG_INFO, "backtrace[%d] = %s", + (int) i, func[i]); + return 1; + } + + return 0; +} + +#else + +static inline int testing_fail_alloc(void) +{ + return 0; +} +#endif + void * os_malloc(size_t size) { struct os_alloc_trace *a; + + if (testing_fail_alloc()) + return NULL; + a = malloc(sizeof(*a) + size); if (a == NULL) return NULL; @@ -486,3 +648,57 @@ char * os_strdup(const char *s) } #endif /* WPA_TRACE */ + + +int os_exec(const char *program, const char *arg, int wait_completion) +{ + pid_t pid; + int pid_status; + + pid = fork(); + if (pid < 0) { + perror("fork"); + return -1; + } + + if (pid == 0) { + /* run the external command in the child process */ + const int MAX_ARG = 30; + char *_program, *_arg, *pos; + char *argv[MAX_ARG + 1]; + int i; + + _program = os_strdup(program); + _arg = os_strdup(arg); + + argv[0] = _program; + + i = 1; + pos = _arg; + while (i < MAX_ARG && pos && *pos) { + while (*pos == ' ') + pos++; + if (*pos == '\0') + break; + argv[i++] = pos; + pos = os_strchr(pos, ' '); + if (pos) + *pos++ = '\0'; + } + argv[i] = NULL; + + execv(program, argv); + perror("execv"); + os_free(_program); + os_free(_arg); + exit(0); + return -1; + } + + if (wait_completion) { + /* wait for the child process to complete in the parent */ + waitpid(pid, &pid_status, 0); + } + + return 0; +} |