Serenity Operating System
at portability 771 lines 19 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/Assertions.h> 28#include <AK/HashMap.h> 29#include <AK/StdLibExtras.h> 30#include <AK/Types.h> 31#include <AK/Utf8View.h> 32#include <Kernel/Syscall.h> 33#include <alloca.h> 34#include <assert.h> 35#include <ctype.h> 36#include <errno.h> 37#include <signal.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <sys/mman.h> 42#include <sys/stat.h> 43#include <sys/wait.h> 44#include <unistd.h> 45 46template<typename T, T min_value, T max_value> 47static inline T strtol_impl(const char* nptr, char** endptr, int base) 48{ 49 errno = 0; 50 51 if (base < 0 || base == 1 || base > 36) { 52 errno = EINVAL; 53 if (endptr) 54 *endptr = const_cast<char*>(nptr); 55 return 0; 56 } 57 58 const char* p = nptr; 59 while (isspace(*p)) 60 ++p; 61 62 bool is_negative = false; 63 if (*p == '-') { 64 is_negative = true; 65 ++p; 66 } else { 67 if (*p == '+') 68 ++p; 69 } 70 71 if (base == 0 || base == 16) { 72 if (base == 0) 73 base = 10; 74 if (*p == '0') { 75 if (*(p + 1) == 'X' || *(p + 1) == 'x') { 76 p += 2; 77 base = 16; 78 } else if (base != 16) { 79 base = 8; 80 } 81 } 82 } 83 84 T cutoff_point = is_negative ? (min_value / base) : (max_value / base); 85 int max_valid_digit_at_cutoff_point = is_negative ? (min_value % base) : (max_value % base); 86 87 T num = 0; 88 89 bool has_overflowed = false; 90 unsigned digits_consumed = 0; 91 92 for (;;) { 93 char ch = *(p++); 94 int digit; 95 if (isdigit(ch)) 96 digit = ch - '0'; 97 else if (islower(ch)) 98 digit = ch - ('a' - 10); 99 else if (isupper(ch)) 100 digit = ch - ('A' - 10); 101 else 102 break; 103 104 if (digit >= base) 105 break; 106 107 if (has_overflowed) 108 continue; 109 110 bool is_past_cutoff = is_negative ? num < cutoff_point : num > cutoff_point; 111 112 if (is_past_cutoff || (num == cutoff_point && digit > max_valid_digit_at_cutoff_point)) { 113 has_overflowed = true; 114 num = is_negative ? min_value : max_value; 115 errno = ERANGE; 116 } else { 117 num *= base; 118 num += is_negative ? -digit : digit; 119 ++digits_consumed; 120 } 121 } 122 123 if (endptr) { 124 if (has_overflowed || digits_consumed > 0) 125 *endptr = const_cast<char*>(p - 1); 126 else 127 *endptr = const_cast<char*>(nptr); 128 } 129 return num; 130} 131 132__attribute__((warn_unused_result)) int __generate_unique_filename(char* pattern) 133{ 134 size_t length = strlen(pattern); 135 136 if (length < 6 || memcmp(pattern + length - 6, "XXXXXX", 6)) { 137 errno = EINVAL; 138 return -1; 139 } 140 141 size_t start = length - 6; 142 143 static constexpr char random_characters[] = "abcdefghijklmnopqrstuvwxyz0123456789"; 144 145 for (int attempt = 0; attempt < 100; ++attempt) { 146 for (int i = 0; i < 6; ++i) 147 pattern[start + i] = random_characters[(rand() % sizeof(random_characters))]; 148 struct stat st; 149 int rc = lstat(pattern, &st); 150 if (rc < 0 && errno == ENOENT) 151 return 0; 152 } 153 errno = EEXIST; 154 return -1; 155} 156 157extern "C" { 158 159// Itanium C++ ABI methods defined in crt0.cpp 160extern int __cxa_atexit(void (*function)(void*), void* paramter, void* dso_handle); 161extern void __cxa_finalize(void* dso_handle); 162 163void exit(int status) 164{ 165 __cxa_finalize(nullptr); 166 extern void _fini(); 167 _fini(); 168 fflush(stdout); 169 fflush(stderr); 170 _exit(status); 171 ASSERT_NOT_REACHED(); 172} 173 174static void __atexit_to_cxa_atexit(void* handler) 175{ 176 reinterpret_cast<void (*)()>(handler)(); 177} 178 179int atexit(void (*handler)()) 180{ 181 return __cxa_atexit(__atexit_to_cxa_atexit, (void*)handler, nullptr); 182} 183 184void abort() 185{ 186 raise(SIGABRT); 187 ASSERT_NOT_REACHED(); 188} 189 190static HashTable<const char*> s_malloced_environment_variables; 191 192static void free_environment_variable_if_needed(const char* var) 193{ 194 if (!s_malloced_environment_variables.contains(var)) 195 return; 196 free(const_cast<char*>(var)); 197 s_malloced_environment_variables.remove(var); 198} 199 200char* getenv(const char* name) 201{ 202 size_t vl = strlen(name); 203 for (size_t i = 0; environ[i]; ++i) { 204 const char* decl = environ[i]; 205 char* eq = strchr(decl, '='); 206 if (!eq) 207 continue; 208 size_t varLength = eq - decl; 209 if (vl != varLength) 210 continue; 211 if (strncmp(decl, name, varLength) == 0) { 212 return eq + 1; 213 } 214 } 215 return nullptr; 216} 217 218int unsetenv(const char* name) 219{ 220 auto new_var_len = strlen(name); 221 size_t environ_size = 0; 222 int skip = -1; 223 224 for (; environ[environ_size]; ++environ_size) { 225 char* old_var = environ[environ_size]; 226 char* old_eq = strchr(old_var, '='); 227 ASSERT(old_eq); 228 size_t old_var_len = old_eq - old_var; 229 230 if (new_var_len != old_var_len) 231 continue; // can't match 232 233 if (strncmp(name, old_var, new_var_len) == 0) 234 skip = environ_size; 235 } 236 237 if (skip == -1) 238 return 0; // not found: no failure. 239 240 // Shuffle the existing array down by one. 241 memmove(&environ[skip], &environ[skip + 1], ((environ_size - 1) - skip) * sizeof(environ[0])); 242 environ[environ_size - 1] = nullptr; 243 244 free_environment_variable_if_needed(name); 245 return 0; 246} 247 248int setenv(const char* name, const char* value, int overwrite) 249{ 250 if (!overwrite && !getenv(name)) 251 return 0; 252 auto length = strlen(name) + strlen(value) + 2; 253 auto* var = (char*)malloc(length); 254 snprintf(var, length, "%s=%s", name, value); 255 s_malloced_environment_variables.set(var); 256 return putenv(var); 257} 258 259int putenv(char* new_var) 260{ 261 char* new_eq = strchr(new_var, '='); 262 263 if (!new_eq) 264 return unsetenv(new_var); 265 266 auto new_var_len = new_eq - new_var; 267 int environ_size = 0; 268 for (; environ[environ_size]; ++environ_size) { 269 char* old_var = environ[environ_size]; 270 char* old_eq = strchr(old_var, '='); 271 ASSERT(old_eq); 272 auto old_var_len = old_eq - old_var; 273 274 if (new_var_len != old_var_len) 275 continue; // can't match 276 277 if (strncmp(new_var, old_var, new_var_len) == 0) { 278 free_environment_variable_if_needed(old_var); 279 environ[environ_size] = new_var; 280 return 0; 281 } 282 } 283 284 // At this point, we need to append the new var. 285 // 2 here: one for the new var, one for the sentinel value. 286 char** new_environ = (char**)malloc((environ_size + 2) * sizeof(char*)); 287 if (new_environ == nullptr) { 288 errno = ENOMEM; 289 return -1; 290 } 291 292 for (int i = 0; environ[i]; ++i) { 293 new_environ[i] = environ[i]; 294 } 295 296 new_environ[environ_size] = new_var; 297 new_environ[environ_size + 1] = nullptr; 298 299 // swap new and old 300 // note that the initial environ is not heap allocated! 301 extern bool __environ_is_malloced; 302 if (__environ_is_malloced) 303 free(environ); 304 __environ_is_malloced = true; 305 environ = new_environ; 306 return 0; 307} 308 309double strtod(const char* str, char** endptr) 310{ 311 size_t len = strlen(str); 312 size_t weight = 1; 313 int exp_val = 0; 314 double value = 0.0f; 315 double fraction = 0.0f; 316 bool has_sign = false; 317 bool is_negative = false; 318 bool is_fractional = false; 319 bool is_scientific = false; 320 321 if (str[0] == '-') { 322 is_negative = true; 323 has_sign = true; 324 } 325 if (str[0] == '+') { 326 has_sign = true; 327 } 328 size_t i; 329 for (i = has_sign; i < len; i++) { 330 331 // Looks like we're about to start working on the fractional part 332 if (str[i] == '.') { 333 is_fractional = true; 334 continue; 335 } 336 337 if (str[i] == 'e' || str[i] == 'E') { 338 if (str[i + 1] == '-' || str[i + 1] == '+') 339 exp_val = atoi(str + i + 2); 340 else 341 exp_val = atoi(str + i + 1); 342 343 is_scientific = true; 344 continue; 345 } 346 347 if (str[i] < '0' || str[i] > '9' || exp_val != 0) 348 continue; 349 350 if (is_fractional) { 351 fraction *= 10; 352 fraction += str[i] - '0'; 353 weight *= 10; 354 } else { 355 value = value * 10; 356 value += str[i] - '0'; 357 } 358 } 359 360 fraction /= weight; 361 value += fraction; 362 363 if (is_scientific) { 364 bool divide = exp_val < 0; 365 if (divide) 366 exp_val *= -1; 367 368 for (int i = 0; i < exp_val; i++) { 369 if (divide) 370 value /= 10; 371 else 372 value *= 10; 373 } 374 } 375 //FIXME: Not entirely sure if this is correct, but seems to work. 376 if (endptr) 377 *endptr = const_cast<char*>(str + i); 378 return is_negative ? -value : value; 379} 380 381long double strtold(const char* str, char** endptr) 382{ 383 (void)str; 384 (void)endptr; 385 dbgprintf("LibC: strtold: '%s'\n", str); 386 ASSERT_NOT_REACHED(); 387} 388 389float strtof(const char* str, char** endptr) 390{ 391 (void)str; 392 (void)endptr; 393 dbgprintf("LibC: strtof: '%s'\n", str); 394 ASSERT_NOT_REACHED(); 395} 396 397double atof(const char* str) 398{ 399 size_t len = strlen(str); 400 size_t weight = 1; 401 int exp_val = 0; 402 double value = 0.0f; 403 double fraction = 0.0f; 404 bool has_sign = false; 405 bool is_negative = false; 406 bool is_fractional = false; 407 bool is_scientific = false; 408 409 if (str[0] == '-') { 410 is_negative = true; 411 has_sign = true; 412 } 413 if (str[0] == '+') { 414 has_sign = true; 415 } 416 417 for (size_t i = has_sign; i < len; i++) { 418 419 // Looks like we're about to start working on the fractional part 420 if (str[i] == '.') { 421 is_fractional = true; 422 continue; 423 } 424 425 if (str[i] == 'e' || str[i] == 'E') { 426 if (str[i + 1] == '-' || str[i + 1] == '+') 427 exp_val = atoi(str + i + 2); 428 else 429 exp_val = atoi(str + i + 1); 430 431 is_scientific = true; 432 continue; 433 } 434 435 if (str[i] < '0' || str[i] > '9' || exp_val != 0) 436 continue; 437 438 if (is_fractional) { 439 fraction *= 10; 440 fraction += str[i] - '0'; 441 weight *= 10; 442 } else { 443 value = value * 10; 444 value += str[i] - '0'; 445 } 446 } 447 448 fraction /= weight; 449 value += fraction; 450 451 if (is_scientific) { 452 bool divide = exp_val < 0; 453 if (divide) 454 exp_val *= -1; 455 456 for (int i = 0; i < exp_val; i++) { 457 if (divide) 458 value /= 10; 459 else 460 value *= 10; 461 } 462 } 463 464 return is_negative ? -value : value; 465} 466 467int atoi(const char* str) 468{ 469 size_t len = strlen(str); 470 int value = 0; 471 bool isNegative = false; 472 for (size_t i = 0; i < len; ++i) { 473 if (i == 0 && str[0] == '-') { 474 isNegative = true; 475 continue; 476 } 477 if (str[i] < '0' || str[i] > '9') 478 return value; 479 value = value * 10; 480 value += str[i] - '0'; 481 } 482 return isNegative ? -value : value; 483} 484 485long atol(const char* str) 486{ 487 static_assert(sizeof(int) == sizeof(long)); 488 return atoi(str); 489} 490 491long long atoll(const char* str) 492{ 493 dbgprintf("FIXME(Libc): atoll('%s') passing through to atol()\n", str); 494 return atol(str); 495} 496 497static char ptsname_buf[32]; 498char* ptsname(int fd) 499{ 500 if (ptsname_r(fd, ptsname_buf, sizeof(ptsname_buf)) < 0) 501 return nullptr; 502 return ptsname_buf; 503} 504 505int ptsname_r(int fd, char* buffer, size_t size) 506{ 507 int rc = syscall(SC_ptsname_r, fd, buffer, size); 508 __RETURN_WITH_ERRNO(rc, rc, -1); 509} 510 511static unsigned long s_next_rand = 1; 512 513int rand() 514{ 515 s_next_rand = s_next_rand * 1103515245 + 12345; 516 return ((unsigned)(s_next_rand / ((RAND_MAX + 1) * 2)) % (RAND_MAX + 1)); 517} 518 519void srand(unsigned seed) 520{ 521 s_next_rand = seed; 522} 523 524int abs(int i) 525{ 526 return i < 0 ? -i : i; 527} 528 529long int random() 530{ 531 return rand(); 532} 533 534void srandom(unsigned seed) 535{ 536 srand(seed); 537} 538 539int system(const char* command) 540{ 541 if (!command) 542 return 1; 543 544 auto child = fork(); 545 if (child < 0) 546 return -1; 547 548 if (!child) { 549 int rc = execl("/bin/sh", "sh", "-c", command, nullptr); 550 ASSERT(rc < 0); 551 perror("execl"); 552 exit(127); 553 } 554 int wstatus; 555 waitpid(child, &wstatus, 0); 556 return WEXITSTATUS(wstatus); 557} 558 559char* mktemp(char* pattern) 560{ 561 if (__generate_unique_filename(pattern) < 0) 562 pattern[0] = '\0'; 563 564 return pattern; 565} 566 567int mkstemp(char* pattern) 568{ 569 char* path = mktemp(pattern); 570 571 int fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); // I'm using the flags I saw glibc using. 572 if (fd >= 0) 573 return fd; 574 575 return -1; 576} 577 578char* mkdtemp(char* pattern) 579{ 580 if (__generate_unique_filename(pattern) < 0) 581 return nullptr; 582 583 if (mkdir(pattern, 0700) < 0) 584 return nullptr; 585 586 return pattern; 587} 588 589void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)) 590{ 591 int low = 0; 592 int high = nmemb - 1; 593 while (low <= high) { 594 int middle = (low + high) / 2; 595 void* middle_memb = const_cast<char*>((const char*)base + middle * size); 596 int comparison = compar(key, middle_memb); 597 if (comparison < 0) 598 high = middle - 1; 599 else if (comparison > 0) 600 low = middle + 1; 601 else 602 return middle_memb; 603 } 604 605 return NULL; 606} 607 608div_t div(int numerator, int denominator) 609{ 610 div_t result; 611 result.quot = numerator / denominator; 612 result.rem = numerator % denominator; 613 614 if (numerator >= 0 && result.rem < 0) { 615 result.quot++; 616 result.rem -= denominator; 617 } 618 return result; 619} 620 621ldiv_t ldiv(long numerator, long denominator) 622{ 623 ldiv_t result; 624 result.quot = numerator / denominator; 625 result.rem = numerator % denominator; 626 627 if (numerator >= 0 && result.rem < 0) { 628 result.quot++; 629 result.rem -= denominator; 630 } 631 return result; 632} 633 634size_t mbstowcs(wchar_t*, const char*, size_t) 635{ 636 ASSERT_NOT_REACHED(); 637} 638 639size_t mbtowc(wchar_t* wch, const char* data, size_t data_size) 640{ 641 // FIXME: This needs a real implementation. 642 UNUSED_PARAM(data_size); 643 644 if (wch && data) { 645 *wch = *data; 646 return 1; 647 } 648 649 if (!wch && data) { 650 return 1; 651 } 652 653 return 0; 654} 655 656int wctomb(char*, wchar_t) 657{ 658 ASSERT_NOT_REACHED(); 659} 660 661size_t wcstombs(char* dest, const wchar_t* src, size_t max) 662{ 663 char* originalDest = dest; 664 while ((size_t)(dest - originalDest) < max) { 665 StringView v { (const char*)src, sizeof(wchar_t) }; 666 667 // FIXME: dependent on locale, for now utf-8 is supported. 668 Utf8View utf8 { v }; 669 if (*utf8.begin() == '\0') { 670 *dest = '\0'; 671 return (size_t)(dest - originalDest); // Exclude null character in returned size 672 } 673 674 for (auto byte : utf8) { 675 if (byte != '\0') 676 *dest++ = byte; 677 } 678 ++src; 679 } 680 return max; 681} 682 683long strtol(const char* str, char** endptr, int base) 684{ 685 return strtol_impl<long, LONG_MIN, LONG_MAX>(str, endptr, base); 686} 687 688unsigned long strtoul(const char* str, char** endptr, int base) 689{ 690 auto value = strtol(str, endptr, base); 691 ASSERT(value >= 0); 692 return value; 693} 694 695long long strtoll(const char* str, char** endptr, int base) 696{ 697 return strtol_impl<long long, LONG_LONG_MIN, LONG_LONG_MAX>(str, endptr, base); 698} 699 700unsigned long long strtoull(const char* str, char** endptr, int base) 701{ 702 auto value = strtoll(str, endptr, base); 703 ASSERT(value >= 0); 704 return value; 705} 706 707// Serenity's PRNG is not cryptographically secure. Do not rely on this for 708// any real crypto! These functions (for now) are for compatibility. 709// TODO: In the future, rand can be made determinstic and this not. 710uint32_t arc4random(void) 711{ 712 char buf[4]; 713 syscall(SC_getrandom, buf, 4, 0); 714 return *(uint32_t*)buf; 715} 716 717void arc4random_buf(void* buffer, size_t buffer_size) 718{ 719 // arc4random_buf should never fail, but user supplied buffers could fail. 720 // However, if the user passes a garbage buffer, that's on them. 721 syscall(SC_getrandom, buffer, buffer_size, 0); 722} 723 724uint32_t arc4random_uniform(uint32_t max_bounds) 725{ 726 // XXX: Should actually apply special rules for uniformity; avoid what is 727 // called "modulo bias". 728 return arc4random() % max_bounds; 729} 730 731char* realpath(const char* pathname, char* buffer) 732{ 733 if (!pathname) { 734 errno = EFAULT; 735 return nullptr; 736 } 737 size_t size = PATH_MAX; 738 if (buffer == nullptr) 739 buffer = (char*)malloc(size); 740 Syscall::SC_realpath_params params { { pathname, strlen(pathname) }, { buffer, size } }; 741 int rc = syscall(SC_realpath, &params); 742 if (rc < 0) { 743 errno = -rc; 744 return nullptr; 745 } 746 errno = 0; 747 return buffer; 748} 749 750int posix_openpt(int flags) 751{ 752 if (flags & ~(O_RDWR | O_NOCTTY | O_CLOEXEC)) { 753 errno = EINVAL; 754 return -1; 755 } 756 757 return open("/dev/ptmx", flags); 758} 759 760int grantpt(int fd) 761{ 762 (void)fd; 763 return 0; 764} 765 766int unlockpt(int fd) 767{ 768 (void)fd; 769 return 0; 770} 771}