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