139beb93cSSam Leffler /* 2*e28a4053SRui Paulo * OS specific functions for UNIX/POSIX systems 3*e28a4053SRui Paulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler #include "os.h" 1839beb93cSSam Leffler 19*e28a4053SRui Paulo #ifdef WPA_TRACE 20*e28a4053SRui Paulo 21*e28a4053SRui Paulo #include "common.h" 22*e28a4053SRui Paulo #include "list.h" 23*e28a4053SRui Paulo #include "wpa_debug.h" 24*e28a4053SRui Paulo #include "trace.h" 25*e28a4053SRui Paulo 26*e28a4053SRui Paulo static struct dl_list alloc_list; 27*e28a4053SRui Paulo 28*e28a4053SRui Paulo #define ALLOC_MAGIC 0xa84ef1b2 29*e28a4053SRui Paulo #define FREED_MAGIC 0x67fd487a 30*e28a4053SRui Paulo 31*e28a4053SRui Paulo struct os_alloc_trace { 32*e28a4053SRui Paulo unsigned int magic; 33*e28a4053SRui Paulo struct dl_list list; 34*e28a4053SRui Paulo size_t len; 35*e28a4053SRui Paulo WPA_TRACE_INFO 36*e28a4053SRui Paulo }; 37*e28a4053SRui Paulo 38*e28a4053SRui Paulo #endif /* WPA_TRACE */ 39*e28a4053SRui Paulo 40*e28a4053SRui Paulo 4139beb93cSSam Leffler void os_sleep(os_time_t sec, os_time_t usec) 4239beb93cSSam Leffler { 4339beb93cSSam Leffler if (sec) 4439beb93cSSam Leffler sleep(sec); 4539beb93cSSam Leffler if (usec) 4639beb93cSSam Leffler usleep(usec); 4739beb93cSSam Leffler } 4839beb93cSSam Leffler 4939beb93cSSam Leffler 5039beb93cSSam Leffler int os_get_time(struct os_time *t) 5139beb93cSSam Leffler { 5239beb93cSSam Leffler int res; 5339beb93cSSam Leffler struct timeval tv; 5439beb93cSSam Leffler res = gettimeofday(&tv, NULL); 5539beb93cSSam Leffler t->sec = tv.tv_sec; 5639beb93cSSam Leffler t->usec = tv.tv_usec; 5739beb93cSSam Leffler return res; 5839beb93cSSam Leffler } 5939beb93cSSam Leffler 6039beb93cSSam Leffler 6139beb93cSSam Leffler int os_mktime(int year, int month, int day, int hour, int min, int sec, 6239beb93cSSam Leffler os_time_t *t) 6339beb93cSSam Leffler { 6439beb93cSSam Leffler struct tm tm, *tm1; 6539beb93cSSam Leffler time_t t_local, t1, t2; 6639beb93cSSam Leffler os_time_t tz_offset; 6739beb93cSSam Leffler 6839beb93cSSam Leffler if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 6939beb93cSSam Leffler hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 7039beb93cSSam Leffler sec > 60) 7139beb93cSSam Leffler return -1; 7239beb93cSSam Leffler 7339beb93cSSam Leffler memset(&tm, 0, sizeof(tm)); 7439beb93cSSam Leffler tm.tm_year = year - 1900; 7539beb93cSSam Leffler tm.tm_mon = month - 1; 7639beb93cSSam Leffler tm.tm_mday = day; 7739beb93cSSam Leffler tm.tm_hour = hour; 7839beb93cSSam Leffler tm.tm_min = min; 7939beb93cSSam Leffler tm.tm_sec = sec; 8039beb93cSSam Leffler 8139beb93cSSam Leffler t_local = mktime(&tm); 8239beb93cSSam Leffler 8339beb93cSSam Leffler /* figure out offset to UTC */ 8439beb93cSSam Leffler tm1 = localtime(&t_local); 8539beb93cSSam Leffler if (tm1) { 8639beb93cSSam Leffler t1 = mktime(tm1); 8739beb93cSSam Leffler tm1 = gmtime(&t_local); 8839beb93cSSam Leffler if (tm1) { 8939beb93cSSam Leffler t2 = mktime(tm1); 9039beb93cSSam Leffler tz_offset = t2 - t1; 9139beb93cSSam Leffler } else 9239beb93cSSam Leffler tz_offset = 0; 9339beb93cSSam Leffler } else 9439beb93cSSam Leffler tz_offset = 0; 9539beb93cSSam Leffler 9639beb93cSSam Leffler *t = (os_time_t) t_local - tz_offset; 9739beb93cSSam Leffler return 0; 9839beb93cSSam Leffler } 9939beb93cSSam Leffler 10039beb93cSSam Leffler 10139beb93cSSam Leffler #ifdef __APPLE__ 10239beb93cSSam Leffler #include <fcntl.h> 10339beb93cSSam Leffler static int os_daemon(int nochdir, int noclose) 10439beb93cSSam Leffler { 10539beb93cSSam Leffler int devnull; 10639beb93cSSam Leffler 10739beb93cSSam Leffler if (chdir("/") < 0) 10839beb93cSSam Leffler return -1; 10939beb93cSSam Leffler 11039beb93cSSam Leffler devnull = open("/dev/null", O_RDWR); 11139beb93cSSam Leffler if (devnull < 0) 11239beb93cSSam Leffler return -1; 11339beb93cSSam Leffler 11439beb93cSSam Leffler if (dup2(devnull, STDIN_FILENO) < 0) { 11539beb93cSSam Leffler close(devnull); 11639beb93cSSam Leffler return -1; 11739beb93cSSam Leffler } 11839beb93cSSam Leffler 11939beb93cSSam Leffler if (dup2(devnull, STDOUT_FILENO) < 0) { 12039beb93cSSam Leffler close(devnull); 12139beb93cSSam Leffler return -1; 12239beb93cSSam Leffler } 12339beb93cSSam Leffler 12439beb93cSSam Leffler if (dup2(devnull, STDERR_FILENO) < 0) { 12539beb93cSSam Leffler close(devnull); 12639beb93cSSam Leffler return -1; 12739beb93cSSam Leffler } 12839beb93cSSam Leffler 12939beb93cSSam Leffler return 0; 13039beb93cSSam Leffler } 13139beb93cSSam Leffler #else /* __APPLE__ */ 13239beb93cSSam Leffler #define os_daemon daemon 13339beb93cSSam Leffler #endif /* __APPLE__ */ 13439beb93cSSam Leffler 13539beb93cSSam Leffler 13639beb93cSSam Leffler int os_daemonize(const char *pid_file) 13739beb93cSSam Leffler { 13839beb93cSSam Leffler #ifdef __uClinux__ 13939beb93cSSam Leffler return -1; 14039beb93cSSam Leffler #else /* __uClinux__ */ 14139beb93cSSam Leffler if (os_daemon(0, 0)) { 14239beb93cSSam Leffler perror("daemon"); 14339beb93cSSam Leffler return -1; 14439beb93cSSam Leffler } 14539beb93cSSam Leffler 14639beb93cSSam Leffler if (pid_file) { 14739beb93cSSam Leffler FILE *f = fopen(pid_file, "w"); 14839beb93cSSam Leffler if (f) { 14939beb93cSSam Leffler fprintf(f, "%u\n", getpid()); 15039beb93cSSam Leffler fclose(f); 15139beb93cSSam Leffler } 15239beb93cSSam Leffler } 15339beb93cSSam Leffler 15439beb93cSSam Leffler return -0; 15539beb93cSSam Leffler #endif /* __uClinux__ */ 15639beb93cSSam Leffler } 15739beb93cSSam Leffler 15839beb93cSSam Leffler 15939beb93cSSam Leffler void os_daemonize_terminate(const char *pid_file) 16039beb93cSSam Leffler { 16139beb93cSSam Leffler if (pid_file) 16239beb93cSSam Leffler unlink(pid_file); 16339beb93cSSam Leffler } 16439beb93cSSam Leffler 16539beb93cSSam Leffler 16639beb93cSSam Leffler int os_get_random(unsigned char *buf, size_t len) 16739beb93cSSam Leffler { 16839beb93cSSam Leffler FILE *f; 16939beb93cSSam Leffler size_t rc; 17039beb93cSSam Leffler 17139beb93cSSam Leffler f = fopen("/dev/urandom", "rb"); 17239beb93cSSam Leffler if (f == NULL) { 17339beb93cSSam Leffler printf("Could not open /dev/urandom.\n"); 17439beb93cSSam Leffler return -1; 17539beb93cSSam Leffler } 17639beb93cSSam Leffler 17739beb93cSSam Leffler rc = fread(buf, 1, len, f); 17839beb93cSSam Leffler fclose(f); 17939beb93cSSam Leffler 18039beb93cSSam Leffler return rc != len ? -1 : 0; 18139beb93cSSam Leffler } 18239beb93cSSam Leffler 18339beb93cSSam Leffler 18439beb93cSSam Leffler unsigned long os_random(void) 18539beb93cSSam Leffler { 18639beb93cSSam Leffler return random(); 18739beb93cSSam Leffler } 18839beb93cSSam Leffler 18939beb93cSSam Leffler 19039beb93cSSam Leffler char * os_rel2abs_path(const char *rel_path) 19139beb93cSSam Leffler { 19239beb93cSSam Leffler char *buf = NULL, *cwd, *ret; 19339beb93cSSam Leffler size_t len = 128, cwd_len, rel_len, ret_len; 19439beb93cSSam Leffler int last_errno; 19539beb93cSSam Leffler 19639beb93cSSam Leffler if (rel_path[0] == '/') 197*e28a4053SRui Paulo return os_strdup(rel_path); 19839beb93cSSam Leffler 19939beb93cSSam Leffler for (;;) { 200*e28a4053SRui Paulo buf = os_malloc(len); 20139beb93cSSam Leffler if (buf == NULL) 20239beb93cSSam Leffler return NULL; 20339beb93cSSam Leffler cwd = getcwd(buf, len); 20439beb93cSSam Leffler if (cwd == NULL) { 20539beb93cSSam Leffler last_errno = errno; 206*e28a4053SRui Paulo os_free(buf); 20739beb93cSSam Leffler if (last_errno != ERANGE) 20839beb93cSSam Leffler return NULL; 20939beb93cSSam Leffler len *= 2; 21039beb93cSSam Leffler if (len > 2000) 21139beb93cSSam Leffler return NULL; 21239beb93cSSam Leffler } else { 21339beb93cSSam Leffler buf[len - 1] = '\0'; 21439beb93cSSam Leffler break; 21539beb93cSSam Leffler } 21639beb93cSSam Leffler } 21739beb93cSSam Leffler 218*e28a4053SRui Paulo cwd_len = os_strlen(cwd); 219*e28a4053SRui Paulo rel_len = os_strlen(rel_path); 22039beb93cSSam Leffler ret_len = cwd_len + 1 + rel_len + 1; 221*e28a4053SRui Paulo ret = os_malloc(ret_len); 22239beb93cSSam Leffler if (ret) { 223*e28a4053SRui Paulo os_memcpy(ret, cwd, cwd_len); 22439beb93cSSam Leffler ret[cwd_len] = '/'; 225*e28a4053SRui Paulo os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 22639beb93cSSam Leffler ret[ret_len - 1] = '\0'; 22739beb93cSSam Leffler } 228*e28a4053SRui Paulo os_free(buf); 22939beb93cSSam Leffler return ret; 23039beb93cSSam Leffler } 23139beb93cSSam Leffler 23239beb93cSSam Leffler 23339beb93cSSam Leffler int os_program_init(void) 23439beb93cSSam Leffler { 235*e28a4053SRui Paulo #ifdef WPA_TRACE 236*e28a4053SRui Paulo dl_list_init(&alloc_list); 237*e28a4053SRui Paulo #endif /* WPA_TRACE */ 23839beb93cSSam Leffler return 0; 23939beb93cSSam Leffler } 24039beb93cSSam Leffler 24139beb93cSSam Leffler 24239beb93cSSam Leffler void os_program_deinit(void) 24339beb93cSSam Leffler { 244*e28a4053SRui Paulo #ifdef WPA_TRACE 245*e28a4053SRui Paulo struct os_alloc_trace *a; 246*e28a4053SRui Paulo unsigned long total = 0; 247*e28a4053SRui Paulo dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 248*e28a4053SRui Paulo total += a->len; 249*e28a4053SRui Paulo if (a->magic != ALLOC_MAGIC) { 250*e28a4053SRui Paulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 251*e28a4053SRui Paulo "len %lu", 252*e28a4053SRui Paulo a, a->magic, (unsigned long) a->len); 253*e28a4053SRui Paulo continue; 254*e28a4053SRui Paulo } 255*e28a4053SRui Paulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 256*e28a4053SRui Paulo a, (unsigned long) a->len); 257*e28a4053SRui Paulo wpa_trace_dump("memleak", a); 258*e28a4053SRui Paulo } 259*e28a4053SRui Paulo if (total) 260*e28a4053SRui Paulo wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 261*e28a4053SRui Paulo (unsigned long) total); 262*e28a4053SRui Paulo #endif /* WPA_TRACE */ 26339beb93cSSam Leffler } 26439beb93cSSam Leffler 26539beb93cSSam Leffler 26639beb93cSSam Leffler int os_setenv(const char *name, const char *value, int overwrite) 26739beb93cSSam Leffler { 26839beb93cSSam Leffler return setenv(name, value, overwrite); 26939beb93cSSam Leffler } 27039beb93cSSam Leffler 27139beb93cSSam Leffler 27239beb93cSSam Leffler int os_unsetenv(const char *name) 27339beb93cSSam Leffler { 2743157ba21SRui Paulo #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 2753157ba21SRui Paulo defined(__OpenBSD__) 27639beb93cSSam Leffler unsetenv(name); 27739beb93cSSam Leffler return 0; 27839beb93cSSam Leffler #else 27939beb93cSSam Leffler return unsetenv(name); 28039beb93cSSam Leffler #endif 28139beb93cSSam Leffler } 28239beb93cSSam Leffler 28339beb93cSSam Leffler 28439beb93cSSam Leffler char * os_readfile(const char *name, size_t *len) 28539beb93cSSam Leffler { 28639beb93cSSam Leffler FILE *f; 28739beb93cSSam Leffler char *buf; 28839beb93cSSam Leffler 28939beb93cSSam Leffler f = fopen(name, "rb"); 29039beb93cSSam Leffler if (f == NULL) 29139beb93cSSam Leffler return NULL; 29239beb93cSSam Leffler 29339beb93cSSam Leffler fseek(f, 0, SEEK_END); 29439beb93cSSam Leffler *len = ftell(f); 29539beb93cSSam Leffler fseek(f, 0, SEEK_SET); 29639beb93cSSam Leffler 297*e28a4053SRui Paulo buf = os_malloc(*len); 29839beb93cSSam Leffler if (buf == NULL) { 29939beb93cSSam Leffler fclose(f); 30039beb93cSSam Leffler return NULL; 30139beb93cSSam Leffler } 30239beb93cSSam Leffler 30339beb93cSSam Leffler if (fread(buf, 1, *len, f) != *len) { 30439beb93cSSam Leffler fclose(f); 305*e28a4053SRui Paulo os_free(buf); 30639beb93cSSam Leffler return NULL; 30739beb93cSSam Leffler } 30839beb93cSSam Leffler 30939beb93cSSam Leffler fclose(f); 31039beb93cSSam Leffler 31139beb93cSSam Leffler return buf; 31239beb93cSSam Leffler } 31339beb93cSSam Leffler 31439beb93cSSam Leffler 315*e28a4053SRui Paulo #ifndef WPA_TRACE 31639beb93cSSam Leffler void * os_zalloc(size_t size) 31739beb93cSSam Leffler { 31839beb93cSSam Leffler return calloc(1, size); 31939beb93cSSam Leffler } 320*e28a4053SRui Paulo #endif /* WPA_TRACE */ 32139beb93cSSam Leffler 32239beb93cSSam Leffler 32339beb93cSSam Leffler size_t os_strlcpy(char *dest, const char *src, size_t siz) 32439beb93cSSam Leffler { 32539beb93cSSam Leffler const char *s = src; 32639beb93cSSam Leffler size_t left = siz; 32739beb93cSSam Leffler 32839beb93cSSam Leffler if (left) { 32939beb93cSSam Leffler /* Copy string up to the maximum size of the dest buffer */ 33039beb93cSSam Leffler while (--left != 0) { 33139beb93cSSam Leffler if ((*dest++ = *s++) == '\0') 33239beb93cSSam Leffler break; 33339beb93cSSam Leffler } 33439beb93cSSam Leffler } 33539beb93cSSam Leffler 33639beb93cSSam Leffler if (left == 0) { 33739beb93cSSam Leffler /* Not enough room for the string; force NUL-termination */ 33839beb93cSSam Leffler if (siz != 0) 33939beb93cSSam Leffler *dest = '\0'; 34039beb93cSSam Leffler while (*s++) 34139beb93cSSam Leffler ; /* determine total src string length */ 34239beb93cSSam Leffler } 34339beb93cSSam Leffler 34439beb93cSSam Leffler return s - src - 1; 34539beb93cSSam Leffler } 346*e28a4053SRui Paulo 347*e28a4053SRui Paulo 348*e28a4053SRui Paulo #ifdef WPA_TRACE 349*e28a4053SRui Paulo 350*e28a4053SRui Paulo void * os_malloc(size_t size) 351*e28a4053SRui Paulo { 352*e28a4053SRui Paulo struct os_alloc_trace *a; 353*e28a4053SRui Paulo a = malloc(sizeof(*a) + size); 354*e28a4053SRui Paulo if (a == NULL) 355*e28a4053SRui Paulo return NULL; 356*e28a4053SRui Paulo a->magic = ALLOC_MAGIC; 357*e28a4053SRui Paulo dl_list_add(&alloc_list, &a->list); 358*e28a4053SRui Paulo a->len = size; 359*e28a4053SRui Paulo wpa_trace_record(a); 360*e28a4053SRui Paulo return a + 1; 361*e28a4053SRui Paulo } 362*e28a4053SRui Paulo 363*e28a4053SRui Paulo 364*e28a4053SRui Paulo void * os_realloc(void *ptr, size_t size) 365*e28a4053SRui Paulo { 366*e28a4053SRui Paulo struct os_alloc_trace *a; 367*e28a4053SRui Paulo size_t copy_len; 368*e28a4053SRui Paulo void *n; 369*e28a4053SRui Paulo 370*e28a4053SRui Paulo if (ptr == NULL) 371*e28a4053SRui Paulo return os_malloc(size); 372*e28a4053SRui Paulo 373*e28a4053SRui Paulo a = (struct os_alloc_trace *) ptr - 1; 374*e28a4053SRui Paulo if (a->magic != ALLOC_MAGIC) { 375*e28a4053SRui Paulo wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 376*e28a4053SRui Paulo a, a->magic, 377*e28a4053SRui Paulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 378*e28a4053SRui Paulo wpa_trace_show("Invalid os_realloc() call"); 379*e28a4053SRui Paulo abort(); 380*e28a4053SRui Paulo } 381*e28a4053SRui Paulo n = os_malloc(size); 382*e28a4053SRui Paulo if (n == NULL) 383*e28a4053SRui Paulo return NULL; 384*e28a4053SRui Paulo copy_len = a->len; 385*e28a4053SRui Paulo if (copy_len > size) 386*e28a4053SRui Paulo copy_len = size; 387*e28a4053SRui Paulo os_memcpy(n, a + 1, copy_len); 388*e28a4053SRui Paulo os_free(ptr); 389*e28a4053SRui Paulo return n; 390*e28a4053SRui Paulo } 391*e28a4053SRui Paulo 392*e28a4053SRui Paulo 393*e28a4053SRui Paulo void os_free(void *ptr) 394*e28a4053SRui Paulo { 395*e28a4053SRui Paulo struct os_alloc_trace *a; 396*e28a4053SRui Paulo 397*e28a4053SRui Paulo if (ptr == NULL) 398*e28a4053SRui Paulo return; 399*e28a4053SRui Paulo a = (struct os_alloc_trace *) ptr - 1; 400*e28a4053SRui Paulo if (a->magic != ALLOC_MAGIC) { 401*e28a4053SRui Paulo wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 402*e28a4053SRui Paulo a, a->magic, 403*e28a4053SRui Paulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 404*e28a4053SRui Paulo wpa_trace_show("Invalid os_free() call"); 405*e28a4053SRui Paulo abort(); 406*e28a4053SRui Paulo } 407*e28a4053SRui Paulo dl_list_del(&a->list); 408*e28a4053SRui Paulo a->magic = FREED_MAGIC; 409*e28a4053SRui Paulo 410*e28a4053SRui Paulo wpa_trace_check_ref(ptr); 411*e28a4053SRui Paulo free(a); 412*e28a4053SRui Paulo } 413*e28a4053SRui Paulo 414*e28a4053SRui Paulo 415*e28a4053SRui Paulo void * os_zalloc(size_t size) 416*e28a4053SRui Paulo { 417*e28a4053SRui Paulo void *ptr = os_malloc(size); 418*e28a4053SRui Paulo if (ptr) 419*e28a4053SRui Paulo os_memset(ptr, 0, size); 420*e28a4053SRui Paulo return ptr; 421*e28a4053SRui Paulo } 422*e28a4053SRui Paulo 423*e28a4053SRui Paulo 424*e28a4053SRui Paulo char * os_strdup(const char *s) 425*e28a4053SRui Paulo { 426*e28a4053SRui Paulo size_t len; 427*e28a4053SRui Paulo char *d; 428*e28a4053SRui Paulo len = os_strlen(s); 429*e28a4053SRui Paulo d = os_malloc(len + 1); 430*e28a4053SRui Paulo if (d == NULL) 431*e28a4053SRui Paulo return NULL; 432*e28a4053SRui Paulo os_memcpy(d, s, len); 433*e28a4053SRui Paulo d[len] = '\0'; 434*e28a4053SRui Paulo return d; 435*e28a4053SRui Paulo } 436*e28a4053SRui Paulo 437*e28a4053SRui Paulo #endif /* WPA_TRACE */ 438