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