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] == '-' || 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, ¶ms);
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}