139beb93cSSam Leffler /* 2e28a4053SRui Paulo * OS specific functions for UNIX/POSIX systems 3e28a4053SRui Paulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 11f05cddf9SRui Paulo #include <time.h> 12*5b9c547cSRui Paulo #include <sys/wait.h> 13f05cddf9SRui Paulo 14f05cddf9SRui Paulo #ifdef ANDROID 15*5b9c547cSRui Paulo #include <sys/capability.h> 16*5b9c547cSRui Paulo #include <sys/prctl.h> 17f05cddf9SRui Paulo #include <private/android_filesystem_config.h> 18f05cddf9SRui Paulo #endif /* ANDROID */ 19f05cddf9SRui Paulo 2039beb93cSSam Leffler #include "os.h" 21*5b9c547cSRui Paulo #include "common.h" 2239beb93cSSam Leffler 23e28a4053SRui Paulo #ifdef WPA_TRACE 24e28a4053SRui Paulo 25e28a4053SRui Paulo #include "wpa_debug.h" 26e28a4053SRui Paulo #include "trace.h" 27f05cddf9SRui Paulo #include "list.h" 28e28a4053SRui Paulo 29*5b9c547cSRui Paulo static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list); 30e28a4053SRui Paulo 31e28a4053SRui Paulo #define ALLOC_MAGIC 0xa84ef1b2 32e28a4053SRui Paulo #define FREED_MAGIC 0x67fd487a 33e28a4053SRui Paulo 34e28a4053SRui Paulo struct os_alloc_trace { 35e28a4053SRui Paulo unsigned int magic; 36e28a4053SRui Paulo struct dl_list list; 37e28a4053SRui Paulo size_t len; 38e28a4053SRui Paulo WPA_TRACE_INFO 39e28a4053SRui Paulo }; 40e28a4053SRui Paulo 41e28a4053SRui Paulo #endif /* WPA_TRACE */ 42e28a4053SRui Paulo 43e28a4053SRui Paulo 4439beb93cSSam Leffler void os_sleep(os_time_t sec, os_time_t usec) 4539beb93cSSam Leffler { 4639beb93cSSam Leffler if (sec) 4739beb93cSSam Leffler sleep(sec); 4839beb93cSSam Leffler if (usec) 4939beb93cSSam Leffler usleep(usec); 5039beb93cSSam Leffler } 5139beb93cSSam Leffler 5239beb93cSSam Leffler 5339beb93cSSam Leffler int os_get_time(struct os_time *t) 5439beb93cSSam Leffler { 5539beb93cSSam Leffler int res; 5639beb93cSSam Leffler struct timeval tv; 5739beb93cSSam Leffler res = gettimeofday(&tv, NULL); 5839beb93cSSam Leffler t->sec = tv.tv_sec; 5939beb93cSSam Leffler t->usec = tv.tv_usec; 6039beb93cSSam Leffler return res; 6139beb93cSSam Leffler } 6239beb93cSSam Leffler 6339beb93cSSam Leffler 64*5b9c547cSRui Paulo int os_get_reltime(struct os_reltime *t) 65*5b9c547cSRui Paulo { 66*5b9c547cSRui Paulo #if defined(CLOCK_BOOTTIME) 67*5b9c547cSRui Paulo static clockid_t clock_id = CLOCK_BOOTTIME; 68*5b9c547cSRui Paulo #elif defined(CLOCK_MONOTONIC) 69*5b9c547cSRui Paulo static clockid_t clock_id = CLOCK_MONOTONIC; 70*5b9c547cSRui Paulo #else 71*5b9c547cSRui Paulo static clockid_t clock_id = CLOCK_REALTIME; 72*5b9c547cSRui Paulo #endif 73*5b9c547cSRui Paulo struct timespec ts; 74*5b9c547cSRui Paulo int res; 75*5b9c547cSRui Paulo 76*5b9c547cSRui Paulo while (1) { 77*5b9c547cSRui Paulo res = clock_gettime(clock_id, &ts); 78*5b9c547cSRui Paulo if (res == 0) { 79*5b9c547cSRui Paulo t->sec = ts.tv_sec; 80*5b9c547cSRui Paulo t->usec = ts.tv_nsec / 1000; 81*5b9c547cSRui Paulo return 0; 82*5b9c547cSRui Paulo } 83*5b9c547cSRui Paulo switch (clock_id) { 84*5b9c547cSRui Paulo #ifdef CLOCK_BOOTTIME 85*5b9c547cSRui Paulo case CLOCK_BOOTTIME: 86*5b9c547cSRui Paulo clock_id = CLOCK_MONOTONIC; 87*5b9c547cSRui Paulo break; 88*5b9c547cSRui Paulo #endif 89*5b9c547cSRui Paulo #ifdef CLOCK_MONOTONIC 90*5b9c547cSRui Paulo case CLOCK_MONOTONIC: 91*5b9c547cSRui Paulo clock_id = CLOCK_REALTIME; 92*5b9c547cSRui Paulo break; 93*5b9c547cSRui Paulo #endif 94*5b9c547cSRui Paulo case CLOCK_REALTIME: 95*5b9c547cSRui Paulo return -1; 96*5b9c547cSRui Paulo } 97*5b9c547cSRui Paulo } 98*5b9c547cSRui Paulo } 99*5b9c547cSRui Paulo 100*5b9c547cSRui Paulo 10139beb93cSSam Leffler int os_mktime(int year, int month, int day, int hour, int min, int sec, 10239beb93cSSam Leffler os_time_t *t) 10339beb93cSSam Leffler { 10439beb93cSSam Leffler struct tm tm, *tm1; 10539beb93cSSam Leffler time_t t_local, t1, t2; 10639beb93cSSam Leffler os_time_t tz_offset; 10739beb93cSSam Leffler 10839beb93cSSam Leffler if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 10939beb93cSSam Leffler hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 11039beb93cSSam Leffler sec > 60) 11139beb93cSSam Leffler return -1; 11239beb93cSSam Leffler 11339beb93cSSam Leffler memset(&tm, 0, sizeof(tm)); 11439beb93cSSam Leffler tm.tm_year = year - 1900; 11539beb93cSSam Leffler tm.tm_mon = month - 1; 11639beb93cSSam Leffler tm.tm_mday = day; 11739beb93cSSam Leffler tm.tm_hour = hour; 11839beb93cSSam Leffler tm.tm_min = min; 11939beb93cSSam Leffler tm.tm_sec = sec; 12039beb93cSSam Leffler 12139beb93cSSam Leffler t_local = mktime(&tm); 12239beb93cSSam Leffler 12339beb93cSSam Leffler /* figure out offset to UTC */ 12439beb93cSSam Leffler tm1 = localtime(&t_local); 12539beb93cSSam Leffler if (tm1) { 12639beb93cSSam Leffler t1 = mktime(tm1); 12739beb93cSSam Leffler tm1 = gmtime(&t_local); 12839beb93cSSam Leffler if (tm1) { 12939beb93cSSam Leffler t2 = mktime(tm1); 13039beb93cSSam Leffler tz_offset = t2 - t1; 13139beb93cSSam Leffler } else 13239beb93cSSam Leffler tz_offset = 0; 13339beb93cSSam Leffler } else 13439beb93cSSam Leffler tz_offset = 0; 13539beb93cSSam Leffler 13639beb93cSSam Leffler *t = (os_time_t) t_local - tz_offset; 13739beb93cSSam Leffler return 0; 13839beb93cSSam Leffler } 13939beb93cSSam Leffler 14039beb93cSSam Leffler 141f05cddf9SRui Paulo int os_gmtime(os_time_t t, struct os_tm *tm) 142f05cddf9SRui Paulo { 143f05cddf9SRui Paulo struct tm *tm2; 144f05cddf9SRui Paulo time_t t2 = t; 145f05cddf9SRui Paulo 146f05cddf9SRui Paulo tm2 = gmtime(&t2); 147f05cddf9SRui Paulo if (tm2 == NULL) 148f05cddf9SRui Paulo return -1; 149f05cddf9SRui Paulo tm->sec = tm2->tm_sec; 150f05cddf9SRui Paulo tm->min = tm2->tm_min; 151f05cddf9SRui Paulo tm->hour = tm2->tm_hour; 152f05cddf9SRui Paulo tm->day = tm2->tm_mday; 153f05cddf9SRui Paulo tm->month = tm2->tm_mon + 1; 154f05cddf9SRui Paulo tm->year = tm2->tm_year + 1900; 155f05cddf9SRui Paulo return 0; 156f05cddf9SRui Paulo } 157f05cddf9SRui Paulo 158f05cddf9SRui Paulo 15939beb93cSSam Leffler #ifdef __APPLE__ 16039beb93cSSam Leffler #include <fcntl.h> 16139beb93cSSam Leffler static int os_daemon(int nochdir, int noclose) 16239beb93cSSam Leffler { 16339beb93cSSam Leffler int devnull; 16439beb93cSSam Leffler 16539beb93cSSam Leffler if (chdir("/") < 0) 16639beb93cSSam Leffler return -1; 16739beb93cSSam Leffler 16839beb93cSSam Leffler devnull = open("/dev/null", O_RDWR); 16939beb93cSSam Leffler if (devnull < 0) 17039beb93cSSam Leffler return -1; 17139beb93cSSam Leffler 17239beb93cSSam Leffler if (dup2(devnull, STDIN_FILENO) < 0) { 17339beb93cSSam Leffler close(devnull); 17439beb93cSSam Leffler return -1; 17539beb93cSSam Leffler } 17639beb93cSSam Leffler 17739beb93cSSam Leffler if (dup2(devnull, STDOUT_FILENO) < 0) { 17839beb93cSSam Leffler close(devnull); 17939beb93cSSam Leffler return -1; 18039beb93cSSam Leffler } 18139beb93cSSam Leffler 18239beb93cSSam Leffler if (dup2(devnull, STDERR_FILENO) < 0) { 18339beb93cSSam Leffler close(devnull); 18439beb93cSSam Leffler return -1; 18539beb93cSSam Leffler } 18639beb93cSSam Leffler 18739beb93cSSam Leffler return 0; 18839beb93cSSam Leffler } 18939beb93cSSam Leffler #else /* __APPLE__ */ 19039beb93cSSam Leffler #define os_daemon daemon 19139beb93cSSam Leffler #endif /* __APPLE__ */ 19239beb93cSSam Leffler 19339beb93cSSam Leffler 194a061720cSJohn-Mark Gurney #ifdef __FreeBSD__ 195a061720cSJohn-Mark Gurney #include <err.h> 196a061720cSJohn-Mark Gurney #include <libutil.h> 197a061720cSJohn-Mark Gurney #include <stdint.h> 198a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */ 199a061720cSJohn-Mark Gurney 20039beb93cSSam Leffler int os_daemonize(const char *pid_file) 20139beb93cSSam Leffler { 202f05cddf9SRui Paulo #if defined(__uClinux__) || defined(__sun__) 20339beb93cSSam Leffler return -1; 204f05cddf9SRui Paulo #else /* defined(__uClinux__) || defined(__sun__) */ 205a061720cSJohn-Mark Gurney #ifdef __FreeBSD__ 206a061720cSJohn-Mark Gurney pid_t otherpid; 207a061720cSJohn-Mark Gurney struct pidfh *pfh; 208a061720cSJohn-Mark Gurney 209a061720cSJohn-Mark Gurney pfh = pidfile_open(pid_file, 0600, &otherpid); 210a061720cSJohn-Mark Gurney if (pfh == NULL) { 211a061720cSJohn-Mark Gurney if (errno == EEXIST) { 212a061720cSJohn-Mark Gurney errx(1, "Daemon already running, pid: %jd.", 213a061720cSJohn-Mark Gurney (intmax_t)otherpid); 214a061720cSJohn-Mark Gurney } 215a061720cSJohn-Mark Gurney warn("Cannot open or create pidfile."); 216a061720cSJohn-Mark Gurney } 217a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */ 218a061720cSJohn-Mark Gurney 21939beb93cSSam Leffler if (os_daemon(0, 0)) { 22039beb93cSSam Leffler perror("daemon"); 221a061720cSJohn-Mark Gurney #ifdef __FreeBSD__ 222a061720cSJohn-Mark Gurney pidfile_remove(pfh); 223a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */ 22439beb93cSSam Leffler return -1; 22539beb93cSSam Leffler } 22639beb93cSSam Leffler 227a061720cSJohn-Mark Gurney #ifndef __FreeBSD__ 22839beb93cSSam Leffler if (pid_file) { 22939beb93cSSam Leffler FILE *f = fopen(pid_file, "w"); 23039beb93cSSam Leffler if (f) { 23139beb93cSSam Leffler fprintf(f, "%u\n", getpid()); 23239beb93cSSam Leffler fclose(f); 23339beb93cSSam Leffler } 23439beb93cSSam Leffler } 235a061720cSJohn-Mark Gurney #else /* __FreeBSD__ */ 236a061720cSJohn-Mark Gurney pidfile_write(pfh); 237a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */ 23839beb93cSSam Leffler 23939beb93cSSam Leffler return -0; 240f05cddf9SRui Paulo #endif /* defined(__uClinux__) || defined(__sun__) */ 24139beb93cSSam Leffler } 24239beb93cSSam Leffler 24339beb93cSSam Leffler 24439beb93cSSam Leffler void os_daemonize_terminate(const char *pid_file) 24539beb93cSSam Leffler { 24639beb93cSSam Leffler if (pid_file) 24739beb93cSSam Leffler unlink(pid_file); 24839beb93cSSam Leffler } 24939beb93cSSam Leffler 25039beb93cSSam Leffler 25139beb93cSSam Leffler int os_get_random(unsigned char *buf, size_t len) 25239beb93cSSam Leffler { 25339beb93cSSam Leffler FILE *f; 25439beb93cSSam Leffler size_t rc; 25539beb93cSSam Leffler 25639beb93cSSam Leffler f = fopen("/dev/urandom", "rb"); 25739beb93cSSam Leffler if (f == NULL) { 25839beb93cSSam Leffler printf("Could not open /dev/urandom.\n"); 25939beb93cSSam Leffler return -1; 26039beb93cSSam Leffler } 26139beb93cSSam Leffler 26239beb93cSSam Leffler rc = fread(buf, 1, len, f); 26339beb93cSSam Leffler fclose(f); 26439beb93cSSam Leffler 26539beb93cSSam Leffler return rc != len ? -1 : 0; 26639beb93cSSam Leffler } 26739beb93cSSam Leffler 26839beb93cSSam Leffler 26939beb93cSSam Leffler unsigned long os_random(void) 27039beb93cSSam Leffler { 27139beb93cSSam Leffler return random(); 27239beb93cSSam Leffler } 27339beb93cSSam Leffler 27439beb93cSSam Leffler 27539beb93cSSam Leffler char * os_rel2abs_path(const char *rel_path) 27639beb93cSSam Leffler { 27739beb93cSSam Leffler char *buf = NULL, *cwd, *ret; 27839beb93cSSam Leffler size_t len = 128, cwd_len, rel_len, ret_len; 27939beb93cSSam Leffler int last_errno; 28039beb93cSSam Leffler 281*5b9c547cSRui Paulo if (!rel_path) 282*5b9c547cSRui Paulo return NULL; 283*5b9c547cSRui Paulo 28439beb93cSSam Leffler if (rel_path[0] == '/') 285e28a4053SRui Paulo return os_strdup(rel_path); 28639beb93cSSam Leffler 28739beb93cSSam Leffler for (;;) { 288e28a4053SRui Paulo buf = os_malloc(len); 28939beb93cSSam Leffler if (buf == NULL) 29039beb93cSSam Leffler return NULL; 29139beb93cSSam Leffler cwd = getcwd(buf, len); 29239beb93cSSam Leffler if (cwd == NULL) { 29339beb93cSSam Leffler last_errno = errno; 294e28a4053SRui Paulo os_free(buf); 29539beb93cSSam Leffler if (last_errno != ERANGE) 29639beb93cSSam Leffler return NULL; 29739beb93cSSam Leffler len *= 2; 29839beb93cSSam Leffler if (len > 2000) 29939beb93cSSam Leffler return NULL; 30039beb93cSSam Leffler } else { 30139beb93cSSam Leffler buf[len - 1] = '\0'; 30239beb93cSSam Leffler break; 30339beb93cSSam Leffler } 30439beb93cSSam Leffler } 30539beb93cSSam Leffler 306e28a4053SRui Paulo cwd_len = os_strlen(cwd); 307e28a4053SRui Paulo rel_len = os_strlen(rel_path); 30839beb93cSSam Leffler ret_len = cwd_len + 1 + rel_len + 1; 309e28a4053SRui Paulo ret = os_malloc(ret_len); 31039beb93cSSam Leffler if (ret) { 311e28a4053SRui Paulo os_memcpy(ret, cwd, cwd_len); 31239beb93cSSam Leffler ret[cwd_len] = '/'; 313e28a4053SRui Paulo os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 31439beb93cSSam Leffler ret[ret_len - 1] = '\0'; 31539beb93cSSam Leffler } 316e28a4053SRui Paulo os_free(buf); 31739beb93cSSam Leffler return ret; 31839beb93cSSam Leffler } 31939beb93cSSam Leffler 32039beb93cSSam Leffler 32139beb93cSSam Leffler int os_program_init(void) 32239beb93cSSam Leffler { 323f05cddf9SRui Paulo #ifdef ANDROID 324f05cddf9SRui Paulo /* 325f05cddf9SRui Paulo * We ignore errors here since errors are normal if we 326f05cddf9SRui Paulo * are already running as non-root. 327f05cddf9SRui Paulo */ 328*5b9c547cSRui Paulo #ifdef ANDROID_SETGROUPS_OVERRIDE 329*5b9c547cSRui Paulo gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; 330*5b9c547cSRui Paulo #else /* ANDROID_SETGROUPS_OVERRIDE */ 331f05cddf9SRui Paulo gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; 332*5b9c547cSRui Paulo #endif /* ANDROID_SETGROUPS_OVERRIDE */ 333f05cddf9SRui Paulo struct __user_cap_header_struct header; 334f05cddf9SRui Paulo struct __user_cap_data_struct cap; 335f05cddf9SRui Paulo 336*5b9c547cSRui Paulo setgroups(ARRAY_SIZE(groups), groups); 337f05cddf9SRui Paulo 338f05cddf9SRui Paulo prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); 339f05cddf9SRui Paulo 340f05cddf9SRui Paulo setgid(AID_WIFI); 341f05cddf9SRui Paulo setuid(AID_WIFI); 342f05cddf9SRui Paulo 343f05cddf9SRui Paulo header.version = _LINUX_CAPABILITY_VERSION; 344f05cddf9SRui Paulo header.pid = 0; 345f05cddf9SRui Paulo cap.effective = cap.permitted = 346f05cddf9SRui Paulo (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); 347f05cddf9SRui Paulo cap.inheritable = 0; 348f05cddf9SRui Paulo capset(&header, &cap); 349f05cddf9SRui Paulo #endif /* ANDROID */ 350f05cddf9SRui Paulo 35139beb93cSSam Leffler return 0; 35239beb93cSSam Leffler } 35339beb93cSSam Leffler 35439beb93cSSam Leffler 35539beb93cSSam Leffler void os_program_deinit(void) 35639beb93cSSam Leffler { 357e28a4053SRui Paulo #ifdef WPA_TRACE 358e28a4053SRui Paulo struct os_alloc_trace *a; 359e28a4053SRui Paulo unsigned long total = 0; 360e28a4053SRui Paulo dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 361e28a4053SRui Paulo total += a->len; 362e28a4053SRui Paulo if (a->magic != ALLOC_MAGIC) { 363e28a4053SRui Paulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 364e28a4053SRui Paulo "len %lu", 365e28a4053SRui Paulo a, a->magic, (unsigned long) a->len); 366e28a4053SRui Paulo continue; 367e28a4053SRui Paulo } 368e28a4053SRui Paulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 369e28a4053SRui Paulo a, (unsigned long) a->len); 370e28a4053SRui Paulo wpa_trace_dump("memleak", a); 371e28a4053SRui Paulo } 372e28a4053SRui Paulo if (total) 373e28a4053SRui Paulo wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 374e28a4053SRui Paulo (unsigned long) total); 375e28a4053SRui Paulo #endif /* WPA_TRACE */ 37639beb93cSSam Leffler } 37739beb93cSSam Leffler 37839beb93cSSam Leffler 37939beb93cSSam Leffler int os_setenv(const char *name, const char *value, int overwrite) 38039beb93cSSam Leffler { 38139beb93cSSam Leffler return setenv(name, value, overwrite); 38239beb93cSSam Leffler } 38339beb93cSSam Leffler 38439beb93cSSam Leffler 38539beb93cSSam Leffler int os_unsetenv(const char *name) 38639beb93cSSam Leffler { 3873157ba21SRui Paulo #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 3883157ba21SRui Paulo defined(__OpenBSD__) 38939beb93cSSam Leffler unsetenv(name); 39039beb93cSSam Leffler return 0; 39139beb93cSSam Leffler #else 39239beb93cSSam Leffler return unsetenv(name); 39339beb93cSSam Leffler #endif 39439beb93cSSam Leffler } 39539beb93cSSam Leffler 39639beb93cSSam Leffler 39739beb93cSSam Leffler char * os_readfile(const char *name, size_t *len) 39839beb93cSSam Leffler { 39939beb93cSSam Leffler FILE *f; 40039beb93cSSam Leffler char *buf; 401f05cddf9SRui Paulo long pos; 40239beb93cSSam Leffler 40339beb93cSSam Leffler f = fopen(name, "rb"); 40439beb93cSSam Leffler if (f == NULL) 40539beb93cSSam Leffler return NULL; 40639beb93cSSam Leffler 407f05cddf9SRui Paulo if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) { 408f05cddf9SRui Paulo fclose(f); 409f05cddf9SRui Paulo return NULL; 410f05cddf9SRui Paulo } 411f05cddf9SRui Paulo *len = pos; 412f05cddf9SRui Paulo if (fseek(f, 0, SEEK_SET) < 0) { 413f05cddf9SRui Paulo fclose(f); 414f05cddf9SRui Paulo return NULL; 415f05cddf9SRui Paulo } 41639beb93cSSam Leffler 417e28a4053SRui Paulo buf = os_malloc(*len); 41839beb93cSSam Leffler if (buf == NULL) { 41939beb93cSSam Leffler fclose(f); 42039beb93cSSam Leffler return NULL; 42139beb93cSSam Leffler } 42239beb93cSSam Leffler 42339beb93cSSam Leffler if (fread(buf, 1, *len, f) != *len) { 42439beb93cSSam Leffler fclose(f); 425e28a4053SRui Paulo os_free(buf); 42639beb93cSSam Leffler return NULL; 42739beb93cSSam Leffler } 42839beb93cSSam Leffler 42939beb93cSSam Leffler fclose(f); 43039beb93cSSam Leffler 43139beb93cSSam Leffler return buf; 43239beb93cSSam Leffler } 43339beb93cSSam Leffler 43439beb93cSSam Leffler 435*5b9c547cSRui Paulo int os_file_exists(const char *fname) 436*5b9c547cSRui Paulo { 437*5b9c547cSRui Paulo FILE *f = fopen(fname, "rb"); 438*5b9c547cSRui Paulo if (f == NULL) 439*5b9c547cSRui Paulo return 0; 440*5b9c547cSRui Paulo fclose(f); 441*5b9c547cSRui Paulo return 1; 442*5b9c547cSRui Paulo } 443*5b9c547cSRui Paulo 444*5b9c547cSRui Paulo 445e28a4053SRui Paulo #ifndef WPA_TRACE 44639beb93cSSam Leffler void * os_zalloc(size_t size) 44739beb93cSSam Leffler { 44839beb93cSSam Leffler return calloc(1, size); 44939beb93cSSam Leffler } 450e28a4053SRui Paulo #endif /* WPA_TRACE */ 45139beb93cSSam Leffler 45239beb93cSSam Leffler 45339beb93cSSam Leffler size_t os_strlcpy(char *dest, const char *src, size_t siz) 45439beb93cSSam Leffler { 45539beb93cSSam Leffler const char *s = src; 45639beb93cSSam Leffler size_t left = siz; 45739beb93cSSam Leffler 45839beb93cSSam Leffler if (left) { 45939beb93cSSam Leffler /* Copy string up to the maximum size of the dest buffer */ 46039beb93cSSam Leffler while (--left != 0) { 46139beb93cSSam Leffler if ((*dest++ = *s++) == '\0') 46239beb93cSSam Leffler break; 46339beb93cSSam Leffler } 46439beb93cSSam Leffler } 46539beb93cSSam Leffler 46639beb93cSSam Leffler if (left == 0) { 46739beb93cSSam Leffler /* Not enough room for the string; force NUL-termination */ 46839beb93cSSam Leffler if (siz != 0) 46939beb93cSSam Leffler *dest = '\0'; 47039beb93cSSam Leffler while (*s++) 47139beb93cSSam Leffler ; /* determine total src string length */ 47239beb93cSSam Leffler } 47339beb93cSSam Leffler 47439beb93cSSam Leffler return s - src - 1; 47539beb93cSSam Leffler } 476e28a4053SRui Paulo 477e28a4053SRui Paulo 478*5b9c547cSRui Paulo int os_memcmp_const(const void *a, const void *b, size_t len) 479*5b9c547cSRui Paulo { 480*5b9c547cSRui Paulo const u8 *aa = a; 481*5b9c547cSRui Paulo const u8 *bb = b; 482*5b9c547cSRui Paulo size_t i; 483*5b9c547cSRui Paulo u8 res; 484*5b9c547cSRui Paulo 485*5b9c547cSRui Paulo for (res = 0, i = 0; i < len; i++) 486*5b9c547cSRui Paulo res |= aa[i] ^ bb[i]; 487*5b9c547cSRui Paulo 488*5b9c547cSRui Paulo return res; 489*5b9c547cSRui Paulo } 490*5b9c547cSRui Paulo 491*5b9c547cSRui Paulo 492e28a4053SRui Paulo #ifdef WPA_TRACE 493e28a4053SRui Paulo 494*5b9c547cSRui Paulo #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) 495*5b9c547cSRui Paulo char wpa_trace_fail_func[256] = { 0 }; 496*5b9c547cSRui Paulo unsigned int wpa_trace_fail_after; 497*5b9c547cSRui Paulo 498*5b9c547cSRui Paulo static int testing_fail_alloc(void) 499*5b9c547cSRui Paulo { 500*5b9c547cSRui Paulo const char *func[WPA_TRACE_LEN]; 501*5b9c547cSRui Paulo size_t i, res, len; 502*5b9c547cSRui Paulo char *pos, *next; 503*5b9c547cSRui Paulo int match; 504*5b9c547cSRui Paulo 505*5b9c547cSRui Paulo if (!wpa_trace_fail_after) 506*5b9c547cSRui Paulo return 0; 507*5b9c547cSRui Paulo 508*5b9c547cSRui Paulo res = wpa_trace_calling_func(func, WPA_TRACE_LEN); 509*5b9c547cSRui Paulo i = 0; 510*5b9c547cSRui Paulo if (i < res && os_strcmp(func[i], __func__) == 0) 511*5b9c547cSRui Paulo i++; 512*5b9c547cSRui Paulo if (i < res && os_strcmp(func[i], "os_malloc") == 0) 513*5b9c547cSRui Paulo i++; 514*5b9c547cSRui Paulo if (i < res && os_strcmp(func[i], "os_zalloc") == 0) 515*5b9c547cSRui Paulo i++; 516*5b9c547cSRui Paulo if (i < res && os_strcmp(func[i], "os_calloc") == 0) 517*5b9c547cSRui Paulo i++; 518*5b9c547cSRui Paulo if (i < res && os_strcmp(func[i], "os_realloc") == 0) 519*5b9c547cSRui Paulo i++; 520*5b9c547cSRui Paulo if (i < res && os_strcmp(func[i], "os_realloc_array") == 0) 521*5b9c547cSRui Paulo i++; 522*5b9c547cSRui Paulo if (i < res && os_strcmp(func[i], "os_strdup") == 0) 523*5b9c547cSRui Paulo i++; 524*5b9c547cSRui Paulo 525*5b9c547cSRui Paulo pos = wpa_trace_fail_func; 526*5b9c547cSRui Paulo 527*5b9c547cSRui Paulo match = 0; 528*5b9c547cSRui Paulo while (i < res) { 529*5b9c547cSRui Paulo int allow_skip = 1; 530*5b9c547cSRui Paulo int maybe = 0; 531*5b9c547cSRui Paulo 532*5b9c547cSRui Paulo if (*pos == '=') { 533*5b9c547cSRui Paulo allow_skip = 0; 534*5b9c547cSRui Paulo pos++; 535*5b9c547cSRui Paulo } else if (*pos == '?') { 536*5b9c547cSRui Paulo maybe = 1; 537*5b9c547cSRui Paulo pos++; 538*5b9c547cSRui Paulo } 539*5b9c547cSRui Paulo next = os_strchr(pos, ';'); 540*5b9c547cSRui Paulo if (next) 541*5b9c547cSRui Paulo len = next - pos; 542*5b9c547cSRui Paulo else 543*5b9c547cSRui Paulo len = os_strlen(pos); 544*5b9c547cSRui Paulo if (os_memcmp(pos, func[i], len) != 0) { 545*5b9c547cSRui Paulo if (maybe && next) { 546*5b9c547cSRui Paulo pos = next + 1; 547*5b9c547cSRui Paulo continue; 548*5b9c547cSRui Paulo } 549*5b9c547cSRui Paulo if (allow_skip) { 550*5b9c547cSRui Paulo i++; 551*5b9c547cSRui Paulo continue; 552*5b9c547cSRui Paulo } 553*5b9c547cSRui Paulo return 0; 554*5b9c547cSRui Paulo } 555*5b9c547cSRui Paulo if (!next) { 556*5b9c547cSRui Paulo match = 1; 557*5b9c547cSRui Paulo break; 558*5b9c547cSRui Paulo } 559*5b9c547cSRui Paulo pos = next + 1; 560*5b9c547cSRui Paulo i++; 561*5b9c547cSRui Paulo } 562*5b9c547cSRui Paulo if (!match) 563*5b9c547cSRui Paulo return 0; 564*5b9c547cSRui Paulo 565*5b9c547cSRui Paulo wpa_trace_fail_after--; 566*5b9c547cSRui Paulo if (wpa_trace_fail_after == 0) { 567*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "TESTING: fail allocation at %s", 568*5b9c547cSRui Paulo wpa_trace_fail_func); 569*5b9c547cSRui Paulo for (i = 0; i < res; i++) 570*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "backtrace[%d] = %s", 571*5b9c547cSRui Paulo (int) i, func[i]); 572*5b9c547cSRui Paulo return 1; 573*5b9c547cSRui Paulo } 574*5b9c547cSRui Paulo 575*5b9c547cSRui Paulo return 0; 576*5b9c547cSRui Paulo } 577*5b9c547cSRui Paulo 578*5b9c547cSRui Paulo #else 579*5b9c547cSRui Paulo 580*5b9c547cSRui Paulo static inline int testing_fail_alloc(void) 581*5b9c547cSRui Paulo { 582*5b9c547cSRui Paulo return 0; 583*5b9c547cSRui Paulo } 584*5b9c547cSRui Paulo #endif 585*5b9c547cSRui Paulo 586e28a4053SRui Paulo void * os_malloc(size_t size) 587e28a4053SRui Paulo { 588e28a4053SRui Paulo struct os_alloc_trace *a; 589*5b9c547cSRui Paulo 590*5b9c547cSRui Paulo if (testing_fail_alloc()) 591*5b9c547cSRui Paulo return NULL; 592*5b9c547cSRui Paulo 593e28a4053SRui Paulo a = malloc(sizeof(*a) + size); 594e28a4053SRui Paulo if (a == NULL) 595e28a4053SRui Paulo return NULL; 596e28a4053SRui Paulo a->magic = ALLOC_MAGIC; 597e28a4053SRui Paulo dl_list_add(&alloc_list, &a->list); 598e28a4053SRui Paulo a->len = size; 599e28a4053SRui Paulo wpa_trace_record(a); 600e28a4053SRui Paulo return a + 1; 601e28a4053SRui Paulo } 602e28a4053SRui Paulo 603e28a4053SRui Paulo 604e28a4053SRui Paulo void * os_realloc(void *ptr, size_t size) 605e28a4053SRui Paulo { 606e28a4053SRui Paulo struct os_alloc_trace *a; 607e28a4053SRui Paulo size_t copy_len; 608e28a4053SRui Paulo void *n; 609e28a4053SRui Paulo 610e28a4053SRui Paulo if (ptr == NULL) 611e28a4053SRui Paulo return os_malloc(size); 612e28a4053SRui Paulo 613e28a4053SRui Paulo a = (struct os_alloc_trace *) ptr - 1; 614e28a4053SRui Paulo if (a->magic != ALLOC_MAGIC) { 615e28a4053SRui Paulo wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 616e28a4053SRui Paulo a, a->magic, 617e28a4053SRui Paulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 618e28a4053SRui Paulo wpa_trace_show("Invalid os_realloc() call"); 619e28a4053SRui Paulo abort(); 620e28a4053SRui Paulo } 621e28a4053SRui Paulo n = os_malloc(size); 622e28a4053SRui Paulo if (n == NULL) 623e28a4053SRui Paulo return NULL; 624e28a4053SRui Paulo copy_len = a->len; 625e28a4053SRui Paulo if (copy_len > size) 626e28a4053SRui Paulo copy_len = size; 627e28a4053SRui Paulo os_memcpy(n, a + 1, copy_len); 628e28a4053SRui Paulo os_free(ptr); 629e28a4053SRui Paulo return n; 630e28a4053SRui Paulo } 631e28a4053SRui Paulo 632e28a4053SRui Paulo 633e28a4053SRui Paulo void os_free(void *ptr) 634e28a4053SRui Paulo { 635e28a4053SRui Paulo struct os_alloc_trace *a; 636e28a4053SRui Paulo 637e28a4053SRui Paulo if (ptr == NULL) 638e28a4053SRui Paulo return; 639e28a4053SRui Paulo a = (struct os_alloc_trace *) ptr - 1; 640e28a4053SRui Paulo if (a->magic != ALLOC_MAGIC) { 641e28a4053SRui Paulo wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 642e28a4053SRui Paulo a, a->magic, 643e28a4053SRui Paulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 644e28a4053SRui Paulo wpa_trace_show("Invalid os_free() call"); 645e28a4053SRui Paulo abort(); 646e28a4053SRui Paulo } 647e28a4053SRui Paulo dl_list_del(&a->list); 648e28a4053SRui Paulo a->magic = FREED_MAGIC; 649e28a4053SRui Paulo 650e28a4053SRui Paulo wpa_trace_check_ref(ptr); 651e28a4053SRui Paulo free(a); 652e28a4053SRui Paulo } 653e28a4053SRui Paulo 654e28a4053SRui Paulo 655e28a4053SRui Paulo void * os_zalloc(size_t size) 656e28a4053SRui Paulo { 657e28a4053SRui Paulo void *ptr = os_malloc(size); 658e28a4053SRui Paulo if (ptr) 659e28a4053SRui Paulo os_memset(ptr, 0, size); 660e28a4053SRui Paulo return ptr; 661e28a4053SRui Paulo } 662e28a4053SRui Paulo 663e28a4053SRui Paulo 664e28a4053SRui Paulo char * os_strdup(const char *s) 665e28a4053SRui Paulo { 666e28a4053SRui Paulo size_t len; 667e28a4053SRui Paulo char *d; 668e28a4053SRui Paulo len = os_strlen(s); 669e28a4053SRui Paulo d = os_malloc(len + 1); 670e28a4053SRui Paulo if (d == NULL) 671e28a4053SRui Paulo return NULL; 672e28a4053SRui Paulo os_memcpy(d, s, len); 673e28a4053SRui Paulo d[len] = '\0'; 674e28a4053SRui Paulo return d; 675e28a4053SRui Paulo } 676e28a4053SRui Paulo 677e28a4053SRui Paulo #endif /* WPA_TRACE */ 678*5b9c547cSRui Paulo 679*5b9c547cSRui Paulo 680*5b9c547cSRui Paulo int os_exec(const char *program, const char *arg, int wait_completion) 681*5b9c547cSRui Paulo { 682*5b9c547cSRui Paulo pid_t pid; 683*5b9c547cSRui Paulo int pid_status; 684*5b9c547cSRui Paulo 685*5b9c547cSRui Paulo pid = fork(); 686*5b9c547cSRui Paulo if (pid < 0) { 687*5b9c547cSRui Paulo perror("fork"); 688*5b9c547cSRui Paulo return -1; 689*5b9c547cSRui Paulo } 690*5b9c547cSRui Paulo 691*5b9c547cSRui Paulo if (pid == 0) { 692*5b9c547cSRui Paulo /* run the external command in the child process */ 693*5b9c547cSRui Paulo const int MAX_ARG = 30; 694*5b9c547cSRui Paulo char *_program, *_arg, *pos; 695*5b9c547cSRui Paulo char *argv[MAX_ARG + 1]; 696*5b9c547cSRui Paulo int i; 697*5b9c547cSRui Paulo 698*5b9c547cSRui Paulo _program = os_strdup(program); 699*5b9c547cSRui Paulo _arg = os_strdup(arg); 700*5b9c547cSRui Paulo 701*5b9c547cSRui Paulo argv[0] = _program; 702*5b9c547cSRui Paulo 703*5b9c547cSRui Paulo i = 1; 704*5b9c547cSRui Paulo pos = _arg; 705*5b9c547cSRui Paulo while (i < MAX_ARG && pos && *pos) { 706*5b9c547cSRui Paulo while (*pos == ' ') 707*5b9c547cSRui Paulo pos++; 708*5b9c547cSRui Paulo if (*pos == '\0') 709*5b9c547cSRui Paulo break; 710*5b9c547cSRui Paulo argv[i++] = pos; 711*5b9c547cSRui Paulo pos = os_strchr(pos, ' '); 712*5b9c547cSRui Paulo if (pos) 713*5b9c547cSRui Paulo *pos++ = '\0'; 714*5b9c547cSRui Paulo } 715*5b9c547cSRui Paulo argv[i] = NULL; 716*5b9c547cSRui Paulo 717*5b9c547cSRui Paulo execv(program, argv); 718*5b9c547cSRui Paulo perror("execv"); 719*5b9c547cSRui Paulo os_free(_program); 720*5b9c547cSRui Paulo os_free(_arg); 721*5b9c547cSRui Paulo exit(0); 722*5b9c547cSRui Paulo return -1; 723*5b9c547cSRui Paulo } 724*5b9c547cSRui Paulo 725*5b9c547cSRui Paulo if (wait_completion) { 726*5b9c547cSRui Paulo /* wait for the child process to complete in the parent */ 727*5b9c547cSRui Paulo waitpid(pid, &pid_status, 0); 728*5b9c547cSRui Paulo } 729*5b9c547cSRui Paulo 730*5b9c547cSRui Paulo return 0; 731*5b9c547cSRui Paulo } 732