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