1/* 2 * wpa_supplicant/hostapd / Internal implementation of OS specific functions 3 * Copyright (c) 2005-2006, 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 * This file is an example of operating system specific wrapper functions. 9 * This version implements many of the functions internally, so it can be used 10 * to fill in missing functions from the target system C libraries. 11 * 12 * Some of the functions are using standard C library calls in order to keep 13 * this file in working condition to allow the functions to be tested on a 14 * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for 15 * this file to work correctly. Note that these implementations are only 16 * examples and are not optimized for speed. 17 */ 18 19#include "includes.h" 20#include <time.h> 21#include <sys/wait.h> 22 23#undef OS_REJECT_C_LIB_FUNCTIONS 24#include "common.h" 25 26void os_sleep(os_time_t sec, os_time_t usec) 27{ 28 if (sec) 29 sleep(sec); 30 if (usec) 31 usleep(usec); 32} 33 34 35int os_get_time(struct os_time *t) 36{ 37 int res; 38 struct timeval tv; 39 res = gettimeofday(&tv, NULL); 40 t->sec = tv.tv_sec; 41 t->usec = tv.tv_usec; 42 return res; 43} 44 45 46int os_get_reltime(struct os_reltime *t) 47{ 48 int res; 49 struct timeval tv; 50 res = gettimeofday(&tv, NULL); 51 t->sec = tv.tv_sec; 52 t->usec = tv.tv_usec; 53 return res; 54} 55 56 57int os_mktime(int year, int month, int day, int hour, int min, int sec, 58 os_time_t *t) 59{ 60 struct tm tm; 61 62 if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 63 hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 64 sec > 60) 65 return -1; 66 67 os_memset(&tm, 0, sizeof(tm)); 68 tm.tm_year = year - 1900; 69 tm.tm_mon = month - 1; 70 tm.tm_mday = day; 71 tm.tm_hour = hour; 72 tm.tm_min = min; 73 tm.tm_sec = sec; 74 75 *t = (os_time_t) mktime(&tm); 76 return 0; 77} 78 79 80int os_gmtime(os_time_t t, struct os_tm *tm) 81{ 82 struct tm *tm2; 83 time_t t2 = t; 84 85 tm2 = gmtime(&t2); 86 if (tm2 == NULL) 87 return -1; 88 tm->sec = tm2->tm_sec; 89 tm->min = tm2->tm_min; 90 tm->hour = tm2->tm_hour; 91 tm->day = tm2->tm_mday; 92 tm->month = tm2->tm_mon + 1; 93 tm->year = tm2->tm_year + 1900; 94 return 0; 95} 96 97 98int os_daemonize(const char *pid_file) 99{ 100 if (daemon(0, 0)) { 101 wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); 102 return -1; 103 } 104 105 if (pid_file) { 106 FILE *f = fopen(pid_file, "w"); 107 if (f) { 108 fprintf(f, "%u\n", getpid()); 109 fclose(f); 110 } 111 } 112 113 return -0; 114} 115 116 117void os_daemonize_terminate(const char *pid_file) 118{ 119 if (pid_file) 120 unlink(pid_file); 121} 122 123 124int os_get_random(unsigned char *buf, size_t len) 125{ 126#if defined(TEST_FUZZ) || defined(CONFIG_TEST_RANDOM) 127 size_t i; 128 129 for (i = 0; i < len; i++) 130 buf[i] = i & 0xff; 131 return 0; 132#else /* TEST_FUZZ */ 133 FILE *f; 134 size_t rc; 135 136 f = fopen("/dev/urandom", "rb"); 137 if (f == NULL) { 138 printf("Could not open /dev/urandom.\n"); 139 return -1; 140 } 141 142 rc = fread(buf, 1, len, f); 143 fclose(f); 144 145 return rc != len ? -1 : 0; 146#endif 147} 148 149 150unsigned long os_random(void) 151{ 152 return random(); 153} 154 155 156char * os_rel2abs_path(const char *rel_path) 157{ 158 char *buf = NULL, *cwd, *ret; 159 size_t len = 128, cwd_len, rel_len, ret_len; 160 161 if (rel_path[0] == '/') 162 return os_strdup(rel_path); 163 164 for (;;) { 165 buf = os_malloc(len); 166 if (buf == NULL) 167 return NULL; 168 cwd = getcwd(buf, len); 169 if (cwd == NULL) { 170 os_free(buf); 171 if (errno != ERANGE) { 172 return NULL; 173 } 174 len *= 2; 175 } else { 176 break; 177 } 178 } 179 180 cwd_len = os_strlen(cwd); 181 rel_len = os_strlen(rel_path); 182 ret_len = cwd_len + 1 + rel_len + 1; 183 ret = os_malloc(ret_len); 184 if (ret) { 185 os_memcpy(ret, cwd, cwd_len); 186 ret[cwd_len] = '/'; 187 os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 188 ret[ret_len - 1] = '\0'; 189 } 190 os_free(buf); 191 return ret; 192} 193 194 195int os_program_init(void) 196{ 197 return 0; 198} 199 200 201void os_program_deinit(void) 202{ 203} 204 205 206int os_setenv(const char *name, const char *value, int overwrite) 207{ 208 return setenv(name, value, overwrite); 209} 210 211 212int os_unsetenv(const char *name) 213{ 214#if defined(__FreeBSD__) || defined(__NetBSD__) 215 unsetenv(name); 216 return 0; 217#else 218 return unsetenv(name); 219#endif 220} 221 222 223char * os_readfile(const char *name, size_t *len) 224{ 225 FILE *f; 226 char *buf; 227 228 f = fopen(name, "rb"); 229 if (f == NULL) 230 return NULL; 231 232 fseek(f, 0, SEEK_END); 233 *len = ftell(f); 234 fseek(f, 0, SEEK_SET); 235 236 buf = os_malloc(*len); 237 if (buf == NULL) { 238 fclose(f); 239 return NULL; 240 } 241 242 if (fread(buf, 1, *len, f) != *len) { 243 fclose(f); 244 os_free(buf); 245 return NULL; 246 } 247 248 fclose(f); 249 250 return buf; 251} 252 253 254int os_fdatasync(FILE *stream) 255{ 256 return 0; 257} 258 259 260void * os_zalloc(size_t size) 261{ 262 void *n = os_malloc(size); 263 if (n) 264 os_memset(n, 0, size); 265 return n; 266} 267 268 269void * os_malloc(size_t size) 270{ 271 return malloc(size); 272} 273 274 275void * os_realloc(void *ptr, size_t size) 276{ 277 return realloc(ptr, size); 278} 279 280 281void os_free(void *ptr) 282{ 283 free(ptr); 284} 285 286 287void * os_memcpy(void *dest, const void *src, size_t n) 288{ 289 char *d = dest; 290 const char *s = src; 291 while (n--) 292 *d++ = *s++; 293 return dest; 294} 295 296 297void * os_memmove(void *dest, const void *src, size_t n) 298{ 299 if (dest < src) 300 os_memcpy(dest, src, n); 301 else { 302 /* overlapping areas */ 303 char *d = (char *) dest + n; 304 const char *s = (const char *) src + n; 305 while (n--) 306 *--d = *--s; 307 } 308 return dest; 309} 310 311 312void * os_memset(void *s, int c, size_t n) 313{ 314 char *p = s; 315 while (n--) 316 *p++ = c; 317 return s; 318} 319 320 321int os_memcmp(const void *s1, const void *s2, size_t n) 322{ 323 const unsigned char *p1 = s1, *p2 = s2; 324 325 if (n == 0) 326 return 0; 327 328 while (*p1 == *p2) { 329 p1++; 330 p2++; 331 n--; 332 if (n == 0) 333 return 0; 334 } 335 336 return *p1 - *p2; 337} 338 339 340char * os_strdup(const char *s) 341{ 342 char *res; 343 size_t len; 344 if (s == NULL) 345 return NULL; 346 len = os_strlen(s); 347 res = os_malloc(len + 1); 348 if (res) 349 os_memcpy(res, s, len + 1); 350 return res; 351} 352 353 354size_t os_strlen(const char *s) 355{ 356 const char *p = s; 357 while (*p) 358 p++; 359 return p - s; 360} 361 362 363int os_strcasecmp(const char *s1, const char *s2) 364{ 365 /* 366 * Ignoring case is not required for main functionality, so just use 367 * the case sensitive version of the function. 368 */ 369 return os_strcmp(s1, s2); 370} 371 372 373int os_strncasecmp(const char *s1, const char *s2, size_t n) 374{ 375 /* 376 * Ignoring case is not required for main functionality, so just use 377 * the case sensitive version of the function. 378 */ 379 return os_strncmp(s1, s2, n); 380} 381 382 383char * os_strchr(const char *s, int c) 384{ 385 while (*s) { 386 if (*s == c) 387 return (char *) s; 388 s++; 389 } 390 return NULL; 391} 392 393 394char * os_strrchr(const char *s, int c) 395{ 396 const char *p = s; 397 while (*p) 398 p++; 399 p--; 400 while (p >= s) { 401 if (*p == c) 402 return (char *) p; 403 p--; 404 } 405 return NULL; 406} 407 408 409int os_strcmp(const char *s1, const char *s2) 410{ 411 while (*s1 == *s2) { 412 if (*s1 == '\0') 413 break; 414 s1++; 415 s2++; 416 } 417 418 return *s1 - *s2; 419} 420 421 422int os_strncmp(const char *s1, const char *s2, size_t n) 423{ 424 if (n == 0) 425 return 0; 426 427 while (*s1 == *s2) { 428 if (*s1 == '\0') 429 break; 430 s1++; 431 s2++; 432 n--; 433 if (n == 0) 434 return 0; 435 } 436 437 return *s1 - *s2; 438} 439 440 441size_t os_strlcpy(char *dest, const char *src, size_t siz) 442{ 443 const char *s = src; 444 size_t left = siz; 445 446 if (left) { 447 /* Copy string up to the maximum size of the dest buffer */ 448 while (--left != 0) { 449 if ((*dest++ = *s++) == '\0') 450 break; 451 } 452 } 453 454 if (left == 0) { 455 /* Not enough room for the string; force NUL-termination */ 456 if (siz != 0) 457 *dest = '\0'; 458 while (*s++) 459 ; /* determine total src string length */ 460 } 461 462 return s - src - 1; 463} 464 465 466int os_memcmp_const(const void *a, const void *b, size_t len) 467{ 468 const u8 *aa = a; 469 const u8 *bb = b; 470 size_t i; 471 u8 res; 472 473 for (res = 0, i = 0; i < len; i++) 474 res |= aa[i] ^ bb[i]; 475 476 return res; 477} 478 479 480char * os_strstr(const char *haystack, const char *needle) 481{ 482 size_t len = os_strlen(needle); 483 while (*haystack) { 484 if (os_strncmp(haystack, needle, len) == 0) 485 return (char *) haystack; 486 haystack++; 487 } 488 489 return NULL; 490} 491 492 493int os_snprintf(char *str, size_t size, const char *format, ...) 494{ 495 va_list ap; 496 int ret; 497 498 /* See http://www.ijs.si/software/snprintf/ for portable 499 * implementation of snprintf. 500 */ 501 502 va_start(ap, format); 503 ret = vsnprintf(str, size, format, ap); 504 va_end(ap); 505 if (size > 0) 506 str[size - 1] = '\0'; 507 return ret; 508} 509 510 511int os_exec(const char *program, const char *arg, int wait_completion) 512{ 513 pid_t pid; 514 int pid_status; 515 516 pid = fork(); 517 if (pid < 0) { 518 wpa_printf(MSG_ERROR, "fork: %s", strerror(errno)); 519 return -1; 520 } 521 522 if (pid == 0) { 523 /* run the external command in the child process */ 524 const int MAX_ARG = 30; 525 char *_program, *_arg, *pos; 526 char *argv[MAX_ARG + 1]; 527 int i; 528 529 _program = os_strdup(program); 530 _arg = os_strdup(arg); 531 532 argv[0] = _program; 533 534 i = 1; 535 pos = _arg; 536 while (i < MAX_ARG && pos && *pos) { 537 while (*pos == ' ') 538 pos++; 539 if (*pos == '\0') 540 break; 541 argv[i++] = pos; 542 pos = os_strchr(pos, ' '); 543 if (pos) 544 *pos++ = '\0'; 545 } 546 argv[i] = NULL; 547 548 execv(program, argv); 549 wpa_printf(MSG_ERROR, "execv: %s", strerror(errno)); 550 os_free(_program); 551 os_free(_arg); 552 exit(0); 553 return -1; 554 } 555 556 if (wait_completion) { 557 /* wait for the child process to complete in the parent */ 558 waitpid(pid, &pid_status, 0); 559 } 560 561 return 0; 562} 563