Add os_fuchsia implementation.
Based off of the existing os_unix.c, this implements the os abstraction
for Fuchsia. Uneeded sections have been removed but custom
implementations will be implemented in future CLs to make it easier to
review.
Change-Id: I3e1290d1e41594f9b397db62e99220f74e2698da
diff --git a/src/utils/os_fuchsia.c b/src/utils/os_fuchsia.c
new file mode 100644
index 0000000..a690736
--- /dev/null
+++ b/src/utils/os_fuchsia.c
@@ -0,0 +1,686 @@
+/*
+ * OS specific functions for Fuchsia OS.
+ *
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2016 The Fuchsia Authors
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * OS specific functions for Fuchsia. Based off os_unix.c.
+ */
+
+#include "includes.h"
+
+#include <time.h>
+#include <sys/wait.h>
+
+#include "os.h"
+#include "common.h"
+
+#ifdef WPA_TRACE
+
+#include "wpa_debug.h"
+#include "trace.h"
+#include "list.h"
+
+static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
+
+#define ALLOC_MAGIC 0xa84ef1b2
+#define FREED_MAGIC 0x67fd487a
+
+struct os_alloc_trace {
+ unsigned int magic;
+ struct dl_list list;
+ size_t len;
+ WPA_TRACE_INFO
+} __attribute__((aligned(16)));
+
+#endif /* WPA_TRACE */
+
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+ if (sec)
+ sleep(sec);
+ if (usec)
+ usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ int res;
+ struct timeval tv;
+ res = gettimeofday(&tv, NULL);
+ t->sec = tv.tv_sec;
+ t->usec = tv.tv_usec;
+ return res;
+}
+
+
+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)
+{
+ struct tm tm, *tm1;
+ time_t t_local, t1, t2;
+ os_time_t tz_offset;
+
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+ sec > 60)
+ return -1;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ t_local = mktime(&tm);
+
+ /* figure out offset to UTC */
+ tm1 = localtime(&t_local);
+ if (tm1) {
+ t1 = mktime(tm1);
+ tm1 = gmtime(&t_local);
+ if (tm1) {
+ t2 = mktime(tm1);
+ tz_offset = t2 - t1;
+ } else
+ tz_offset = 0;
+ } else
+ tz_offset = 0;
+
+ *t = (os_time_t) t_local - tz_offset;
+ return 0;
+}
+
+
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+ struct tm *tm2;
+ time_t t2 = t;
+
+ tm2 = gmtime(&t2);
+ if (tm2 == NULL)
+ return -1;
+ tm->sec = tm2->tm_sec;
+ tm->min = tm2->tm_min;
+ tm->hour = tm2->tm_hour;
+ tm->day = tm2->tm_mday;
+ tm->month = tm2->tm_mon + 1;
+ tm->year = tm2->tm_year + 1900;
+ return 0;
+}
+
+#define os_daemon daemon
+
+int os_daemonize(const char *pid_file)
+{
+ /* Not supported */
+ return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+ /* Not supported */
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ FILE *f;
+ size_t rc;
+
+ if (TEST_FAIL())
+ return -1;
+
+ /* TODO(alangardner): implement using random for now */
+ f = fopen("/dev/urandom", "rb");
+ if (f == NULL) {
+ printf("Could not open /dev/urandom.\n");
+ return -1;
+ }
+
+ rc = fread(buf, 1, len, f);
+ fclose(f);
+
+ return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+ return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ char *buf = NULL, *cwd, *ret;
+ 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);
+
+ for (;;) {
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ cwd = getcwd(buf, len);
+ if (cwd == NULL) {
+ last_errno = errno;
+ os_free(buf);
+ if (last_errno != ERANGE)
+ return NULL;
+ len *= 2;
+ if (len > 2000)
+ return NULL;
+ } else {
+ buf[len - 1] = '\0';
+ break;
+ }
+ }
+
+ cwd_len = os_strlen(cwd);
+ rel_len = os_strlen(rel_path);
+ ret_len = cwd_len + 1 + rel_len + 1;
+ ret = os_malloc(ret_len);
+ if (ret) {
+ os_memcpy(ret, cwd, cwd_len);
+ ret[cwd_len] = '/';
+ os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+ ret[ret_len - 1] = '\0';
+ }
+ os_free(buf);
+ return ret;
+}
+
+
+int os_program_init(void)
+{
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+#ifdef WPA_TRACE
+ struct os_alloc_trace *a;
+ unsigned long total = 0;
+ dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
+ total += a->len;
+ if (a->magic != ALLOC_MAGIC) {
+ wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
+ "len %lu",
+ a, a->magic, (unsigned long) a->len);
+ continue;
+ }
+ wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
+ a, (unsigned long) a->len);
+ wpa_trace_dump("memleak", a);
+ }
+ if (total)
+ wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
+ (unsigned long) total);
+#endif /* WPA_TRACE */
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+ return unsetenv(name);
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ FILE *f;
+ char *buf;
+ long pos;
+
+ f = fopen(name, "rb");
+ if (f == NULL)
+ return NULL;
+
+ if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
+ fclose(f);
+ return NULL;
+ }
+ *len = pos;
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ fclose(f);
+ return NULL;
+ }
+
+ buf = os_malloc(*len);
+ if (buf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ if (fread(buf, 1, *len, f) != *len) {
+ fclose(f);
+ os_free(buf);
+ return NULL;
+ }
+
+ fclose(f);
+
+ return buf;
+}
+
+
+int os_file_exists(const char *fname)
+{
+ FILE *f = fopen(fname, "rb");
+ if (f == NULL)
+ return 0;
+ fclose(f);
+ return 1;
+}
+
+
+int os_fdatasync(FILE *stream)
+{
+ if (!fflush(stream)) {
+ return fdatasync(fileno(stream));
+ }
+
+ return -1;
+}
+
+
+#ifndef WPA_TRACE
+void * os_zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+#endif /* WPA_TRACE */
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+ return strlcpy(dest, src, 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;
+}
+
+
+char wpa_trace_test_fail_func[256] = { 0 };
+unsigned int wpa_trace_test_fail_after;
+
+int testing_test_fail(void)
+{
+ const char *func[WPA_TRACE_LEN];
+ size_t i, res, len;
+ char *pos, *next;
+ int match;
+
+ if (!wpa_trace_test_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++;
+
+ pos = wpa_trace_test_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_test_fail_after--;
+ if (wpa_trace_test_fail_after == 0) {
+ wpa_printf(MSG_INFO, "TESTING: fail at %s",
+ wpa_trace_test_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;
+ a->magic = ALLOC_MAGIC;
+ dl_list_add(&alloc_list, &a->list);
+ a->len = size;
+ wpa_trace_record(a);
+ return a + 1;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+ struct os_alloc_trace *a;
+ size_t copy_len;
+ void *n;
+
+ if (ptr == NULL)
+ return os_malloc(size);
+
+ a = (struct os_alloc_trace *) ptr - 1;
+ if (a->magic != ALLOC_MAGIC) {
+ wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
+ a, a->magic,
+ a->magic == FREED_MAGIC ? " (already freed)" : "");
+ wpa_trace_show("Invalid os_realloc() call");
+ abort();
+ }
+ n = os_malloc(size);
+ if (n == NULL)
+ return NULL;
+ copy_len = a->len;
+ if (copy_len > size)
+ copy_len = size;
+ os_memcpy(n, a + 1, copy_len);
+ os_free(ptr);
+ return n;
+}
+
+
+void os_free(void *ptr)
+{
+ struct os_alloc_trace *a;
+
+ if (ptr == NULL)
+ return;
+ a = (struct os_alloc_trace *) ptr - 1;
+ if (a->magic != ALLOC_MAGIC) {
+ wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
+ a, a->magic,
+ a->magic == FREED_MAGIC ? " (already freed)" : "");
+ wpa_trace_show("Invalid os_free() call");
+ abort();
+ }
+ dl_list_del(&a->list);
+ a->magic = FREED_MAGIC;
+
+ wpa_trace_check_ref(ptr);
+ free(a);
+}
+
+
+void * os_zalloc(size_t size)
+{
+ void *ptr = os_malloc(size);
+ if (ptr)
+ os_memset(ptr, 0, size);
+ return ptr;
+}
+
+
+char * os_strdup(const char *s)
+{
+ size_t len;
+ char *d;
+ len = os_strlen(s);
+ d = os_malloc(len + 1);
+ if (d == NULL)
+ return NULL;
+ os_memcpy(d, s, len);
+ d[len] = '\0';
+ return d;
+}
+
+#endif /* WPA_TRACE */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ /* TODO(alangardner): Implement using launchpad */
+ 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;
+}
+
diff --git a/wpa_supplicant/BUILD.gn b/wpa_supplicant/BUILD.gn
index 5d7ee65..524b6d1 100644
--- a/wpa_supplicant/BUILD.gn
+++ b/wpa_supplicant/BUILD.gn
@@ -27,7 +27,7 @@
"../src/utils/common.c",
"../src/utils/wpa_debug.c",
"../src/utils/wpabuf.c",
- "../src/utils/os_none.c",
+ "../src/utils/os_fuchsia.c",
"../src/utils/eloop.c",
"config.c",
"notify.c",
@@ -68,6 +68,5 @@
"-DCONFIG_NO_WPA",
"-DCONFIG_NO_ROAMING",
"-DCONFIG_SHA256",
- "-DOS_NO_C_LIB_DEFINES",
]
}