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