os_unix.c revision 214734
1/* 2 * OS specific functions for UNIX/POSIX systems 3 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include "includes.h" 16 17#include "os.h" 18 19#ifdef WPA_TRACE 20 21#include "common.h" 22#include "list.h" 23#include "wpa_debug.h" 24#include "trace.h" 25 26static struct dl_list alloc_list; 27 28#define ALLOC_MAGIC 0xa84ef1b2 29#define FREED_MAGIC 0x67fd487a 30 31struct os_alloc_trace { 32 unsigned int magic; 33 struct dl_list list; 34 size_t len; 35 WPA_TRACE_INFO 36}; 37 38#endif /* WPA_TRACE */ 39 40 41void os_sleep(os_time_t sec, os_time_t usec) 42{ 43 if (sec) 44 sleep(sec); 45 if (usec) 46 usleep(usec); 47} 48 49 50int os_get_time(struct os_time *t) 51{ 52 int res; 53 struct timeval tv; 54 res = gettimeofday(&tv, NULL); 55 t->sec = tv.tv_sec; 56 t->usec = tv.tv_usec; 57 return res; 58} 59 60 61int os_mktime(int year, int month, int day, int hour, int min, int sec, 62 os_time_t *t) 63{ 64 struct tm tm, *tm1; 65 time_t t_local, t1, t2; 66 os_time_t tz_offset; 67 68 if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 69 hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 70 sec > 60) 71 return -1; 72 73 memset(&tm, 0, sizeof(tm)); 74 tm.tm_year = year - 1900; 75 tm.tm_mon = month - 1; 76 tm.tm_mday = day; 77 tm.tm_hour = hour; 78 tm.tm_min = min; 79 tm.tm_sec = sec; 80 81 t_local = mktime(&tm); 82 83 /* figure out offset to UTC */ 84 tm1 = localtime(&t_local); 85 if (tm1) { 86 t1 = mktime(tm1); 87 tm1 = gmtime(&t_local); 88 if (tm1) { 89 t2 = mktime(tm1); 90 tz_offset = t2 - t1; 91 } else 92 tz_offset = 0; 93 } else 94 tz_offset = 0; 95 96 *t = (os_time_t) t_local - tz_offset; 97 return 0; 98} 99 100 101#ifdef __APPLE__ 102#include <fcntl.h> 103static int os_daemon(int nochdir, int noclose) 104{ 105 int devnull; 106 107 if (chdir("/") < 0) 108 return -1; 109 110 devnull = open("/dev/null", O_RDWR); 111 if (devnull < 0) 112 return -1; 113 114 if (dup2(devnull, STDIN_FILENO) < 0) { 115 close(devnull); 116 return -1; 117 } 118 119 if (dup2(devnull, STDOUT_FILENO) < 0) { 120 close(devnull); 121 return -1; 122 } 123 124 if (dup2(devnull, STDERR_FILENO) < 0) { 125 close(devnull); 126 return -1; 127 } 128 129 return 0; 130} 131#else /* __APPLE__ */ 132#define os_daemon daemon 133#endif /* __APPLE__ */ 134 135 136int os_daemonize(const char *pid_file) 137{ 138#ifdef __uClinux__ 139 return -1; 140#else /* __uClinux__ */ 141 if (os_daemon(0, 0)) { 142 perror("daemon"); 143 return -1; 144 } 145 146 if (pid_file) { 147 FILE *f = fopen(pid_file, "w"); 148 if (f) { 149 fprintf(f, "%u\n", getpid()); 150 fclose(f); 151 } 152 } 153 154 return -0; 155#endif /* __uClinux__ */ 156} 157 158 159void os_daemonize_terminate(const char *pid_file) 160{ 161 if (pid_file) 162 unlink(pid_file); 163} 164 165 166int os_get_random(unsigned char *buf, size_t len) 167{ 168 FILE *f; 169 size_t rc; 170 171 f = fopen("/dev/urandom", "rb"); 172 if (f == NULL) { 173 printf("Could not open /dev/urandom.\n"); 174 return -1; 175 } 176 177 rc = fread(buf, 1, len, f); 178 fclose(f); 179 180 return rc != len ? -1 : 0; 181} 182 183 184unsigned long os_random(void) 185{ 186 return random(); 187} 188 189 190char * os_rel2abs_path(const char *rel_path) 191{ 192 char *buf = NULL, *cwd, *ret; 193 size_t len = 128, cwd_len, rel_len, ret_len; 194 int last_errno; 195 196 if (rel_path[0] == '/') 197 return os_strdup(rel_path); 198 199 for (;;) { 200 buf = os_malloc(len); 201 if (buf == NULL) 202 return NULL; 203 cwd = getcwd(buf, len); 204 if (cwd == NULL) { 205 last_errno = errno; 206 os_free(buf); 207 if (last_errno != ERANGE) 208 return NULL; 209 len *= 2; 210 if (len > 2000) 211 return NULL; 212 } else { 213 buf[len - 1] = '\0'; 214 break; 215 } 216 } 217 218 cwd_len = os_strlen(cwd); 219 rel_len = os_strlen(rel_path); 220 ret_len = cwd_len + 1 + rel_len + 1; 221 ret = os_malloc(ret_len); 222 if (ret) { 223 os_memcpy(ret, cwd, cwd_len); 224 ret[cwd_len] = '/'; 225 os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 226 ret[ret_len - 1] = '\0'; 227 } 228 os_free(buf); 229 return ret; 230} 231 232 233int os_program_init(void) 234{ 235#ifdef WPA_TRACE 236 dl_list_init(&alloc_list); 237#endif /* WPA_TRACE */ 238 return 0; 239} 240 241 242void os_program_deinit(void) 243{ 244#ifdef WPA_TRACE 245 struct os_alloc_trace *a; 246 unsigned long total = 0; 247 dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 248 total += a->len; 249 if (a->magic != ALLOC_MAGIC) { 250 wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 251 "len %lu", 252 a, a->magic, (unsigned long) a->len); 253 continue; 254 } 255 wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 256 a, (unsigned long) a->len); 257 wpa_trace_dump("memleak", a); 258 } 259 if (total) 260 wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 261 (unsigned long) total); 262#endif /* WPA_TRACE */ 263} 264 265 266int os_setenv(const char *name, const char *value, int overwrite) 267{ 268 return setenv(name, value, overwrite); 269} 270 271 272int os_unsetenv(const char *name) 273{ 274#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 275 defined(__OpenBSD__) 276 unsetenv(name); 277 return 0; 278#else 279 return unsetenv(name); 280#endif 281} 282 283 284char * os_readfile(const char *name, size_t *len) 285{ 286 FILE *f; 287 char *buf; 288 289 f = fopen(name, "rb"); 290 if (f == NULL) 291 return NULL; 292 293 fseek(f, 0, SEEK_END); 294 *len = ftell(f); 295 fseek(f, 0, SEEK_SET); 296 297 buf = os_malloc(*len); 298 if (buf == NULL) { 299 fclose(f); 300 return NULL; 301 } 302 303 if (fread(buf, 1, *len, f) != *len) { 304 fclose(f); 305 os_free(buf); 306 return NULL; 307 } 308 309 fclose(f); 310 311 return buf; 312} 313 314 315#ifndef WPA_TRACE 316void * os_zalloc(size_t size) 317{ 318 return calloc(1, size); 319} 320#endif /* WPA_TRACE */ 321 322 323size_t os_strlcpy(char *dest, const char *src, size_t siz) 324{ 325 const char *s = src; 326 size_t left = siz; 327 328 if (left) { 329 /* Copy string up to the maximum size of the dest buffer */ 330 while (--left != 0) { 331 if ((*dest++ = *s++) == '\0') 332 break; 333 } 334 } 335 336 if (left == 0) { 337 /* Not enough room for the string; force NUL-termination */ 338 if (siz != 0) 339 *dest = '\0'; 340 while (*s++) 341 ; /* determine total src string length */ 342 } 343 344 return s - src - 1; 345} 346 347 348#ifdef WPA_TRACE 349 350void * os_malloc(size_t size) 351{ 352 struct os_alloc_trace *a; 353 a = malloc(sizeof(*a) + size); 354 if (a == NULL) 355 return NULL; 356 a->magic = ALLOC_MAGIC; 357 dl_list_add(&alloc_list, &a->list); 358 a->len = size; 359 wpa_trace_record(a); 360 return a + 1; 361} 362 363 364void * os_realloc(void *ptr, size_t size) 365{ 366 struct os_alloc_trace *a; 367 size_t copy_len; 368 void *n; 369 370 if (ptr == NULL) 371 return os_malloc(size); 372 373 a = (struct os_alloc_trace *) ptr - 1; 374 if (a->magic != ALLOC_MAGIC) { 375 wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 376 a, a->magic, 377 a->magic == FREED_MAGIC ? " (already freed)" : ""); 378 wpa_trace_show("Invalid os_realloc() call"); 379 abort(); 380 } 381 n = os_malloc(size); 382 if (n == NULL) 383 return NULL; 384 copy_len = a->len; 385 if (copy_len > size) 386 copy_len = size; 387 os_memcpy(n, a + 1, copy_len); 388 os_free(ptr); 389 return n; 390} 391 392 393void os_free(void *ptr) 394{ 395 struct os_alloc_trace *a; 396 397 if (ptr == NULL) 398 return; 399 a = (struct os_alloc_trace *) ptr - 1; 400 if (a->magic != ALLOC_MAGIC) { 401 wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 402 a, a->magic, 403 a->magic == FREED_MAGIC ? " (already freed)" : ""); 404 wpa_trace_show("Invalid os_free() call"); 405 abort(); 406 } 407 dl_list_del(&a->list); 408 a->magic = FREED_MAGIC; 409 410 wpa_trace_check_ref(ptr); 411 free(a); 412} 413 414 415void * os_zalloc(size_t size) 416{ 417 void *ptr = os_malloc(size); 418 if (ptr) 419 os_memset(ptr, 0, size); 420 return ptr; 421} 422 423 424char * os_strdup(const char *s) 425{ 426 size_t len; 427 char *d; 428 len = os_strlen(s); 429 d = os_malloc(len + 1); 430 if (d == NULL) 431 return NULL; 432 os_memcpy(d, s, len); 433 d[len] = '\0'; 434 return d; 435} 436 437#endif /* WPA_TRACE */ 438