1189251Ssam/* 2214734Srpaulo * OS specific functions for UNIX/POSIX systems 3214734Srpaulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "os.h" 18189251Ssam 19214734Srpaulo#ifdef WPA_TRACE 20214734Srpaulo 21214734Srpaulo#include "common.h" 22214734Srpaulo#include "list.h" 23214734Srpaulo#include "wpa_debug.h" 24214734Srpaulo#include "trace.h" 25214734Srpaulo 26214734Srpaulostatic struct dl_list alloc_list; 27214734Srpaulo 28214734Srpaulo#define ALLOC_MAGIC 0xa84ef1b2 29214734Srpaulo#define FREED_MAGIC 0x67fd487a 30214734Srpaulo 31214734Srpaulostruct os_alloc_trace { 32214734Srpaulo unsigned int magic; 33214734Srpaulo struct dl_list list; 34214734Srpaulo size_t len; 35214734Srpaulo WPA_TRACE_INFO 36214734Srpaulo}; 37214734Srpaulo 38214734Srpaulo#endif /* WPA_TRACE */ 39214734Srpaulo 40214734Srpaulo 41189251Ssamvoid os_sleep(os_time_t sec, os_time_t usec) 42189251Ssam{ 43189251Ssam if (sec) 44189251Ssam sleep(sec); 45189251Ssam if (usec) 46189251Ssam usleep(usec); 47189251Ssam} 48189251Ssam 49189251Ssam 50189251Ssamint os_get_time(struct os_time *t) 51189251Ssam{ 52189251Ssam int res; 53189251Ssam struct timeval tv; 54189251Ssam res = gettimeofday(&tv, NULL); 55189251Ssam t->sec = tv.tv_sec; 56189251Ssam t->usec = tv.tv_usec; 57189251Ssam return res; 58189251Ssam} 59189251Ssam 60189251Ssam 61189251Ssamint os_mktime(int year, int month, int day, int hour, int min, int sec, 62189251Ssam os_time_t *t) 63189251Ssam{ 64189251Ssam struct tm tm, *tm1; 65189251Ssam time_t t_local, t1, t2; 66189251Ssam os_time_t tz_offset; 67189251Ssam 68189251Ssam if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 69189251Ssam hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 70189251Ssam sec > 60) 71189251Ssam return -1; 72189251Ssam 73189251Ssam memset(&tm, 0, sizeof(tm)); 74189251Ssam tm.tm_year = year - 1900; 75189251Ssam tm.tm_mon = month - 1; 76189251Ssam tm.tm_mday = day; 77189251Ssam tm.tm_hour = hour; 78189251Ssam tm.tm_min = min; 79189251Ssam tm.tm_sec = sec; 80189251Ssam 81189251Ssam t_local = mktime(&tm); 82189251Ssam 83189251Ssam /* figure out offset to UTC */ 84189251Ssam tm1 = localtime(&t_local); 85189251Ssam if (tm1) { 86189251Ssam t1 = mktime(tm1); 87189251Ssam tm1 = gmtime(&t_local); 88189251Ssam if (tm1) { 89189251Ssam t2 = mktime(tm1); 90189251Ssam tz_offset = t2 - t1; 91189251Ssam } else 92189251Ssam tz_offset = 0; 93189251Ssam } else 94189251Ssam tz_offset = 0; 95189251Ssam 96189251Ssam *t = (os_time_t) t_local - tz_offset; 97189251Ssam return 0; 98189251Ssam} 99189251Ssam 100189251Ssam 101189251Ssam#ifdef __APPLE__ 102189251Ssam#include <fcntl.h> 103189251Ssamstatic int os_daemon(int nochdir, int noclose) 104189251Ssam{ 105189251Ssam int devnull; 106189251Ssam 107189251Ssam if (chdir("/") < 0) 108189251Ssam return -1; 109189251Ssam 110189251Ssam devnull = open("/dev/null", O_RDWR); 111189251Ssam if (devnull < 0) 112189251Ssam return -1; 113189251Ssam 114189251Ssam if (dup2(devnull, STDIN_FILENO) < 0) { 115189251Ssam close(devnull); 116189251Ssam return -1; 117189251Ssam } 118189251Ssam 119189251Ssam if (dup2(devnull, STDOUT_FILENO) < 0) { 120189251Ssam close(devnull); 121189251Ssam return -1; 122189251Ssam } 123189251Ssam 124189251Ssam if (dup2(devnull, STDERR_FILENO) < 0) { 125189251Ssam close(devnull); 126189251Ssam return -1; 127189251Ssam } 128189251Ssam 129189251Ssam return 0; 130189251Ssam} 131189251Ssam#else /* __APPLE__ */ 132189251Ssam#define os_daemon daemon 133189251Ssam#endif /* __APPLE__ */ 134189251Ssam 135189251Ssam 136189251Ssamint os_daemonize(const char *pid_file) 137189251Ssam{ 138189251Ssam#ifdef __uClinux__ 139189251Ssam return -1; 140189251Ssam#else /* __uClinux__ */ 141189251Ssam if (os_daemon(0, 0)) { 142189251Ssam perror("daemon"); 143189251Ssam return -1; 144189251Ssam } 145189251Ssam 146189251Ssam if (pid_file) { 147189251Ssam FILE *f = fopen(pid_file, "w"); 148189251Ssam if (f) { 149189251Ssam fprintf(f, "%u\n", getpid()); 150189251Ssam fclose(f); 151189251Ssam } 152189251Ssam } 153189251Ssam 154189251Ssam return -0; 155189251Ssam#endif /* __uClinux__ */ 156189251Ssam} 157189251Ssam 158189251Ssam 159189251Ssamvoid os_daemonize_terminate(const char *pid_file) 160189251Ssam{ 161189251Ssam if (pid_file) 162189251Ssam unlink(pid_file); 163189251Ssam} 164189251Ssam 165189251Ssam 166189251Ssamint os_get_random(unsigned char *buf, size_t len) 167189251Ssam{ 168189251Ssam FILE *f; 169189251Ssam size_t rc; 170189251Ssam 171189251Ssam f = fopen("/dev/urandom", "rb"); 172189251Ssam if (f == NULL) { 173189251Ssam printf("Could not open /dev/urandom.\n"); 174189251Ssam return -1; 175189251Ssam } 176189251Ssam 177189251Ssam rc = fread(buf, 1, len, f); 178189251Ssam fclose(f); 179189251Ssam 180189251Ssam return rc != len ? -1 : 0; 181189251Ssam} 182189251Ssam 183189251Ssam 184189251Ssamunsigned long os_random(void) 185189251Ssam{ 186189251Ssam return random(); 187189251Ssam} 188189251Ssam 189189251Ssam 190189251Ssamchar * os_rel2abs_path(const char *rel_path) 191189251Ssam{ 192189251Ssam char *buf = NULL, *cwd, *ret; 193189251Ssam size_t len = 128, cwd_len, rel_len, ret_len; 194189251Ssam int last_errno; 195189251Ssam 196189251Ssam if (rel_path[0] == '/') 197214734Srpaulo return os_strdup(rel_path); 198189251Ssam 199189251Ssam for (;;) { 200214734Srpaulo buf = os_malloc(len); 201189251Ssam if (buf == NULL) 202189251Ssam return NULL; 203189251Ssam cwd = getcwd(buf, len); 204189251Ssam if (cwd == NULL) { 205189251Ssam last_errno = errno; 206214734Srpaulo os_free(buf); 207189251Ssam if (last_errno != ERANGE) 208189251Ssam return NULL; 209189251Ssam len *= 2; 210189251Ssam if (len > 2000) 211189251Ssam return NULL; 212189251Ssam } else { 213189251Ssam buf[len - 1] = '\0'; 214189251Ssam break; 215189251Ssam } 216189251Ssam } 217189251Ssam 218214734Srpaulo cwd_len = os_strlen(cwd); 219214734Srpaulo rel_len = os_strlen(rel_path); 220189251Ssam ret_len = cwd_len + 1 + rel_len + 1; 221214734Srpaulo ret = os_malloc(ret_len); 222189251Ssam if (ret) { 223214734Srpaulo os_memcpy(ret, cwd, cwd_len); 224189251Ssam ret[cwd_len] = '/'; 225214734Srpaulo os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 226189251Ssam ret[ret_len - 1] = '\0'; 227189251Ssam } 228214734Srpaulo os_free(buf); 229189251Ssam return ret; 230189251Ssam} 231189251Ssam 232189251Ssam 233189251Ssamint os_program_init(void) 234189251Ssam{ 235214734Srpaulo#ifdef WPA_TRACE 236214734Srpaulo dl_list_init(&alloc_list); 237214734Srpaulo#endif /* WPA_TRACE */ 238189251Ssam return 0; 239189251Ssam} 240189251Ssam 241189251Ssam 242189251Ssamvoid os_program_deinit(void) 243189251Ssam{ 244214734Srpaulo#ifdef WPA_TRACE 245214734Srpaulo struct os_alloc_trace *a; 246214734Srpaulo unsigned long total = 0; 247214734Srpaulo dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 248214734Srpaulo total += a->len; 249214734Srpaulo if (a->magic != ALLOC_MAGIC) { 250214734Srpaulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 251214734Srpaulo "len %lu", 252214734Srpaulo a, a->magic, (unsigned long) a->len); 253214734Srpaulo continue; 254214734Srpaulo } 255214734Srpaulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 256214734Srpaulo a, (unsigned long) a->len); 257214734Srpaulo wpa_trace_dump("memleak", a); 258214734Srpaulo } 259214734Srpaulo if (total) 260214734Srpaulo wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 261214734Srpaulo (unsigned long) total); 262214734Srpaulo#endif /* WPA_TRACE */ 263189251Ssam} 264189251Ssam 265189251Ssam 266189251Ssamint os_setenv(const char *name, const char *value, int overwrite) 267189251Ssam{ 268189251Ssam return setenv(name, value, overwrite); 269189251Ssam} 270189251Ssam 271189251Ssam 272189251Ssamint os_unsetenv(const char *name) 273189251Ssam{ 274209158Srpaulo#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 275209158Srpaulo defined(__OpenBSD__) 276189251Ssam unsetenv(name); 277189251Ssam return 0; 278189251Ssam#else 279189251Ssam return unsetenv(name); 280189251Ssam#endif 281189251Ssam} 282189251Ssam 283189251Ssam 284189251Ssamchar * os_readfile(const char *name, size_t *len) 285189251Ssam{ 286189251Ssam FILE *f; 287189251Ssam char *buf; 288189251Ssam 289189251Ssam f = fopen(name, "rb"); 290189251Ssam if (f == NULL) 291189251Ssam return NULL; 292189251Ssam 293189251Ssam fseek(f, 0, SEEK_END); 294189251Ssam *len = ftell(f); 295189251Ssam fseek(f, 0, SEEK_SET); 296189251Ssam 297214734Srpaulo buf = os_malloc(*len); 298189251Ssam if (buf == NULL) { 299189251Ssam fclose(f); 300189251Ssam return NULL; 301189251Ssam } 302189251Ssam 303189251Ssam if (fread(buf, 1, *len, f) != *len) { 304189251Ssam fclose(f); 305214734Srpaulo os_free(buf); 306189251Ssam return NULL; 307189251Ssam } 308189251Ssam 309189251Ssam fclose(f); 310189251Ssam 311189251Ssam return buf; 312189251Ssam} 313189251Ssam 314189251Ssam 315214734Srpaulo#ifndef WPA_TRACE 316189251Ssamvoid * os_zalloc(size_t size) 317189251Ssam{ 318189251Ssam return calloc(1, size); 319189251Ssam} 320214734Srpaulo#endif /* WPA_TRACE */ 321189251Ssam 322189251Ssam 323189251Ssamsize_t os_strlcpy(char *dest, const char *src, size_t siz) 324189251Ssam{ 325189251Ssam const char *s = src; 326189251Ssam size_t left = siz; 327189251Ssam 328189251Ssam if (left) { 329189251Ssam /* Copy string up to the maximum size of the dest buffer */ 330189251Ssam while (--left != 0) { 331189251Ssam if ((*dest++ = *s++) == '\0') 332189251Ssam break; 333189251Ssam } 334189251Ssam } 335189251Ssam 336189251Ssam if (left == 0) { 337189251Ssam /* Not enough room for the string; force NUL-termination */ 338189251Ssam if (siz != 0) 339189251Ssam *dest = '\0'; 340189251Ssam while (*s++) 341189251Ssam ; /* determine total src string length */ 342189251Ssam } 343189251Ssam 344189251Ssam return s - src - 1; 345189251Ssam} 346214734Srpaulo 347214734Srpaulo 348214734Srpaulo#ifdef WPA_TRACE 349214734Srpaulo 350214734Srpaulovoid * os_malloc(size_t size) 351214734Srpaulo{ 352214734Srpaulo struct os_alloc_trace *a; 353214734Srpaulo a = malloc(sizeof(*a) + size); 354214734Srpaulo if (a == NULL) 355214734Srpaulo return NULL; 356214734Srpaulo a->magic = ALLOC_MAGIC; 357214734Srpaulo dl_list_add(&alloc_list, &a->list); 358214734Srpaulo a->len = size; 359214734Srpaulo wpa_trace_record(a); 360214734Srpaulo return a + 1; 361214734Srpaulo} 362214734Srpaulo 363214734Srpaulo 364214734Srpaulovoid * os_realloc(void *ptr, size_t size) 365214734Srpaulo{ 366214734Srpaulo struct os_alloc_trace *a; 367214734Srpaulo size_t copy_len; 368214734Srpaulo void *n; 369214734Srpaulo 370214734Srpaulo if (ptr == NULL) 371214734Srpaulo return os_malloc(size); 372214734Srpaulo 373214734Srpaulo a = (struct os_alloc_trace *) ptr - 1; 374214734Srpaulo if (a->magic != ALLOC_MAGIC) { 375214734Srpaulo wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 376214734Srpaulo a, a->magic, 377214734Srpaulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 378214734Srpaulo wpa_trace_show("Invalid os_realloc() call"); 379214734Srpaulo abort(); 380214734Srpaulo } 381214734Srpaulo n = os_malloc(size); 382214734Srpaulo if (n == NULL) 383214734Srpaulo return NULL; 384214734Srpaulo copy_len = a->len; 385214734Srpaulo if (copy_len > size) 386214734Srpaulo copy_len = size; 387214734Srpaulo os_memcpy(n, a + 1, copy_len); 388214734Srpaulo os_free(ptr); 389214734Srpaulo return n; 390214734Srpaulo} 391214734Srpaulo 392214734Srpaulo 393214734Srpaulovoid os_free(void *ptr) 394214734Srpaulo{ 395214734Srpaulo struct os_alloc_trace *a; 396214734Srpaulo 397214734Srpaulo if (ptr == NULL) 398214734Srpaulo return; 399214734Srpaulo a = (struct os_alloc_trace *) ptr - 1; 400214734Srpaulo if (a->magic != ALLOC_MAGIC) { 401214734Srpaulo wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 402214734Srpaulo a, a->magic, 403214734Srpaulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 404214734Srpaulo wpa_trace_show("Invalid os_free() call"); 405214734Srpaulo abort(); 406214734Srpaulo } 407214734Srpaulo dl_list_del(&a->list); 408214734Srpaulo a->magic = FREED_MAGIC; 409214734Srpaulo 410214734Srpaulo wpa_trace_check_ref(ptr); 411214734Srpaulo free(a); 412214734Srpaulo} 413214734Srpaulo 414214734Srpaulo 415214734Srpaulovoid * os_zalloc(size_t size) 416214734Srpaulo{ 417214734Srpaulo void *ptr = os_malloc(size); 418214734Srpaulo if (ptr) 419214734Srpaulo os_memset(ptr, 0, size); 420214734Srpaulo return ptr; 421214734Srpaulo} 422214734Srpaulo 423214734Srpaulo 424214734Srpaulochar * os_strdup(const char *s) 425214734Srpaulo{ 426214734Srpaulo size_t len; 427214734Srpaulo char *d; 428214734Srpaulo len = os_strlen(s); 429214734Srpaulo d = os_malloc(len + 1); 430214734Srpaulo if (d == NULL) 431214734Srpaulo return NULL; 432214734Srpaulo os_memcpy(d, s, len); 433214734Srpaulo d[len] = '\0'; 434214734Srpaulo return d; 435214734Srpaulo} 436214734Srpaulo 437214734Srpaulo#endif /* WPA_TRACE */ 438