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 26 static struct dl_list alloc_list; 27 28 #define ALLOC_MAGIC 0xa84ef1b2 29 #define FREED_MAGIC 0x67fd487a 30 31 struct 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 41 void 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 50 int 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 61 int 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> 103 static 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 136 int 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 159 void os_daemonize_terminate(const char *pid_file) 160 { 161 if (pid_file) 162 unlink(pid_file); 163 } 164 165 166 int 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 184 unsigned long os_random(void) 185 { 186 return random(); 187 } 188 189 190 char * 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 233 int 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 242 void 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 266 int os_setenv(const char *name, const char *value, int overwrite) 267 { 268 return setenv(name, value, overwrite); 269 } 270 271 272 int 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 284 char * 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 316 void * os_zalloc(size_t size) 317 { 318 return calloc(1, size); 319 } 320 #endif /* WPA_TRACE */ 321 322 323 size_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 350 void * 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 364 void * 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 393 void 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 415 void * 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 424 char * 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