Serenity Operating System
at hosted 773 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] == '-') 339 exp_val = -atoi(str + i + 2); 340 else if (str[i + 1] == '+') 341 exp_val = atoi(str + i + 2); 342 else 343 exp_val = atoi(str + i + 1); 344 345 is_scientific = true; 346 continue; 347 } 348 349 if (str[i] < '0' || str[i] > '9' || exp_val != 0) 350 continue; 351 352 if (is_fractional) { 353 fraction *= 10; 354 fraction += str[i] - '0'; 355 weight *= 10; 356 } else { 357 value = value * 10; 358 value += str[i] - '0'; 359 } 360 } 361 362 fraction /= weight; 363 value += fraction; 364 365 if (is_scientific) { 366 bool divide = exp_val < 0; 367 if (divide) 368 exp_val *= -1; 369 370 for (int i = 0; i < exp_val; i++) { 371 if (divide) 372 value /= 10; 373 else 374 value *= 10; 375 } 376 } 377 //FIXME: Not entirely sure if this is correct, but seems to work. 378 if (endptr) 379 *endptr = const_cast<char*>(str + i); 380 return is_negative ? -value : value; 381} 382 383long double strtold(const char* str, char** endptr) 384{ 385 (void)str; 386 (void)endptr; 387 dbgprintf("LibC: strtold: '%s'\n", str); 388 ASSERT_NOT_REACHED(); 389} 390 391float strtof(const char* str, char** endptr) 392{ 393 (void)str; 394 (void)endptr; 395 dbgprintf("LibC: strtof: '%s'\n", str); 396 ASSERT_NOT_REACHED(); 397} 398 399double atof(const char* str) 400{ 401 size_t len = strlen(str); 402 size_t weight = 1; 403 int exp_val = 0; 404 double value = 0.0f; 405 double fraction = 0.0f; 406 bool has_sign = false; 407 bool is_negative = false; 408 bool is_fractional = false; 409 bool is_scientific = false; 410 411 if (str[0] == '-') { 412 is_negative = true; 413 has_sign = true; 414 } 415 if (str[0] == '+') { 416 has_sign = true; 417 } 418 419 for (size_t i = has_sign; i < len; i++) { 420 421 // Looks like we're about to start working on the fractional part 422 if (str[i] == '.') { 423 is_fractional = true; 424 continue; 425 } 426 427 if (str[i] == 'e' || str[i] == 'E') { 428 if (str[i + 1] == '-' || str[i + 1] == '+') 429 exp_val = atoi(str + i + 2); 430 else 431 exp_val = atoi(str + i + 1); 432 433 is_scientific = true; 434 continue; 435 } 436 437 if (str[i] < '0' || str[i] > '9' || exp_val != 0) 438 continue; 439 440 if (is_fractional) { 441 fraction *= 10; 442 fraction += str[i] - '0'; 443 weight *= 10; 444 } else { 445 value = value * 10; 446 value += str[i] - '0'; 447 } 448 } 449 450 fraction /= weight; 451 value += fraction; 452 453 if (is_scientific) { 454 bool divide = exp_val < 0; 455 if (divide) 456 exp_val *= -1; 457 458 for (int i = 0; i < exp_val; i++) { 459 if (divide) 460 value /= 10; 461 else 462 value *= 10; 463 } 464 } 465 466 return is_negative ? -value : value; 467} 468 469int atoi(const char* str) 470{ 471 size_t len = strlen(str); 472 int value = 0; 473 bool isNegative = false; 474 for (size_t i = 0; i < len; ++i) { 475 if (i == 0 && str[0] == '-') { 476 isNegative = true; 477 continue; 478 } 479 if (str[i] < '0' || str[i] > '9') 480 return value; 481 value = value * 10; 482 value += str[i] - '0'; 483 } 484 return isNegative ? -value : value; 485} 486 487long atol(const char* str) 488{ 489 static_assert(sizeof(int) == sizeof(long)); 490 return atoi(str); 491} 492 493long long atoll(const char* str) 494{ 495 dbgprintf("FIXME(Libc): atoll('%s') passing through to atol()\n", str); 496 return atol(str); 497} 498 499static char ptsname_buf[32]; 500char* ptsname(int fd) 501{ 502 if (ptsname_r(fd, ptsname_buf, sizeof(ptsname_buf)) < 0) 503 return nullptr; 504 return ptsname_buf; 505} 506 507int ptsname_r(int fd, char* buffer, size_t size) 508{ 509 int rc = syscall(SC_ptsname_r, fd, buffer, size); 510 __RETURN_WITH_ERRNO(rc, rc, -1); 511} 512 513static unsigned long s_next_rand = 1; 514 515int rand() 516{ 517 s_next_rand = s_next_rand * 1103515245 + 12345; 518 return ((unsigned)(s_next_rand / ((RAND_MAX + 1) * 2)) % (RAND_MAX + 1)); 519} 520 521void srand(unsigned seed) 522{ 523 s_next_rand = seed; 524} 525 526int abs(int i) 527{ 528 return i < 0 ? -i : i; 529} 530 531long int random() 532{ 533 return rand(); 534} 535 536void srandom(unsigned seed) 537{ 538 srand(seed); 539} 540 541int system(const char* command) 542{ 543 if (!command) 544 return 1; 545 546 auto child = fork(); 547 if (child < 0) 548 return -1; 549 550 if (!child) { 551 int rc = execl("/bin/sh", "sh", "-c", command, nullptr); 552 ASSERT(rc < 0); 553 perror("execl"); 554 exit(127); 555 } 556 int wstatus; 557 waitpid(child, &wstatus, 0); 558 return WEXITSTATUS(wstatus); 559} 560 561char* mktemp(char* pattern) 562{ 563 if (__generate_unique_filename(pattern) < 0) 564 pattern[0] = '\0'; 565 566 return pattern; 567} 568 569int mkstemp(char* pattern) 570{ 571 char* path = mktemp(pattern); 572 573 int fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); // I'm using the flags I saw glibc using. 574 if (fd >= 0) 575 return fd; 576 577 return -1; 578} 579 580char* mkdtemp(char* pattern) 581{ 582 if (__generate_unique_filename(pattern) < 0) 583 return nullptr; 584 585 if (mkdir(pattern, 0700) < 0) 586 return nullptr; 587 588 return pattern; 589} 590 591void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)) 592{ 593 int low = 0; 594 int high = nmemb - 1; 595 while (low <= high) { 596 int middle = (low + high) / 2; 597 void* middle_memb = const_cast<char*>((const char*)base + middle * size); 598 int comparison = compar(key, middle_memb); 599 if (comparison < 0) 600 high = middle - 1; 601 else if (comparison > 0) 602 low = middle + 1; 603 else 604 return middle_memb; 605 } 606 607 return NULL; 608} 609 610div_t div(int numerator, int denominator) 611{ 612 div_t result; 613 result.quot = numerator / denominator; 614 result.rem = numerator % denominator; 615 616 if (numerator >= 0 && result.rem < 0) { 617 result.quot++; 618 result.rem -= denominator; 619 } 620 return result; 621} 622 623ldiv_t ldiv(long numerator, long denominator) 624{ 625 ldiv_t result; 626 result.quot = numerator / denominator; 627 result.rem = numerator % denominator; 628 629 if (numerator >= 0 && result.rem < 0) { 630 result.quot++; 631 result.rem -= denominator; 632 } 633 return result; 634} 635 636size_t mbstowcs(wchar_t*, const char*, size_t) 637{ 638 ASSERT_NOT_REACHED(); 639} 640 641size_t mbtowc(wchar_t* wch, const char* data, size_t data_size) 642{ 643 // FIXME: This needs a real implementation. 644 UNUSED_PARAM(data_size); 645 646 if (wch && data) { 647 *wch = *data; 648 return 1; 649 } 650 651 if (!wch && data) { 652 return 1; 653 } 654 655 return 0; 656} 657 658int wctomb(char*, wchar_t) 659{ 660 ASSERT_NOT_REACHED(); 661} 662 663size_t wcstombs(char* dest, const wchar_t* src, size_t max) 664{ 665 char* originalDest = dest; 666 while ((size_t)(dest - originalDest) < max) { 667 StringView v { (const char*)src, sizeof(wchar_t) }; 668 669 // FIXME: dependent on locale, for now utf-8 is supported. 670 Utf8View utf8 { v }; 671 if (*utf8.begin() == '\0') { 672 *dest = '\0'; 673 return (size_t)(dest - originalDest); // Exclude null character in returned size 674 } 675 676 for (auto byte : utf8) { 677 if (byte != '\0') 678 *dest++ = byte; 679 } 680 ++src; 681 } 682 return max; 683} 684 685long strtol(const char* str, char** endptr, int base) 686{ 687 return strtol_impl<long, LONG_MIN, LONG_MAX>(str, endptr, base); 688} 689 690unsigned long strtoul(const char* str, char** endptr, int base) 691{ 692 auto value = strtol(str, endptr, base); 693 ASSERT(value >= 0); 694 return value; 695} 696 697long long strtoll(const char* str, char** endptr, int base) 698{ 699 return strtol_impl<long long, LONG_LONG_MIN, LONG_LONG_MAX>(str, endptr, base); 700} 701 702unsigned long long strtoull(const char* str, char** endptr, int base) 703{ 704 auto value = strtoll(str, endptr, base); 705 ASSERT(value >= 0); 706 return value; 707} 708 709// Serenity's PRNG is not cryptographically secure. Do not rely on this for 710// any real crypto! These functions (for now) are for compatibility. 711// TODO: In the future, rand can be made determinstic and this not. 712uint32_t arc4random(void) 713{ 714 char buf[4]; 715 syscall(SC_getrandom, buf, 4, 0); 716 return *(uint32_t*)buf; 717} 718 719void arc4random_buf(void* buffer, size_t buffer_size) 720{ 721 // arc4random_buf should never fail, but user supplied buffers could fail. 722 // However, if the user passes a garbage buffer, that's on them. 723 syscall(SC_getrandom, buffer, buffer_size, 0); 724} 725 726uint32_t arc4random_uniform(uint32_t max_bounds) 727{ 728 // XXX: Should actually apply special rules for uniformity; avoid what is 729 // called "modulo bias". 730 return arc4random() % max_bounds; 731} 732 733char* realpath(const char* pathname, char* buffer) 734{ 735 if (!pathname) { 736 errno = EFAULT; 737 return nullptr; 738 } 739 size_t size = PATH_MAX; 740 if (buffer == nullptr) 741 buffer = (char*)malloc(size); 742 Syscall::SC_realpath_params params { { pathname, strlen(pathname) }, { buffer, size } }; 743 int rc = syscall(SC_realpath, &params); 744 if (rc < 0) { 745 errno = -rc; 746 return nullptr; 747 } 748 errno = 0; 749 return buffer; 750} 751 752int posix_openpt(int flags) 753{ 754 if (flags & ~(O_RDWR | O_NOCTTY | O_CLOEXEC)) { 755 errno = EINVAL; 756 return -1; 757 } 758 759 return open("/dev/ptmx", flags); 760} 761 762int grantpt(int fd) 763{ 764 (void)fd; 765 return 0; 766} 767 768int unlockpt(int fd) 769{ 770 (void)fd; 771 return 0; 772} 773}