Serenity Operating System
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, ¶ms);
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}