summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibC
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibC')
-rw-r--r--Userland/Libraries/LibC/CMakeLists.txt90
-rw-r--r--Userland/Libraries/LibC/alloca.h29
-rw-r--r--Userland/Libraries/LibC/arpa/inet.cpp92
-rw-r--r--Userland/Libraries/LibC/arpa/inet.h75
-rw-r--r--Userland/Libraries/LibC/assert.cpp54
-rw-r--r--Userland/Libraries/LibC/assert.h56
-rw-r--r--Userland/Libraries/LibC/bits/FILE.h38
-rw-r--r--Userland/Libraries/LibC/bits/posix1_lim.h65
-rw-r--r--Userland/Libraries/LibC/bits/stdint.h144
-rw-r--r--Userland/Libraries/LibC/byteswap.h37
-rw-r--r--Userland/Libraries/LibC/crt0.cpp76
-rw-r--r--Userland/Libraries/LibC/crt0_shared.cpp66
-rw-r--r--Userland/Libraries/LibC/crti.S35
-rw-r--r--Userland/Libraries/LibC/crtn.S33
-rw-r--r--Userland/Libraries/LibC/ctype.cpp63
-rw-r--r--Userland/Libraries/LibC/ctype.h106
-rw-r--r--Userland/Libraries/LibC/cxxabi.cpp89
-rw-r--r--Userland/Libraries/LibC/dirent.cpp200
-rw-r--r--Userland/Libraries/LibC/dirent.h77
-rw-r--r--Userland/Libraries/LibC/dlfcn.cpp131
-rw-r--r--Userland/Libraries/LibC/dlfcn.h44
-rw-r--r--Userland/Libraries/LibC/endian.h109
-rw-r--r--Userland/Libraries/LibC/errno.h55
-rw-r--r--Userland/Libraries/LibC/errno_numbers.h103
-rw-r--r--Userland/Libraries/LibC/fcntl.cpp106
-rw-r--r--Userland/Libraries/LibC/fcntl.h111
-rw-r--r--Userland/Libraries/LibC/fd_set.h39
-rw-r--r--Userland/Libraries/LibC/float.h27
-rw-r--r--Userland/Libraries/LibC/getopt.cpp369
-rw-r--r--Userland/Libraries/LibC/getopt.h46
-rw-r--r--Userland/Libraries/LibC/grp.cpp182
-rw-r--r--Userland/Libraries/LibC/grp.h49
-rw-r--r--Userland/Libraries/LibC/iconv.h40
-rw-r--r--Userland/Libraries/LibC/inttypes.h70
-rw-r--r--Userland/Libraries/LibC/ioctl.cpp44
-rw-r--r--Userland/Libraries/LibC/libcinit.cpp48
-rw-r--r--Userland/Libraries/LibC/libgen.cpp84
-rw-r--r--Userland/Libraries/LibC/libgen.h36
-rw-r--r--Userland/Libraries/LibC/limits.h78
-rw-r--r--Userland/Libraries/LibC/locale.cpp78
-rw-r--r--Userland/Libraries/LibC/locale.h72
-rw-r--r--Userland/Libraries/LibC/malloc.cpp472
-rw-r--r--Userland/Libraries/LibC/mallocdefs.h95
-rw-r--r--Userland/Libraries/LibC/memory.h29
-rw-r--r--Userland/Libraries/LibC/mman.cpp111
-rw-r--r--Userland/Libraries/LibC/mman.h67
-rw-r--r--Userland/Libraries/LibC/mntent.cpp37
-rw-r--r--Userland/Libraries/LibC/mntent.h48
-rw-r--r--Userland/Libraries/LibC/net/if.h71
-rw-r--r--Userland/Libraries/LibC/net/route.h40
-rw-r--r--Userland/Libraries/LibC/netdb.cpp590
-rw-r--r--Userland/Libraries/LibC/netdb.h78
-rw-r--r--Userland/Libraries/LibC/netinet/in.h74
-rw-r--r--Userland/Libraries/LibC/netinet/ip.h29
-rw-r--r--Userland/Libraries/LibC/netinet/ip_icmp.h47
-rw-r--r--Userland/Libraries/LibC/netinet/tcp.h29
-rw-r--r--Userland/Libraries/LibC/paths.h30
-rw-r--r--Userland/Libraries/LibC/poll.cpp51
-rw-r--r--Userland/Libraries/LibC/poll.h53
-rw-r--r--Userland/Libraries/LibC/pwd.cpp189
-rw-r--r--Userland/Libraries/LibC/pwd.h52
-rw-r--r--Userland/Libraries/LibC/qsort.cpp102
-rw-r--r--Userland/Libraries/LibC/regex.h125
-rw-r--r--Userland/Libraries/LibC/scanf.cpp227
-rw-r--r--Userland/Libraries/LibC/sched.cpp60
-rw-r--r--Userland/Libraries/LibC/sched.h50
-rw-r--r--Userland/Libraries/LibC/serenity.cpp139
-rw-r--r--Userland/Libraries/LibC/serenity.h99
-rw-r--r--Userland/Libraries/LibC/setjmp.S57
-rw-r--r--Userland/Libraries/LibC/setjmp.h52
-rw-r--r--Userland/Libraries/LibC/signal.cpp248
-rw-r--r--Userland/Libraries/LibC/signal.h109
-rw-r--r--Userland/Libraries/LibC/signal_numbers.h61
-rw-r--r--Userland/Libraries/LibC/spawn.cpp289
-rw-r--r--Userland/Libraries/LibC/spawn.h99
-rw-r--r--Userland/Libraries/LibC/ssp.cpp55
-rw-r--r--Userland/Libraries/LibC/stat.cpp99
-rw-r--r--Userland/Libraries/LibC/stdarg.h44
-rw-r--r--Userland/Libraries/LibC/stdbool.h42
-rw-r--r--Userland/Libraries/LibC/stddef.h42
-rw-r--r--Userland/Libraries/LibC/stdint.h31
-rw-r--r--Userland/Libraries/LibC/stdio.cpp1219
-rw-r--r--Userland/Libraries/LibC/stdio.h120
-rw-r--r--Userland/Libraries/LibC/stdlib.cpp1083
-rw-r--r--Userland/Libraries/LibC/stdlib.h109
-rw-r--r--Userland/Libraries/LibC/string.cpp486
-rw-r--r--Userland/Libraries/LibC/string.h74
-rw-r--r--Userland/Libraries/LibC/strings.cpp72
-rw-r--r--Userland/Libraries/LibC/strings.h39
-rw-r--r--Userland/Libraries/LibC/sys/arch/i386/regs.h48
-rw-r--r--Userland/Libraries/LibC/sys/cdefs.h54
-rw-r--r--Userland/Libraries/LibC/sys/file.h27
-rw-r--r--Userland/Libraries/LibC/sys/internals.h48
-rw-r--r--Userland/Libraries/LibC/sys/ioctl.h36
-rw-r--r--Userland/Libraries/LibC/sys/ioctl_numbers.h94
-rw-r--r--Userland/Libraries/LibC/sys/mman.h29
-rw-r--r--Userland/Libraries/LibC/sys/param.h30
-rw-r--r--Userland/Libraries/LibC/sys/prctl.cpp40
-rw-r--r--Userland/Libraries/LibC/sys/prctl.h37
-rw-r--r--Userland/Libraries/LibC/sys/prctl_numbers.h30
-rw-r--r--Userland/Libraries/LibC/sys/ptrace.cpp69
-rw-r--r--Userland/Libraries/LibC/sys/ptrace.h48
-rw-r--r--Userland/Libraries/LibC/sys/resource.h58
-rw-r--r--Userland/Libraries/LibC/sys/select.cpp52
-rw-r--r--Userland/Libraries/LibC/sys/select.h40
-rw-r--r--Userland/Libraries/LibC/sys/socket.cpp159
-rw-r--r--Userland/Libraries/LibC/sys/socket.h183
-rw-r--r--Userland/Libraries/LibC/sys/stat.h72
-rw-r--r--Userland/Libraries/LibC/sys/sysmacros.h27
-rw-r--r--Userland/Libraries/LibC/sys/time.h135
-rw-r--r--Userland/Libraries/LibC/sys/times.h43
-rw-r--r--Userland/Libraries/LibC/sys/types.h108
-rw-r--r--Userland/Libraries/LibC/sys/uio.cpp38
-rw-r--r--Userland/Libraries/LibC/sys/uio.h41
-rw-r--r--Userland/Libraries/LibC/sys/un.h39
-rw-r--r--Userland/Libraries/LibC/sys/utsname.h45
-rw-r--r--Userland/Libraries/LibC/sys/wait.cpp102
-rw-r--r--Userland/Libraries/LibC/sys/wait.h59
-rw-r--r--Userland/Libraries/LibC/syslog.cpp159
-rw-r--r--Userland/Libraries/LibC/syslog.h177
-rw-r--r--Userland/Libraries/LibC/termcap.cpp164
-rw-r--r--Userland/Libraries/LibC/termcap.h44
-rw-r--r--Userland/Libraries/LibC/termios.cpp149
-rw-r--r--Userland/Libraries/LibC/termios.h235
-rw-r--r--Userland/Libraries/LibC/time.cpp376
-rw-r--r--Userland/Libraries/LibC/time.h91
-rw-r--r--Userland/Libraries/LibC/times.cpp35
-rw-r--r--Userland/Libraries/LibC/ulimit.cpp45
-rw-r--r--Userland/Libraries/LibC/ulimit.h35
-rw-r--r--Userland/Libraries/LibC/unistd.cpp725
-rw-r--r--Userland/Libraries/LibC/unistd.h210
-rw-r--r--Userland/Libraries/LibC/utime.cpp43
-rw-r--r--Userland/Libraries/LibC/utime.h35
-rw-r--r--Userland/Libraries/LibC/utmp.h78
-rw-r--r--Userland/Libraries/LibC/utsname.cpp38
-rw-r--r--Userland/Libraries/LibC/wchar.cpp150
-rw-r--r--Userland/Libraries/LibC/wchar.h48
137 files changed, 15398 insertions, 0 deletions
diff --git a/Userland/Libraries/LibC/CMakeLists.txt b/Userland/Libraries/LibC/CMakeLists.txt
new file mode 100644
index 0000000000..393addb934
--- /dev/null
+++ b/Userland/Libraries/LibC/CMakeLists.txt
@@ -0,0 +1,90 @@
+set(LIBC_SOURCES
+ arpa/inet.cpp
+ assert.cpp
+ ctype.cpp
+ cxxabi.cpp
+ dirent.cpp
+ dlfcn.cpp
+ fcntl.cpp
+ getopt.cpp
+ grp.cpp
+ ioctl.cpp
+ libcinit.cpp
+ libgen.cpp
+ locale.cpp
+ malloc.cpp
+ mman.cpp
+ mntent.cpp
+ netdb.cpp
+ poll.cpp
+ pwd.cpp
+ qsort.cpp
+ scanf.cpp
+ sched.cpp
+ serenity.cpp
+ setjmp.S
+ signal.cpp
+ spawn.cpp
+ stat.cpp
+ stdio.cpp
+ stdlib.cpp
+ string.cpp
+ strings.cpp
+ syslog.cpp
+ sys/prctl.cpp
+ sys/ptrace.cpp
+ sys/select.cpp
+ sys/socket.cpp
+ sys/uio.cpp
+ sys/wait.cpp
+ termcap.cpp
+ termios.cpp
+ time.cpp
+ times.cpp
+ ulimit.cpp
+ unistd.cpp
+ utime.cpp
+ utsname.cpp
+ wchar.cpp
+)
+
+file(GLOB AK_SOURCES CONFIGURE_DEPENDS "../../../AK/*.cpp")
+file(GLOB ELF_SOURCES CONFIGURE_DEPENDS "../LibELF/*.cpp")
+set(ELF_SOURCES ${ELF_SOURCES} ../LibELF/Arch/i386/plt_trampoline.S)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option -DSERENITY_LIBC_BUILD")
+
+find_program(INSTALL_COMMAND ginstall)
+if(NOT INSTALL_COMMAND)
+ set(INSTALL_COMMAND install)
+endif()
+
+add_library(crt0 STATIC crt0.cpp)
+add_custom_command(
+ TARGET crt0
+ COMMAND ${INSTALL_COMMAND} -D $<TARGET_OBJECTS:crt0> ${CMAKE_INSTALL_PREFIX}/usr/lib/crt0.o
+)
+add_library(crt0_shared STATIC crt0_shared.cpp)
+add_custom_command(
+ TARGET crt0_shared
+ COMMAND ${INSTALL_COMMAND} -D $<TARGET_OBJECTS:crt0_shared> ${CMAKE_INSTALL_PREFIX}/usr/lib/crt0_shared.o
+)
+
+set_source_files_properties (ssp.cpp PROPERTIES COMPILE_FLAGS
+ "-fno-stack-protector")
+add_library(ssp STATIC ssp.cpp)
+add_custom_command(
+ TARGET ssp
+ COMMAND ${INSTALL_COMMAND} -D $<TARGET_OBJECTS:ssp> ${CMAKE_INSTALL_PREFIX}/usr/lib/ssp.o
+)
+
+set(SOURCES ${LIBC_SOURCES} ${AK_SOURCES} ${ELF_SOURCES})
+
+serenity_libc_static(LibCStatic c)
+target_link_libraries(LibCStatic crt0 ssp)
+add_dependencies(LibCStatic LibM)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")
+serenity_libc(LibC c)
+target_link_libraries(LibC crt0 ssp)
+add_dependencies(LibC LibM)
diff --git a/Userland/Libraries/LibC/alloca.h b/Userland/Libraries/LibC/alloca.h
new file mode 100644
index 0000000000..c31dccc400
--- /dev/null
+++ b/Userland/Libraries/LibC/alloca.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define alloca __builtin_alloca
diff --git a/Userland/Libraries/LibC/arpa/inet.cpp b/Userland/Libraries/LibC/arpa/inet.cpp
new file mode 100644
index 0000000000..3cf7cc48a4
--- /dev/null
+++ b/Userland/Libraries/LibC/arpa/inet.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+extern "C" {
+
+const char* inet_ntop(int af, const void* src, char* dst, socklen_t len)
+{
+ if (af != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return nullptr;
+ }
+ auto* bytes = (const unsigned char*)src;
+ snprintf(dst, len, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2], bytes[3]);
+ return (const char*)dst;
+}
+
+int inet_pton(int af, const char* src, void* dst)
+{
+ if (af != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ int count = sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d);
+ if (count != 4) {
+ errno = EINVAL;
+ return 0;
+ }
+ union {
+ struct {
+ uint8_t a;
+ uint8_t b;
+ uint8_t c;
+ uint8_t d;
+ };
+ uint32_t l;
+ } u;
+ u.a = a;
+ u.b = b;
+ u.c = c;
+ u.d = d;
+ *(uint32_t*)dst = u.l;
+ return 1;
+}
+
+in_addr_t inet_addr(const char* str)
+{
+ in_addr_t tmp {};
+ int rc = inet_pton(AF_INET, str, &tmp);
+ if (rc < 0)
+ return INADDR_NONE;
+ return tmp;
+}
+
+char* inet_ntoa(struct in_addr in)
+{
+ static char buffer[32];
+ inet_ntop(AF_INET, &in.s_addr, buffer, sizeof(buffer));
+ return buffer;
+}
+}
diff --git a/Userland/Libraries/LibC/arpa/inet.h b/Userland/Libraries/LibC/arpa/inet.h
new file mode 100644
index 0000000000..28ac7096f9
--- /dev/null
+++ b/Userland/Libraries/LibC/arpa/inet.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <endian.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+
+__BEGIN_DECLS
+
+#define INET_ADDRSTRLEN 16
+
+const char* inet_ntop(int af, const void* src, char* dst, socklen_t);
+int inet_pton(int af, const char* src, void* dst);
+
+static inline int inet_aton(const char* cp, struct in_addr* inp)
+{
+ return inet_pton(AF_INET, cp, inp);
+}
+
+char* inet_ntoa(struct in_addr);
+
+inline uint16_t htons(uint16_t value)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap16(value);
+#else
+ return value;
+#endif
+}
+
+inline uint16_t ntohs(uint16_t value)
+{
+ return htons(value);
+}
+
+inline uint32_t htonl(uint32_t value)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap32(value);
+#else
+ return value;
+#endif
+}
+
+inline uint32_t ntohl(uint32_t value)
+{
+ return htonl(value);
+}
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/assert.cpp b/Userland/Libraries/LibC/assert.cpp
new file mode 100644
index 0000000000..7dcd7a5258
--- /dev/null
+++ b/Userland/Libraries/LibC/assert.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/internals.h>
+#include <unistd.h>
+
+extern "C" {
+
+extern bool __stdio_is_initialized;
+#ifdef DEBUG
+void __assertion_failed(const char* msg)
+{
+ dbgprintf("USERSPACE(%d) ASSERTION FAILED: %s\n", getpid(), msg);
+ if (__stdio_is_initialized)
+ fprintf(stderr, "ASSERTION FAILED: %s\n", msg);
+
+ Syscall::SC_set_coredump_metadata_params params {
+ { "assertion", strlen("assertion") },
+ { msg, strlen(msg) },
+ };
+ syscall(SC_set_coredump_metadata, &params);
+ syscall(SC_abort);
+ for (;;) { }
+}
+#endif
+}
diff --git a/Userland/Libraries/LibC/assert.h b/Userland/Libraries/LibC/assert.h
new file mode 100644
index 0000000000..055553514b
--- /dev/null
+++ b/Userland/Libraries/LibC/assert.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#ifdef DEBUG
+__attribute__((noreturn)) void __assertion_failed(const char* msg);
+# define __stringify_helper(x) # x
+# define __stringify(x) __stringify_helper(x)
+# define assert(expr) \
+ do { \
+ if (__builtin_expect(!(expr), 0)) \
+ __assertion_failed(#expr "\n" __FILE__ ":" __stringify(__LINE__)); \
+ } while (0)
+# define ASSERT_NOT_REACHED() assert(false)
+#else
+# define assert(expr) ((void)(0))
+# define ASSERT_NOT_REACHED() CRASH()
+#endif
+
+#define CRASH() \
+ do { \
+ asm volatile("ud2"); \
+ } while (0)
+#define ASSERT assert
+#define RELEASE_ASSERT assert
+#define TODO ASSERT_NOT_REACHED
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/bits/FILE.h b/Userland/Libraries/LibC/bits/FILE.h
new file mode 100644
index 0000000000..94af1c5ed7
--- /dev/null
+++ b/Userland/Libraries/LibC/bits/FILE.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2020, Jesse Buhagiar <jooster669@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#define BUFSIZ 1024
+
+__BEGIN_DECLS
+
+typedef struct FILE FILE;
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/bits/posix1_lim.h b/Userland/Libraries/LibC/bits/posix1_lim.h
new file mode 100644
index 0000000000..9ec60a51e9
--- /dev/null
+++ b/Userland/Libraries/LibC/bits/posix1_lim.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define _POSIX_AIO_LISTIO_MAX 2 /* The number of I/O operations that can be specified in a list I/O call. */
+#define _POSIX_AIO_MAX 1 /* The number of outstanding asynchronous I/O operations. */
+#define _POSIX_ARG_MAX 4096 /* Maximum length of argument to the exec functions including environment data. */
+#define _POSIX_CHILD_MAX 25 /* Maximum number of simultaneous processes per real user ID. */
+#define _POSIX_DELAYTIMER_MAX 32 /* The number of timer expiration overruns. */
+#define _POSIX_HOST_NAME_MAX 255 /* Maximum length of a host name (not including the terminating null) as returned from the gethostname() function. */
+#define _POSIX_LINK_MAX 8 /* Maximum number of links to a single file. */
+#define _POSIX_LOGIN_NAME_MAX 9 /* The size of the storage required for a login name, in bytes, including the terminating null. */
+#define _POSIX_MAX_CANON 255 /* Maximum number of bytes in a terminal canonical input queue. */
+#define _POSIX_MAX_INPUT 255 /* Maximum number of bytes allowed in a terminal input queue. */
+#define _POSIX_MQ_OPEN_MAX 8 /* The number of message queues that can be open for a single process.) */
+#define _POSIX_MQ_PRIO_MAX 32 /* The maximum number of message priorities supported by the implementation. */
+#define _POSIX_NAME_MAX 14 /* Maximum number of bytes in a filename (not including terminating null). */
+#define _POSIX_NGROUPS_MAX 8 /* Maximum number of simultaneous supplementary group IDs per process. */
+#define _POSIX_OPEN_MAX 20 /* Maximum number of files that one process can have open at any one time. */
+#define _POSIX_PATH_MAX 256 /* Maximum number of bytes in a pathname. */
+#define _POSIX_PIPE_BUF 512 /* Maximum number of bytes that is guaranteed to be atomic when writing to a pipe. */
+#define _POSIX_RE_DUP_MAX 255 /* The number of repeated occurrences of a BRE permitted by the regexec() and regcomp() functions when using the interval notation #define \(m,n\}; see BREs Matching Multiple Characters. */
+#define _POSIX_RTSIG_MAX 8 /* The number of realtime signal numbers reserved for application use. */
+#define _POSIX_SEM_NSEMS_MAX 256 /* The number of semaphores that a process may have. */
+#define _POSIX_SEM_VALUE_MAX 32767 /* The maximum value a semaphore may have. */
+#define _POSIX_SIGQUEUE_MAX 32 /* The number of queued signals that a process may send and have pending at the receiver(s) at any time. */
+#define _POSIX_SSIZE_MAX 32767 /* The value that can be stored in an object of type ssize_t. */
+#define _POSIX_SS_REPL_MAX 4 /* The number of replenishment operations that may be simultaneously pending for a particular sporadic server scheduler. */
+#define _POSIX_STREAM_MAX 8 /* The number of streams that one process can have open at one time. */
+#define _POSIX_SYMLINK_MAX 255 /* The number of bytes in a symbolic link. */
+#define _POSIX_SYMLOOP_MAX 8 /* The number of symbolic links that can be traversed in the resolution of a pathname in the absence of a loop. */
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 /* The number of attempts made to destroy a thread's thread-specific data values on thread exit. */
+#define _POSIX_THREAD_KEYS_MAX 128 /* The number of data keys per process. */
+#define _POSIX_THREAD_THREADS_MAX 64 /* The number of threads per process. */
+#define _POSIX_TIMER_MAX 32 /* The per-process number of timers. */
+#define _POSIX_TRACE_EVENT_NAME_MAX 30 /* The length in bytes of a trace event name. */
+#define _POSIX_TRACE_NAME_MAX 8 /* The length in bytes of a trace generation version string or a trace stream name. */
+#define _POSIX_TRACE_SYS_MAX 8 /* The number of trace streams that may simultaneously exist in the system. */
+#define _POSIX_TRACE_USER_EVENT_MAX 32 /* The number of user trace event type identifiers that may simultaneously exist in a traced process, including the predefined user trace event POSIX_TRACE_UNNAMED_USER_EVENT. */
+#define _POSIX_TTY_NAME_MAX 9 /* The size of the storage required for a terminal device name, in bytes, including the terminating null. */
+#define _POSIX_TZNAME_MAX 6 /* Maximum number of bytes supported for the name of a timezone (not of the TZ variable). */
diff --git a/Userland/Libraries/LibC/bits/stdint.h b/Userland/Libraries/LibC/bits/stdint.h
new file mode 100644
index 0000000000..7c07ea72a3
--- /dev/null
+++ b/Userland/Libraries/LibC/bits/stdint.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef __UINT64_TYPE__ uint64_t;
+typedef __UINT32_TYPE__ uint32_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT8_TYPE__ uint8_t;
+
+typedef __INT64_TYPE__ int64_t;
+typedef __INT32_TYPE__ int32_t;
+typedef __INT16_TYPE__ int16_t;
+typedef __INT8_TYPE__ int8_t;
+
+typedef __UINT_FAST8_TYPE__ uint_fast8_t;
+typedef __UINT_FAST16_TYPE__ uint_fast16_t;
+typedef __UINT_FAST32_TYPE__ uint_fast32_t;
+typedef __UINT_FAST64_TYPE__ uint_fast64_t;
+
+typedef __INT_FAST8_TYPE__ int_fast8_t;
+typedef __INT_FAST16_TYPE__ int_fast16_t;
+typedef __INT_FAST32_TYPE__ int_fast32_t;
+typedef __INT_FAST64_TYPE__ int_fast64_t;
+
+typedef __UINT_LEAST8_TYPE__ uint_least8_t;
+typedef __UINT_LEAST16_TYPE__ uint_least16_t;
+typedef __UINT_LEAST32_TYPE__ uint_least32_t;
+typedef __UINT_LEAST64_TYPE__ uint_least64_t;
+
+typedef __INT_LEAST8_TYPE__ int_least8_t;
+typedef __INT_LEAST16_TYPE__ int_least16_t;
+typedef __INT_LEAST32_TYPE__ int_least32_t;
+typedef __INT_LEAST64_TYPE__ int_least64_t;
+
+#define __int8_t_defined 1
+#define __uint8_t_defined 1
+#define __int16_t_defined 1
+#define __uint16_t_defined 1
+#define __int32_t_defined 1
+#define __uint32_t_defined 1
+#define __int64_t_defined 1
+#define __uint64_t_defined 1
+
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __INTPTR_TYPE__ intptr_t;
+
+typedef __UINTMAX_TYPE__ uintmax_t;
+#define UINTMAX_MAX __UINTMAX_MAX__
+#define UINTMAX_MIN __UINTMAX_MIN__
+
+typedef __INTMAX_TYPE__ intmax_t;
+#define INTMAX_MAX __INTMAX_MAX__
+#define INTMAX_MIN (-INTMAX_MAX - 1)
+
+#define INT8_MIN (-128)
+#define INT16_MIN (-32767 - 1)
+#define INT32_MIN (-2147483647 - 1)
+#define INT64_MIN (-9223372036854775807LL - 1LL)
+#define INT8_MAX (127)
+#define INT16_MAX (32767)
+#define INT32_MAX (2147483647)
+#define INT64_MAX (9223372036854775807LL)
+#define UINT8_MAX (255)
+#define UINT16_MAX (65535)
+#define UINT32_MAX (4294967295U)
+#define UINT64_MAX (18446744073709551615ULL)
+
+#define INTPTR_MAX INT32_MAX
+#define INTPTR_MIN INT32_MIN
+#define UINTPTR_MAX UINT32_MAX
+
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST64_MIN INT64_MIN
+
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MAX INT64_MAX
+
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
+
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
+
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define INT8_C(x) x
+#define UINT8_C(x) x
+
+#define INT16_C(x) x
+#define UINT16_C(x) x
+
+#define INT32_C(x) x
+#define UINT32_C(x) x
+
+#define INT64_C(x) x##LL
+#define UINT64_C(x) x##ULL
+
+#define SIZE_MAX ((size_t)-1)
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/byteswap.h b/Userland/Libraries/LibC/byteswap.h
new file mode 100644
index 0000000000..92ebf54db9
--- /dev/null
+++ b/Userland/Libraries/LibC/byteswap.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#pragma once
+
+__BEGIN_DECLS
+
+#define bswap_16(x) (__builtin_bswap16(x))
+#define bswap_32(x) (__builtin_bswap32(x))
+#define bswap_64(x) (__builtin_bswap64(x))
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/crt0.cpp b/Userland/Libraries/LibC/crt0.cpp
new file mode 100644
index 0000000000..a02a4d14b2
--- /dev/null
+++ b/Userland/Libraries/LibC/crt0.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Types.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/internals.h>
+#include <unistd.h>
+
+extern "C" {
+
+extern u32 __stack_chk_guard;
+
+int main(int, char**, char**);
+
+// Tell the compiler that this may be called from somewhere else.
+int _start(int argc, char** argv, char** env);
+
+int _start(int argc, char** argv, char** env)
+{
+ u32 original_stack_chk = __stack_chk_guard;
+ arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard));
+
+ if (__stack_chk_guard == 0)
+ __stack_chk_guard = original_stack_chk;
+
+ environ = env;
+ __environ_is_malloced = false;
+
+ __libc_init();
+
+ _init();
+
+ extern void (*__init_array_start[])(int, char**, char**) __attribute__((visibility("hidden")));
+ extern void (*__init_array_end[])(int, char**, char**) __attribute__((visibility("hidden")));
+
+ const size_t size = __init_array_end - __init_array_start;
+ for (size_t i = 0; i < size; i++)
+ (*__init_array_start[i])(argc, argv, env);
+
+ int status = main(argc, argv, environ);
+
+ exit(status);
+
+ // We should never get here, but if we ever do, make sure to
+ // restore the stack guard to the value we entered _start with.
+ // Then we won't trigger the stack canary check on the way out.
+ __stack_chk_guard = original_stack_chk;
+
+ return 20150614;
+}
+}
diff --git a/Userland/Libraries/LibC/crt0_shared.cpp b/Userland/Libraries/LibC/crt0_shared.cpp
new file mode 100644
index 0000000000..df834b7580
--- /dev/null
+++ b/Userland/Libraries/LibC/crt0_shared.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Types.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/internals.h>
+#include <unistd.h>
+
+extern "C" {
+
+extern u32 __stack_chk_guard;
+
+int main(int, char**, char**);
+
+extern void __libc_init();
+extern void _init();
+extern char** environ;
+extern bool __environ_is_malloced;
+
+int _start(int argc, char** argv, char** env);
+int _start(int argc, char** argv, char** env)
+{
+ u32 original_stack_chk = __stack_chk_guard;
+ arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard));
+
+ if (__stack_chk_guard == 0)
+ __stack_chk_guard = original_stack_chk;
+
+ _init();
+
+ int status = main(argc, argv, env);
+
+ // Restore the stack guard to the value we entered _start with,
+ // so we don't trigger the stack canary check on the way out.
+ __stack_chk_guard = original_stack_chk;
+
+ return status;
+}
+}
+
+void* __dso_handle __attribute__((__weak__));
diff --git a/Userland/Libraries/LibC/crti.S b/Userland/Libraries/LibC/crti.S
new file mode 100644
index 0000000000..10576a17c0
--- /dev/null
+++ b/Userland/Libraries/LibC/crti.S
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.global _init
+.section .init
+_init:
+ push %ebp
+
+.global _fini
+.section .fini
+_fini:
+ push %ebp
diff --git a/Userland/Libraries/LibC/crtn.S b/Userland/Libraries/LibC/crtn.S
new file mode 100644
index 0000000000..d7327a0090
--- /dev/null
+++ b/Userland/Libraries/LibC/crtn.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.section .init
+ pop %ebp
+ ret
+
+.section .fini
+ pop %ebp
+ ret
diff --git a/Userland/Libraries/LibC/ctype.cpp b/Userland/Libraries/LibC/ctype.cpp
new file mode 100644
index 0000000000..3649afba31
--- /dev/null
+++ b/Userland/Libraries/LibC/ctype.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+
+extern "C" {
+
+const char _ctype_[256] = {
+ _C, _C, _C, _C, _C, _C, _C, _C,
+ _C, _C | _S, _C | _S, _C | _S, _C | _S, _C | _S, _C, _C,
+ _C, _C, _C, _C, _C, _C, _C, _C,
+ _C, _C, _C, _C, _C, _C, _C, _C,
+ (char)(_S | _B), _P, _P, _P, _P, _P, _P, _P,
+ _P, _P, _P, _P, _P, _P, _P, _P,
+ _N, _N, _N, _N, _N, _N, _N, _N,
+ _N, _N, _P, _P, _P, _P, _P, _P,
+ _P, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U,
+ _U, _U, _U, _U, _U, _U, _U, _U,
+ _U, _U, _U, _U, _U, _U, _U, _U,
+ _U, _U, _U, _P, _P, _P, _P, _P,
+ _P, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L,
+ _L, _L, _L, _L, _L, _L, _L, _L,
+ _L, _L, _L, _L, _L, _L, _L, _L,
+ _L, _L, _L, _P, _P, _P, _P, _C
+};
+
+int tolower(int c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return c | 0x20;
+ return c;
+}
+
+int toupper(int c)
+{
+ if (c >= 'a' && c <= 'z')
+ return c & ~0x20;
+ return c;
+}
+}
diff --git a/Userland/Libraries/LibC/ctype.h b/Userland/Libraries/LibC/ctype.h
new file mode 100644
index 0000000000..e49c7086d0
--- /dev/null
+++ b/Userland/Libraries/LibC/ctype.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Do what newlib does to appease GCC's --with-newlib option. */
+#define _U 01
+#define _L 02
+#define _N 04
+#define _S 010
+#define _P 020
+#define _C 040
+#define _X 0100
+#define _B 0200
+
+extern const char _ctype_[256];
+
+int tolower(int);
+int toupper(int);
+
+static inline int isalnum(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_U | _L | _N));
+}
+
+static inline int isalpha(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_U | _L));
+}
+
+static inline int iscntrl(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_C));
+}
+
+static inline int isdigit(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_N));
+}
+
+static inline int isxdigit(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_N | _X));
+}
+
+static inline int isspace(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_S));
+}
+
+static inline int ispunct(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_P));
+}
+
+static inline int isprint(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_P | _U | _L | _N | _B));
+}
+
+static inline int isgraph(int c)
+{
+ return (_ctype_[(unsigned char)(c)] & (_P | _U | _L | _N));
+}
+
+static inline int islower(int c)
+{
+ return ((_ctype_[(unsigned char)(c)] & (_U | _L)) == _L);
+}
+
+static inline int isupper(int c)
+{
+ return ((_ctype_[(unsigned char)(c)] & (_U | _L)) == _U);
+}
+
+#define isascii(c) ((unsigned)c <= 127)
+#define toascii(c) ((c)&127)
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/cxxabi.cpp b/Userland/Libraries/LibC/cxxabi.cpp
new file mode 100644
index 0000000000..05978bfe9b
--- /dev/null
+++ b/Userland/Libraries/LibC/cxxabi.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019-2020, Andrew Kaster <andrewdkaster@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/internals.h>
+
+//#define GLOBAL_DTORS_DEBUG
+
+extern "C" {
+
+struct __exit_entry {
+ AtExitFunction method;
+ void* parameter;
+ void* dso_handle;
+ bool has_been_called;
+};
+
+static __exit_entry __exit_entries[1024] {};
+static int __exit_entry_count = 0;
+
+int __cxa_atexit(AtExitFunction exit_function, void* parameter, void* dso_handle)
+{
+ if (__exit_entry_count >= 1024)
+ return -1;
+
+ __exit_entries[__exit_entry_count++] = { exit_function, parameter, dso_handle, false };
+
+ return 0;
+}
+
+void __cxa_finalize(void* dso_handle)
+{
+ // From the itanium abi, https://itanium-cxx-abi.github.io/cxx-abi/abi.html#dso-dtor-runtime-api
+ //
+ // When __cxa_finalize(d) is called, it should walk the termination function list, calling each in turn
+ // if d matches __dso_handle for the termination function entry. If d == NULL, it should call all of them.
+ // Multiple calls to __cxa_finalize shall not result in calling termination function entries multiple times;
+ // the implementation may either remove entries or mark them finished.
+
+ int entry_index = __exit_entry_count;
+
+#ifdef GLOBAL_DTORS_DEBUG
+ dbgprintf("__cxa_finalize: %d entries in the finalizer list\n", entry_index);
+#endif
+
+ while (--entry_index >= 0) {
+ auto& exit_entry = __exit_entries[entry_index];
+ bool needs_calling = !exit_entry.has_been_called && (!dso_handle || dso_handle == exit_entry.dso_handle);
+ if (needs_calling) {
+#ifdef GLOBAL_DTORS_DEBUG
+ dbgprintf("__cxa_finalize: calling entry[%d] %p(%p) dso: %p\n", entry_index, exit_entry.method, exit_entry.parameter, exit_entry.dso_handle);
+#endif
+ exit_entry.method(exit_entry.parameter);
+ exit_entry.has_been_called = true;
+ }
+ }
+}
+
+[[noreturn]] void __cxa_pure_virtual()
+{
+ ASSERT_NOT_REACHED();
+}
+
+} // extern "C"
diff --git a/Userland/Libraries/LibC/dirent.cpp b/Userland/Libraries/LibC/dirent.cpp
new file mode 100644
index 0000000000..8e9701177d
--- /dev/null
+++ b/Userland/Libraries/LibC/dirent.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <AK/StdLibExtras.h>
+#include <Kernel/API/Syscall.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern "C" {
+
+DIR* opendir(const char* name)
+{
+ int fd = open(name, O_RDONLY | O_DIRECTORY);
+ if (fd == -1)
+ return nullptr;
+ DIR* dirp = (DIR*)malloc(sizeof(DIR));
+ dirp->fd = fd;
+ dirp->buffer = nullptr;
+ dirp->buffer_size = 0;
+ dirp->nextptr = nullptr;
+ return dirp;
+}
+
+int closedir(DIR* dirp)
+{
+ if (!dirp || dirp->fd == -1)
+ return -EBADF;
+ if (dirp->buffer)
+ free(dirp->buffer);
+ int rc = close(dirp->fd);
+ if (rc == 0)
+ dirp->fd = -1;
+ free(dirp);
+ return rc;
+}
+
+struct [[gnu::packed]] sys_dirent {
+ ino_t ino;
+ u8 file_type;
+ size_t namelen;
+ char name[];
+ size_t total_size()
+ {
+ return sizeof(ino_t) + sizeof(u8) + sizeof(size_t) + sizeof(char) * namelen;
+ }
+};
+
+static void create_struct_dirent(sys_dirent* sys_ent, struct dirent* str_ent)
+{
+ str_ent->d_ino = sys_ent->ino;
+ str_ent->d_type = sys_ent->file_type;
+ str_ent->d_off = 0;
+ str_ent->d_reclen = sys_ent->total_size();
+ for (size_t i = 0; i < sys_ent->namelen; ++i)
+ str_ent->d_name[i] = sys_ent->name[i];
+ // FIXME: I think this null termination behavior is not supposed to be here.
+ str_ent->d_name[sys_ent->namelen] = '\0';
+}
+
+static int allocate_dirp_buffer(DIR* dirp)
+{
+ if (dirp->buffer) {
+ return 0;
+ }
+
+ struct stat st;
+ // preserve errno since this could be a reentrant call
+ int old_errno = errno;
+ int rc = fstat(dirp->fd, &st);
+ if (rc < 0) {
+ int new_errno = errno;
+ errno = old_errno;
+ return new_errno;
+ }
+ size_t size_to_allocate = max(st.st_size, static_cast<off_t>(4096));
+ dirp->buffer = (char*)malloc(size_to_allocate);
+ ssize_t nread = syscall(SC_get_dir_entries, dirp->fd, dirp->buffer, size_to_allocate);
+ if (nread < 0) {
+ // uh-oh, the syscall returned an error
+ free(dirp->buffer);
+ dirp->buffer = nullptr;
+ return -nread;
+ }
+ dirp->buffer_size = nread;
+ dirp->nextptr = dirp->buffer;
+ return 0;
+}
+
+dirent* readdir(DIR* dirp)
+{
+ if (!dirp)
+ return nullptr;
+ if (dirp->fd == -1)
+ return nullptr;
+
+ if (int new_errno = allocate_dirp_buffer(dirp)) {
+ // readdir is allowed to mutate errno
+ errno = new_errno;
+ return nullptr;
+ }
+
+ if (dirp->nextptr >= (dirp->buffer + dirp->buffer_size))
+ return nullptr;
+
+ auto* sys_ent = (sys_dirent*)dirp->nextptr;
+ create_struct_dirent(sys_ent, &dirp->cur_ent);
+
+ dirp->nextptr += sys_ent->total_size();
+ return &dirp->cur_ent;
+}
+
+static bool compare_sys_struct_dirent(sys_dirent* sys_ent, struct dirent* str_ent)
+{
+ size_t namelen = min((size_t)256, sys_ent->namelen);
+ // These fields are guaranteed by create_struct_dirent to be the same
+ return sys_ent->ino == str_ent->d_ino
+ && sys_ent->file_type == str_ent->d_type
+ && sys_ent->total_size() == str_ent->d_reclen
+ && strncmp(sys_ent->name, str_ent->d_name, namelen) == 0;
+}
+
+int readdir_r(DIR* dirp, struct dirent* entry, struct dirent** result)
+{
+ if (!dirp || dirp->fd == -1) {
+ *result = nullptr;
+ return EBADF;
+ }
+
+ if (int new_errno = allocate_dirp_buffer(dirp)) {
+ *result = nullptr;
+ return new_errno;
+ }
+
+ // This doesn't care about dirp state; seek until we find the entry.
+ // Unfortunately, we can't just compare struct dirent to sys_dirent, so
+ // manually compare the fields. This seems a bit risky, but could work.
+ auto* buffer = dirp->buffer;
+ auto* sys_ent = (sys_dirent*)buffer;
+ bool found = false;
+ while (!(found || buffer >= dirp->buffer + dirp->buffer_size)) {
+ found = compare_sys_struct_dirent(sys_ent, entry);
+
+ // Make sure if we found one, it's the one after (end of buffer or not)
+ buffer += sys_ent->total_size();
+ sys_ent = (sys_dirent*)buffer;
+ }
+
+ // If we found one, but hit end of buffer, then EOD
+ if (found && buffer >= dirp->buffer + dirp->buffer_size) {
+ *result = nullptr;
+ return 0;
+ }
+ // If we never found a match for entry in buffer, start from the beginning
+ else if (!found) {
+ buffer = dirp->buffer;
+ sys_ent = (sys_dirent*)buffer;
+ }
+
+ *result = entry;
+ create_struct_dirent(sys_ent, entry);
+
+ return 0;
+}
+
+int dirfd(DIR* dirp)
+{
+ ASSERT(dirp);
+ return dirp->fd;
+}
+}
diff --git a/Userland/Libraries/LibC/dirent.h b/Userland/Libraries/LibC/dirent.h
new file mode 100644
index 0000000000..027f09a057
--- /dev/null
+++ b/Userland/Libraries/LibC/dirent.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+enum {
+ DT_UNKNOWN = 0,
+#define DT_UNKNOWN DT_UNKNOWN
+ DT_FIFO = 1,
+#define DT_FIFO DT_FIFO
+ DT_CHR = 2,
+#define DT_CHR DT_CHR
+ DT_DIR = 4,
+#define DT_DIR DT_DIR
+ DT_BLK = 6,
+#define DT_BLK DT_BLK
+ DT_REG = 8,
+#define DT_REG DT_REG
+ DT_LNK = 10,
+#define DT_LNK DT_LNK
+ DT_SOCK = 12,
+#define DT_SOCK DT_SOCK
+ DT_WHT = 14
+#define DT_WHT DT_WHT
+};
+
+struct dirent {
+ ino_t d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[256];
+};
+
+struct __DIR {
+ int fd;
+ struct dirent cur_ent;
+ char* buffer;
+ size_t buffer_size;
+ char* nextptr;
+};
+typedef struct __DIR DIR;
+
+DIR* opendir(const char* name);
+int closedir(DIR*);
+struct dirent* readdir(DIR*);
+int readdir_r(DIR*, struct dirent*, struct dirent**);
+int dirfd(DIR*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/dlfcn.cpp b/Userland/Libraries/LibC/dlfcn.cpp
new file mode 100644
index 0000000000..04f742fcc3
--- /dev/null
+++ b/Userland/Libraries/LibC/dlfcn.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <AK/HashMap.h>
+#include <AK/LexicalPath.h>
+#include <AK/RefPtr.h>
+#include <AK/ScopeGuard.h>
+#include <AK/String.h>
+#include <AK/StringBuilder.h>
+#include <LibELF/DynamicLoader.h>
+
+// NOTE: The string here should never include a trailing newline (according to POSIX)
+String g_dlerror_msg;
+
+HashMap<String, RefPtr<ELF::DynamicLoader>> g_elf_objects;
+
+extern "C" {
+
+int dlclose(void*)
+{
+ g_dlerror_msg = "dlclose not implemented!";
+ return -1;
+}
+
+char* dlerror()
+{
+ return const_cast<char*>(g_dlerror_msg.characters());
+}
+
+void* dlopen(const char* filename, int flags)
+{
+ // FIXME: Create a global mutex/semaphore/lock for dlopen/dlclose/dlsym and (?) dlerror
+ // FIXME: refcount?
+
+ if (!filename) {
+ // FIXME: Return the handle for "the main executable"
+ // The Serenity Kernel will keep a mapping of the main elf binary resident in memory,
+ // But a future dynamic loader might have a different idea/way of letting us access this information
+ ASSERT_NOT_REACHED();
+ }
+
+ auto basename = LexicalPath(filename).basename();
+
+ auto existing_elf_object = g_elf_objects.get(basename);
+ if (existing_elf_object.has_value()) {
+ return const_cast<ELF::DynamicLoader*>(existing_elf_object.value());
+ }
+
+ int fd = open(filename, O_RDONLY);
+ if (!fd) {
+ g_dlerror_msg = String::format("Unable to open file %s", filename);
+ return nullptr;
+ }
+
+ ScopeGuard close_fd_guard([fd]() { close(fd); });
+
+ struct stat file_stats {
+ };
+
+ int ret = fstat(fd, &file_stats);
+ if (ret < 0) {
+ g_dlerror_msg = String::format("Unable to stat file %s", filename);
+ return nullptr;
+ }
+
+ auto loader = ELF::DynamicLoader::construct(filename, fd, file_stats.st_size);
+
+ if (!loader->is_valid()) {
+ g_dlerror_msg = String::format("%s is not a valid ELF dynamic shared object!", filename);
+ return nullptr;
+ }
+
+ if (!loader->load_from_image(flags,
+ 0 // total_tls_size = 0, FIXME: Support TLS when using dlopen()
+ )) {
+ g_dlerror_msg = String::format("Failed to load ELF object %s", filename);
+ return nullptr;
+ }
+
+ g_elf_objects.set(basename, move(loader));
+ g_dlerror_msg = "Successfully loaded ELF object.";
+
+ // we have one refcount already
+ return const_cast<ELF::DynamicLoader*>(g_elf_objects.get(basename).value());
+}
+
+void* dlsym(void* handle, const char* symbol_name)
+{
+ // FIXME: When called with a NULL handle we're supposed to search every dso in the process... that'll get expensive
+ ASSERT(handle);
+ auto* dso = reinterpret_cast<ELF::DynamicLoader*>(handle);
+ void* symbol = dso->symbol_for_name(symbol_name);
+ if (!symbol) {
+ g_dlerror_msg = "Symbol not found";
+ return nullptr;
+ }
+ return symbol;
+}
+
+} // extern "C"
diff --git a/Userland/Libraries/LibC/dlfcn.h b/Userland/Libraries/LibC/dlfcn.h
new file mode 100644
index 0000000000..9363261ca6
--- /dev/null
+++ b/Userland/Libraries/LibC/dlfcn.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define RTLD_DEFAULT 0
+#define RTLD_LAZY 2
+#define RTLD_NOW 4
+#define RTLD_GLOBAL 8
+#define RTLD_LOCAL 16
+
+int dlclose(void*);
+char* dlerror();
+void* dlopen(const char*, int);
+void* dlsym(void*, const char*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/endian.h b/Userland/Libraries/LibC/endian.h
new file mode 100644
index 0000000000..ebaf6cde3e
--- /dev/null
+++ b/Userland/Libraries/LibC/endian.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __PDP_ENDIAN 3412
+
+#if defined(__GNUC__) && defined(__BYTE_ORDER__)
+# define __BYTE_ORDER __BYTE_ORDER__
+#else
+# include <bits/endian.h>
+#endif
+
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+
+# include <stdint.h>
+
+static __inline uint16_t __bswap16(uint16_t x)
+{
+ return __builtin_bswap16(x);
+}
+
+static __inline uint32_t __bswap32(uint32_t x)
+{
+ return __builtin_bswap32(x);
+}
+
+static __inline uint64_t __bswap64(uint64_t x)
+{
+ return __builtin_bswap64(x);
+}
+
+# define LITTLE_ENDIAN __LITTLE_ENDIAN
+# define BIG_ENDIAN __BIG_ENDIAN
+# define PDP_ENDIAN __PDP_ENDIAN
+# define BYTE_ORDER __BYTE_ORDER
+
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+# define htole16(x) ((uint16_t)(x))
+# define le16toh(x) ((uint16_t)(x))
+# define letoh16(x) ((uint16_t)(x))
+# define htole32(x) ((uint32_t)(x))
+# define le32toh(x) ((uint32_t)(x))
+# define letoh32(x) ((uint32_t)(x))
+# define htole64(x) ((uint64_t)(x))
+# define le64toh(x) ((uint64_t)(x))
+# define letoh64(x) ((uint64_t)(x))
+# define htobe16(x) (__builtin_bswap16(x))
+# define be16toh(x) (__builtin_bswap16(x))
+# define betoh16(x) (__builtin_bswap16(x))
+# define htobe32(x) (__builtin_bswap32(x))
+# define be32toh(x) (__builtin_bswap32(x))
+# define betoh32(x) (__builtin_bswap32(x))
+# define htobe64(x) (__builtin_bswap64(x))
+# define be64toh(x) (__builtin_bswap64(x))
+# define betoh64(x) (__builtin_bswap64(x))
+# else
+# define htole16(x) (__builtin_bswap16(x))
+# define le16toh(x) (__builtin_bswap16(x))
+# define letoh16(x) (__builtin_bswap16(x))
+# define htole32(x) (__builtin_bswap32(x))
+# define le32toh(x) (__builtin_bswap32(x))
+# define letoh32(x) (__builtin_bswap32(x))
+# define htole64(x) (__builtin_bswap64(x))
+# define le64toh(x) (__builtin_bswap64(x))
+# define letoh64(x) (__builtin_bswap64(x))
+# define htobe16(x) ((uint16_t)(x))
+# define be16toh(x) ((uint16_t)(x))
+# define betoh16(x) ((uint16_t)(x))
+# define htobe32(x) ((uint32_t)(x))
+# define be32toh(x) ((uint32_t)(x))
+# define betoh32(x) ((uint32_t)(x))
+# define htobe64(x) ((uint64_t)(x))
+# define be64toh(x) ((uint64_t)(x))
+# define betoh64(x) ((uint64_t)(x))
+# endif
+
+#endif
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/errno.h b/Userland/Libraries/LibC/errno.h
new file mode 100644
index 0000000000..f763dbc914
--- /dev/null
+++ b/Userland/Libraries/LibC/errno.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <errno_numbers.h>
+#include <sys/cdefs.h>
+
+#define __RETURN_WITH_ERRNO(rc, good_ret, bad_ret) \
+ do { \
+ if (rc < 0) { \
+ errno = -rc; \
+ return (bad_ret); \
+ } \
+ errno = 0; \
+ return (good_ret); \
+ } while (0)
+
+__BEGIN_DECLS
+
+extern const char* const sys_errlist[];
+extern int sys_nerr;
+
+#ifdef NO_TLS
+extern int errno;
+#else
+extern __thread int errno;
+#endif
+
+#define errno errno
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/errno_numbers.h b/Userland/Libraries/LibC/errno_numbers.h
new file mode 100644
index 0000000000..fc067b171d
--- /dev/null
+++ b/Userland/Libraries/LibC/errno_numbers.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EIO 5
+#define ENXIO 6
+#define E2BIG 7
+#define ENOEXEC 8
+#define EBADF 9
+#define ECHILD 10
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EFAULT 14
+#define ENOTBLK 15
+#define EBUSY 16
+#define EEXIST 17
+#define EXDEV 18
+#define ENODEV 19
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define ENFILE 23
+#define EMFILE 24
+#define ENOTTY 25
+#define ETXTBSY 26
+#define EFBIG 27
+#define ENOSPC 28
+#define ESPIPE 29
+#define EROFS 30
+#define EMLINK 31
+#define EPIPE 32
+#define ERANGE 33
+#define ENAMETOOLONG 34
+#define ELOOP 35
+#define EOVERFLOW 36
+#define EOPNOTSUPP 37
+#define ENOSYS 38
+#define ENOTIMPL 39
+#define EAFNOSUPPORT 40
+#define ENOTSOCK 41
+#define EADDRINUSE 42
+#define EWHYTHO 43
+#define ENOTEMPTY 44
+#define EDOM 45
+#define ECONNREFUSED 46
+#define EADDRNOTAVAIL 47
+#define EISCONN 48
+#define ECONNABORTED 49
+#define EALREADY 50
+#define ECONNRESET 51
+#define EDESTADDRREQ 52
+#define EHOSTUNREACH 53
+#define EILSEQ 54
+#define EMSGSIZE 55
+#define ENETDOWN 56
+#define ENETUNREACH 57
+#define ENETRESET 58
+#define ENOBUFS 59
+#define ENOLCK 60
+#define ENOMSG 61
+#define ENOPROTOOPT 62
+#define ENOTCONN 63
+#define EWOULDBLOCK 64
+#define EPROTONOSUPPORT 65
+#define EDEADLK 66
+#define ETIMEDOUT 67
+#define EPROTOTYPE 68
+#define EINPROGRESS 69
+#define ENOTHREAD 70
+#define EPROTO 71
+#define ENOTSUP 72
+#define EPFNOSUPPORT 73
+#define EDIRINTOSELF 74
+#define EMAXERRNO 75
diff --git a/Userland/Libraries/LibC/fcntl.cpp b/Userland/Libraries/LibC/fcntl.cpp
new file mode 100644
index 0000000000..dd71fd1559
--- /dev/null
+++ b/Userland/Libraries/LibC/fcntl.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+
+extern "C" {
+
+int fcntl(int fd, int cmd, ...)
+{
+ va_list ap;
+ va_start(ap, cmd);
+ u32 extra_arg = va_arg(ap, u32);
+ int rc = syscall(SC_fcntl, fd, cmd, extra_arg);
+ va_end(ap);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int watch_file(const char* path, size_t path_length)
+{
+ int rc = syscall(SC_watch_file, path, path_length);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int creat(const char* path, mode_t mode)
+{
+ return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
+}
+
+int creat_with_path_length(const char* path, size_t path_length, mode_t mode)
+{
+ return open_with_path_length(path, path_length, O_CREAT | O_WRONLY | O_TRUNC, mode);
+}
+
+int open_with_path_length(const char* path, size_t path_length, int options, mode_t mode)
+{
+ return openat_with_path_length(AT_FDCWD, path, path_length, options, mode);
+}
+
+int openat_with_path_length(int dirfd, const char* path, size_t path_length, int options, mode_t mode)
+{
+ if (!path) {
+ errno = EFAULT;
+ return -1;
+ }
+ if (path_length > INT32_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ Syscall::SC_open_params params { dirfd, { path, path_length }, options, mode };
+ int rc = syscall(SC_open, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int open(const char* path, int options, ...)
+{
+ if (!path) {
+ errno = EFAULT;
+ return -1;
+ }
+ va_list ap;
+ va_start(ap, options);
+ auto mode = (mode_t)va_arg(ap, unsigned);
+ va_end(ap);
+ return open_with_path_length(path, strlen(path), options, mode);
+}
+
+int openat(int dirfd, const char* path, int options, ...)
+{
+ if (!path) {
+ errno = EFAULT;
+ return -1;
+ }
+ va_list ap;
+ va_start(ap, options);
+ auto mode = (mode_t)va_arg(ap, unsigned);
+ va_end(ap);
+ return openat_with_path_length(dirfd, path, strlen(path), options, mode);
+}
+}
diff --git a/Userland/Libraries/LibC/fcntl.h b/Userland/Libraries/LibC/fcntl.h
new file mode 100644
index 0000000000..1aa6e6cd09
--- /dev/null
+++ b/Userland/Libraries/LibC/fcntl.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+#define F_DUPFD 0
+#define F_GETFD 1
+#define F_SETFD 2
+#define F_GETFL 3
+#define F_SETFL 4
+#define F_ISTTY 5
+
+#define FD_CLOEXEC 1
+
+#define O_RDONLY (1 << 0)
+#define O_WRONLY (1 << 1)
+#define O_RDWR (O_RDONLY | O_WRONLY)
+#define O_ACCMODE (O_RDONLY | O_WRONLY)
+#define O_EXEC (1 << 2)
+#define O_CREAT (1 << 3)
+#define O_EXCL (1 << 4)
+#define O_NOCTTY (1 << 5)
+#define O_TRUNC (1 << 6)
+#define O_APPEND (1 << 7)
+#define O_NONBLOCK (1 << 8)
+#define O_DIRECTORY (1 << 9)
+#define O_NOFOLLOW (1 << 10)
+#define O_CLOEXEC (1 << 11)
+#define O_DIRECT (1 << 12)
+
+#define S_IFMT 0170000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFBLK 0060000
+#define S_IFREG 0100000
+#define S_IFIFO 0010000
+#define S_IFLNK 0120000
+#define S_IFSOCK 0140000
+
+#define S_ISUID 04000
+#define S_ISGID 02000
+#define S_ISVTX 01000
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#define S_IXUSR 0100
+#define S_IRGRP 0040
+#define S_IWGRP 0020
+#define S_IXGRP 0010
+#define S_IROTH 0004
+#define S_IWOTH 0002
+#define S_IXOTH 0001
+
+#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+
+#define S_IRWXG (S_IRWXU >> 3)
+#define S_IRWXO (S_IRWXG >> 3)
+
+int creat(const char* path, mode_t);
+int open(const char* path, int options, ...);
+int creat_with_path_length(const char* path, size_t path_length, mode_t);
+int open_with_path_length(const char* path, size_t path_length, int options, mode_t);
+#define AT_FDCWD -100
+int openat(int dirfd, const char* path, int options, ...);
+int openat_with_path_length(int dirfd, const char* path, size_t path_length, int options, mode_t);
+
+int fcntl(int fd, int cmd, ...);
+int watch_file(const char* path, size_t path_length);
+
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+#define F_SETLK 6
+#define F_SETLKW 7
+
+struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+};
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/fd_set.h b/Userland/Libraries/LibC/fd_set.h
new file mode 100644
index 0000000000..254a1ba49c
--- /dev/null
+++ b/Userland/Libraries/LibC/fd_set.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define FD_SETSIZE 64
+#define FD_ZERO(set) memset((set), 0, sizeof(fd_set));
+#define FD_CLR(fd, set) ((set)->bits[(fd / 8)] &= ~(1 << (fd) % 8))
+#define FD_SET(fd, set) ((set)->bits[(fd / 8)] |= (1 << (fd) % 8))
+#define FD_ISSET(fd, set) ((set)->bits[(fd / 8)] & (1 << (fd) % 8))
+
+struct __fd_set {
+ unsigned char bits[FD_SETSIZE / 8];
+};
+
+typedef struct __fd_set fd_set;
diff --git a/Userland/Libraries/LibC/float.h b/Userland/Libraries/LibC/float.h
new file mode 100644
index 0000000000..2bf8abd099
--- /dev/null
+++ b/Userland/Libraries/LibC/float.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
diff --git a/Userland/Libraries/LibC/getopt.cpp b/Userland/Libraries/LibC/getopt.cpp
new file mode 100644
index 0000000000..a8142262d7
--- /dev/null
+++ b/Userland/Libraries/LibC/getopt.cpp
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/StringView.h>
+#include <AK/Vector.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int opterr = 1;
+int optopt = 0;
+int optind = 1;
+int optreset = 0;
+char* optarg = nullptr;
+
+// POSIX says, "When an element of argv[] contains multiple option characters,
+// it is unspecified how getopt() determines which options have already been
+// processed". Well, this is how we do it.
+static size_t s_index_into_multioption_argument = 0;
+
+static inline void report_error(const char* format, ...)
+{
+ if (!opterr)
+ return;
+
+ fputs("\033[31m", stderr);
+
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+
+ fputs("\033[0m\n", stderr);
+}
+
+namespace {
+
+class OptionParser {
+public:
+ OptionParser(int argc, char** argv, const StringView& short_options, const option* long_options, int* out_long_option_index = nullptr);
+ int getopt();
+
+private:
+ bool lookup_short_option(char option, int& needs_value) const;
+ int handle_short_option();
+
+ const option* lookup_long_option(char* raw) const;
+ int handle_long_option();
+
+ void shift_argv();
+ bool find_next_option();
+
+ size_t m_argc { 0 };
+ char** m_argv { nullptr };
+ StringView m_short_options;
+ const option* m_long_options { nullptr };
+ int* m_out_long_option_index { nullptr };
+ bool m_stop_on_first_non_option { false };
+
+ size_t m_arg_index { 0 };
+ size_t m_consumed_args { 0 };
+};
+
+OptionParser::OptionParser(int argc, char** argv, const StringView& short_options, const option* long_options, int* out_long_option_index)
+ : m_argc(argc)
+ , m_argv(argv)
+ , m_short_options(short_options)
+ , m_long_options(long_options)
+ , m_out_long_option_index(out_long_option_index)
+{
+ // In the following case:
+ // $ foo bar -o baz
+ // we want to parse the option (-o baz) first, and leave the argument (bar)
+ // in argv after we return -1 when invoked the second time. So we reorder
+ // argv to put options first and positional arguments next. To turn this
+ // behavior off, start the short options spec with a "+". This is a GNU
+ // extension that we support.
+ m_stop_on_first_non_option = short_options.starts_with('+');
+
+ // See if we should reset the internal state.
+ if (optreset || optind == 0) {
+ optreset = 0;
+ optind = 1;
+ s_index_into_multioption_argument = 0;
+ }
+
+ optopt = 0;
+ optarg = nullptr;
+}
+
+int OptionParser::getopt()
+{
+ bool should_reorder_argv = !m_stop_on_first_non_option;
+ int res = -1;
+
+ bool found_an_option = find_next_option();
+ StringView arg = m_argv[m_arg_index];
+
+ if (!found_an_option) {
+ res = -1;
+ if (arg == "--")
+ m_consumed_args = 1;
+ else
+ m_consumed_args = 0;
+ } else {
+ // Alright, so we have an option on our hands!
+ bool is_long_option = arg.starts_with("--");
+ if (is_long_option)
+ res = handle_long_option();
+ else
+ res = handle_short_option();
+
+ // If we encountered an error, return immediately.
+ if (res == '?')
+ return '?';
+ }
+
+ if (should_reorder_argv)
+ shift_argv();
+ else
+ ASSERT(optind == static_cast<int>(m_arg_index));
+ optind += m_consumed_args;
+
+ return res;
+}
+
+bool OptionParser::lookup_short_option(char option, int& needs_value) const
+{
+ Vector<StringView> parts = m_short_options.split_view(option, true);
+
+ ASSERT(parts.size() <= 2);
+ if (parts.size() < 2) {
+ // Haven't found the option in the spec.
+ return false;
+ }
+
+ if (parts[1].starts_with("::")) {
+ // If an option is followed by two colons, it optionally accepts an
+ // argument.
+ needs_value = optional_argument;
+ } else if (parts[1].starts_with(':')) {
+ // If it's followed by one colon, it requires an argument.
+ needs_value = required_argument;
+ } else {
+ // Otherwise, it doesn't accept arguments.
+ needs_value = no_argument;
+ }
+ return true;
+}
+
+int OptionParser::handle_short_option()
+{
+ StringView arg = m_argv[m_arg_index];
+ ASSERT(arg.starts_with('-'));
+
+ if (s_index_into_multioption_argument == 0) {
+ // Just starting to parse this argument, skip the "-".
+ s_index_into_multioption_argument = 1;
+ }
+ char option = arg[s_index_into_multioption_argument];
+ s_index_into_multioption_argument++;
+
+ int needs_value = no_argument;
+ bool ok = lookup_short_option(option, needs_value);
+ if (!ok) {
+ optopt = option;
+ report_error("Unrecognized option \033[1m-%c\033[22m", option);
+ return '?';
+ }
+
+ // Let's see if we're at the end of this argument already.
+ if (s_index_into_multioption_argument < arg.length()) {
+ // This not yet the end.
+ if (needs_value == no_argument) {
+ optarg = nullptr;
+ m_consumed_args = 0;
+ } else {
+ // Treat the rest of the argument as the value, the "-ovalue"
+ // syntax.
+ optarg = m_argv[m_arg_index] + s_index_into_multioption_argument;
+ // Next time, process the next argument.
+ s_index_into_multioption_argument = 0;
+ m_consumed_args = 1;
+ }
+ } else {
+ s_index_into_multioption_argument = 0;
+ if (needs_value != required_argument) {
+ optarg = nullptr;
+ m_consumed_args = 1;
+ } else if (m_arg_index + 1 < m_argc) {
+ // Treat the next argument as a value, the "-o value" syntax.
+ optarg = m_argv[m_arg_index + 1];
+ m_consumed_args = 2;
+ } else {
+ report_error("Missing value for option \033[1m-%c\033[22m", option);
+ return '?';
+ }
+ }
+
+ return option;
+}
+
+const option* OptionParser::lookup_long_option(char* raw) const
+{
+ StringView arg = raw;
+
+ for (size_t index = 0; m_long_options[index].name; index++) {
+ auto& option = m_long_options[index];
+ StringView name = option.name;
+
+ if (!arg.starts_with(name))
+ continue;
+
+ // It would be better to not write out the index at all unless we're
+ // sure we've found the right option, but whatever.
+ if (m_out_long_option_index)
+ *m_out_long_option_index = index;
+
+ // Can either be "--option" or "--option=value".
+ if (arg.length() == name.length()) {
+ optarg = nullptr;
+ return &option;
+ }
+ ASSERT(arg.length() > name.length());
+ if (arg[name.length()] == '=') {
+ optarg = raw + name.length() + 1;
+ return &option;
+ }
+ }
+
+ return nullptr;
+}
+
+int OptionParser::handle_long_option()
+{
+ ASSERT(StringView(m_argv[m_arg_index]).starts_with("--"));
+
+ // We cannot set optopt to anything sensible for long options, so set it to 0.
+ optopt = 0;
+
+ auto* option = lookup_long_option(m_argv[m_arg_index] + 2);
+ if (!option) {
+ report_error("Unrecognized option \033[1m%s\033[22m", m_argv[m_arg_index]);
+ return '?';
+ }
+ // lookup_long_option() will also set optarg if the value of the option is
+ // specified using "--option=value" syntax.
+
+ // Figure out whether this option needs and/or has a value (also called "an
+ // argument", but let's not call it that to distinguish it from argv
+ // elements).
+ switch (option->has_arg) {
+ case no_argument:
+ if (optarg) {
+ report_error("Option \033[1m--%s\033[22m doesn't accept an argument", option->name);
+ return '?';
+ }
+ m_consumed_args = 1;
+ break;
+ case optional_argument:
+ m_consumed_args = 1;
+ break;
+ case required_argument:
+ if (optarg) {
+ // Value specified using "--option=value" syntax.
+ m_consumed_args = 1;
+ } else if (m_arg_index + 1 < m_argc) {
+ // Treat the next argument as a value in "--option value" syntax.
+ optarg = m_argv[m_arg_index + 1];
+ m_consumed_args = 2;
+ } else {
+ report_error("Missing value for option \033[1m--%s\033[22m", option->name);
+ return '?';
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ // Now that we've figured the value out, see about reporting this option to
+ // our caller.
+ if (option->flag) {
+ *option->flag = option->val;
+ return 0;
+ }
+ return option->val;
+}
+
+void OptionParser::shift_argv()
+{
+ // We've just parsed an option (which perhaps has a value).
+ // Put the option (along with it value, if any) in front of other arguments.
+ ASSERT(optind <= static_cast<int>(m_arg_index));
+
+ if (optind == static_cast<int>(m_arg_index) || m_consumed_args == 0) {
+ // Nothing to do!
+ return;
+ }
+
+ char* buffer[m_consumed_args];
+ memcpy(buffer, &m_argv[m_arg_index], sizeof(char*) * m_consumed_args);
+ memmove(&m_argv[optind + m_consumed_args], &m_argv[optind], sizeof(char*) * (m_arg_index - optind));
+ memcpy(&m_argv[optind], buffer, sizeof(char*) * m_consumed_args);
+}
+
+bool OptionParser::find_next_option()
+{
+ for (m_arg_index = optind; m_arg_index < m_argc && m_argv[m_arg_index]; m_arg_index++) {
+ StringView arg = m_argv[m_arg_index];
+ // Anything that doesn't start with a "-" is not an option.
+ if (!arg.starts_with('-')) {
+ if (m_stop_on_first_non_option)
+ return false;
+ continue;
+ }
+ // As a special case, a single "-" is not an option either.
+ // (It's typically used by programs to refer to stdin).
+ if (arg == "-")
+ continue;
+ // As another special case, a "--" is not an option either, and we stop
+ // looking for further options if we encounter it.
+ if (arg == "--")
+ return false;
+ // Otherwise, we have found an option!
+ return true;
+ }
+
+ // Reached the end and still found no options.
+ return false;
+}
+
+}
+
+int getopt(int argc, char** argv, const char* short_options)
+{
+ option dummy { nullptr, 0, nullptr, 0 };
+ OptionParser parser { argc, argv, short_options, &dummy };
+ return parser.getopt();
+}
+
+int getopt_long(int argc, char** argv, const char* short_options, const struct option* long_options, int* out_long_option_index)
+{
+ OptionParser parser { argc, argv, short_options, long_options, out_long_option_index };
+ return parser.getopt();
+}
diff --git a/Userland/Libraries/LibC/getopt.h b/Userland/Libraries/LibC/getopt.h
new file mode 100644
index 0000000000..0aaddf2820
--- /dev/null
+++ b/Userland/Libraries/LibC/getopt.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+struct option {
+ const char* name;
+ int has_arg;
+ int* flag;
+ int val;
+};
+
+int getopt_long(int argc, char** argv, const char* short_options, const struct option* long_options, int* out_long_option_index);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/grp.cpp b/Userland/Libraries/LibC/grp.cpp
new file mode 100644
index 0000000000..9750389281
--- /dev/null
+++ b/Userland/Libraries/LibC/grp.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <errno_numbers.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern "C" {
+
+static FILE* s_stream = nullptr;
+static unsigned s_line_number = 0;
+static struct group s_group;
+
+static String s_name;
+static String s_passwd;
+static Vector<String> s_members;
+static Vector<const char*> s_members_ptrs;
+
+void setgrent()
+{
+ s_line_number = 0;
+ if (s_stream) {
+ rewind(s_stream);
+ } else {
+ s_stream = fopen("/etc/group", "r");
+ if (!s_stream) {
+ perror("open /etc/group");
+ }
+ }
+}
+
+void endgrent()
+{
+ s_line_number = 0;
+ if (s_stream) {
+ fclose(s_stream);
+ s_stream = nullptr;
+ }
+
+ memset(&s_group, 0, sizeof(s_group));
+
+ s_name = {};
+ s_passwd = {};
+ s_members = {};
+ s_members_ptrs = {};
+}
+
+struct group* getgrgid(gid_t gid)
+{
+ setgrent();
+ while (auto* gr = getgrent()) {
+ if (gr->gr_gid == gid)
+ return gr;
+ }
+ return nullptr;
+}
+
+struct group* getgrnam(const char* name)
+{
+ setgrent();
+ while (auto* gr = getgrent()) {
+ if (!strcmp(gr->gr_name, name))
+ return gr;
+ }
+ return nullptr;
+}
+
+static bool parse_grpdb_entry(const String& line)
+{
+ auto parts = line.split_view(':', true);
+ if (parts.size() != 4) {
+ fprintf(stderr, "getgrent(): Malformed entry on line %u: '%s' has %zu parts\n", s_line_number, line.characters(), parts.size());
+ return false;
+ }
+
+ s_name = parts[0];
+ s_passwd = parts[1];
+
+ auto& gid_string = parts[2];
+ String members_string = parts[3];
+
+ auto gid = gid_string.to_uint();
+ if (!gid.has_value()) {
+ fprintf(stderr, "getgrent(): Malformed GID on line %u\n", s_line_number);
+ return false;
+ }
+
+ s_members = members_string.split(',');
+ s_members_ptrs.clear_with_capacity();
+ s_members_ptrs.ensure_capacity(s_members.size() + 1);
+ for (auto& member : s_members) {
+ s_members_ptrs.append(member.characters());
+ }
+ s_members_ptrs.append(nullptr);
+
+ s_group.gr_gid = gid.value();
+ s_group.gr_name = const_cast<char*>(s_name.characters());
+ s_group.gr_passwd = const_cast<char*>(s_passwd.characters());
+ s_group.gr_mem = const_cast<char**>(s_members_ptrs.data());
+
+ return true;
+}
+
+struct group* getgrent()
+{
+ if (!s_stream)
+ setgrent();
+
+ while (true) {
+ if (!s_stream || feof(s_stream))
+ return nullptr;
+
+ if (ferror(s_stream)) {
+ fprintf(stderr, "getgrent(): Read error: %s\n", strerror(ferror(s_stream)));
+ return nullptr;
+ }
+
+ char buffer[1024];
+ ++s_line_number;
+ char* s = fgets(buffer, sizeof(buffer), s_stream);
+
+ // Silently tolerate an empty line at the end.
+ if ((!s || !s[0]) && feof(s_stream))
+ return nullptr;
+
+ String line(s, Chomp);
+ if (parse_grpdb_entry(line))
+ return &s_group;
+ // Otherwise, proceed to the next line.
+ }
+}
+
+int initgroups(const char* user, gid_t extra_gid)
+{
+ size_t count = 0;
+ gid_t gids[32];
+ bool extra_gid_added = false;
+ setgrent();
+ while (auto* gr = getgrent()) {
+ for (auto* mem = gr->gr_mem; *mem; ++mem) {
+ if (!strcmp(*mem, user)) {
+ gids[count++] = gr->gr_gid;
+ if (gr->gr_gid == extra_gid)
+ extra_gid_added = true;
+ break;
+ }
+ }
+ }
+ endgrent();
+ if (!extra_gid_added)
+ gids[count++] = extra_gid;
+ return setgroups(count, gids);
+}
+}
diff --git a/Userland/Libraries/LibC/grp.h b/Userland/Libraries/LibC/grp.h
new file mode 100644
index 0000000000..a4cb414871
--- /dev/null
+++ b/Userland/Libraries/LibC/grp.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct group {
+ char* gr_name;
+ char* gr_passwd;
+ gid_t gr_gid;
+ char** gr_mem;
+};
+
+struct group* getgrent();
+void setgrent();
+void endgrent();
+struct group* getgrnam(const char* name);
+struct group* getgrgid(gid_t);
+
+int initgroups(const char* user, gid_t);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/iconv.h b/Userland/Libraries/LibC/iconv.h
new file mode 100644
index 0000000000..afcede1e71
--- /dev/null
+++ b/Userland/Libraries/LibC/iconv.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef void* iconv_t;
+
+extern iconv_t iconv_open(const char* tocode, const char* fromcode);
+extern size_t iconv(iconv_t, char** inbuf, size_t* inbytesleft, char** outbuf, size_t* outbytesleft);
+extern int iconv_close(iconv_t);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/inttypes.h b/Userland/Libraries/LibC/inttypes.h
new file mode 100644
index 0000000000..b983f16699
--- /dev/null
+++ b/Userland/Libraries/LibC/inttypes.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/stdint.h>
+
+#define PRId8 "d"
+#define PRId16 "d"
+#define PRId32 "d"
+#define PRId64 "lld"
+#define PRIi8 "d"
+#define PRIi16 "d"
+#define PRIi32 "d"
+#define PRIi64 "lld"
+#define PRIu8 "u"
+#define PRIo8 "o"
+#define PRIo16 "o"
+#define PRIo32 "o"
+#define PRIo64 "llo"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "llu"
+#define PRIx8 "b"
+#define PRIx16 "w"
+#define PRIx32 "x"
+#define PRIX32 "X"
+#define PRIx64 "llx"
+#define PRIX64 "llX"
+
+#define __PRI64_PREFIX "ll"
+#define __PRIPTR_PREFIX
+
+#define PRIdPTR __PRIPTR_PREFIX "d"
+#define PRIiPTR __PRIPTR_PREFIX "i"
+#define PRIXPTR __PRIPTR_PREFIX "X"
+
+#define PRIdMAX __PRI64_PREFIX "d"
+#define PRIoMAX __PRI64_PREFIX "o"
+#define PRIuMAX __PRI64_PREFIX "u"
+
+#define SCNdMAX __PRI64_PREFIX "d"
+#define SCNoMAX __PRI64_PREFIX "o"
+#define SCNuMAX __PRI64_PREFIX "u"
+
+#define SCNu64 __PRI64_PREFIX "u"
+#define SCNd64 __PRI64_PREFIX "d"
diff --git a/Userland/Libraries/LibC/ioctl.cpp b/Userland/Libraries/LibC/ioctl.cpp
new file mode 100644
index 0000000000..c5fee3951e
--- /dev/null
+++ b/Userland/Libraries/LibC/ioctl.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+
+extern "C" {
+
+int ioctl(int fd, unsigned request, ...)
+{
+ va_list ap;
+ va_start(ap, request);
+ unsigned arg = va_arg(ap, unsigned);
+ int rc = syscall(SC_ioctl, fd, request, arg);
+ va_end(ap);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/libcinit.cpp b/Userland/Libraries/LibC/libcinit.cpp
new file mode 100644
index 0000000000..83209b9ca4
--- /dev/null
+++ b/Userland/Libraries/LibC/libcinit.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Types.h>
+#include <assert.h>
+#include <sys/internals.h>
+#include <unistd.h>
+
+extern "C" {
+
+#ifdef NO_TLS
+int errno;
+#else
+__thread int errno;
+#endif
+char** environ;
+bool __environ_is_malloced;
+bool __stdio_is_initialized;
+
+void __libc_init()
+{
+ __malloc_init();
+ __stdio_init();
+}
+}
diff --git a/Userland/Libraries/LibC/libgen.cpp b/Userland/Libraries/LibC/libgen.cpp
new file mode 100644
index 0000000000..13b6e668b8
--- /dev/null
+++ b/Userland/Libraries/LibC/libgen.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <libgen.h>
+#include <string.h>
+
+static char dot[] = ".";
+static char slash[] = "/";
+
+char* dirname(char* path)
+{
+ if (path == nullptr)
+ return dot;
+
+ int len = strlen(path);
+ if (len == 0)
+ return dot;
+
+ while (len > 1 && path[len - 1] == '/') {
+ path[len - 1] = 0;
+ len--;
+ }
+
+ char* last_slash = strrchr(path, '/');
+ if (last_slash == nullptr)
+ return dot;
+
+ if (last_slash == path)
+ return slash;
+
+ *last_slash = 0;
+ return path;
+}
+
+char* basename(char* path)
+{
+ if (path == nullptr)
+ return dot;
+
+ int len = strlen(path);
+ if (len == 0)
+ return dot;
+
+ while (len > 1 && path[len - 1] == '/') {
+ path[len - 1] = 0;
+ len--;
+ }
+
+ char* last_slash = strrchr(path, '/');
+ if (last_slash == nullptr)
+ return path;
+
+ if (len == 1) {
+ ASSERT(last_slash == path);
+ ASSERT(path[0] == '/');
+ return slash;
+ }
+
+ return last_slash + 1;
+}
diff --git a/Userland/Libraries/LibC/libgen.h b/Userland/Libraries/LibC/libgen.h
new file mode 100644
index 0000000000..9cbf66b0e6
--- /dev/null
+++ b/Userland/Libraries/LibC/libgen.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+char* dirname(char* path);
+char* basename(char* path);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/limits.h b/Userland/Libraries/LibC/limits.h
new file mode 100644
index 0000000000..ac53662cb7
--- /dev/null
+++ b/Userland/Libraries/LibC/limits.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/stdint.h>
+
+#ifndef PAGE_SIZE
+# define PAGE_SIZE 4096
+#endif
+
+#define PATH_MAX 4096
+#if !defined MAXPATHLEN && defined PATH_MAX
+# define MAXPATHLEN PATH_MAX
+#endif
+
+#define NAME_MAX 255
+
+#define PIPE_BUF 4096
+
+#define INT_MAX INT32_MAX
+#define INT_MIN INT32_MIN
+
+#define UINT_MAX UINT32_MAX
+#define UINT_MIN UINT32_MIN
+
+#define CHAR_BIT 8
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+#define UCHAR_MAX 255
+
+#define LONG_MAX 2147483647L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+#define ULONG_MAX 4294967295UL
+
+#define LONG_LONG_MAX 9223372036854775807LL
+#define LONG_LONG_MIN (-LONG_LONG_MAX - 1LL)
+
+#define ULONG_LONG_MAX 18446744073709551615ULL
+
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+#define MB_LEN_MAX 16
+
+#define ARG_MAX 65536
+
+#define PTHREAD_STACK_MIN 65536
+
+#define SSIZE_MAX 2147483647
+
+#ifdef __USE_POSIX
+# include <bits/posix1_lim.h>
+#endif
diff --git a/Userland/Libraries/LibC/locale.cpp b/Userland/Libraries/LibC/locale.cpp
new file mode 100644
index 0000000000..5bfcfc0e24
--- /dev/null
+++ b/Userland/Libraries/LibC/locale.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/LogStream.h>
+#include <assert.h>
+#include <locale.h>
+#include <stdio.h>
+
+extern "C" {
+
+static char default_decimal_point[] = ".";
+static char default_thousands_sep[] = ",";
+static char default_grouping[] = "\x03\x03";
+
+static char default_empty_string[] = "";
+static char default_empty_value = 127;
+
+static struct lconv default_locale = {
+ default_decimal_point,
+ default_thousands_sep,
+ default_grouping,
+ default_empty_string,
+ default_empty_string,
+ default_empty_string,
+ default_empty_string,
+ default_empty_string,
+ default_empty_string,
+ default_empty_string,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value,
+ default_empty_value
+};
+
+char* setlocale(int category, const char* locale)
+{
+ dbgln("FIXME(LibC): setlocale({}, '{}')", category, locale);
+ return nullptr;
+}
+
+struct lconv* localeconv()
+{
+ return &default_locale;
+}
+}
diff --git a/Userland/Libraries/LibC/locale.h b/Userland/Libraries/LibC/locale.h
new file mode 100644
index 0000000000..60afc205ee
--- /dev/null
+++ b/Userland/Libraries/LibC/locale.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+enum {
+ LC_ALL,
+ LC_NUMERIC,
+ LC_CTYPE,
+ LC_COLLATE,
+ LC_TIME,
+ LC_MONETARY,
+};
+
+struct lconv {
+ char* decimal_point;
+ char* thousands_sep;
+ char* grouping;
+ char* int_curr_symbol;
+ char* currency_symbol;
+ char* mon_decimal_point;
+ char* mon_thousands_sep;
+ char* mon_grouping;
+ char* positive_sign;
+ char* negative_sign;
+ char int_frac_digits;
+ char frac_digits;
+ char p_cs_precedes;
+ char p_sep_by_space;
+ char n_cs_precedes;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+ char int_p_cs_precedes;
+ char int_p_sep_by_space;
+ char int_n_cs_precedes;
+ char int_n_sep_by_space;
+ char int_p_sign_posn;
+ char int_n_sign_posn;
+};
+
+struct lconv* localeconv();
+char* setlocale(int category, const char* locale);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/malloc.cpp b/Userland/Libraries/LibC/malloc.cpp
new file mode 100644
index 0000000000..3d1c4abe2c
--- /dev/null
+++ b/Userland/Libraries/LibC/malloc.cpp
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/InlineLinkedList.h>
+#include <AK/LogStream.h>
+#include <AK/ScopedValueRollback.h>
+#include <AK/Vector.h>
+#include <LibThread/Lock.h>
+#include <assert.h>
+#include <mallocdefs.h>
+#include <serenity.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/internals.h>
+#include <sys/mman.h>
+
+// FIXME: Thread safety.
+
+//#define MALLOC_DEBUG
+#define RECYCLE_BIG_ALLOCATIONS
+
+#define PAGE_ROUND_UP(x) ((((size_t)(x)) + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)))
+
+ALWAYS_INLINE static void ue_notify_malloc(const void* ptr, size_t size)
+{
+ send_secret_data_to_userspace_emulator(1, size, (FlatPtr)ptr);
+}
+
+ALWAYS_INLINE static void ue_notify_free(const void* ptr)
+{
+ send_secret_data_to_userspace_emulator(2, (FlatPtr)ptr, 0);
+}
+
+ALWAYS_INLINE static void ue_notify_realloc(const void* ptr, size_t size)
+{
+ send_secret_data_to_userspace_emulator(3, size, (FlatPtr)ptr);
+}
+
+static LibThread::Lock& malloc_lock()
+{
+ static u32 lock_storage[sizeof(LibThread::Lock) / sizeof(u32)];
+ return *reinterpret_cast<LibThread::Lock*>(&lock_storage);
+}
+
+constexpr size_t number_of_chunked_blocks_to_keep_around_per_size_class = 4;
+constexpr size_t number_of_big_blocks_to_keep_around_per_size_class = 8;
+
+static bool s_log_malloc = false;
+static bool s_scrub_malloc = true;
+static bool s_scrub_free = true;
+static bool s_profiling = false;
+
+struct MallocStats {
+ size_t number_of_malloc_calls;
+
+ size_t number_of_big_allocator_hits;
+ size_t number_of_big_allocator_purge_hits;
+ size_t number_of_big_allocs;
+
+ size_t number_of_empty_block_hits;
+ size_t number_of_empty_block_purge_hits;
+ size_t number_of_block_allocs;
+ size_t number_of_blocks_full;
+
+ size_t number_of_free_calls;
+
+ size_t number_of_big_allocator_keeps;
+ size_t number_of_big_allocator_frees;
+
+ size_t number_of_freed_full_blocks;
+ size_t number_of_keeps;
+ size_t number_of_frees;
+};
+static MallocStats g_malloc_stats = {};
+
+struct Allocator {
+ size_t size { 0 };
+ size_t block_count { 0 };
+ size_t empty_block_count { 0 };
+ ChunkedBlock* empty_blocks[number_of_chunked_blocks_to_keep_around_per_size_class] { nullptr };
+ InlineLinkedList<ChunkedBlock> usable_blocks;
+ InlineLinkedList<ChunkedBlock> full_blocks;
+};
+
+struct BigAllocator {
+ Vector<BigAllocationBlock*, number_of_big_blocks_to_keep_around_per_size_class> blocks;
+};
+
+// Allocators will be initialized in __malloc_init.
+// We can not rely on global constructors to initialize them,
+// because they must be initialized before other global constructors
+// are run. Similarly, we can not allow global destructors to destruct
+// them. We could have used AK::NeverDestoyed to prevent the latter,
+// but it would have not helped with the former.
+static u8 g_allocators_storage[sizeof(Allocator) * num_size_classes];
+static u8 g_big_allocators_storage[sizeof(BigAllocator)];
+
+static inline Allocator (&allocators())[num_size_classes]
+{
+ return reinterpret_cast<Allocator(&)[num_size_classes]>(g_allocators_storage);
+}
+
+static inline BigAllocator (&big_allocators())[1]
+{
+ return reinterpret_cast<BigAllocator(&)[1]>(g_big_allocators_storage);
+}
+
+static Allocator* allocator_for_size(size_t size, size_t& good_size)
+{
+ for (size_t i = 0; size_classes[i]; ++i) {
+ if (size <= size_classes[i]) {
+ good_size = size_classes[i];
+ return &allocators()[i];
+ }
+ }
+ good_size = PAGE_ROUND_UP(size);
+ return nullptr;
+}
+
+#ifdef RECYCLE_BIG_ALLOCATIONS
+static BigAllocator* big_allocator_for_size(size_t size)
+{
+ if (size == 65536)
+ return &big_allocators()[0];
+ return nullptr;
+}
+#endif
+
+extern "C" {
+
+static void* os_alloc(size_t size, const char* name)
+{
+ auto* ptr = serenity_mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, ChunkedBlock::block_size, name);
+ ASSERT(ptr != MAP_FAILED);
+ return ptr;
+}
+
+static void os_free(void* ptr, size_t size)
+{
+ int rc = munmap(ptr, size);
+ assert(rc == 0);
+}
+
+static void* malloc_impl(size_t size)
+{
+ LOCKER(malloc_lock());
+
+ if (s_log_malloc)
+ dbgprintf("LibC: malloc(%zu)\n", size);
+
+ if (!size)
+ return nullptr;
+
+ g_malloc_stats.number_of_malloc_calls++;
+
+ size_t good_size;
+ auto* allocator = allocator_for_size(size, good_size);
+
+ if (!allocator) {
+ size_t real_size = round_up_to_power_of_two(sizeof(BigAllocationBlock) + size, ChunkedBlock::block_size);
+#ifdef RECYCLE_BIG_ALLOCATIONS
+ if (auto* allocator = big_allocator_for_size(real_size)) {
+ if (!allocator->blocks.is_empty()) {
+ g_malloc_stats.number_of_big_allocator_hits++;
+ auto* block = allocator->blocks.take_last();
+ int rc = madvise(block, real_size, MADV_SET_NONVOLATILE);
+ bool this_block_was_purged = rc == 1;
+ if (rc < 0) {
+ perror("madvise");
+ ASSERT_NOT_REACHED();
+ }
+ if (mprotect(block, real_size, PROT_READ | PROT_WRITE) < 0) {
+ perror("mprotect");
+ ASSERT_NOT_REACHED();
+ }
+ if (this_block_was_purged) {
+ g_malloc_stats.number_of_big_allocator_purge_hits++;
+ new (block) BigAllocationBlock(real_size);
+ }
+
+ ue_notify_malloc(&block->m_slot[0], size);
+ return &block->m_slot[0];
+ }
+ }
+#endif
+ g_malloc_stats.number_of_big_allocs++;
+ auto* block = (BigAllocationBlock*)os_alloc(real_size, "malloc: BigAllocationBlock");
+ new (block) BigAllocationBlock(real_size);
+ ue_notify_malloc(&block->m_slot[0], size);
+ return &block->m_slot[0];
+ }
+
+ ChunkedBlock* block = nullptr;
+
+ for (block = allocator->usable_blocks.head(); block; block = block->next()) {
+ if (block->free_chunks())
+ break;
+ }
+
+ if (!block && allocator->empty_block_count) {
+ g_malloc_stats.number_of_empty_block_hits++;
+ block = allocator->empty_blocks[--allocator->empty_block_count];
+ int rc = madvise(block, ChunkedBlock::block_size, MADV_SET_NONVOLATILE);
+ bool this_block_was_purged = rc == 1;
+ if (rc < 0) {
+ perror("madvise");
+ ASSERT_NOT_REACHED();
+ }
+ rc = mprotect(block, ChunkedBlock::block_size, PROT_READ | PROT_WRITE);
+ if (rc < 0) {
+ perror("mprotect");
+ ASSERT_NOT_REACHED();
+ }
+ if (this_block_was_purged) {
+ g_malloc_stats.number_of_empty_block_purge_hits++;
+ new (block) ChunkedBlock(good_size);
+ }
+ allocator->usable_blocks.append(block);
+ }
+
+ if (!block) {
+ g_malloc_stats.number_of_block_allocs++;
+ char buffer[64];
+ snprintf(buffer, sizeof(buffer), "malloc: ChunkedBlock(%zu)", good_size);
+ block = (ChunkedBlock*)os_alloc(ChunkedBlock::block_size, buffer);
+ new (block) ChunkedBlock(good_size);
+ allocator->usable_blocks.append(block);
+ ++allocator->block_count;
+ }
+
+ --block->m_free_chunks;
+ void* ptr = block->m_freelist;
+ ASSERT(ptr);
+ block->m_freelist = block->m_freelist->next;
+ if (block->is_full()) {
+ g_malloc_stats.number_of_blocks_full++;
+#ifdef MALLOC_DEBUG
+ dbgprintf("Block %p is now full in size class %zu\n", block, good_size);
+#endif
+ allocator->usable_blocks.remove(block);
+ allocator->full_blocks.append(block);
+ }
+#ifdef MALLOC_DEBUG
+ dbgprintf("LibC: allocated %p (chunk in block %p, size %zu)\n", ptr, block, block->bytes_per_chunk());
+#endif
+
+ if (s_scrub_malloc)
+ memset(ptr, MALLOC_SCRUB_BYTE, block->m_size);
+
+ ue_notify_malloc(ptr, size);
+ return ptr;
+}
+
+static void free_impl(void* ptr)
+{
+ ScopedValueRollback rollback(errno);
+
+ if (!ptr)
+ return;
+
+ g_malloc_stats.number_of_free_calls++;
+
+ LOCKER(malloc_lock());
+
+ void* block_base = (void*)((FlatPtr)ptr & ChunkedBlock::ChunkedBlock::block_mask);
+ size_t magic = *(size_t*)block_base;
+
+ if (magic == MAGIC_BIGALLOC_HEADER) {
+ auto* block = (BigAllocationBlock*)block_base;
+#ifdef RECYCLE_BIG_ALLOCATIONS
+ if (auto* allocator = big_allocator_for_size(block->m_size)) {
+ if (allocator->blocks.size() < number_of_big_blocks_to_keep_around_per_size_class) {
+ g_malloc_stats.number_of_big_allocator_keeps++;
+ allocator->blocks.append(block);
+ size_t this_block_size = block->m_size;
+ if (mprotect(block, this_block_size, PROT_NONE) < 0) {
+ perror("mprotect");
+ ASSERT_NOT_REACHED();
+ }
+ if (madvise(block, this_block_size, MADV_SET_VOLATILE) != 0) {
+ perror("madvise");
+ ASSERT_NOT_REACHED();
+ }
+ return;
+ }
+ }
+#endif
+ g_malloc_stats.number_of_big_allocator_frees++;
+ os_free(block, block->m_size);
+ return;
+ }
+
+ assert(magic == MAGIC_PAGE_HEADER);
+ auto* block = (ChunkedBlock*)block_base;
+
+#ifdef MALLOC_DEBUG
+ dbgprintf("LibC: freeing %p in allocator %p (size=%zu, used=%zu)\n", ptr, block, block->bytes_per_chunk(), block->used_chunks());
+#endif
+
+ if (s_scrub_free)
+ memset(ptr, FREE_SCRUB_BYTE, block->bytes_per_chunk());
+
+ auto* entry = (FreelistEntry*)ptr;
+ entry->next = block->m_freelist;
+ block->m_freelist = entry;
+
+ if (block->is_full()) {
+ size_t good_size;
+ auto* allocator = allocator_for_size(block->m_size, good_size);
+#ifdef MALLOC_DEBUG
+ dbgprintf("Block %p no longer full in size class %zu\n", block, good_size);
+#endif
+ g_malloc_stats.number_of_freed_full_blocks++;
+ allocator->full_blocks.remove(block);
+ allocator->usable_blocks.prepend(block);
+ }
+
+ ++block->m_free_chunks;
+
+ if (!block->used_chunks()) {
+ size_t good_size;
+ auto* allocator = allocator_for_size(block->m_size, good_size);
+ if (allocator->block_count < number_of_chunked_blocks_to_keep_around_per_size_class) {
+#ifdef MALLOC_DEBUG
+ dbgprintf("Keeping block %p around for size class %zu\n", block, good_size);
+#endif
+ g_malloc_stats.number_of_keeps++;
+ allocator->usable_blocks.remove(block);
+ allocator->empty_blocks[allocator->empty_block_count++] = block;
+ mprotect(block, ChunkedBlock::block_size, PROT_NONE);
+ madvise(block, ChunkedBlock::block_size, MADV_SET_VOLATILE);
+ return;
+ }
+#ifdef MALLOC_DEBUG
+ dbgprintf("Releasing block %p for size class %zu\n", block, good_size);
+#endif
+ g_malloc_stats.number_of_frees++;
+ allocator->usable_blocks.remove(block);
+ --allocator->block_count;
+ os_free(block, ChunkedBlock::block_size);
+ }
+}
+
+[[gnu::flatten]] void* malloc(size_t size)
+{
+ void* ptr = malloc_impl(size);
+ if (s_profiling)
+ perf_event(PERF_EVENT_MALLOC, size, reinterpret_cast<FlatPtr>(ptr));
+ return ptr;
+}
+
+[[gnu::flatten]] void free(void* ptr)
+{
+ if (s_profiling)
+ perf_event(PERF_EVENT_FREE, reinterpret_cast<FlatPtr>(ptr), 0);
+ ue_notify_free(ptr);
+ free_impl(ptr);
+}
+
+void* calloc(size_t count, size_t size)
+{
+ size_t new_size = count * size;
+ auto* ptr = malloc(new_size);
+ if (ptr)
+ memset(ptr, 0, new_size);
+ return ptr;
+}
+
+size_t malloc_size(void* ptr)
+{
+ if (!ptr)
+ return 0;
+ LOCKER(malloc_lock());
+ void* page_base = (void*)((FlatPtr)ptr & ChunkedBlock::block_mask);
+ auto* header = (const CommonHeader*)page_base;
+ auto size = header->m_size;
+ if (header->m_magic == MAGIC_BIGALLOC_HEADER)
+ size -= sizeof(CommonHeader);
+ else
+ ASSERT(header->m_magic == MAGIC_PAGE_HEADER);
+ return size;
+}
+
+void* realloc(void* ptr, size_t size)
+{
+ if (!ptr)
+ return malloc(size);
+ if (!size)
+ return nullptr;
+
+ LOCKER(malloc_lock());
+ auto existing_allocation_size = malloc_size(ptr);
+
+ if (size <= existing_allocation_size) {
+ ue_notify_realloc(ptr, size);
+ return ptr;
+ }
+ auto* new_ptr = malloc(size);
+ if (new_ptr) {
+ memcpy(new_ptr, ptr, min(existing_allocation_size, size));
+ free(ptr);
+ }
+ return new_ptr;
+}
+
+void __malloc_init()
+{
+ new (&malloc_lock()) LibThread::Lock();
+ if (getenv("LIBC_NOSCRUB_MALLOC"))
+ s_scrub_malloc = false;
+ if (getenv("LIBC_NOSCRUB_FREE"))
+ s_scrub_free = false;
+ if (getenv("LIBC_LOG_MALLOC"))
+ s_log_malloc = true;
+ if (getenv("LIBC_PROFILE_MALLOC"))
+ s_profiling = true;
+
+ for (size_t i = 0; i < num_size_classes; ++i) {
+ new (&allocators()[i]) Allocator();
+ allocators()[i].size = size_classes[i];
+ }
+
+ new (&big_allocators()[0])(BigAllocator);
+}
+
+void serenity_dump_malloc_stats()
+{
+ dbgln("# malloc() calls: {}", g_malloc_stats.number_of_malloc_calls);
+ dbgln();
+ dbgln("big alloc hits: {}", g_malloc_stats.number_of_big_allocator_hits);
+ dbgln("big alloc hits that were purged: {}", g_malloc_stats.number_of_big_allocator_purge_hits);
+ dbgln("big allocs: {}", g_malloc_stats.number_of_big_allocs);
+ dbgln();
+ dbgln("empty block hits: {}", g_malloc_stats.number_of_empty_block_hits);
+ dbgln("empty block hits that were purged: {}", g_malloc_stats.number_of_empty_block_purge_hits);
+ dbgln("block allocs: {}", g_malloc_stats.number_of_block_allocs);
+ dbgln("filled blocks: {}", g_malloc_stats.number_of_blocks_full);
+ dbgln();
+ dbgln("# free() calls: {}", g_malloc_stats.number_of_free_calls);
+ dbgln();
+ dbgln("big alloc keeps: {}", g_malloc_stats.number_of_big_allocator_keeps);
+ dbgln("big alloc frees: {}", g_malloc_stats.number_of_big_allocator_frees);
+ dbgln();
+ dbgln("full block frees: {}", g_malloc_stats.number_of_freed_full_blocks);
+ dbgln("number of keeps: {}", g_malloc_stats.number_of_keeps);
+ dbgln("number of frees: {}", g_malloc_stats.number_of_frees);
+}
+}
diff --git a/Userland/Libraries/LibC/mallocdefs.h b/Userland/Libraries/LibC/mallocdefs.h
new file mode 100644
index 0000000000..d639c512cd
--- /dev/null
+++ b/Userland/Libraries/LibC/mallocdefs.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <AK/InlineLinkedList.h>
+#include <AK/Types.h>
+
+#define MAGIC_PAGE_HEADER 0x42657274 // 'Bert'
+#define MAGIC_BIGALLOC_HEADER 0x42697267 // 'Birg'
+#define MALLOC_SCRUB_BYTE 0xdc
+#define FREE_SCRUB_BYTE 0xed
+
+static constexpr unsigned short size_classes[] = { 8, 16, 32, 64, 128, 256, 500, 1016, 2032, 4088, 8184, 16376, 32752, 0 };
+static constexpr size_t num_size_classes = (sizeof(size_classes) / sizeof(unsigned short)) - 1;
+
+struct CommonHeader {
+ size_t m_magic;
+ size_t m_size;
+};
+
+struct BigAllocationBlock : public CommonHeader {
+ BigAllocationBlock(size_t size)
+ {
+ m_magic = MAGIC_BIGALLOC_HEADER;
+ m_size = size;
+ }
+ unsigned char* m_slot[0];
+};
+
+struct FreelistEntry {
+ FreelistEntry* next;
+};
+
+struct ChunkedBlock
+ : public CommonHeader
+ , public InlineLinkedListNode<ChunkedBlock> {
+
+ static constexpr size_t block_size = 64 * KiB;
+ static constexpr size_t block_mask = ~(block_size - 1);
+
+ ChunkedBlock(size_t bytes_per_chunk)
+ {
+ m_magic = MAGIC_PAGE_HEADER;
+ m_size = bytes_per_chunk;
+ m_free_chunks = chunk_capacity();
+ m_freelist = (FreelistEntry*)chunk(0);
+ for (size_t i = 0; i < chunk_capacity(); ++i) {
+ auto* entry = (FreelistEntry*)chunk(i);
+ if (i != chunk_capacity() - 1)
+ entry->next = (FreelistEntry*)chunk(i + 1);
+ else
+ entry->next = nullptr;
+ }
+ }
+
+ ChunkedBlock* m_prev { nullptr };
+ ChunkedBlock* m_next { nullptr };
+ FreelistEntry* m_freelist { nullptr };
+ size_t m_free_chunks { 0 };
+ [[gnu::aligned(8)]] unsigned char m_slot[0];
+
+ void* chunk(size_t index)
+ {
+ return &m_slot[index * m_size];
+ }
+ bool is_full() const { return m_free_chunks == 0; }
+ size_t bytes_per_chunk() const { return m_size; }
+ size_t free_chunks() const { return m_free_chunks; }
+ size_t used_chunks() const { return chunk_capacity() - m_free_chunks; }
+ size_t chunk_capacity() const { return (block_size - sizeof(ChunkedBlock)) / m_size; }
+};
diff --git a/Userland/Libraries/LibC/memory.h b/Userland/Libraries/LibC/memory.h
new file mode 100644
index 0000000000..506244f4ce
--- /dev/null
+++ b/Userland/Libraries/LibC/memory.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <string.h>
diff --git a/Userland/Libraries/LibC/mman.cpp b/Userland/Libraries/LibC/mman.cpp
new file mode 100644
index 0000000000..3df02a46da
--- /dev/null
+++ b/Userland/Libraries/LibC/mman.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <mman.h>
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+
+void* serenity_mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset, size_t alignment, const char* name)
+{
+ Syscall::SC_mmap_params params { (uintptr_t)addr, size, alignment, prot, flags, fd, offset, { name, name ? strlen(name) : 0 } };
+ ssize_t rc = syscall(SC_mmap, &params);
+ if (rc < 0 && -rc < EMAXERRNO) {
+ errno = -rc;
+ return MAP_FAILED;
+ }
+ return (void*)rc;
+}
+
+void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset)
+{
+ return serenity_mmap(addr, size, prot, flags, fd, offset, PAGE_SIZE, nullptr);
+}
+
+void* mmap_with_name(void* addr, size_t size, int prot, int flags, int fd, off_t offset, const char* name)
+{
+ return serenity_mmap(addr, size, prot, flags, fd, offset, PAGE_SIZE, name);
+}
+
+void* mremap(void* old_address, size_t old_size, size_t new_size, int flags)
+{
+ Syscall::SC_mremap_params params { (uintptr_t)old_address, old_size, new_size, flags };
+ ssize_t rc = syscall(SC_mremap, &params);
+ if (rc < 0 && -rc < EMAXERRNO) {
+ errno = -rc;
+ return MAP_FAILED;
+ }
+ return (void*)rc;
+}
+
+int munmap(void* addr, size_t size)
+{
+ int rc = syscall(SC_munmap, addr, size);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int mprotect(void* addr, size_t size, int prot)
+{
+ int rc = syscall(SC_mprotect, addr, size, prot);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int set_mmap_name(void* addr, size_t size, const char* name)
+{
+ if (!name) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_set_mmap_name_params params { addr, size, { name, strlen(name) } };
+ int rc = syscall(SC_set_mmap_name, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int madvise(void* address, size_t size, int advice)
+{
+ int rc = syscall(SC_madvise, address, size, advice);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int minherit(void* address, size_t size, int inherit)
+{
+ int rc = syscall(SC_minherit, address, size, inherit);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+void* allocate_tls(size_t size)
+{
+ int rc = syscall(SC_allocate_tls, size);
+ if (rc < 0 && -rc < EMAXERRNO) {
+ errno = -rc;
+ return MAP_FAILED;
+ }
+ return (void*)rc;
+}
+}
diff --git a/Userland/Libraries/LibC/mman.h b/Userland/Libraries/LibC/mman.h
new file mode 100644
index 0000000000..5b02c59902
--- /dev/null
+++ b/Userland/Libraries/LibC/mman.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#define MAP_FILE 0x00
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#define MAP_FIXED 0x10
+#define MAP_ANONYMOUS 0x20
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_STACK 0x40
+#define MAP_NORESERVE 0x80
+
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#define PROT_EXEC 0x4
+#define PROT_NONE 0x0
+
+#define MAP_FAILED ((void*)-1)
+
+#define MADV_SET_VOLATILE 0x100
+#define MADV_SET_NONVOLATILE 0x200
+#define MADV_GET_VOLATILE 0x400
+
+#define MAP_INHERIT_ZERO 1
+
+__BEGIN_DECLS
+
+void* mmap(void* addr, size_t, int prot, int flags, int fd, off_t);
+void* mmap_with_name(void* addr, size_t, int prot, int flags, int fd, off_t, const char* name);
+void* serenity_mmap(void* addr, size_t, int prot, int flags, int fd, off_t, size_t alignment, const char* name);
+void* mremap(void* old_address, size_t old_size, size_t new_size, int flags);
+int munmap(void*, size_t);
+int mprotect(void*, size_t, int prot);
+int set_mmap_name(void*, size_t, const char*);
+int madvise(void*, size_t, int advice);
+int minherit(void*, size_t, int inherit);
+void* allocate_tls(size_t);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/mntent.cpp b/Userland/Libraries/LibC/mntent.cpp
new file mode 100644
index 0000000000..c1f234bfb2
--- /dev/null
+++ b/Userland/Libraries/LibC/mntent.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <mntent.h>
+
+extern "C" {
+
+struct mntent* getmntent(FILE*)
+{
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+}
diff --git a/Userland/Libraries/LibC/mntent.h b/Userland/Libraries/LibC/mntent.h
new file mode 100644
index 0000000000..fc319b3dc9
--- /dev/null
+++ b/Userland/Libraries/LibC/mntent.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define MOUNTED "/etc/mtab"
+#define MNTTAB "/etc/fstab"
+
+struct mntent {
+ char* mnt_fsname;
+ char* mnt_dir;
+ char* mnt_type;
+ char* mnt_opts;
+ int mnt_freq;
+ int mnt_passno;
+};
+
+struct mntent* getmntent(FILE* stream);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/net/if.h b/Userland/Libraries/LibC/net/if.h
new file mode 100644
index 0000000000..b82258a7b0
--- /dev/null
+++ b/Userland/Libraries/LibC/net/if.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+
+__BEGIN_DECLS
+
+struct ifreq {
+#define IFNAMSIZ 16
+ char ifr_name[IFNAMSIZ];
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_metric;
+ int64_t ifru_vnetid;
+ uint64_t ifru_media;
+ void* ifru_data;
+ unsigned int ifru_index;
+ } ifr_ifru;
+
+ // clang-format off
+#define ifr_addr ifr_ifru.ifru_addr // address
+#define ifr_dstaddr ifr_ifru.ifru_dstaddr // other end of p-to-p link
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address
+#define ifr_netmask ifr_ifru.ifru_netmask // network mask
+#define ifr_flags ifr_ifru.ifru_flags // flags
+#define ifr_metric ifr_ifru.ifru_metric // metric
+#define ifr_mtu ifr_ifru.ifru_metric // mtu (overload)
+#define ifr_hardmtu ifr_ifru.ifru_metric // hardmtu (overload)
+#define ifr_media ifr_ifru.ifru_media // media options
+#define ifr_rdomainid ifr_ifru.ifru_metric // VRF instance (overload)
+#define ifr_vnetid ifr_ifru.ifru_vnetid // Virtual Net Id
+#define ifr_ttl ifr_ifru.ifru_metric // tunnel TTL (overload)
+#define ifr_data ifr_ifru.ifru_data // for use by interface
+#define ifr_index ifr_ifru.ifru_index // interface index
+#define ifr_llprio ifr_ifru.ifru_metric // link layer priority
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr // MAC address
+ // clang-format on
+};
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/net/route.h b/Userland/Libraries/LibC/net/route.h
new file mode 100644
index 0000000000..a059c28708
--- /dev/null
+++ b/Userland/Libraries/LibC/net/route.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020, Marios Prokopakis <mariosprokopakis@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/socket.h>
+
+struct rtentry {
+ struct sockaddr rt_gateway; /* the gateway address */
+ struct sockaddr rt_genmask; /* the target network mask */
+ unsigned short int rt_flags;
+ char* rt_dev;
+ /* FIXME: complete the struct */
+};
+
+#define RTF_UP 0x1 /* do not delete the route */
+#define RTF_GATEWAY 0x2 /* the route is a gateway and not an end host */
diff --git a/Userland/Libraries/LibC/netdb.cpp b/Userland/Libraries/LibC/netdb.cpp
new file mode 100644
index 0000000000..6f0af1bf68
--- /dev/null
+++ b/Userland/Libraries/LibC/netdb.cpp
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <AK/ByteBuffer.h>
+#include <AK/ScopeGuard.h>
+#include <AK/String.h>
+#include <Kernel/Net/IPv4.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+extern "C" {
+
+int h_errno;
+
+static hostent __gethostbyname_buffer;
+static in_addr_t __gethostbyname_address;
+static in_addr_t* __gethostbyname_address_list_buffer[2];
+
+static hostent __gethostbyaddr_buffer;
+static in_addr_t* __gethostbyaddr_address_list_buffer[2];
+
+// Get service entry buffers and file information for the getservent() family of functions.
+static FILE* services_file = nullptr;
+static const char* services_path = "/etc/services";
+
+static bool fill_getserv_buffers(const char* line, ssize_t read);
+static servent __getserv_buffer;
+static String __getserv_name_buffer;
+static String __getserv_protocol_buffer;
+static int __getserv_port_buffer;
+static Vector<ByteBuffer> __getserv_alias_list_buffer;
+static Vector<char*> __getserv_alias_list;
+static bool keep_service_file_open = false;
+static ssize_t service_file_offset = 0;
+
+// Get protocol entry buffers and file information for the getprotent() family of functions.
+static FILE* protocols_file = nullptr;
+static const char* protocols_path = "/etc/protocols";
+
+static bool fill_getproto_buffers(const char* line, ssize_t read);
+static protoent __getproto_buffer;
+static String __getproto_name_buffer;
+static Vector<ByteBuffer> __getproto_alias_list_buffer;
+static Vector<char*> __getproto_alias_list;
+static int __getproto_protocol_buffer;
+static bool keep_protocols_file_open = false;
+static ssize_t protocol_file_offset = 0;
+
+static int connect_to_lookup_server()
+{
+ int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ sockaddr_un address {
+ AF_LOCAL,
+ "/tmp/portal/lookup"
+ };
+
+ if (connect(fd, (const sockaddr*)&address, sizeof(address)) < 0) {
+ perror("connect_to_lookup_server");
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static String gethostbyname_name_buffer;
+
+hostent* gethostbyname(const char* name)
+{
+ auto ipv4_address = IPv4Address::from_string(name);
+
+ if (ipv4_address.has_value()) {
+ gethostbyname_name_buffer = ipv4_address.value().to_string();
+ __gethostbyname_buffer.h_name = const_cast<char*>(gethostbyname_name_buffer.characters());
+ __gethostbyname_buffer.h_aliases = nullptr;
+ __gethostbyname_buffer.h_addrtype = AF_INET;
+ new (&__gethostbyname_address) IPv4Address(ipv4_address.value());
+ __gethostbyname_address_list_buffer[0] = &__gethostbyname_address;
+ __gethostbyname_address_list_buffer[1] = nullptr;
+ __gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer;
+ __gethostbyname_buffer.h_length = 4;
+
+ return &__gethostbyname_buffer;
+ }
+
+ int fd = connect_to_lookup_server();
+ if (fd < 0)
+ return nullptr;
+
+ auto close_fd_on_exit = ScopeGuard([fd] {
+ close(fd);
+ });
+
+ auto line = String::format("L%s\n", name);
+ int nsent = write(fd, line.characters(), line.length());
+ if (nsent < 0) {
+ perror("write");
+ return nullptr;
+ }
+
+ ASSERT((size_t)nsent == line.length());
+
+ char buffer[1024];
+ int nrecv = read(fd, buffer, sizeof(buffer) - 1);
+ if (nrecv < 0) {
+ perror("recv");
+ return nullptr;
+ }
+
+ if (!memcmp(buffer, "Not found.", sizeof("Not found.") - 1))
+ return nullptr;
+
+ auto responses = String(buffer, nrecv).split('\n');
+ if (responses.is_empty())
+ return nullptr;
+
+ auto& response = responses[0];
+
+ int rc = inet_pton(AF_INET, response.characters(), &__gethostbyname_address);
+ if (rc <= 0)
+ return nullptr;
+
+ gethostbyname_name_buffer = name;
+ __gethostbyname_buffer.h_name = const_cast<char*>(gethostbyname_name_buffer.characters());
+ __gethostbyname_buffer.h_aliases = nullptr;
+ __gethostbyname_buffer.h_addrtype = AF_INET;
+ __gethostbyname_address_list_buffer[0] = &__gethostbyname_address;
+ __gethostbyname_address_list_buffer[1] = nullptr;
+ __gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer;
+ __gethostbyname_buffer.h_length = 4;
+
+ return &__gethostbyname_buffer;
+}
+
+static String gethostbyaddr_name_buffer;
+
+hostent* gethostbyaddr(const void* addr, socklen_t addr_size, int type)
+{
+
+ if (type != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return nullptr;
+ }
+
+ if (addr_size < sizeof(in_addr)) {
+ errno = EINVAL;
+ return nullptr;
+ }
+
+ int fd = connect_to_lookup_server();
+ if (fd < 0)
+ return nullptr;
+
+ auto close_fd_on_exit = ScopeGuard([fd] {
+ close(fd);
+ });
+
+ IPv4Address ipv4_address((const u8*)&((const in_addr*)addr)->s_addr);
+
+ auto line = String::format("R%d.%d.%d.%d.in-addr.arpa\n",
+ ipv4_address[3],
+ ipv4_address[2],
+ ipv4_address[1],
+ ipv4_address[0]);
+ int nsent = write(fd, line.characters(), line.length());
+ if (nsent < 0) {
+ perror("write");
+ return nullptr;
+ }
+
+ ASSERT((size_t)nsent == line.length());
+
+ char buffer[1024];
+ int nrecv = read(fd, buffer, sizeof(buffer) - 1);
+ if (nrecv < 0) {
+ perror("recv");
+ return nullptr;
+ }
+
+ if (!memcmp(buffer, "Not found.", sizeof("Not found.") - 1))
+ return nullptr;
+
+ auto responses = String(buffer, nrecv).split('\n');
+ if (responses.is_empty())
+ return nullptr;
+
+ gethostbyaddr_name_buffer = responses[0];
+ __gethostbyaddr_buffer.h_name = const_cast<char*>(gethostbyaddr_name_buffer.characters());
+ __gethostbyaddr_buffer.h_aliases = nullptr;
+ __gethostbyaddr_buffer.h_addrtype = AF_INET;
+ // FIXME: Should we populate the hostent's address list here with a sockaddr_in for the provided host?
+ __gethostbyaddr_address_list_buffer[0] = nullptr;
+ __gethostbyaddr_buffer.h_addr_list = (char**)__gethostbyaddr_address_list_buffer;
+ __gethostbyaddr_buffer.h_length = 4;
+
+ return &__gethostbyaddr_buffer;
+}
+
+struct servent* getservent()
+{
+ //If the services file is not open, attempt to open it and return null if it fails.
+ if (!services_file) {
+ services_file = fopen(services_path, "r");
+
+ if (!services_file) {
+ perror("error opening services file");
+ return nullptr;
+ }
+ }
+
+ if (fseek(services_file, service_file_offset, SEEK_SET) != 0) {
+ perror("error seeking file");
+ fclose(services_file);
+ return nullptr;
+ }
+ char* line = nullptr;
+ size_t len = 0;
+ ssize_t read;
+
+ auto free_line_on_exit = ScopeGuard([line] {
+ if (line) {
+ free(line);
+ }
+ });
+
+ // Read lines from services file until an actual service name is found.
+ do {
+ read = getline(&line, &len, services_file);
+ service_file_offset += read;
+ if (read > 0 && (line[0] >= 65 && line[0] <= 122)) {
+ break;
+ }
+ } while (read != -1);
+ if (read == -1) {
+ fclose(services_file);
+ services_file = nullptr;
+ service_file_offset = 0;
+ return nullptr;
+ }
+
+ servent* service_entry = nullptr;
+ if (!fill_getserv_buffers(line, read))
+ return nullptr;
+
+ __getserv_buffer.s_name = const_cast<char*>(__getserv_name_buffer.characters());
+ __getserv_buffer.s_port = __getserv_port_buffer;
+ __getserv_buffer.s_proto = const_cast<char*>(__getserv_protocol_buffer.characters());
+
+ __getserv_alias_list.clear_with_capacity();
+ __getserv_alias_list.ensure_capacity(__getserv_alias_list_buffer.size() + 1);
+ for (auto& alias : __getserv_alias_list_buffer)
+ __getserv_alias_list.unchecked_append(reinterpret_cast<char*>(alias.data()));
+ __getserv_alias_list.unchecked_append(nullptr);
+
+ __getserv_buffer.s_aliases = __getserv_alias_list.data();
+ service_entry = &__getserv_buffer;
+
+ if (!keep_service_file_open) {
+ endservent();
+ }
+ return service_entry;
+}
+
+struct servent* getservbyname(const char* name, const char* protocol)
+{
+ bool previous_file_open_setting = keep_service_file_open;
+ setservent(1);
+ struct servent* current_service = nullptr;
+ auto service_file_handler = ScopeGuard([previous_file_open_setting] {
+ if (!previous_file_open_setting) {
+ endservent();
+ }
+ });
+
+ while (true) {
+ current_service = getservent();
+ if (current_service == nullptr)
+ break;
+ else if (!protocol && strcmp(current_service->s_name, name) == 0)
+ break;
+ else if (strcmp(current_service->s_name, name) == 0 && strcmp(current_service->s_proto, protocol) == 0)
+ break;
+ }
+
+ return current_service;
+}
+
+struct servent* getservbyport(int port, const char* protocol)
+{
+ bool previous_file_open_setting = keep_service_file_open;
+ setservent(1);
+ struct servent* current_service = nullptr;
+ auto service_file_handler = ScopeGuard([previous_file_open_setting] {
+ if (!previous_file_open_setting) {
+ endservent();
+ }
+ });
+ while (true) {
+ current_service = getservent();
+ if (current_service == nullptr)
+ break;
+ else if (!protocol && current_service->s_port == port)
+ break;
+ else if (current_service->s_port == port && (strcmp(current_service->s_proto, protocol) == 0))
+ break;
+ }
+
+ return current_service;
+}
+
+void setservent(int stay_open)
+{
+ if (!services_file) {
+ services_file = fopen(services_path, "r");
+
+ if (!services_file) {
+ perror("error opening services file");
+ return;
+ }
+ }
+ rewind(services_file);
+ keep_service_file_open = stay_open;
+ service_file_offset = 0;
+}
+
+void endservent()
+{
+ if (!services_file) {
+ return;
+ }
+ fclose(services_file);
+ services_file = nullptr;
+}
+
+// Fill the service entry buffer with the information contained
+// in the currently read line, returns true if successful,
+// false if failure occurs.
+static bool fill_getserv_buffers(const char* line, ssize_t read)
+{
+ //Splitting the line by tab delimiter and filling the servent buffers name, port, and protocol members.
+ String string_line = String(line, read);
+ string_line.replace(" ", "\t", true);
+ auto split_line = string_line.split('\t');
+
+ // This indicates an incorrect file format.
+ // Services file entries should always at least contain
+ // name and port/protocol, separated by tabs.
+ if (split_line.size() < 2) {
+ fprintf(stderr, "getservent(): malformed services file\n");
+ return false;
+ }
+ __getserv_name_buffer = split_line[0];
+
+ auto port_protocol_split = String(split_line[1]).split('/');
+ if (port_protocol_split.size() < 2) {
+ fprintf(stderr, "getservent(): malformed services file\n");
+ return false;
+ }
+ auto number = port_protocol_split[0].to_int();
+ if (!number.has_value())
+ return false;
+
+ __getserv_port_buffer = number.value();
+
+ // Remove any annoying whitespace at the end of the protocol.
+ port_protocol_split[1].replace(" ", "", true);
+ port_protocol_split[1].replace("\t", "", true);
+ port_protocol_split[1].replace("\n", "", true);
+
+ __getserv_protocol_buffer = port_protocol_split[1];
+ __getserv_alias_list_buffer.clear();
+
+ // If there are aliases for the service, we will fill the alias list buffer.
+ if (split_line.size() > 2 && !split_line[2].starts_with('#')) {
+
+ for (size_t i = 2; i < split_line.size(); i++) {
+ if (split_line[i].starts_with('#')) {
+ break;
+ }
+ auto alias = split_line[i].to_byte_buffer();
+ alias.append("\0", sizeof(char));
+ __getserv_alias_list_buffer.append(alias);
+ }
+ }
+
+ return true;
+}
+
+struct protoent* getprotoent()
+{
+ // If protocols file isn't open, attempt to open and return null on failure.
+ if (!protocols_file) {
+ protocols_file = fopen(protocols_path, "r");
+
+ if (!protocols_file) {
+ perror("error opening protocols file");
+ return nullptr;
+ }
+ }
+
+ if (fseek(protocols_file, protocol_file_offset, SEEK_SET) != 0) {
+ perror("error seeking protocols file");
+ fclose(protocols_file);
+ return nullptr;
+ }
+
+ char* line = nullptr;
+ size_t len = 0;
+ ssize_t read;
+
+ auto free_line_on_exit = ScopeGuard([line] {
+ if (line) {
+ free(line);
+ }
+ });
+
+ do {
+ read = getline(&line, &len, protocols_file);
+ protocol_file_offset += read;
+ if (read > 0 && (line[0] >= 65 && line[0] <= 122)) {
+ break;
+ }
+ } while (read != -1);
+
+ if (read == -1) {
+ fclose(protocols_file);
+ protocols_file = nullptr;
+ protocol_file_offset = 0;
+ return nullptr;
+ }
+
+ struct protoent* protocol_entry = nullptr;
+ if (!fill_getproto_buffers(line, read))
+ return nullptr;
+
+ __getproto_buffer.p_name = const_cast<char*>(__getproto_name_buffer.characters());
+ __getproto_buffer.p_proto = __getproto_protocol_buffer;
+
+ __getproto_alias_list.clear_with_capacity();
+ __getproto_alias_list.ensure_capacity(__getproto_alias_list_buffer.size() + 1);
+ for (auto& alias : __getproto_alias_list_buffer)
+ __getproto_alias_list.unchecked_append(reinterpret_cast<char*>(alias.data()));
+ __getserv_alias_list.unchecked_append(nullptr);
+
+ __getproto_buffer.p_aliases = __getproto_alias_list.data();
+ protocol_entry = &__getproto_buffer;
+
+ if (!keep_protocols_file_open)
+ endprotoent();
+
+ return protocol_entry;
+}
+
+struct protoent* getprotobyname(const char* name)
+{
+ bool previous_file_open_setting = keep_protocols_file_open;
+ setprotoent(1);
+ struct protoent* current_protocol = nullptr;
+ auto protocol_file_handler = ScopeGuard([previous_file_open_setting] {
+ if (!previous_file_open_setting) {
+ endprotoent();
+ }
+ });
+
+ while (true) {
+ current_protocol = getprotoent();
+ if (current_protocol == nullptr)
+ break;
+ else if (strcmp(current_protocol->p_name, name) == 0)
+ break;
+ }
+
+ return current_protocol;
+}
+
+struct protoent* getprotobynumber(int proto)
+{
+ bool previous_file_open_setting = keep_protocols_file_open;
+ setprotoent(1);
+ struct protoent* current_protocol = nullptr;
+ auto protocol_file_handler = ScopeGuard([previous_file_open_setting] {
+ if (!previous_file_open_setting) {
+ endprotoent();
+ }
+ });
+
+ while (true) {
+ current_protocol = getprotoent();
+ if (current_protocol == nullptr)
+ break;
+ else if (current_protocol->p_proto == proto)
+ break;
+ }
+
+ return current_protocol;
+}
+
+void setprotoent(int stay_open)
+{
+ if (!protocols_file) {
+ protocols_file = fopen(protocols_path, "r");
+
+ if (!protocols_file) {
+ perror("setprotoent(): error opening protocols file");
+ return;
+ }
+ }
+ rewind(protocols_file);
+ keep_protocols_file_open = stay_open;
+ protocol_file_offset = 0;
+}
+
+void endprotoent()
+{
+ if (!protocols_file) {
+ return;
+ }
+ fclose(protocols_file);
+ protocols_file = nullptr;
+}
+
+static bool fill_getproto_buffers(const char* line, ssize_t read)
+{
+ String string_line = String(line, read);
+ string_line.replace(" ", "\t", true);
+ auto split_line = string_line.split('\t');
+
+ // This indicates an incorrect file format. Protocols file entries should
+ // always have at least a name and a protocol.
+ if (split_line.size() < 2) {
+ fprintf(stderr, "getprotoent(): malformed protocols file\n");
+ return false;
+ }
+ __getproto_name_buffer = split_line[0];
+
+ auto number = split_line[1].to_int();
+ if (!number.has_value())
+ return false;
+
+ __getproto_protocol_buffer = number.value();
+
+ __getproto_alias_list_buffer.clear();
+
+ // If there are aliases for the protocol, we will fill the alias list buffer.
+ if (split_line.size() > 2 && !split_line[2].starts_with('#')) {
+
+ for (size_t i = 2; i < split_line.size(); i++) {
+ if (split_line[i].starts_with('#'))
+ break;
+ auto alias = split_line[i].to_byte_buffer();
+ alias.append("\0", sizeof(char));
+ __getproto_alias_list_buffer.append(alias);
+ }
+ }
+
+ return true;
+}
+}
diff --git a/Userland/Libraries/LibC/netdb.h b/Userland/Libraries/LibC/netdb.h
new file mode 100644
index 0000000000..c2bd5a130f
--- /dev/null
+++ b/Userland/Libraries/LibC/netdb.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct hostent {
+ char* h_name;
+ char** h_aliases;
+ int h_addrtype;
+ int h_length;
+ char** h_addr_list;
+#define h_addr h_addr_list[0]
+};
+
+struct hostent* gethostbyname(const char*);
+struct hostent* gethostbyaddr(const void* addr, socklen_t len, int type);
+
+struct servent {
+ char* s_name;
+ char** s_aliases;
+ int s_port;
+ char* s_proto;
+};
+
+struct servent* getservent();
+struct servent* getservbyname(const char* name, const char* protocol);
+struct servent* getservbyport(int port, const char* protocol);
+void setservent(int stay_open);
+void endservent();
+
+struct protoent {
+ char* p_name;
+ char** p_aliases;
+ int p_proto;
+};
+
+void endprotoent();
+struct protoent* getprotobyname(const char* name);
+struct protoent* getprotobynumber(int proto);
+struct protoent* getprotoent();
+void setprotoent(int stay_open);
+
+extern int h_errno;
+
+#define HOST_NOT_FOUND 101
+#define NO_DATA 102
+#define NO_RECOVERY 103
+#define TRY_AGAIN 104
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/netinet/in.h b/Userland/Libraries/LibC/netinet/in.h
new file mode 100644
index 0000000000..a08040ca2a
--- /dev/null
+++ b/Userland/Libraries/LibC/netinet/in.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/stdint.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+
+__BEGIN_DECLS
+
+typedef uint32_t in_addr_t;
+in_addr_t inet_addr(const char*);
+
+#define INADDR_ANY ((in_addr_t)0)
+#define INADDR_NONE ((in_addr_t)-1)
+#define INADDR_LOOPBACK 0x7f000001
+
+#define IN_LOOPBACKNET 127
+
+#define IP_TTL 2
+
+#define IPPORT_RESERVED 1024
+#define IPPORT_USERRESERVED 5000
+
+typedef uint16_t in_port_t;
+
+struct in_addr {
+ uint32_t s_addr;
+};
+
+struct sockaddr_in {
+ sa_family_t sin_family;
+ in_port_t sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+};
+
+struct in6_addr {
+ uint8_t s6_addr[16];
+};
+
+struct sockaddr_in6 {
+ sa_family_t sin6_family; // AF_INET6.
+ in_port_t sin6_port; // Port number.
+ uint32_t sin6_flowinfo; // IPv6 traffic class and flow information.
+ struct in6_addr sin6_addr; // IPv6 address.
+ uint32_t sin6_scope_id; // Set of interfaces for a scop
+};
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/netinet/ip.h b/Userland/Libraries/LibC/netinet/ip.h
new file mode 100644
index 0000000000..3fc6b40a93
--- /dev/null
+++ b/Userland/Libraries/LibC/netinet/ip.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "in.h"
diff --git a/Userland/Libraries/LibC/netinet/ip_icmp.h b/Userland/Libraries/LibC/netinet/ip_icmp.h
new file mode 100644
index 0000000000..14d1f8c352
--- /dev/null
+++ b/Userland/Libraries/LibC/netinet/ip_icmp.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct icmphdr {
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ union {
+ struct {
+ uint16_t id;
+ uint16_t sequence;
+ } echo;
+ uint32_t gateway;
+ } un;
+};
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/netinet/tcp.h b/Userland/Libraries/LibC/netinet/tcp.h
new file mode 100644
index 0000000000..8dc5da8e32
--- /dev/null
+++ b/Userland/Libraries/LibC/netinet/tcp.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define TCP_NODELAY 10
diff --git a/Userland/Libraries/LibC/paths.h b/Userland/Libraries/LibC/paths.h
new file mode 100644
index 0000000000..07cfcdbb0d
--- /dev/null
+++ b/Userland/Libraries/LibC/paths.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020, The SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+// FIXME: This is just a default value to satisfy OpenSSH, feel free to change it.
+#define _PATH_MAILDIR "/var/mail"
diff --git a/Userland/Libraries/LibC/poll.cpp b/Userland/Libraries/LibC/poll.cpp
new file mode 100644
index 0000000000..437ea8243a
--- /dev/null
+++ b/Userland/Libraries/LibC/poll.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/time.h>
+
+extern "C" {
+
+int poll(pollfd* fds, nfds_t nfds, int timeout_ms)
+{
+ timespec timeout;
+ timespec* timeout_ts = &timeout;
+ if (timeout_ms < 0)
+ timeout_ts = nullptr;
+ else
+ timeout = { timeout_ms / 1000, (timeout_ms % 1000) * 1'000'000 };
+ return ppoll(fds, nfds, timeout_ts, nullptr);
+}
+
+int ppoll(pollfd* fds, nfds_t nfds, const timespec* timeout, const sigset_t* sigmask)
+{
+ Syscall::SC_poll_params params { fds, nfds, timeout, sigmask };
+ int rc = syscall(SC_poll, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/poll.h b/Userland/Libraries/LibC/poll.h
new file mode 100644
index 0000000000..ff0a1112b7
--- /dev/null
+++ b/Userland/Libraries/LibC/poll.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <signal.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define POLLIN (1u << 0)
+#define POLLPRI (1u << 1)
+#define POLLOUT (1u << 2)
+#define POLLERR (1u << 3)
+#define POLLHUP (1u << 4)
+#define POLLNVAL (1u << 5)
+#define POLLRDHUP (1u << 13)
+
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+typedef unsigned nfds_t;
+
+int poll(struct pollfd* fds, nfds_t nfds, int timeout);
+int ppoll(struct pollfd* fds, nfds_t nfds, const struct timespec* timeout, const sigset_t* sigmask);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/pwd.cpp b/Userland/Libraries/LibC/pwd.cpp
new file mode 100644
index 0000000000..7af0d67d68
--- /dev/null
+++ b/Userland/Libraries/LibC/pwd.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <errno_numbers.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern "C" {
+
+static FILE* s_stream = nullptr;
+static unsigned s_line_number = 0;
+static struct passwd s_passwd_entry;
+
+static String s_name;
+static String s_passwd;
+static String s_gecos;
+static String s_dir;
+static String s_shell;
+
+void setpwent()
+{
+ s_line_number = 0;
+ if (s_stream) {
+ rewind(s_stream);
+ } else {
+ s_stream = fopen("/etc/passwd", "r");
+ if (!s_stream) {
+ perror("open /etc/passwd");
+ }
+ }
+}
+
+void endpwent()
+{
+ s_line_number = 0;
+ if (s_stream) {
+ fclose(s_stream);
+ s_stream = nullptr;
+ }
+
+ memset(&s_passwd_entry, 0, sizeof(s_passwd_entry));
+
+ s_name = {};
+ s_passwd = {};
+ s_gecos = {};
+ s_dir = {};
+ s_shell = {};
+}
+
+struct passwd* getpwuid(uid_t uid)
+{
+ setpwent();
+ while (auto* pw = getpwent()) {
+ if (pw->pw_uid == uid)
+ return pw;
+ }
+ return nullptr;
+}
+
+struct passwd* getpwnam(const char* name)
+{
+ setpwent();
+ while (auto* pw = getpwent()) {
+ if (!strcmp(pw->pw_name, name))
+ return pw;
+ }
+ return nullptr;
+}
+
+static bool parse_pwddb_entry(const String& line)
+{
+ auto parts = line.split_view(':', true);
+ if (parts.size() != 7) {
+ fprintf(stderr, "getpwent(): Malformed entry on line %u\n", s_line_number);
+ return false;
+ }
+
+ s_name = parts[0];
+ s_passwd = parts[1];
+ auto& uid_string = parts[2];
+ auto& gid_string = parts[3];
+ s_gecos = parts[4];
+ s_dir = parts[5];
+ s_shell = parts[6];
+
+ auto uid = uid_string.to_uint();
+ if (!uid.has_value()) {
+ fprintf(stderr, "getpwent(): Malformed UID on line %u\n", s_line_number);
+ return false;
+ }
+ auto gid = gid_string.to_uint();
+ if (!gid.has_value()) {
+ fprintf(stderr, "getpwent(): Malformed GID on line %u\n", s_line_number);
+ return false;
+ }
+
+ s_passwd_entry.pw_name = const_cast<char*>(s_name.characters());
+ s_passwd_entry.pw_passwd = const_cast<char*>(s_passwd.characters());
+ s_passwd_entry.pw_uid = uid.value();
+ s_passwd_entry.pw_gid = gid.value();
+ s_passwd_entry.pw_gecos = const_cast<char*>(s_gecos.characters());
+ s_passwd_entry.pw_dir = const_cast<char*>(s_dir.characters());
+ s_passwd_entry.pw_shell = const_cast<char*>(s_shell.characters());
+
+ return true;
+}
+
+struct passwd* getpwent()
+{
+ if (!s_stream)
+ setpwent();
+
+ while (true) {
+ if (!s_stream || feof(s_stream))
+ return nullptr;
+
+ if (ferror(s_stream)) {
+ fprintf(stderr, "getpwent(): Read error: %s\n", strerror(ferror(s_stream)));
+ return nullptr;
+ }
+
+ char buffer[1024];
+ ++s_line_number;
+ char* s = fgets(buffer, sizeof(buffer), s_stream);
+
+ // Silently tolerate an empty line at the end.
+ if ((!s || !s[0]) && feof(s_stream))
+ return nullptr;
+
+ String line(s, Chomp);
+ if (parse_pwddb_entry(line))
+ return &s_passwd_entry;
+ // Otherwise, proceed to the next line.
+ }
+}
+
+int putpwent(const struct passwd* p, FILE* stream)
+{
+ if (!p || !stream || !p->pw_passwd || !p->pw_name || !p->pw_dir || !p->pw_gecos || !p->pw_shell) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ auto is_valid_field = [](const char* str) {
+ return str && !strpbrk(str, ":\n");
+ };
+
+ if (!is_valid_field(p->pw_name) || !is_valid_field(p->pw_dir) || !is_valid_field(p->pw_gecos) || !is_valid_field(p->pw_shell)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int nwritten = fprintf(stream, "%s:%s:%u:%u:%s,,,:%s:%s\n", p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
+ if (!nwritten || nwritten < 0) {
+ errno = ferror(stream);
+ return -1;
+ }
+
+ return 0;
+}
+}
diff --git a/Userland/Libraries/LibC/pwd.h b/Userland/Libraries/LibC/pwd.h
new file mode 100644
index 0000000000..334b04b05f
--- /dev/null
+++ b/Userland/Libraries/LibC/pwd.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/FILE.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct passwd {
+ char* pw_name;
+ char* pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ char* pw_gecos;
+ char* pw_dir;
+ char* pw_shell;
+};
+
+struct passwd* getpwent();
+void setpwent();
+void endpwent();
+struct passwd* getpwnam(const char* name);
+struct passwd* getpwuid(uid_t);
+int putpwent(const struct passwd* p, FILE* stream);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/qsort.cpp b/Userland/Libraries/LibC/qsort.cpp
new file mode 100644
index 0000000000..145cb1b19f
--- /dev/null
+++ b/Userland/Libraries/LibC/qsort.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <AK/QuickSort.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+class SizedObject {
+public:
+ SizedObject() = delete;
+ SizedObject(void* data, size_t size)
+ : m_data(data)
+ , m_size(size)
+ {
+ }
+ void* data() const { return m_data; }
+ size_t size() const { return m_size; }
+
+private:
+ void* m_data;
+ size_t m_size;
+};
+
+namespace AK {
+
+template<>
+inline void swap(const SizedObject& a, const SizedObject& b)
+{
+ ASSERT(a.size() == b.size());
+ const size_t size = a.size();
+ const auto a_data = reinterpret_cast<char*>(a.data());
+ const auto b_data = reinterpret_cast<char*>(b.data());
+ for (auto i = 0u; i < size; ++i) {
+ swap(a_data[i], b_data[i]);
+ }
+}
+
+}
+
+class SizedObjectSlice {
+public:
+ SizedObjectSlice() = delete;
+ SizedObjectSlice(void* data, size_t element_size)
+ : m_data(data)
+ , m_element_size(element_size)
+ {
+ }
+ const SizedObject operator[](size_t index)
+ {
+ return { static_cast<char*>(m_data) + index * m_element_size, m_element_size };
+ }
+
+private:
+ void* m_data;
+ size_t m_element_size;
+};
+
+void qsort(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*))
+{
+ if (nmemb <= 1) {
+ return;
+ }
+
+ SizedObjectSlice slice { bot, size };
+
+ AK::dual_pivot_quick_sort(slice, 0, nmemb - 1, [=](const SizedObject& a, const SizedObject& b) { return compar(a.data(), b.data()) < 0; });
+}
+
+void qsort_r(void* bot, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void* arg)
+{
+ if (nmemb <= 1) {
+ return;
+ }
+
+ SizedObjectSlice slice { bot, size };
+
+ AK::dual_pivot_quick_sort(slice, 0, nmemb - 1, [=](const SizedObject& a, const SizedObject& b) { return compar(a.data(), b.data(), arg) < 0; });
+}
diff --git a/Userland/Libraries/LibC/regex.h b/Userland/Libraries/LibC/regex.h
new file mode 100644
index 0000000000..b7e01ae981
--- /dev/null
+++ b/Userland/Libraries/LibC/regex.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+typedef ssize_t regoff_t;
+
+struct regex_t {
+ void* __data;
+};
+
+enum __Regex_Error {
+ __Regex_NoError,
+ __Regex_InvalidPattern, // Invalid regular expression.
+ __Regex_InvalidCollationElement, // Invalid collating element referenced.
+ __Regex_InvalidCharacterClass, // Invalid character class type referenced.
+ __Regex_InvalidTrailingEscape, // Trailing \ in pattern.
+ __Regex_InvalidNumber, // Number in \digit invalid or in error.
+ __Regex_MismatchingBracket, // [ ] imbalance.
+ __Regex_MismatchingParen, // ( ) imbalance.
+ __Regex_MismatchingBrace, // { } imbalance.
+ __Regex_InvalidBraceContent, // Content of {} invalid: not a number, number too large, more than two numbers, first larger than second.
+ __Regex_InvalidBracketContent, // Content of [] invalid.
+ __Regex_InvalidRange, // Invalid endpoint in range expression.
+ __Regex_InvalidRepetitionMarker, // ?, * or + not preceded by valid regular expression.
+ __Regex_ReachedMaxRecursion, // MaximumRecursion has been reached.
+ __Regex_EmptySubExpression, // Sub expression has empty content.
+ __Regex_InvalidCaptureGroup, // Content of capture group is invalid.
+ __Regex_InvalidNameForCaptureGroup, // Name of capture group is invalid.
+};
+
+enum ReError {
+ REG_NOERR = __Regex_NoError,
+ REG_BADPAT = __Regex_InvalidPattern, // Invalid regular expression.
+ REG_ECOLLATE = __Regex_InvalidCollationElement, // Invalid collating element referenced.
+ REG_ECTYPE = __Regex_InvalidCharacterClass, // Invalid character class type referenced.
+ REG_EESCAPE = __Regex_InvalidTrailingEscape, // Trailing \ in pattern.
+ REG_ESUBREG = __Regex_InvalidNumber, // Number in \digit invalid or in error.
+ REG_EBRACK = __Regex_MismatchingBracket, // [ ] imbalance.
+ REG_EPAREN = __Regex_MismatchingParen, // \( \) or ( ) imbalance.
+ REG_EBRACE = __Regex_MismatchingBrace, // \{ \} imbalance.
+ REG_BADBR = __Regex_InvalidBraceContent, // Content of \{ \} invalid: not a number, number too large, more than two numbers, first larger than second.
+ REG_ERANGE = __Regex_InvalidRange, // Invalid endpoint in range expression.
+ REG_BADRPT = __Regex_InvalidRepetitionMarker, // ?, * or + not preceded by valid regular expression.
+ REG_EMPTY_EXPR = __Regex_EmptySubExpression, // Empty expression
+ REG_ENOSYS, // The implementation does not support the function.
+ REG_ESPACE, // Out of memory.
+ REG_NOMATCH, // regexec() failed to match.
+};
+
+struct regmatch_t {
+ regoff_t rm_so; // byte offset from start of string to start of substring
+ regoff_t rm_eo; // byte offset from start of string of the first character after the end of substring
+ regoff_t rm_cnt; // number of matches
+};
+
+enum __RegexAllFlags {
+ __Regex_Global = 1, // All matches (don't return after first match)
+ __Regex_Insensitive = __Regex_Global << 1, // Case insensitive match (ignores case of [a-zA-Z])
+ __Regex_Ungreedy = __Regex_Global << 2, // The match becomes lazy by default. Now a ? following a quantifier makes it greedy
+ __Regex_Unicode = __Regex_Global << 3, // Enable all unicode features and interpret all unicode escape sequences as such
+ __Regex_Extended = __Regex_Global << 4, // Ignore whitespaces. Spaces and text after a # in the pattern are ignored
+ __Regex_Extra = __Regex_Global << 5, // Disallow meaningless escapes. A \ followed by a letter with no special meaning is faulted
+ __Regex_MatchNotBeginOfLine = __Regex_Global << 6, // Pattern is not forced to ^ -> search in whole string!
+ __Regex_MatchNotEndOfLine = __Regex_Global << 7, // Don't Force the dollar sign, $, to always match end of the string, instead of end of the line. This option is ignored if the Multiline-flag is set
+ __Regex_SkipSubExprResults = __Regex_Global << 8, // Do not return sub expressions in the result
+ __Regex_StringCopyMatches = __Regex_Global << 9, // Do explicitly copy results into new allocated string instead of StringView to original string.
+ __Regex_SingleLine = __Regex_Global << 10, // Dot matches newline characters
+ __Regex_Sticky = __Regex_Global << 11, // Force the pattern to only match consecutive matches from where the previous match ended.
+ __Regex_Multiline = __Regex_Global << 12, // Handle newline characters. Match each line, one by one.
+ __Regex_SkipTrimEmptyMatches = __Regex_Global << 13, // Do not remove empty capture group results.
+ __Regex_Internal_Stateful = __Regex_Global << 14, // Internal flag; enables stateful matches.
+ __Regex_Last = __Regex_SkipTrimEmptyMatches
+};
+
+// clang-format off
+// Values for the cflags parameter to the regcomp() function:
+#define REG_EXTENDED __Regex_Extended // Use Extended Regular Expressions.
+#define REG_ICASE __Regex_Insensitive // Ignore case in match.
+#define REG_NOSUB __Regex_SkipSubExprResults // Report only success or fail in regexec().
+#define REG_GLOBAL __Regex_Global // Don't stop searching for more match
+#define REG_NEWLINE (__Regex_Multiline | REG_GLOBAL) // Change the handling of newline.
+
+// Values for the eflags parameter to the regexec() function:
+#define REG_NOTBOL __Regex_MatchNotBeginOfLine // The circumflex character (^), when taken as a special character, will not match the beginning of string.
+#define REG_NOTEOL __Regex_MatchNotEndOfLine // The dollar sign ($), when taken as a special character, will not match the end of string.
+
+//static_assert (sizeof(FlagsUnderlyingType) * 8 >= regex::POSIXFlags::Last << 1), "flags type too small")
+#define REG_SEARCH __Regex_Last << 1
+// clang-format on
+
+int regcomp(regex_t*, const char*, int);
+int regexec(const regex_t*, const char*, size_t, regmatch_t[], int);
+size_t regerror(int, const regex_t*, char*, size_t);
+void regfree(regex_t*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/scanf.cpp b/Userland/Libraries/LibC/scanf.cpp
new file mode 100644
index 0000000000..550240fa23
--- /dev/null
+++ b/Userland/Libraries/LibC/scanf.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Opsycon AB.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <AK/Assertions.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char* determine_base(const char* p, int& base)
+{
+ if (p[0] == '0') {
+ switch (p[1]) {
+ case 'x':
+ base = 16;
+ break;
+ case 't':
+ case 'n':
+ base = 10;
+ break;
+ case 'o':
+ base = 8;
+ break;
+ default:
+ base = 10;
+ return p;
+ }
+ return p + 2;
+ }
+ base = 10;
+ return p;
+}
+
+static int _atob(unsigned long* vp, const char* p, int base)
+{
+ unsigned long value, v1, v2;
+ const char* q;
+ char tmp[20];
+ int digit;
+
+ if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
+ base = 16;
+ p += 2;
+ }
+
+ if (base == 16 && (q = strchr(p, '.')) != 0) {
+ if (q - p > (ssize_t)sizeof(tmp) - 1)
+ return 0;
+ memcpy(tmp, p, q - p);
+ tmp[q - p] = '\0';
+
+ if (!_atob(&v1, tmp, 16))
+ return 0;
+ ++q;
+ if (strchr(q, '.'))
+ return 0;
+ if (!_atob(&v2, q, 16))
+ return 0;
+ *vp = (v1 << 16) + v2;
+ return 1;
+ }
+
+ value = *vp = 0;
+ for (; *p; p++) {
+ if (*p >= '0' && *p <= '9')
+ digit = *p - '0';
+ else if (*p >= 'a' && *p <= 'f')
+ digit = *p - 'a' + 10;
+ else if (*p >= 'A' && *p <= 'F')
+ digit = *p - 'A' + 10;
+ else
+ return 0;
+
+ if (digit >= base)
+ return 0;
+ value *= base;
+ value += digit;
+ }
+ *vp = value;
+ return 1;
+}
+
+static int atob(unsigned int* vp, const char* p, int base)
+{
+ unsigned long v;
+
+ if (base == 0)
+ p = determine_base(p, base);
+ if (_atob(&v, p, base)) {
+ *vp = v;
+ return 1;
+ }
+ return 0;
+}
+
+#define ISSPACE " \t\n\r\f\v"
+
+int vsscanf(const char* buf, const char* s, va_list ap)
+{
+ int base = 10;
+ char* t;
+ char tmp[BUFSIZ];
+ bool noassign = false;
+ int count = 0;
+ int width = 0;
+
+ // FIXME: This doesn't work quite right. For example, it fails to match 'SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.1\r\n'
+ // with 'SSH-%d.%d-%[^\n]\n'
+
+ while (*s && *buf) {
+ while (isspace(*s))
+ s++;
+ if (*s == '%') {
+ s++;
+ for (; *s; s++) {
+ if (strchr("dibouxcsefg%", *s))
+ break;
+ if (*s == '*')
+ noassign = true;
+ else if (*s >= '1' && *s <= '9') {
+ const char* tc;
+ for (tc = s; isdigit(*s); s++)
+ ;
+ ASSERT((ssize_t)sizeof(tmp) >= s - tc + 1);
+ memcpy(tmp, tc, s - tc);
+ tmp[s - tc] = '\0';
+ atob((uint32_t*)&width, tmp, 10);
+ s--;
+ }
+ }
+ if (*s == 's') {
+ while (isspace(*buf))
+ buf++;
+ if (!width)
+ width = strcspn(buf, ISSPACE);
+ if (!noassign) {
+ // In this case, we have no way to ensure the user buffer is not overflown :(
+ memcpy(t = va_arg(ap, char*), buf, width);
+ t[width] = '\0';
+ }
+ buf += width;
+ } else if (*s == 'c') {
+ if (!width)
+ width = 1;
+ if (!noassign) {
+ memcpy(t = va_arg(ap, char*), buf, width);
+ // No null terminator!
+ }
+ buf += width;
+ } else if (strchr("dobxu", *s)) {
+ while (isspace(*buf))
+ buf++;
+ if (*s == 'd' || *s == 'u')
+ base = 10;
+ else if (*s == 'x')
+ base = 16;
+ else if (*s == 'o')
+ base = 8;
+ else if (*s == 'b')
+ base = 2;
+ if (!width) {
+ if (isspace(*(s + 1)) || *(s + 1) == 0) {
+ width = strcspn(buf, ISSPACE);
+ } else {
+ auto* p = strchr(buf, *(s + 1));
+ if (p)
+ width = p - buf;
+ else {
+ noassign = true;
+ width = 0;
+ }
+ }
+ }
+ memcpy(tmp, buf, width);
+ tmp[width] = '\0';
+ buf += width;
+ if (!noassign) {
+ if (!atob(va_arg(ap, uint32_t*), tmp, base))
+ noassign = true;
+ }
+ }
+ if (!noassign)
+ ++count;
+ width = 0;
+ noassign = false;
+ ++s;
+ } else {
+ while (isspace(*buf))
+ buf++;
+ if (*s != *buf)
+ break;
+ else {
+ ++s;
+ ++buf;
+ }
+ }
+ }
+ return count;
+}
diff --git a/Userland/Libraries/LibC/sched.cpp b/Userland/Libraries/LibC/sched.cpp
new file mode 100644
index 0000000000..4e3643bd01
--- /dev/null
+++ b/Userland/Libraries/LibC/sched.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <sched.h>
+
+extern "C" {
+
+int sched_yield()
+{
+ int rc = syscall(SC_yield);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int sched_get_priority_min([[maybe_unused]] int policy)
+{
+ return 0; // Idle
+}
+
+int sched_get_priority_max([[maybe_unused]] int policy)
+{
+ return 3; // High
+}
+
+int sched_setparam(pid_t pid, const struct sched_param* param)
+{
+ int rc = syscall(SC_sched_setparam, pid, param);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int sched_getparam(pid_t pid, struct sched_param* param)
+{
+ int rc = syscall(SC_sched_getparam, pid, param);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/sched.h b/Userland/Libraries/LibC/sched.h
new file mode 100644
index 0000000000..ac7bf9eff9
--- /dev/null
+++ b/Userland/Libraries/LibC/sched.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+int sched_yield();
+
+struct sched_param {
+ int sched_priority;
+};
+
+#define SCHED_FIFO 0
+#define SCHED_RR 1
+#define SCHED_OTHER 2
+#define SCHED_BATCH 3
+
+int sched_get_priority_min(int policy);
+int sched_get_priority_max(int policy);
+int sched_setparam(pid_t pid, const struct sched_param* param);
+int sched_getparam(pid_t pid, struct sched_param* param);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/serenity.cpp b/Userland/Libraries/LibC/serenity.cpp
new file mode 100644
index 0000000000..626a464ee8
--- /dev/null
+++ b/Userland/Libraries/LibC/serenity.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <serenity.h>
+
+extern "C" {
+
+int disown(pid_t pid)
+{
+ int rc = syscall(SC_disown, pid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int module_load(const char* path, size_t path_length)
+{
+ int rc = syscall(SC_module_load, path, path_length);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int module_unload(const char* name, size_t name_length)
+{
+ int rc = syscall(SC_module_unload, name, name_length);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int profiling_enable(pid_t pid)
+{
+ int rc = syscall(SC_profiling_enable, pid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int profiling_disable(pid_t pid)
+{
+ int rc = syscall(SC_profiling_disable, pid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int set_thread_boost(pid_t tid, int amount)
+{
+ int rc = syscall(SC_set_thread_boost, tid, amount);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int set_process_boost(pid_t tid, int amount)
+{
+ int rc = syscall(SC_set_process_boost, tid, amount);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int futex(int32_t* userspace_address, int futex_op, int32_t value, const struct timespec* timeout)
+{
+ Syscall::SC_futex_params params { userspace_address, futex_op, value, timeout };
+ int rc = syscall(SC_futex, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int purge(int mode)
+{
+ int rc = syscall(SC_purge, mode);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int perf_event(int type, uintptr_t arg1, FlatPtr arg2)
+{
+ int rc = syscall(SC_perf_event, type, arg1, arg2);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+void* shbuf_get(int shbuf_id, size_t* size)
+{
+ ssize_t rc = syscall(SC_shbuf_get, shbuf_id, size);
+ if (rc < 0 && -rc < EMAXERRNO) {
+ errno = -rc;
+ return (void*)-1;
+ }
+ return (void*)rc;
+}
+
+int shbuf_release(int shbuf_id)
+{
+ int rc = syscall(SC_shbuf_release, shbuf_id);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int shbuf_seal(int shbuf_id)
+{
+ int rc = syscall(SC_shbuf_seal, shbuf_id);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int shbuf_create(int size, void** buffer)
+{
+ int rc = syscall(SC_shbuf_create, size, buffer);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int shbuf_allow_pid(int shbuf_id, pid_t peer_pid)
+{
+ int rc = syscall(SC_shbuf_allow_pid, shbuf_id, peer_pid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int shbuf_allow_all(int shbuf_id)
+{
+ int rc = syscall(SC_shbuf_allow_all, shbuf_id);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int get_stack_bounds(uintptr_t* user_stack_base, size_t* user_stack_size)
+{
+ int rc = syscall(SC_get_stack_bounds, user_stack_base, user_stack_size);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/serenity.h b/Userland/Libraries/LibC/serenity.h
new file mode 100644
index 0000000000..4654476469
--- /dev/null
+++ b/Userland/Libraries/LibC/serenity.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+int disown(pid_t);
+
+int shbuf_create(int, void** buffer);
+int shbuf_allow_pid(int, pid_t peer_pid);
+int shbuf_allow_all(int);
+void* shbuf_get(int shbuf_id, size_t* size);
+int shbuf_release(int shbuf_id);
+int shbuf_seal(int shbuf_id);
+
+int module_load(const char* path, size_t path_length);
+int module_unload(const char* name, size_t name_length);
+
+int profiling_enable(pid_t);
+int profiling_disable(pid_t);
+
+#define THREAD_PRIORITY_MIN 1
+#define THREAD_PRIORITY_LOW 10
+#define THREAD_PRIORITY_NORMAL 30
+#define THREAD_PRIORITY_HIGH 50
+#define THREAD_PRIORITY_MAX 99
+
+int set_thread_boost(pid_t tid, int amount);
+int set_process_boost(pid_t, int amount);
+
+#define FUTEX_WAIT 1
+#define FUTEX_WAKE 2
+
+int futex(int32_t* userspace_address, int futex_op, int32_t value, const struct timespec* timeout);
+
+#define PURGE_ALL_VOLATILE 0x1
+#define PURGE_ALL_CLEAN_INODE 0x2
+
+int purge(int mode);
+
+#define PERF_EVENT_SAMPLE 0
+#define PERF_EVENT_MALLOC 1
+#define PERF_EVENT_FREE 2
+
+int perf_event(int type, uintptr_t arg1, uintptr_t arg2);
+
+int get_stack_bounds(uintptr_t* user_stack_base, size_t* user_stack_size);
+
+#ifdef __i386__
+ALWAYS_INLINE void send_secret_data_to_userspace_emulator(uintptr_t data1, uintptr_t data2, uintptr_t data3)
+{
+ asm volatile(
+ ".byte 0xd6\n"
+ ".byte 0xd6\n" ::
+ : "eax");
+ asm volatile(
+ "push %%eax\n"
+ "push %%ecx\n"
+ "push %%edx\n"
+ "pop %%edx\n"
+ "pop %%ecx\n"
+ "pop %%eax\n" ::"a"(data1),
+ "c"(data2), "d"(data3)
+ : "memory");
+}
+#elif __x86_64__
+ALWAYS_INLINE void send_secret_data_to_userspace_emulator(uintptr_t, uintptr_t, uintptr_t)
+{
+}
+#endif
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/setjmp.S b/Userland/Libraries/LibC/setjmp.S
new file mode 100644
index 0000000000..6d2c4c4acf
--- /dev/null
+++ b/Userland/Libraries/LibC/setjmp.S
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.global setjmp
+setjmp:
+ mov 4(%esp), %eax
+ mov %ebx, 0(%eax)
+ mov %esi, 4(%eax)
+ mov %edi, 8(%eax)
+ mov %ebp, 12(%eax)
+ lea 4(%esp), %ecx
+ mov %ecx, 16(%eax)
+ mov (%esp), %ecx
+ mov %ecx, 20(%eax)
+ xor %eax, %eax
+ ret
+
+.global longjmp
+longjmp:
+ mov 4(%esp), %edx
+ mov 8(%esp), %eax
+ mov 0(%edx), %ebx
+ mov 4(%edx), %esi
+ mov 8(%edx), %edi
+ mov 12(%edx), %ebp
+ mov 16(%edx), %ecx
+ mov %ecx, %esp
+ mov 20(%edx), %ecx
+ test %eax, %eax
+ jnz .nonzero
+ mov 1, %eax
+.nonzero:
+ jmp *%ecx
+
diff --git a/Userland/Libraries/LibC/setjmp.h b/Userland/Libraries/LibC/setjmp.h
new file mode 100644
index 0000000000..78f3120d14
--- /dev/null
+++ b/Userland/Libraries/LibC/setjmp.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/stdint.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct __jmp_buf {
+ uint32_t regs[6];
+ bool did_save_signal_mask;
+ sigset_t saved_signal_mask;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+typedef struct __jmp_buf sigjmp_buf[1];
+
+int setjmp(jmp_buf);
+void longjmp(jmp_buf, int val);
+
+int sigsetjmp(sigjmp_buf, int savesigs);
+void siglongjmp(sigjmp_buf, int val);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/signal.cpp b/Userland/Libraries/LibC/signal.cpp
new file mode 100644
index 0000000000..a7a7ede8ba
--- /dev/null
+++ b/Userland/Libraries/LibC/signal.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <assert.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+extern "C" {
+
+int kill(pid_t pid, int sig)
+{
+ int rc = syscall(SC_kill, pid, sig);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int killpg(int pgrp, int sig)
+{
+ int rc = syscall(SC_killpg, pgrp, sig);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int raise(int sig)
+{
+ // FIXME: Support multi-threaded programs.
+ return kill(getpid(), sig);
+}
+
+sighandler_t signal(int signum, sighandler_t handler)
+{
+ struct sigaction new_act;
+ struct sigaction old_act;
+ new_act.sa_handler = handler;
+ new_act.sa_flags = 0;
+ new_act.sa_mask = 0;
+ int rc = sigaction(signum, &new_act, &old_act);
+ if (rc < 0)
+ return SIG_ERR;
+ return old_act.sa_handler;
+}
+
+int sigaction(int signum, const struct sigaction* act, struct sigaction* old_act)
+{
+ int rc = syscall(SC_sigaction, signum, act, old_act);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int sigemptyset(sigset_t* set)
+{
+ *set = 0;
+ return 0;
+}
+
+int sigfillset(sigset_t* set)
+{
+ *set = 0xffffffff;
+ return 0;
+}
+
+int sigaddset(sigset_t* set, int sig)
+{
+ if (sig < 1 || sig > 32) {
+ errno = EINVAL;
+ return -1;
+ }
+ *set |= 1 << (sig - 1);
+ return 0;
+}
+
+int sigdelset(sigset_t* set, int sig)
+{
+ if (sig < 1 || sig > 32) {
+ errno = EINVAL;
+ return -1;
+ }
+ *set &= ~(1 << (sig - 1));
+ return 0;
+}
+
+int sigismember(const sigset_t* set, int sig)
+{
+ if (sig < 1 || sig > 32) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (*set & (1 << (sig - 1)))
+ return 1;
+ return 0;
+}
+
+int sigprocmask(int how, const sigset_t* set, sigset_t* old_set)
+{
+ int rc = syscall(SC_sigprocmask, how, set, old_set);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int sigpending(sigset_t* set)
+{
+ int rc = syscall(SC_sigpending, set);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+const char* sys_siglist[NSIG] = {
+ "Invalid signal number",
+ "Hangup",
+ "Interrupt",
+ "Quit",
+ "Illegal instruction",
+ "Trap",
+ "Aborted",
+ "Bus error",
+ "Division by zero",
+ "Killed",
+ "User signal 1",
+ "Segmentation violation",
+ "User signal 2",
+ "Broken pipe",
+ "Alarm clock",
+ "Terminated",
+ "Stack fault",
+ "Child exited",
+ "Continued",
+ "Stopped (signal)",
+ "Stopped",
+ "Stopped (tty input)",
+ "Stopped (tty output)",
+ "Urgent I/O condition)",
+ "CPU limit exceeded",
+ "File size limit exceeded",
+ "Virtual timer expired",
+ "Profiling timer expired",
+ "Window changed",
+ "I/O possible",
+ "Power failure",
+ "Bad system call",
+};
+
+int sigsetjmp(jmp_buf env, int savesigs)
+{
+ if (savesigs) {
+ int rc = sigprocmask(0, nullptr, &env->saved_signal_mask);
+ assert(rc == 0);
+ env->did_save_signal_mask = true;
+ } else {
+ env->did_save_signal_mask = false;
+ }
+ return setjmp(env);
+}
+void siglongjmp(jmp_buf env, int val)
+{
+ if (env->did_save_signal_mask) {
+ int rc = sigprocmask(SIG_SETMASK, &env->saved_signal_mask, nullptr);
+ assert(rc == 0);
+ }
+ longjmp(env, val);
+}
+
+int sigsuspend(const sigset_t*)
+{
+ dbgprintf("FIXME: Implement sigsuspend()\n");
+ ASSERT_NOT_REACHED();
+}
+
+static const char* signal_names[] = {
+ "INVAL",
+ "HUP",
+ "INT",
+ "QUIT",
+ "ILL",
+ "TRAP",
+ "ABRT",
+ "BUS",
+ "FPE",
+ "KILL",
+ "USR1",
+ "SEGV",
+ "USR2",
+ "PIPE",
+ "ALRM",
+ "TERM",
+ "STKFLT",
+ "CHLD",
+ "CONT",
+ "STOP",
+ "TSTP",
+ "TTIN",
+ "TTOU",
+ "URG",
+ "XCPU",
+ "XFSZ",
+ "VTALRM",
+ "PROF",
+ "WINCH",
+ "IO",
+ "INFO",
+ "SYS",
+};
+
+static_assert(sizeof(signal_names) == sizeof(const char*) * NSIG);
+
+int getsignalbyname(const char* name)
+{
+ ASSERT(name);
+ for (size_t i = 0; i < NSIG; ++i) {
+ auto* signal_name = signal_names[i];
+ if (!strcmp(signal_name, name))
+ return i;
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+const char* getsignalname(int signal)
+{
+ if (signal < 0 || signal >= NSIG) {
+ errno = EINVAL;
+ return nullptr;
+ }
+ return signal_names[signal];
+}
+}
diff --git a/Userland/Libraries/LibC/signal.h b/Userland/Libraries/LibC/signal.h
new file mode 100644
index 0000000000..65c98603d4
--- /dev/null
+++ b/Userland/Libraries/LibC/signal.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <signal_numbers.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+typedef void (*__sighandler_t)(int);
+typedef __sighandler_t sighandler_t;
+
+typedef uint32_t sigset_t;
+typedef uint32_t sig_atomic_t;
+
+union sigval {
+ int sival_int;
+ void* sival_ptr;
+};
+
+typedef struct siginfo {
+ int si_signo;
+ int si_code;
+ pid_t si_pid;
+ uid_t si_uid;
+ void* si_addr;
+ int si_status;
+ union sigval si_value;
+} siginfo_t;
+
+struct sigaction {
+ union {
+ void (*sa_handler)(int);
+ void (*sa_sigaction)(int, siginfo_t*, void*);
+ };
+ sigset_t sa_mask;
+ int sa_flags;
+};
+
+int kill(pid_t, int sig);
+int killpg(int pgrp, int sig);
+sighandler_t signal(int sig, sighandler_t);
+int pthread_sigmask(int how, const sigset_t* set, sigset_t* ol_dset);
+int sigaction(int sig, const struct sigaction* act, struct sigaction* old_act);
+int sigemptyset(sigset_t*);
+int sigfillset(sigset_t*);
+int sigaddset(sigset_t*, int sig);
+int sigdelset(sigset_t*, int sig);
+int sigismember(const sigset_t*, int sig);
+int sigprocmask(int how, const sigset_t* set, sigset_t* old_set);
+int sigpending(sigset_t*);
+int sigsuspend(const sigset_t*);
+int raise(int sig);
+int getsignalbyname(const char*);
+const char* getsignalname(int);
+
+extern const char* sys_siglist[NSIG];
+
+#define SIG_DFL ((__sighandler_t)0)
+#define SIG_ERR ((__sighandler_t)-1)
+#define SIG_IGN ((__sighandler_t)1)
+
+#define SA_NOCLDSTOP 1
+#define SA_NOCLDWAIT 2
+#define SA_SIGINFO 4
+#define SA_ONSTACK 0x08000000
+#define SA_RESTART 0x10000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
+
+#define SA_NOMASK SA_NODEFER
+#define SA_ONESHOT SA_RESETHAND
+
+#define SIG_BLOCK 0
+#define SIG_UNBLOCK 1
+#define SIG_SETMASK 2
+
+#define CLD_EXITED 0
+#define CLD_KILLED 1
+#define CLD_DUMPED 2
+#define CLD_TRAPPED 3
+#define CLD_STOPPED 4
+#define CLD_CONTINUED 5
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/signal_numbers.h b/Userland/Libraries/LibC/signal_numbers.h
new file mode 100644
index 0000000000..bc59c0d97c
--- /dev/null
+++ b/Userland/Libraries/LibC/signal_numbers.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define SIGINVAL 0
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGINFO 30
+#define SIGSYS 31
+#define NSIG 32
diff --git a/Userland/Libraries/LibC/spawn.cpp b/Userland/Libraries/LibC/spawn.cpp
new file mode 100644
index 0000000000..797c946c68
--- /dev/null
+++ b/Userland/Libraries/LibC/spawn.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2020, Nico Weber <thakis@chromium.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* posix_spawn and friends
+ *
+ * values from POSIX standard unix specification
+ *
+ * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/spawn.h.html
+ */
+
+#include <spawn.h>
+
+#include <AK/Function.h>
+#include <AK/Vector.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+struct posix_spawn_file_actions_state {
+ Vector<Function<int()>, 4> actions;
+};
+
+extern "C" {
+
+[[noreturn]] static void posix_spawn_child(const char* path, const posix_spawn_file_actions_t* file_actions, const posix_spawnattr_t* attr, char* const argv[], char* const envp[], int (*exec)(const char*, char* const[], char* const[]))
+{
+ if (attr) {
+ short flags = attr->flags;
+ if (flags & POSIX_SPAWN_RESETIDS) {
+ if (seteuid(getuid()) < 0) {
+ perror("posix_spawn seteuid");
+ _exit(127);
+ }
+ if (setegid(getgid()) < 0) {
+ perror("posix_spawn setegid");
+ _exit(127);
+ }
+ }
+ if (flags & POSIX_SPAWN_SETPGROUP) {
+ if (setpgid(0, attr->pgroup) < 0) {
+ perror("posix_spawn setpgid");
+ _exit(127);
+ }
+ }
+ if (flags & POSIX_SPAWN_SETSCHEDPARAM) {
+ if (sched_setparam(0, &attr->schedparam) < 0) {
+ perror("posix_spawn sched_setparam");
+ _exit(127);
+ }
+ }
+ if (flags & POSIX_SPAWN_SETSIGDEF) {
+ struct sigaction default_action;
+ default_action.sa_flags = 0;
+ sigemptyset(&default_action.sa_mask);
+ default_action.sa_handler = SIG_DFL;
+
+ sigset_t sigdefault = attr->sigdefault;
+ for (int i = 0; i < NSIG; ++i) {
+ if (sigismember(&sigdefault, i) && sigaction(i, &default_action, nullptr) < 0) {
+ perror("posix_spawn sigaction");
+ _exit(127);
+ }
+ }
+ }
+ if (flags & POSIX_SPAWN_SETSIGMASK) {
+ if (sigprocmask(SIG_SETMASK, &attr->sigmask, nullptr) < 0) {
+ perror("posix_spawn sigprocmask");
+ _exit(127);
+ }
+ }
+ if (flags & POSIX_SPAWN_SETSID) {
+ if (setsid() < 0) {
+ perror("posix_spawn setsid");
+ _exit(127);
+ }
+ }
+
+ // FIXME: POSIX_SPAWN_SETSCHEDULER
+ }
+
+ if (file_actions) {
+ for (const auto& action : file_actions->state->actions) {
+ if (action() < 0) {
+ perror("posix_spawn file action");
+ _exit(127);
+ }
+ }
+ }
+
+ exec(path, argv, envp);
+ perror("posix_spawn exec");
+ _exit(127);
+}
+
+int posix_spawn(pid_t* out_pid, const char* path, const posix_spawn_file_actions_t* file_actions, const posix_spawnattr_t* attr, char* const argv[], char* const envp[])
+{
+ pid_t child_pid = fork();
+ if (child_pid < 0)
+ return errno;
+
+ if (child_pid != 0) {
+ *out_pid = child_pid;
+ return 0;
+ }
+
+ posix_spawn_child(path, file_actions, attr, argv, envp, execve);
+}
+
+int posix_spawnp(pid_t* out_pid, const char* path, const posix_spawn_file_actions_t* file_actions, const posix_spawnattr_t* attr, char* const argv[], char* const envp[])
+{
+ pid_t child_pid = fork();
+ if (child_pid < 0)
+ return errno;
+
+ if (child_pid != 0) {
+ *out_pid = child_pid;
+ return 0;
+ }
+
+ posix_spawn_child(path, file_actions, attr, argv, envp, execvpe);
+}
+
+int posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t* actions, const char* path)
+{
+ actions->state->actions.append([path]() { return chdir(path); });
+ return 0;
+}
+
+int posix_spawn_file_actions_addfchdir(posix_spawn_file_actions_t* actions, int fd)
+{
+ actions->state->actions.append([fd]() { return fchdir(fd); });
+ return 0;
+}
+
+int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t* actions, int fd)
+{
+ actions->state->actions.append([fd]() { return close(fd); });
+ return 0;
+}
+
+int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t* actions, int old_fd, int new_fd)
+{
+ actions->state->actions.append([old_fd, new_fd]() { return dup2(old_fd, new_fd); });
+ return 0;
+}
+
+int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t* actions, int want_fd, const char* path, int flags, mode_t mode)
+{
+ actions->state->actions.append([want_fd, path, flags, mode]() {
+ int opened_fd = open(path, flags, mode);
+ if (opened_fd < 0 || opened_fd == want_fd)
+ return opened_fd;
+ if (int rc = dup2(opened_fd, want_fd); rc < 0)
+ return rc;
+ return close(opened_fd);
+ });
+ return 0;
+}
+
+int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* actions)
+{
+ delete actions->state;
+ return 0;
+}
+
+int posix_spawn_file_actions_init(posix_spawn_file_actions_t* actions)
+{
+ actions->state = new posix_spawn_file_actions_state;
+ return 0;
+}
+
+int posix_spawnattr_destroy(posix_spawnattr_t*)
+{
+ return 0;
+}
+
+int posix_spawnattr_getflags(const posix_spawnattr_t* attr, short* out_flags)
+{
+ *out_flags = attr->flags;
+ return 0;
+}
+
+int posix_spawnattr_getpgroup(const posix_spawnattr_t* attr, pid_t* out_pgroup)
+{
+ *out_pgroup = attr->pgroup;
+ return 0;
+}
+
+int posix_spawnattr_getschedparam(const posix_spawnattr_t* attr, struct sched_param* out_schedparam)
+{
+ *out_schedparam = attr->schedparam;
+ return 0;
+}
+
+int posix_spawnattr_getschedpolicy(const posix_spawnattr_t* attr, int* out_schedpolicty)
+{
+ *out_schedpolicty = attr->schedpolicy;
+ return 0;
+}
+
+int posix_spawnattr_getsigdefault(const posix_spawnattr_t* attr, sigset_t* out_sigdefault)
+{
+ *out_sigdefault = attr->sigdefault;
+ return 0;
+}
+
+int posix_spawnattr_getsigmask(const posix_spawnattr_t* attr, sigset_t* out_sigmask)
+{
+ *out_sigmask = attr->sigmask;
+ return 0;
+}
+
+int posix_spawnattr_init(posix_spawnattr_t* attr)
+{
+ attr->flags = 0;
+ attr->pgroup = 0;
+ // attr->schedparam intentionally not written; its default value is unspecified.
+ // attr->schedpolicy intentionally not written; its default value is unspecified.
+ sigemptyset(&attr->sigdefault);
+ // attr->sigmask intentionally not written; its default value is unspecified.
+ return 0;
+}
+
+int posix_spawnattr_setflags(posix_spawnattr_t* attr, short flags)
+{
+ if (flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSID))
+ return EINVAL;
+
+ attr->flags = flags;
+ return 0;
+}
+
+int posix_spawnattr_setpgroup(posix_spawnattr_t* attr, pid_t pgroup)
+{
+ attr->pgroup = pgroup;
+ return 0;
+}
+
+int posix_spawnattr_setschedparam(posix_spawnattr_t* attr, const struct sched_param* schedparam)
+{
+ attr->schedparam = *schedparam;
+ return 0;
+}
+
+int posix_spawnattr_setschedpolicy(posix_spawnattr_t* attr, int schedpolicy)
+{
+ attr->schedpolicy = schedpolicy;
+ return 0;
+}
+
+int posix_spawnattr_setsigdefault(posix_spawnattr_t* attr, const sigset_t* sigdefault)
+{
+ attr->sigdefault = *sigdefault;
+ return 0;
+}
+
+int posix_spawnattr_setsigmask(posix_spawnattr_t* attr, const sigset_t* sigmask)
+{
+ attr->sigmask = *sigmask;
+ return 0;
+}
+}
diff --git a/Userland/Libraries/LibC/spawn.h b/Userland/Libraries/LibC/spawn.h
new file mode 100644
index 0000000000..05435ef466
--- /dev/null
+++ b/Userland/Libraries/LibC/spawn.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020, Nico Weber <thakis@chromium.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* posix_spawn and friends
+ *
+ * values from POSIX standard unix specification
+ *
+ * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/spawn.h.html
+ */
+
+#pragma once
+
+#include <sched.h>
+#include <signal.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+enum {
+ POSIX_SPAWN_RESETIDS = 1 << 0,
+ POSIX_SPAWN_SETPGROUP = 1 << 1,
+
+ POSIX_SPAWN_SETSCHEDPARAM = 1 << 2,
+ POSIX_SPAWN_SETSCHEDULER = 1 << 3,
+
+ POSIX_SPAWN_SETSIGDEF = 1 << 4,
+ POSIX_SPAWN_SETSIGMASK = 1 << 5,
+
+ POSIX_SPAWN_SETSID = 1 << 6,
+};
+
+#define POSIX_SPAWN_SETSID POSIX_SPAWN_SETSID
+
+struct posix_spawn_file_actions_state;
+typedef struct {
+ struct posix_spawn_file_actions_state* state;
+} posix_spawn_file_actions_t;
+
+typedef struct {
+ short flags;
+ pid_t pgroup;
+ struct sched_param schedparam;
+ int schedpolicy;
+ sigset_t sigdefault;
+ sigset_t sigmask;
+} posix_spawnattr_t;
+
+int posix_spawn(pid_t*, const char*, const posix_spawn_file_actions_t*, const posix_spawnattr_t*, char* const argv[], char* const envp[]);
+int posix_spawnp(pid_t*, const char*, const posix_spawn_file_actions_t*, const posix_spawnattr_t*, char* const argv[], char* const envp[]);
+
+int posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t*, const char*);
+int posix_spawn_file_actions_addfchdir(posix_spawn_file_actions_t*, int);
+int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t*, int);
+int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t*, int old_fd, int new_fd);
+int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t*, int fd, const char*, int flags, mode_t);
+int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t*);
+int posix_spawn_file_actions_init(posix_spawn_file_actions_t*);
+
+int posix_spawnattr_destroy(posix_spawnattr_t*);
+int posix_spawnattr_getflags(const posix_spawnattr_t*, short*);
+int posix_spawnattr_getpgroup(const posix_spawnattr_t*, pid_t*);
+int posix_spawnattr_getschedparam(const posix_spawnattr_t*, struct sched_param*);
+int posix_spawnattr_getschedpolicy(const posix_spawnattr_t*, int*);
+int posix_spawnattr_getsigdefault(const posix_spawnattr_t*, sigset_t*);
+int posix_spawnattr_getsigmask(const posix_spawnattr_t*, sigset_t*);
+int posix_spawnattr_init(posix_spawnattr_t*);
+int posix_spawnattr_setflags(posix_spawnattr_t*, short);
+int posix_spawnattr_setpgroup(posix_spawnattr_t*, pid_t);
+int posix_spawnattr_setschedparam(posix_spawnattr_t*, const struct sched_param*);
+int posix_spawnattr_setschedpolicy(posix_spawnattr_t*, int);
+int posix_spawnattr_setsigdefault(posix_spawnattr_t*, const sigset_t*);
+int posix_spawnattr_setsigmask(posix_spawnattr_t*, const sigset_t*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/ssp.cpp b/Userland/Libraries/LibC/ssp.cpp
new file mode 100644
index 0000000000..c2715d6ba0
--- /dev/null
+++ b/Userland/Libraries/LibC/ssp.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021, Brian Gianforcaro <b.gianfo@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/internals.h>
+#include <unistd.h>
+
+#if defined __SSP__ || defined __SSP_ALL__
+# error "file must not be compiled with stack protection enabled on it. Use -fno-stack-protector"
+#endif
+
+extern "C" {
+
+extern u32 __stack_chk_guard;
+u32 __stack_chk_guard = (u32)0xc6c7c8c9;
+
+[[noreturn]] void __stack_chk_fail()
+{
+ dbgprintf("Error: USERSPACE(%d) Stack protector failure, stack smashing detected!\n", getpid());
+ if (__stdio_is_initialized)
+ fprintf(stderr, "Error: Stack protector failure, stack smashing detected!\n");
+ abort();
+}
+
+[[noreturn]] void __stack_chk_fail_local()
+{
+ __stack_chk_fail();
+}
+
+} // extern "C"
diff --git a/Userland/Libraries/LibC/stat.cpp b/Userland/Libraries/LibC/stat.cpp
new file mode 100644
index 0000000000..5de2472dfa
--- /dev/null
+++ b/Userland/Libraries/LibC/stat.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern "C" {
+
+mode_t umask(mode_t mask)
+{
+ return syscall(SC_umask, mask);
+}
+
+int mkdir(const char* pathname, mode_t mode)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ int rc = syscall(SC_mkdir, pathname, strlen(pathname), mode);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int chmod(const char* pathname, mode_t mode)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ int rc = syscall(SC_chmod, pathname, strlen(pathname), mode);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int fchmod(int fd, mode_t mode)
+{
+ int rc = syscall(SC_fchmod, fd, mode);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int mkfifo(const char* pathname, mode_t mode)
+{
+ return mknod(pathname, mode | S_IFIFO, 0);
+}
+
+static int do_stat(const char* path, struct stat* statbuf, bool follow_symlinks)
+{
+ if (!path) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_stat_params params { { path, strlen(path) }, statbuf, follow_symlinks };
+ int rc = syscall(SC_stat, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int lstat(const char* path, struct stat* statbuf)
+{
+ return do_stat(path, statbuf, false);
+}
+
+int stat(const char* path, struct stat* statbuf)
+{
+ return do_stat(path, statbuf, true);
+}
+
+int fstat(int fd, struct stat* statbuf)
+{
+ int rc = syscall(SC_fstat, fd, statbuf);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/stdarg.h b/Userland/Libraries/LibC/stdarg.h
new file mode 100644
index 0000000000..5725ead619
--- /dev/null
+++ b/Userland/Libraries/LibC/stdarg.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if defined(KERNEL)
+# define __BEGIN_DECLS
+# define __END_DECLS
+#else
+# include <sys/cdefs.h>
+#endif
+
+__BEGIN_DECLS
+
+typedef __builtin_va_list va_list;
+
+#define va_start(v, l) __builtin_va_start(v, l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v, l) __builtin_va_arg(v, l)
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/stdbool.h b/Userland/Libraries/LibC/stdbool.h
new file mode 100644
index 0000000000..29be4f8549
--- /dev/null
+++ b/Userland/Libraries/LibC/stdbool.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+
+# include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+# define bool _Bool
+# define true 1
+# define false 0
+# define __bool_true_false_are_Defined 1
+
+__END_DECLS
+
+#endif
diff --git a/Userland/Libraries/LibC/stddef.h b/Userland/Libraries/LibC/stddef.h
new file mode 100644
index 0000000000..4f7b710329
--- /dev/null
+++ b/Userland/Libraries/LibC/stddef.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#ifndef KERNEL
+
+# include <sys/cdefs.h>
+
+# ifdef __cplusplus
+# define NULL nullptr
+# else
+# define NULL ((void*)0)
+# endif
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__ size_t;
+
+#endif
diff --git a/Userland/Libraries/LibC/stdint.h b/Userland/Libraries/LibC/stdint.h
new file mode 100644
index 0000000000..4f1b66e766
--- /dev/null
+++ b/Userland/Libraries/LibC/stdint.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <bits/stdint.h>
diff --git a/Userland/Libraries/LibC/stdio.cpp b/Userland/Libraries/LibC/stdio.cpp
new file mode 100644
index 0000000000..1cdf9d4a73
--- /dev/null
+++ b/Userland/Libraries/LibC/stdio.cpp
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/LogStream.h>
+#include <AK/PrintfImplementation.h>
+#include <AK/ScopedValueRollback.h>
+#include <AK/StdLibExtras.h>
+#include <AK/kmalloc.h>
+#include <Kernel/API/Syscall.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/internals.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+struct FILE {
+public:
+ FILE(int fd, int mode)
+ : m_fd(fd)
+ , m_mode(mode)
+ {
+ }
+ ~FILE();
+
+ static FILE* create(int fd, int mode);
+
+ void setbuf(u8* data, int mode, size_t size) { m_buffer.setbuf(data, mode, size); }
+
+ bool flush();
+ bool close();
+
+ int fileno() const { return m_fd; }
+ bool eof() const { return m_eof; }
+
+ int error() const { return m_error; }
+ void clear_err() { m_error = 0; }
+
+ size_t read(u8*, size_t);
+ size_t write(const u8*, size_t);
+
+ bool gets(u8*, size_t);
+ bool ungetc(u8 byte) { return m_buffer.enqueue_front(byte); }
+
+ int seek(off_t offset, int whence);
+ off_t tell();
+
+ pid_t popen_child() { return m_popen_child; }
+ void set_popen_child(pid_t child_pid) { m_popen_child = child_pid; }
+
+ void reopen(int fd, int mode);
+
+private:
+ struct Buffer {
+ // A ringbuffer that also transparently implements ungetc().
+ public:
+ ~Buffer();
+
+ int mode() const { return m_mode; }
+ void setbuf(u8* data, int mode, size_t size);
+ // Make sure to call realize() before enqueuing any data.
+ // Dequeuing can be attempted without it.
+ void realize(int fd);
+ void drop();
+
+ bool may_use() const { return m_ungotten || m_mode != _IONBF; }
+ bool is_not_empty() const { return m_ungotten || !m_empty; }
+ size_t buffered_size() const;
+
+ const u8* begin_dequeue(size_t& available_size) const;
+ void did_dequeue(size_t actual_size);
+
+ u8* begin_enqueue(size_t& available_size) const;
+ void did_enqueue(size_t actual_size);
+
+ bool enqueue_front(u8 byte);
+
+ private:
+ // Note: the fields here are arranged this way
+ // to make sizeof(Buffer) smaller.
+ u8* m_data { nullptr };
+ size_t m_capacity { BUFSIZ };
+ size_t m_begin { 0 };
+ size_t m_end { 0 };
+
+ int m_mode { -1 };
+ u8 m_unget_buffer { 0 };
+ bool m_ungotten : 1 { false };
+ bool m_data_is_malloced : 1 { false };
+ // When m_begin == m_end, we want to distinguish whether
+ // the buffer is full or empty.
+ bool m_empty : 1 { true };
+ };
+
+ // Read or write using the underlying fd, bypassing the buffer.
+ ssize_t do_read(u8*, size_t);
+ ssize_t do_write(const u8*, size_t);
+
+ // Read some data into the buffer.
+ bool read_into_buffer();
+ // Flush *some* data from the buffer.
+ bool write_from_buffer();
+
+ int m_fd { -1 };
+ int m_mode { 0 };
+ int m_error { 0 };
+ bool m_eof { false };
+ pid_t m_popen_child { -1 };
+ Buffer m_buffer;
+};
+
+FILE::~FILE()
+{
+ bool already_closed = m_fd == -1;
+ ASSERT(already_closed);
+}
+
+FILE* FILE::create(int fd, int mode)
+{
+ void* file = calloc(1, sizeof(FILE));
+ new (file) FILE(fd, mode);
+ return (FILE*)file;
+}
+
+bool FILE::close()
+{
+ bool flush_ok = flush();
+ int rc = ::close(m_fd);
+ m_fd = -1;
+ if (!flush_ok) {
+ // Restore the original error from flush().
+ errno = m_error;
+ }
+ return flush_ok && rc == 0;
+}
+
+bool FILE::flush()
+{
+ if (m_mode & O_WRONLY && m_buffer.may_use()) {
+ // When open for writing, write out all the buffered data.
+ while (m_buffer.is_not_empty()) {
+ bool ok = write_from_buffer();
+ if (!ok)
+ return false;
+ }
+ }
+ if (m_mode & O_RDONLY) {
+ // When open for reading, just drop the buffered data.
+ size_t had_buffered = m_buffer.buffered_size();
+ m_buffer.drop();
+ // Attempt to reset the underlying file position to what the user
+ // expects.
+ int rc = lseek(m_fd, -had_buffered, SEEK_CUR);
+ if (rc < 0) {
+ if (errno == ESPIPE) {
+ // We can't set offset on this file; oh well, the user will just
+ // have to cope.
+ errno = 0;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+ssize_t FILE::do_read(u8* data, size_t size)
+{
+ int nread = ::read(m_fd, data, size);
+
+ if (nread < 0) {
+ m_error = errno;
+ } else if (nread == 0) {
+ m_eof = true;
+ }
+ return nread;
+}
+
+ssize_t FILE::do_write(const u8* data, size_t size)
+{
+ int nwritten = ::write(m_fd, data, size);
+
+ if (nwritten < 0)
+ m_error = errno;
+ return nwritten;
+}
+
+bool FILE::read_into_buffer()
+{
+ m_buffer.realize(m_fd);
+
+ size_t available_size;
+ u8* data = m_buffer.begin_enqueue(available_size);
+ // If we want to read, the buffer must have some space!
+ ASSERT(available_size);
+
+ ssize_t nread = do_read(data, available_size);
+
+ if (nread <= 0)
+ return false;
+
+ m_buffer.did_enqueue(nread);
+ return true;
+}
+
+bool FILE::write_from_buffer()
+{
+ size_t size;
+ const u8* data = m_buffer.begin_dequeue(size);
+ // If we want to write, the buffer must have something in it!
+ ASSERT(size);
+
+ ssize_t nwritten = do_write(data, size);
+
+ if (nwritten < 0)
+ return false;
+
+ m_buffer.did_dequeue(nwritten);
+ return true;
+}
+
+size_t FILE::read(u8* data, size_t size)
+{
+ size_t total_read = 0;
+
+ while (size > 0) {
+ size_t actual_size;
+
+ if (m_buffer.may_use()) {
+ // Let's see if the buffer has something queued for us.
+ size_t queued_size;
+ const u8* queued_data = m_buffer.begin_dequeue(queued_size);
+ if (queued_size == 0) {
+ // Nothing buffered; we're going to have to read some.
+ bool read_some_more = read_into_buffer();
+ if (read_some_more) {
+ // Great, now try this again.
+ continue;
+ }
+ return total_read;
+ }
+ actual_size = min(size, queued_size);
+ memcpy(data, queued_data, actual_size);
+ m_buffer.did_dequeue(actual_size);
+ } else {
+ // Read directly into the user buffer.
+ ssize_t nread = do_read(data, size);
+ if (nread <= 0)
+ return total_read;
+ actual_size = nread;
+ }
+
+ total_read += actual_size;
+ data += actual_size;
+ size -= actual_size;
+ }
+
+ return total_read;
+}
+
+size_t FILE::write(const u8* data, size_t size)
+{
+ size_t total_written = 0;
+
+ while (size > 0) {
+ size_t actual_size;
+
+ if (m_buffer.may_use()) {
+ m_buffer.realize(m_fd);
+ // Try writing into the buffer.
+ size_t available_size;
+ u8* buffer_data = m_buffer.begin_enqueue(available_size);
+ if (available_size == 0) {
+ // There's no space in the buffer; we're going to free some.
+ bool freed_some_space = write_from_buffer();
+ if (freed_some_space) {
+ // Great, now try this again.
+ continue;
+ }
+ return total_written;
+ }
+ actual_size = min(size, available_size);
+ memcpy(buffer_data, data, actual_size);
+ m_buffer.did_enqueue(actual_size);
+ // See if we have to flush it.
+ if (m_buffer.mode() == _IOLBF) {
+ bool includes_newline = memchr(data, '\n', actual_size);
+ if (includes_newline)
+ flush();
+ }
+ } else {
+ // Write directly from the user buffer.
+ ssize_t nwritten = do_write(data, size);
+ if (nwritten < 0)
+ return total_written;
+ actual_size = nwritten;
+ }
+
+ total_written += actual_size;
+ data += actual_size;
+ size -= actual_size;
+ }
+
+ return total_written;
+}
+
+bool FILE::gets(u8* data, size_t size)
+{
+ // gets() is a lot like read(), but it is different enough in how it
+ // processes newlines and null-terminates the buffer that it deserves a
+ // separate implementation.
+ size_t total_read = 0;
+
+ if (size == 0)
+ return false;
+
+ while (size > 1) {
+ if (m_buffer.may_use()) {
+ // Let's see if the buffer has something queued for us.
+ size_t queued_size;
+ const u8* queued_data = m_buffer.begin_dequeue(queued_size);
+ if (queued_size == 0) {
+ // Nothing buffered; we're going to have to read some.
+ bool read_some_more = read_into_buffer();
+ if (read_some_more) {
+ // Great, now try this again.
+ continue;
+ }
+ *data = 0;
+ return total_read > 0;
+ }
+ size_t actual_size = min(size - 1, queued_size);
+ u8* newline = reinterpret_cast<u8*>(memchr(queued_data, '\n', actual_size));
+ if (newline)
+ actual_size = newline - queued_data + 1;
+ memcpy(data, queued_data, actual_size);
+ m_buffer.did_dequeue(actual_size);
+ total_read += actual_size;
+ data += actual_size;
+ size -= actual_size;
+ if (newline)
+ break;
+ } else {
+ // Sadly, we have to actually read these characters one by one.
+ u8 byte;
+ ssize_t nread = do_read(&byte, 1);
+ if (nread <= 0) {
+ *data = 0;
+ return total_read > 0;
+ }
+ ASSERT(nread == 1);
+ *data = byte;
+ total_read++;
+ data++;
+ size--;
+ if (byte == '\n')
+ break;
+ }
+ }
+
+ *data = 0;
+ return total_read > 0;
+}
+
+int FILE::seek(off_t offset, int whence)
+{
+ bool ok = flush();
+ if (!ok)
+ return -1;
+
+ off_t off = lseek(m_fd, offset, whence);
+ if (off < 0) {
+ // Note: do not set m_error.
+ return off;
+ }
+
+ m_eof = false;
+ return 0;
+}
+
+off_t FILE::tell()
+{
+ bool ok = flush();
+ if (!ok)
+ return -1;
+
+ return lseek(m_fd, 0, SEEK_CUR);
+}
+
+void FILE::reopen(int fd, int mode)
+{
+ // Dr. POSIX says: "Failure to flush or close the file descriptor
+ // successfully shall be ignored"
+ // and so we ignore any failures these two might have.
+ flush();
+ close();
+
+ // Just in case flush() and close() didn't drop the buffer.
+ m_buffer.drop();
+
+ m_fd = fd;
+ m_mode = mode;
+ m_error = 0;
+ m_eof = false;
+}
+
+FILE::Buffer::~Buffer()
+{
+ if (m_data_is_malloced)
+ free(m_data);
+}
+
+void FILE::Buffer::realize(int fd)
+{
+ if (m_mode == -1)
+ m_mode = isatty(fd) ? _IOLBF : _IOFBF;
+
+ if (m_mode != _IONBF && m_data == nullptr) {
+ m_data = reinterpret_cast<u8*>(malloc(m_capacity));
+ m_data_is_malloced = true;
+ }
+}
+
+void FILE::Buffer::setbuf(u8* data, int mode, size_t size)
+{
+ drop();
+ m_mode = mode;
+ if (data != nullptr) {
+ m_data = data;
+ m_capacity = size;
+ }
+}
+
+void FILE::Buffer::drop()
+{
+ if (m_data_is_malloced) {
+ free(m_data);
+ m_data = nullptr;
+ m_data_is_malloced = false;
+ }
+ m_begin = m_end = 0;
+ m_empty = true;
+ m_ungotten = false;
+}
+
+size_t FILE::Buffer::buffered_size() const
+{
+ // Note: does not include the ungetc() buffer.
+
+ if (m_empty)
+ return 0;
+
+ if (m_begin < m_end)
+ return m_end - m_begin;
+ else
+ return m_capacity - (m_begin - m_end);
+}
+
+const u8* FILE::Buffer::begin_dequeue(size_t& available_size) const
+{
+ if (m_ungotten) {
+ available_size = 1;
+ return &m_unget_buffer;
+ }
+
+ if (m_empty) {
+ available_size = 0;
+ return nullptr;
+ }
+
+ if (m_begin < m_end)
+ available_size = m_end - m_begin;
+ else
+ available_size = m_capacity - m_begin;
+
+ return &m_data[m_begin];
+}
+
+void FILE::Buffer::did_dequeue(size_t actual_size)
+{
+ ASSERT(actual_size > 0);
+
+ if (m_ungotten) {
+ ASSERT(actual_size == 1);
+ m_ungotten = false;
+ return;
+ }
+
+ m_begin += actual_size;
+
+ ASSERT(m_begin <= m_capacity);
+ if (m_begin == m_capacity) {
+ // Wrap around.
+ m_begin = 0;
+ }
+
+ if (m_begin == m_end) {
+ m_empty = true;
+ // As an optimization, move both pointers to the beginning of the
+ // buffer, so that more consecutive space is available next time.
+ m_begin = m_end = 0;
+ }
+}
+
+u8* FILE::Buffer::begin_enqueue(size_t& available_size) const
+{
+ ASSERT(m_data != nullptr);
+
+ if (m_begin < m_end || m_empty)
+ available_size = m_capacity - m_end;
+ else
+ available_size = m_begin - m_end;
+
+ return const_cast<u8*>(&m_data[m_end]);
+}
+
+void FILE::Buffer::did_enqueue(size_t actual_size)
+{
+ ASSERT(m_data != nullptr);
+ ASSERT(actual_size > 0);
+
+ m_end += actual_size;
+
+ ASSERT(m_end <= m_capacity);
+ if (m_end == m_capacity) {
+ // Wrap around.
+ m_end = 0;
+ }
+
+ m_empty = false;
+}
+
+bool FILE::Buffer::enqueue_front(u8 byte)
+{
+ if (m_ungotten) {
+ // Sorry, the place is already taken!
+ return false;
+ }
+
+ m_ungotten = true;
+ m_unget_buffer = byte;
+ return true;
+}
+
+extern "C" {
+
+static u8 default_streams[3][sizeof(FILE)];
+FILE* stdin = reinterpret_cast<FILE*>(&default_streams[0]);
+FILE* stdout = reinterpret_cast<FILE*>(&default_streams[1]);
+FILE* stderr = reinterpret_cast<FILE*>(&default_streams[2]);
+
+void __stdio_init()
+{
+ new (stdin) FILE(0, O_RDONLY);
+ new (stdout) FILE(1, O_WRONLY);
+ new (stderr) FILE(2, O_WRONLY);
+ stderr->setbuf(nullptr, _IONBF, 0);
+ __stdio_is_initialized = true;
+}
+
+int setvbuf(FILE* stream, char* buf, int mode, size_t size)
+{
+ ASSERT(stream);
+ if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) {
+ errno = EINVAL;
+ return -1;
+ }
+ stream->setbuf(reinterpret_cast<u8*>(buf), mode, size);
+ return 0;
+}
+
+void setbuf(FILE* stream, char* buf)
+{
+ setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
+
+void setlinebuf(FILE* stream)
+{
+ setvbuf(stream, nullptr, _IOLBF, 0);
+}
+
+int fileno(FILE* stream)
+{
+ ASSERT(stream);
+ return stream->fileno();
+}
+
+int feof(FILE* stream)
+{
+ ASSERT(stream);
+ return stream->eof();
+}
+
+int fflush(FILE* stream)
+{
+ if (!stream) {
+ dbgln("FIXME: fflush(nullptr) should flush all open streams");
+ return 0;
+ }
+ return stream->flush() ? 0 : EOF;
+}
+
+char* fgets(char* buffer, int size, FILE* stream)
+{
+ ASSERT(stream);
+ bool ok = stream->gets(reinterpret_cast<u8*>(buffer), size);
+ return ok ? buffer : nullptr;
+}
+
+int fgetc(FILE* stream)
+{
+ ASSERT(stream);
+ char ch;
+ size_t nread = fread(&ch, sizeof(char), 1, stream);
+ if (nread == 1)
+ return ch;
+ return EOF;
+}
+
+int getc(FILE* stream)
+{
+ return fgetc(stream);
+}
+
+int getc_unlocked(FILE* stream)
+{
+ return fgetc(stream);
+}
+
+int getchar()
+{
+ return getc(stdin);
+}
+
+ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* stream)
+{
+ if (!lineptr || !n) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*lineptr == nullptr || *n == 0) {
+ *n = BUFSIZ;
+ if ((*lineptr = static_cast<char*>(malloc(*n))) == nullptr) {
+ return -1;
+ }
+ }
+
+ char* ptr;
+ char* eptr;
+ for (ptr = *lineptr, eptr = *lineptr + *n;;) {
+ int c = fgetc(stream);
+ if (c == -1) {
+ if (feof(stream)) {
+ *ptr = '\0';
+ return ptr == *lineptr ? -1 : ptr - *lineptr;
+ } else {
+ return -1;
+ }
+ }
+ *ptr++ = c;
+ if (c == delim) {
+ *ptr = '\0';
+ return ptr - *lineptr;
+ }
+ if (ptr + 2 >= eptr) {
+ char* nbuf;
+ size_t nbuf_sz = *n * 2;
+ ssize_t d = ptr - *lineptr;
+ if ((nbuf = static_cast<char*>(realloc(*lineptr, nbuf_sz))) == nullptr) {
+ return -1;
+ }
+ *lineptr = nbuf;
+ *n = nbuf_sz;
+ eptr = nbuf + nbuf_sz;
+ ptr = nbuf + d;
+ }
+ }
+}
+
+ssize_t getline(char** lineptr, size_t* n, FILE* stream)
+{
+ return getdelim(lineptr, n, '\n', stream);
+}
+
+int ungetc(int c, FILE* stream)
+{
+ ASSERT(stream);
+ bool ok = stream->ungetc(c);
+ return ok ? c : EOF;
+}
+
+int fputc(int ch, FILE* stream)
+{
+ ASSERT(stream);
+ u8 byte = ch;
+ size_t nwritten = stream->write(&byte, 1);
+ if (nwritten == 0)
+ return EOF;
+ ASSERT(nwritten == 1);
+ return byte;
+}
+
+int putc(int ch, FILE* stream)
+{
+ return fputc(ch, stream);
+}
+
+int putchar(int ch)
+{
+ return putc(ch, stdout);
+}
+
+int fputs(const char* s, FILE* stream)
+{
+ ASSERT(stream);
+ size_t len = strlen(s);
+ size_t nwritten = stream->write(reinterpret_cast<const u8*>(s), len);
+ if (nwritten < len)
+ return EOF;
+ return 1;
+}
+
+int puts(const char* s)
+{
+ int rc = fputs(s, stdout);
+ if (rc == EOF)
+ return EOF;
+ return fputc('\n', stdout);
+}
+
+void clearerr(FILE* stream)
+{
+ ASSERT(stream);
+ stream->clear_err();
+}
+
+int ferror(FILE* stream)
+{
+ ASSERT(stream);
+ return stream->error();
+}
+
+size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
+{
+ ASSERT(stream);
+ ASSERT(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
+
+ size_t nread = stream->read(reinterpret_cast<u8*>(ptr), size * nmemb);
+ return nread / size;
+}
+
+size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
+{
+ ASSERT(stream);
+ ASSERT(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
+
+ size_t nwritten = stream->write(reinterpret_cast<const u8*>(ptr), size * nmemb);
+ return nwritten / size;
+}
+
+int fseek(FILE* stream, long offset, int whence)
+{
+ ASSERT(stream);
+ return stream->seek(offset, whence);
+}
+
+int fseeko(FILE* stream, off_t offset, int whence)
+{
+ ASSERT(stream);
+ return stream->seek(offset, whence);
+}
+
+long ftell(FILE* stream)
+{
+ ASSERT(stream);
+ return stream->tell();
+}
+
+off_t ftello(FILE* stream)
+{
+ ASSERT(stream);
+ return stream->tell();
+}
+
+int fgetpos(FILE* stream, fpos_t* pos)
+{
+ ASSERT(stream);
+ ASSERT(pos);
+
+ off_t val = stream->tell();
+ if (val == -1L)
+ return 1;
+
+ *pos = val;
+ return 0;
+}
+
+int fsetpos(FILE* stream, const fpos_t* pos)
+{
+ ASSERT(stream);
+ ASSERT(pos);
+
+ return stream->seek(*pos, SEEK_SET);
+}
+
+void rewind(FILE* stream)
+{
+ ASSERT(stream);
+ int rc = stream->seek(0, SEEK_SET);
+ ASSERT(rc == 0);
+}
+
+int vdbgprintf(const char* fmt, va_list ap)
+{
+ return printf_internal([](char*&, char ch) { dbgputch(ch); }, nullptr, fmt, ap);
+}
+
+int dbgprintf(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = printf_internal([](char*&, char ch) { dbgputch(ch); }, nullptr, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+ALWAYS_INLINE void stdout_putch(char*&, char ch)
+{
+ putchar(ch);
+}
+
+static FILE* __current_stream = nullptr;
+ALWAYS_INLINE static void stream_putch(char*&, char ch)
+{
+ fputc(ch, __current_stream);
+}
+
+int vfprintf(FILE* stream, const char* fmt, va_list ap)
+{
+ __current_stream = stream;
+ return printf_internal(stream_putch, nullptr, fmt, ap);
+}
+
+int fprintf(FILE* stream, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = vfprintf(stream, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int vprintf(const char* fmt, va_list ap)
+{
+ return printf_internal(stdout_putch, nullptr, fmt, ap);
+}
+
+int printf(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = vprintf(fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+static void buffer_putch(char*& bufptr, char ch)
+{
+ *bufptr++ = ch;
+}
+
+int vsprintf(char* buffer, const char* fmt, va_list ap)
+{
+ int ret = printf_internal(buffer_putch, buffer, fmt, ap);
+ buffer[ret] = '\0';
+ return ret;
+}
+
+int sprintf(char* buffer, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+static size_t __vsnprintf_space_remaining;
+ALWAYS_INLINE void sized_buffer_putch(char*& bufptr, char ch)
+{
+ if (__vsnprintf_space_remaining) {
+ *bufptr++ = ch;
+ --__vsnprintf_space_remaining;
+ }
+}
+
+int vsnprintf(char* buffer, size_t size, const char* fmt, va_list ap)
+{
+ if (size) {
+ __vsnprintf_space_remaining = size - 1;
+ } else {
+ __vsnprintf_space_remaining = 0;
+ }
+ int ret = printf_internal(sized_buffer_putch, buffer, fmt, ap);
+ if (__vsnprintf_space_remaining) {
+ buffer[ret] = '\0';
+ } else if (size > 0) {
+ buffer[size - 1] = '\0';
+ }
+ return ret;
+}
+
+int snprintf(char* buffer, size_t size, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = vsnprintf(buffer, size, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+void perror(const char* s)
+{
+ int saved_errno = errno;
+ dbgln("perror(): {}: {}", s, strerror(saved_errno));
+ warnln("{}: {}", s, strerror(saved_errno));
+}
+
+static int parse_mode(const char* mode)
+{
+ int flags = 0;
+
+ // NOTE: rt is a non-standard mode which opens a file for read, explicitly
+ // specifying that it's a text file
+ for (auto* ptr = mode; *ptr; ++ptr) {
+ switch (*ptr) {
+ case 'r':
+ flags |= O_RDONLY;
+ break;
+ case 'w':
+ flags |= O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case 'a':
+ flags |= O_WRONLY | O_APPEND | O_CREAT;
+ break;
+ case '+':
+ flags |= O_RDWR;
+ break;
+ case 'e':
+ flags |= O_CLOEXEC;
+ break;
+ case 'b':
+ // Ok...
+ break;
+ case 't':
+ // Ok...
+ break;
+ default:
+ dbgln("Potentially unsupported fopen mode _{}_ (because of '{}')", mode, *ptr);
+ }
+ }
+
+ return flags;
+}
+
+FILE* fopen(const char* pathname, const char* mode)
+{
+ int flags = parse_mode(mode);
+ int fd = open(pathname, flags, 0666);
+ if (fd < 0)
+ return nullptr;
+ return FILE::create(fd, flags);
+}
+
+FILE* freopen(const char* pathname, const char* mode, FILE* stream)
+{
+ ASSERT(stream);
+ if (!pathname) {
+ // FIXME: Someone should probably implement this path.
+ TODO();
+ }
+
+ int flags = parse_mode(mode);
+ int fd = open(pathname, flags, 0666);
+ if (fd < 0)
+ return nullptr;
+
+ stream->reopen(fd, flags);
+ return stream;
+}
+
+FILE* fdopen(int fd, const char* mode)
+{
+ int flags = parse_mode(mode);
+ // FIXME: Verify that the mode matches how fd is already open.
+ if (fd < 0)
+ return nullptr;
+ return FILE::create(fd, flags);
+}
+
+static inline bool is_default_stream(FILE* stream)
+{
+ return stream == stdin || stream == stdout || stream == stderr;
+}
+
+int fclose(FILE* stream)
+{
+ ASSERT(stream);
+ bool ok = stream->close();
+ ScopedValueRollback errno_restorer(errno);
+
+ stream->~FILE();
+ if (!is_default_stream(stream))
+ free(stream);
+
+ return ok ? 0 : EOF;
+}
+
+int rename(const char* oldpath, const char* newpath)
+{
+ if (!oldpath || !newpath) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_rename_params params { { oldpath, strlen(oldpath) }, { newpath, strlen(newpath) } };
+ int rc = syscall(SC_rename, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+void dbgputch(char ch)
+{
+ syscall(SC_dbgputch, ch);
+}
+
+int dbgputstr(const char* characters, ssize_t length)
+{
+ int rc = syscall(SC_dbgputstr, characters, length);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+char* tmpnam(char*)
+{
+ ASSERT_NOT_REACHED();
+}
+
+FILE* popen(const char* command, const char* type)
+{
+ if (!type || (*type != 'r' && *type != 'w')) {
+ errno = EINVAL;
+ return nullptr;
+ }
+
+ int pipe_fds[2];
+
+ int rc = pipe(pipe_fds);
+ if (rc < 0) {
+ ScopedValueRollback rollback(errno);
+ perror("pipe");
+ return nullptr;
+ }
+
+ pid_t child_pid = fork();
+ if (child_pid < 0) {
+ ScopedValueRollback rollback(errno);
+ perror("fork");
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ return nullptr;
+ } else if (child_pid == 0) {
+ if (*type == 'r') {
+ int rc = dup2(pipe_fds[1], STDOUT_FILENO);
+ if (rc < 0) {
+ perror("dup2");
+ exit(1);
+ }
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ } else if (*type == 'w') {
+ int rc = dup2(pipe_fds[0], STDIN_FILENO);
+ if (rc < 0) {
+ perror("dup2");
+ exit(1);
+ }
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ }
+
+ int rc = execl("/bin/sh", "sh", "-c", command, nullptr);
+ if (rc < 0)
+ perror("execl");
+ exit(1);
+ }
+
+ FILE* file = nullptr;
+ if (*type == 'r') {
+ file = FILE::create(pipe_fds[0], O_RDONLY);
+ close(pipe_fds[1]);
+ } else if (*type == 'w') {
+ file = FILE::create(pipe_fds[1], O_WRONLY);
+ close(pipe_fds[0]);
+ }
+
+ file->set_popen_child(child_pid);
+ return file;
+}
+
+int pclose(FILE* stream)
+{
+ ASSERT(stream);
+ ASSERT(stream->popen_child() != 0);
+
+ int wstatus = 0;
+ int rc = waitpid(stream->popen_child(), &wstatus, 0);
+ if (rc < 0)
+ return rc;
+
+ return wstatus;
+}
+
+int remove(const char* pathname)
+{
+ int rc = unlink(pathname);
+ if (rc < 0 && errno != EISDIR)
+ return -1;
+ return rmdir(pathname);
+}
+
+int scanf(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int count = vfscanf(stdin, fmt, ap);
+ va_end(ap);
+ return count;
+}
+
+int fscanf(FILE* stream, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int count = vfscanf(stream, fmt, ap);
+ va_end(ap);
+ return count;
+}
+
+int sscanf(const char* buffer, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int count = vsscanf(buffer, fmt, ap);
+ va_end(ap);
+ return count;
+}
+
+int vfscanf(FILE* stream, const char* fmt, va_list ap)
+{
+ char buffer[BUFSIZ];
+ if (!fgets(buffer, sizeof(buffer) - 1, stream))
+ return -1;
+ return vsscanf(buffer, fmt, ap);
+}
+
+void flockfile([[maybe_unused]] FILE* filehandle)
+{
+ dbgprintf("FIXME: Implement flockfile()\n");
+}
+
+void funlockfile([[maybe_unused]] FILE* filehandle)
+{
+ dbgprintf("FIXME: Implement funlockfile()\n");
+}
+
+FILE* tmpfile()
+{
+ char tmp_path[] = "/tmp/XXXXXX";
+ if (__generate_unique_filename(tmp_path) < 0)
+ return nullptr;
+
+ int fd = open(tmp_path, O_CREAT | O_EXCL | O_RDWR, S_IWUSR | S_IRUSR);
+ if (fd < 0)
+ return nullptr;
+
+ // FIXME: instead of using this hack, implement with O_TMPFILE or similar
+ unlink(tmp_path);
+
+ return fdopen(fd, "rw");
+}
+}
diff --git a/Userland/Libraries/LibC/stdio.h b/Userland/Libraries/LibC/stdio.h
new file mode 100644
index 0000000000..56d0feb642
--- /dev/null
+++ b/Userland/Libraries/LibC/stdio.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define _STDIO_H // Make GMP believe we exist.
+
+#include <bits/FILE.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#define FILENAME_MAX 1024
+
+__BEGIN_DECLS
+#ifndef EOF
+# define EOF (-1)
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#define _IOFBF 0
+#define _IOLBF 1
+#define _IONBF 2
+
+#define L_tmpnam 256
+
+extern FILE* stdin;
+extern FILE* stdout;
+extern FILE* stderr;
+
+typedef off_t fpos_t;
+
+int fseek(FILE*, long offset, int whence);
+int fseeko(FILE*, off_t offset, int whence);
+int fgetpos(FILE*, fpos_t*);
+int fsetpos(FILE*, const fpos_t*);
+long ftell(FILE*);
+off_t ftello(FILE*);
+char* fgets(char* buffer, int size, FILE*);
+int fputc(int ch, FILE*);
+int fileno(FILE*);
+int fgetc(FILE*);
+int getc(FILE*);
+int getc_unlocked(FILE* stream);
+int getchar();
+ssize_t getdelim(char**, size_t*, int, FILE*);
+ssize_t getline(char**, size_t*, FILE*);
+int ungetc(int c, FILE*);
+int remove(const char* pathname);
+FILE* fdopen(int fd, const char* mode);
+FILE* fopen(const char* pathname, const char* mode);
+FILE* freopen(const char* pathname, const char* mode, FILE*);
+void flockfile(FILE* filehandle);
+void funlockfile(FILE* filehandle);
+int fclose(FILE*);
+void rewind(FILE*);
+void clearerr(FILE*);
+int ferror(FILE*);
+int feof(FILE*);
+int fflush(FILE*);
+size_t fread(void* ptr, size_t size, size_t nmemb, FILE*);
+size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE*);
+int vprintf(const char* fmt, va_list) __attribute__((format(printf, 1, 0)));
+int vfprintf(FILE*, const char* fmt, va_list) __attribute__((format(printf, 2, 0)));
+int vsprintf(char* buffer, const char* fmt, va_list) __attribute__((format(printf, 2, 0)));
+int vsnprintf(char* buffer, size_t, const char* fmt, va_list) __attribute__((format(printf, 3, 0)));
+int fprintf(FILE*, const char* fmt, ...) __attribute__((format(printf, 2, 3)));
+int printf(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
+int dbgprintf(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
+void dbgputch(char);
+int dbgputstr(const char*, ssize_t);
+int sprintf(char* buffer, const char* fmt, ...) __attribute__((format(printf, 2, 3)));
+int snprintf(char* buffer, size_t, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
+int putchar(int ch);
+int putc(int ch, FILE*);
+int puts(const char*);
+int fputs(const char*, FILE*);
+void perror(const char*);
+int scanf(const char* fmt, ...) __attribute__((format(scanf, 1, 2)));
+int sscanf(const char* str, const char* fmt, ...) __attribute__((format(scanf, 2, 3)));
+int fscanf(FILE*, const char* fmt, ...) __attribute__((format(scanf, 2, 3)));
+int vfscanf(FILE*, const char*, va_list) __attribute__((format(scanf, 2, 0)));
+int vsscanf(const char*, const char*, va_list) __attribute__((format(scanf, 2, 0)));
+int setvbuf(FILE*, char* buf, int mode, size_t);
+void setbuf(FILE*, char* buf);
+void setlinebuf(FILE*);
+int rename(const char* oldpath, const char* newpath);
+FILE* tmpfile();
+char* tmpnam(char*);
+FILE* popen(const char* command, const char* type);
+int pclose(FILE*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/stdlib.cpp b/Userland/Libraries/LibC/stdlib.cpp
new file mode 100644
index 0000000000..07f7199bcf
--- /dev/null
+++ b/Userland/Libraries/LibC/stdlib.cpp
@@ -0,0 +1,1083 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <AK/HashMap.h>
+#include <AK/Noncopyable.h>
+#include <AK/StdLibExtras.h>
+#include <AK/Types.h>
+#include <AK/Utf8View.h>
+#include <Kernel/API/Syscall.h>
+#include <alloca.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/internals.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static void strtons(const char* str, char** endptr)
+{
+ assert(endptr);
+ char* ptr = const_cast<char*>(str);
+ while (isspace(*ptr)) {
+ ptr += 1;
+ }
+ *endptr = ptr;
+}
+
+enum Sign {
+ Negative,
+ Positive,
+};
+
+static Sign strtosign(const char* str, char** endptr)
+{
+ assert(endptr);
+ if (*str == '+') {
+ *endptr = const_cast<char*>(str + 1);
+ return Sign::Positive;
+ } else if (*str == '-') {
+ *endptr = const_cast<char*>(str + 1);
+ return Sign::Negative;
+ } else {
+ *endptr = const_cast<char*>(str);
+ return Sign::Positive;
+ }
+}
+
+enum DigitConsumeDecision {
+ Consumed,
+ PosOverflow,
+ NegOverflow,
+ Invalid,
+};
+
+template<typename T, T min_value, T max_value>
+class NumParser {
+ AK_MAKE_NONMOVABLE(NumParser);
+
+public:
+ NumParser(Sign sign, int base)
+ : m_base(base)
+ , m_num(0)
+ , m_sign(sign)
+ {
+ m_cutoff = positive() ? (max_value / base) : (min_value / base);
+ m_max_digit_after_cutoff = positive() ? (max_value % base) : (min_value % base);
+ }
+
+ int parse_digit(char ch)
+ {
+ int digit;
+ if (isdigit(ch))
+ digit = ch - '0';
+ else if (islower(ch))
+ digit = ch - ('a' - 10);
+ else if (isupper(ch))
+ digit = ch - ('A' - 10);
+ else
+ return -1;
+
+ if (static_cast<T>(digit) >= m_base)
+ return -1;
+
+ return digit;
+ }
+
+ DigitConsumeDecision consume(char ch)
+ {
+ int digit = parse_digit(ch);
+ if (digit == -1)
+ return DigitConsumeDecision::Invalid;
+
+ if (!can_append_digit(digit)) {
+ if (m_sign != Sign::Negative) {
+ return DigitConsumeDecision::PosOverflow;
+ } else {
+ return DigitConsumeDecision::NegOverflow;
+ }
+ }
+
+ m_num *= m_base;
+ m_num += positive() ? digit : -digit;
+
+ return DigitConsumeDecision::Consumed;
+ }
+
+ T number() const { return m_num; };
+
+private:
+ bool can_append_digit(int digit)
+ {
+ const bool is_below_cutoff = positive() ? (m_num < m_cutoff) : (m_num > m_cutoff);
+
+ if (is_below_cutoff) {
+ return true;
+ } else {
+ return m_num == m_cutoff && digit < m_max_digit_after_cutoff;
+ }
+ }
+
+ bool positive() const
+ {
+ return m_sign != Sign::Negative;
+ }
+
+ const T m_base;
+ T m_num;
+ T m_cutoff;
+ int m_max_digit_after_cutoff;
+ Sign m_sign;
+};
+
+typedef NumParser<int, INT_MIN, INT_MAX> IntParser;
+typedef NumParser<long long, LONG_LONG_MIN, LONG_LONG_MAX> LongLongParser;
+typedef NumParser<unsigned long long, 0ULL, ULONG_LONG_MAX> ULongLongParser;
+
+static bool is_either(char* str, int offset, char lower, char upper)
+{
+ char ch = *(str + offset);
+ return ch == lower || ch == upper;
+}
+
+__attribute__((warn_unused_result)) int __generate_unique_filename(char* pattern)
+{
+ size_t length = strlen(pattern);
+
+ if (length < 6 || memcmp(pattern + length - 6, "XXXXXX", 6)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ size_t start = length - 6;
+
+ static constexpr char random_characters[] = "abcdefghijklmnopqrstuvwxyz0123456789";
+
+ for (int attempt = 0; attempt < 100; ++attempt) {
+ for (int i = 0; i < 6; ++i)
+ pattern[start + i] = random_characters[(arc4random() % (sizeof(random_characters) - 1))];
+ struct stat st;
+ int rc = lstat(pattern, &st);
+ if (rc < 0 && errno == ENOENT)
+ return 0;
+ }
+ errno = EEXIST;
+ return -1;
+}
+
+extern "C" {
+
+void exit(int status)
+{
+ __cxa_finalize(nullptr);
+
+ if (getenv("LIBC_DUMP_MALLOC_STATS"))
+ serenity_dump_malloc_stats();
+
+ extern void _fini();
+ _fini();
+ fflush(stdout);
+ fflush(stderr);
+ _exit(status);
+}
+
+static void __atexit_to_cxa_atexit(void* handler)
+{
+ reinterpret_cast<void (*)()>(handler)();
+}
+
+int atexit(void (*handler)())
+{
+ return __cxa_atexit(__atexit_to_cxa_atexit, (void*)handler, nullptr);
+}
+
+void abort()
+{
+ // For starters, send ourselves a SIGABRT.
+ raise(SIGABRT);
+ // If that didn't kill us, try harder.
+ raise(SIGKILL);
+ _exit(127);
+}
+
+static HashTable<const char*> s_malloced_environment_variables;
+
+static void free_environment_variable_if_needed(const char* var)
+{
+ if (!s_malloced_environment_variables.contains(var))
+ return;
+ free(const_cast<char*>(var));
+ s_malloced_environment_variables.remove(var);
+}
+
+char* getenv(const char* name)
+{
+ size_t vl = strlen(name);
+ for (size_t i = 0; environ[i]; ++i) {
+ const char* decl = environ[i];
+ char* eq = strchr(decl, '=');
+ if (!eq)
+ continue;
+ size_t varLength = eq - decl;
+ if (vl != varLength)
+ continue;
+ if (strncmp(decl, name, varLength) == 0) {
+ return eq + 1;
+ }
+ }
+ return nullptr;
+}
+
+int unsetenv(const char* name)
+{
+ auto new_var_len = strlen(name);
+ size_t environ_size = 0;
+ int skip = -1;
+
+ for (; environ[environ_size]; ++environ_size) {
+ char* old_var = environ[environ_size];
+ char* old_eq = strchr(old_var, '=');
+ ASSERT(old_eq);
+ size_t old_var_len = old_eq - old_var;
+
+ if (new_var_len != old_var_len)
+ continue; // can't match
+
+ if (strncmp(name, old_var, new_var_len) == 0)
+ skip = environ_size;
+ }
+
+ if (skip == -1)
+ return 0; // not found: no failure.
+
+ // Shuffle the existing array down by one.
+ memmove(&environ[skip], &environ[skip + 1], ((environ_size - 1) - skip) * sizeof(environ[0]));
+ environ[environ_size - 1] = nullptr;
+
+ free_environment_variable_if_needed(name);
+ return 0;
+}
+
+int clearenv()
+{
+ size_t environ_size = 0;
+ for (; environ[environ_size]; ++environ_size) {
+ environ[environ_size] = NULL;
+ }
+ *environ = NULL;
+ return 0;
+}
+
+int setenv(const char* name, const char* value, int overwrite)
+{
+ if (!overwrite && getenv(name))
+ return 0;
+ auto length = strlen(name) + strlen(value) + 2;
+ auto* var = (char*)malloc(length);
+ snprintf(var, length, "%s=%s", name, value);
+ s_malloced_environment_variables.set(var);
+ return putenv(var);
+}
+
+int putenv(char* new_var)
+{
+ char* new_eq = strchr(new_var, '=');
+
+ if (!new_eq)
+ return unsetenv(new_var);
+
+ auto new_var_len = new_eq - new_var;
+ int environ_size = 0;
+ for (; environ[environ_size]; ++environ_size) {
+ char* old_var = environ[environ_size];
+ char* old_eq = strchr(old_var, '=');
+ ASSERT(old_eq);
+ auto old_var_len = old_eq - old_var;
+
+ if (new_var_len != old_var_len)
+ continue; // can't match
+
+ if (strncmp(new_var, old_var, new_var_len) == 0) {
+ free_environment_variable_if_needed(old_var);
+ environ[environ_size] = new_var;
+ return 0;
+ }
+ }
+
+ // At this point, we need to append the new var.
+ // 2 here: one for the new var, one for the sentinel value.
+ char** new_environ = (char**)malloc((environ_size + 2) * sizeof(char*));
+ if (new_environ == nullptr) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (int i = 0; environ[i]; ++i) {
+ new_environ[i] = environ[i];
+ }
+
+ new_environ[environ_size] = new_var;
+ new_environ[environ_size + 1] = nullptr;
+
+ // swap new and old
+ // note that the initial environ is not heap allocated!
+ extern bool __environ_is_malloced;
+ if (__environ_is_malloced)
+ free(environ);
+ __environ_is_malloced = true;
+ environ = new_environ;
+ return 0;
+}
+
+double strtod(const char* str, char** endptr)
+{
+ // Parse spaces, sign, and base
+ char* parse_ptr = const_cast<char*>(str);
+ strtons(parse_ptr, &parse_ptr);
+ const Sign sign = strtosign(parse_ptr, &parse_ptr);
+
+ // Parse inf/nan, if applicable.
+ if (is_either(parse_ptr, 0, 'i', 'I')) {
+ if (is_either(parse_ptr, 1, 'n', 'N')) {
+ if (is_either(parse_ptr, 2, 'f', 'F')) {
+ parse_ptr += 3;
+ if (is_either(parse_ptr, 0, 'i', 'I')) {
+ if (is_either(parse_ptr, 1, 'n', 'N')) {
+ if (is_either(parse_ptr, 2, 'i', 'I')) {
+ if (is_either(parse_ptr, 3, 't', 'T')) {
+ if (is_either(parse_ptr, 4, 'y', 'Y')) {
+ parse_ptr += 5;
+ }
+ }
+ }
+ }
+ }
+ if (endptr)
+ *endptr = parse_ptr;
+ // Don't set errno to ERANGE here:
+ // The caller may want to distinguish between "input is
+ // literal infinity" and "input is not literal infinity
+ // but did not fit into double".
+ if (sign != Sign::Negative) {
+ return __builtin_huge_val();
+ } else {
+ return -__builtin_huge_val();
+ }
+ }
+ }
+ }
+ if (is_either(parse_ptr, 0, 'n', 'N')) {
+ if (is_either(parse_ptr, 1, 'a', 'A')) {
+ if (is_either(parse_ptr, 2, 'n', 'N')) {
+ if (endptr)
+ *endptr = parse_ptr + 3;
+ errno = ERANGE;
+ if (sign != Sign::Negative) {
+ return __builtin_nan("");
+ } else {
+ return -__builtin_nan("");
+ }
+ }
+ }
+ }
+
+ // Parse base
+ char exponent_lower;
+ char exponent_upper;
+ int base = 10;
+ if (*parse_ptr == '0') {
+ const char base_ch = *(parse_ptr + 1);
+ if (base_ch == 'x' || base_ch == 'X') {
+ base = 16;
+ parse_ptr += 2;
+ }
+ }
+
+ if (base == 10) {
+ exponent_lower = 'e';
+ exponent_upper = 'E';
+ } else {
+ exponent_lower = 'p';
+ exponent_upper = 'P';
+ }
+
+ // Parse "digits", possibly keeping track of the exponent offset.
+ // We parse the most significant digits and the position in the
+ // base-`base` representation separately. This allows us to handle
+ // numbers like `0.0000000000000000000000000000000000001234` or
+ // `1234567890123456789012345678901234567890` with ease.
+ LongLongParser digits { sign, base };
+ bool digits_usable = false;
+ bool should_continue = true;
+ bool digits_overflow = false;
+ bool after_decimal = false;
+ int exponent = 0;
+ do {
+ if (!after_decimal && *parse_ptr == '.') {
+ after_decimal = true;
+ parse_ptr += 1;
+ continue;
+ }
+
+ bool is_a_digit;
+ if (digits_overflow) {
+ is_a_digit = digits.parse_digit(*parse_ptr) != -1;
+ } else {
+ DigitConsumeDecision decision = digits.consume(*parse_ptr);
+ switch (decision) {
+ case DigitConsumeDecision::Consumed:
+ is_a_digit = true;
+ // The very first actual digit must pass here:
+ digits_usable = true;
+ break;
+ case DigitConsumeDecision::PosOverflow:
+ case DigitConsumeDecision::NegOverflow:
+ is_a_digit = true;
+ digits_overflow = true;
+ break;
+ case DigitConsumeDecision::Invalid:
+ is_a_digit = false;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ if (is_a_digit) {
+ exponent -= after_decimal ? 1 : 0;
+ exponent += digits_overflow ? 1 : 0;
+ }
+
+ should_continue = is_a_digit;
+ parse_ptr += should_continue;
+ } while (should_continue);
+
+ if (!digits_usable) {
+ // No actual number value available.
+ if (endptr)
+ *endptr = const_cast<char*>(str);
+ return 0.0;
+ }
+
+ // Parse exponent.
+ // We already know the next character is not a digit in the current base,
+ // nor a valid decimal point. Check whether it's an exponent sign.
+ if (*parse_ptr == exponent_lower || *parse_ptr == exponent_upper) {
+ // Need to keep the old parse_ptr around, in case of rollback.
+ char* old_parse_ptr = parse_ptr;
+ parse_ptr += 1;
+
+ // Can't use atol or strtol here: Must accept excessive exponents,
+ // even exponents >64 bits.
+ Sign exponent_sign = strtosign(parse_ptr, &parse_ptr);
+ IntParser exponent_parser { exponent_sign, base };
+ bool exponent_usable = false;
+ bool exponent_overflow = false;
+ should_continue = true;
+ do {
+ bool is_a_digit;
+ if (exponent_overflow) {
+ is_a_digit = exponent_parser.parse_digit(*parse_ptr) != -1;
+ } else {
+ DigitConsumeDecision decision = exponent_parser.consume(*parse_ptr);
+ switch (decision) {
+ case DigitConsumeDecision::Consumed:
+ is_a_digit = true;
+ // The very first actual digit must pass here:
+ exponent_usable = true;
+ break;
+ case DigitConsumeDecision::PosOverflow:
+ case DigitConsumeDecision::NegOverflow:
+ is_a_digit = true;
+ exponent_overflow = true;
+ break;
+ case DigitConsumeDecision::Invalid:
+ is_a_digit = false;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ should_continue = is_a_digit;
+ parse_ptr += should_continue;
+ } while (should_continue);
+
+ if (!exponent_usable) {
+ parse_ptr = old_parse_ptr;
+ } else if (exponent_overflow) {
+ // Technically this is wrong. If someone gives us 5GB of digits,
+ // and then an exponent of -5_000_000_000, the resulting exponent
+ // should be around 0.
+ // However, I think it's safe to assume that we never have to deal
+ // with that many digits anyway.
+ if (sign != Sign::Negative) {
+ exponent = INT_MIN;
+ } else {
+ exponent = INT_MAX;
+ }
+ } else {
+ // Literal exponent is usable and fits in an int.
+ // However, `exponent + exponent_parser.number()` might overflow an int.
+ // This would result in the wrong sign of the exponent!
+ long long new_exponent = static_cast<long long>(exponent) + static_cast<long long>(exponent_parser.number());
+ if (new_exponent < INT_MIN) {
+ exponent = INT_MIN;
+ } else if (new_exponent > INT_MAX) {
+ exponent = INT_MAX;
+ } else {
+ exponent = static_cast<int>(new_exponent);
+ }
+ }
+ }
+
+ // Parsing finished. now we only have to compute the result.
+ if (endptr)
+ *endptr = const_cast<char*>(parse_ptr);
+
+ // If `digits` is zero, we don't even have to look at `exponent`.
+ if (digits.number() == 0) {
+ if (sign != Sign::Negative) {
+ return 0.0;
+ } else {
+ return -0.0;
+ }
+ }
+
+ // Deal with extreme exponents.
+ // The smallest normal is 2^-1022.
+ // The smallest denormal is 2^-1074.
+ // The largest number in `digits` is 2^63 - 1.
+ // Therefore, if "base^exponent" is smaller than 2^-(1074+63), the result is 0.0 anyway.
+ // This threshold is roughly 5.3566 * 10^-343.
+ // So if the resulting exponent is -344 or lower (closer to -inf),
+ // the result is 0.0 anyway.
+ // We only need to avoid false positives, so we can ignore base 16.
+ if (exponent <= -344) {
+ errno = ERANGE;
+ // Definitely can't be represented more precisely.
+ // I lied, sometimes the result is +0.0, and sometimes -0.0.
+ if (sign != Sign::Negative) {
+ return 0.0;
+ } else {
+ return -0.0;
+ }
+ }
+ // The largest normal is 2^+1024-eps.
+ // The smallest number in `digits` is 1.
+ // Therefore, if "base^exponent" is 2^+1024, the result is INF anyway.
+ // This threshold is roughly 1.7977 * 10^-308.
+ // So if the resulting exponent is +309 or higher,
+ // the result is INF anyway.
+ // We only need to avoid false positives, so we can ignore base 16.
+ if (exponent >= 309) {
+ errno = ERANGE;
+ // Definitely can't be represented more precisely.
+ // I lied, sometimes the result is +INF, and sometimes -INF.
+ if (sign != Sign::Negative) {
+ return __builtin_huge_val();
+ } else {
+ return -__builtin_huge_val();
+ }
+ }
+
+ // TODO: If `exponent` is large, this could be made faster.
+ double value = digits.number();
+ if (exponent < 0) {
+ exponent = -exponent;
+ for (int i = 0; i < exponent; ++i) {
+ value /= base;
+ }
+ if (value == -0.0 || value == +0.0) {
+ errno = ERANGE;
+ }
+ } else if (exponent > 0) {
+ for (int i = 0; i < exponent; ++i) {
+ value *= base;
+ }
+ if (value == -__builtin_huge_val() || value == +__builtin_huge_val()) {
+ errno = ERANGE;
+ }
+ }
+
+ return value;
+}
+
+long double strtold(const char* str, char** endptr)
+{
+ assert(sizeof(double) == sizeof(long double));
+ return strtod(str, endptr);
+}
+
+float strtof(const char* str, char** endptr)
+{
+ return strtod(str, endptr);
+}
+
+double atof(const char* str)
+{
+ return strtod(str, nullptr);
+}
+
+int atoi(const char* str)
+{
+ long value = strtol(str, nullptr, 10);
+ if (value > INT_MAX) {
+ return INT_MAX;
+ }
+ return value;
+}
+
+long atol(const char* str)
+{
+ return strtol(str, nullptr, 10);
+}
+
+long long atoll(const char* str)
+{
+ return strtoll(str, nullptr, 10);
+}
+
+static char ptsname_buf[32];
+char* ptsname(int fd)
+{
+ if (ptsname_r(fd, ptsname_buf, sizeof(ptsname_buf)) < 0)
+ return nullptr;
+ return ptsname_buf;
+}
+
+int ptsname_r(int fd, char* buffer, size_t size)
+{
+ int rc = syscall(SC_ptsname, fd, buffer, size);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+static unsigned long s_next_rand = 1;
+
+int rand()
+{
+ s_next_rand = s_next_rand * 1103515245 + 12345;
+ return ((unsigned)(s_next_rand / ((RAND_MAX + 1) * 2)) % (RAND_MAX + 1));
+}
+
+void srand(unsigned seed)
+{
+ s_next_rand = seed;
+}
+
+int abs(int i)
+{
+ return i < 0 ? -i : i;
+}
+
+long int random()
+{
+ return rand();
+}
+
+void srandom(unsigned seed)
+{
+ srand(seed);
+}
+
+int system(const char* command)
+{
+ if (!command)
+ return 1;
+
+ pid_t child;
+ const char* argv[] = { "sh", "-c", command, nullptr };
+ if ((errno = posix_spawn(&child, "/bin/sh", nullptr, nullptr, const_cast<char**>(argv), environ)))
+ return -1;
+ int wstatus;
+ waitpid(child, &wstatus, 0);
+ return WEXITSTATUS(wstatus);
+}
+
+char* mktemp(char* pattern)
+{
+ if (__generate_unique_filename(pattern) < 0)
+ pattern[0] = '\0';
+
+ return pattern;
+}
+
+int mkstemp(char* pattern)
+{
+ char* path = mktemp(pattern);
+
+ int fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); // I'm using the flags I saw glibc using.
+ if (fd >= 0)
+ return fd;
+
+ return -1;
+}
+
+char* mkdtemp(char* pattern)
+{
+ if (__generate_unique_filename(pattern) < 0)
+ return nullptr;
+
+ if (mkdir(pattern, 0700) < 0)
+ return nullptr;
+
+ return pattern;
+}
+
+void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*))
+{
+ char* start = static_cast<char*>(const_cast<void*>(base));
+ while (nmemb > 0) {
+ char* middle_memb = start + (nmemb / 2) * size;
+ int comparison = compar(key, middle_memb);
+ if (comparison == 0)
+ return middle_memb;
+ else if (comparison > 0) {
+ start = middle_memb + size;
+ --nmemb;
+ }
+ nmemb /= 2;
+ }
+
+ return nullptr;
+}
+
+div_t div(int numerator, int denominator)
+{
+ div_t result;
+ result.quot = numerator / denominator;
+ result.rem = numerator % denominator;
+
+ if (numerator >= 0 && result.rem < 0) {
+ result.quot++;
+ result.rem -= denominator;
+ }
+ return result;
+}
+
+ldiv_t ldiv(long numerator, long denominator)
+{
+ ldiv_t result;
+ result.quot = numerator / denominator;
+ result.rem = numerator % denominator;
+
+ if (numerator >= 0 && result.rem < 0) {
+ result.quot++;
+ result.rem -= denominator;
+ }
+ return result;
+}
+
+size_t mbstowcs(wchar_t*, const char*, size_t)
+{
+ ASSERT_NOT_REACHED();
+}
+
+int mbtowc(wchar_t* wch, const char* data, [[maybe_unused]] size_t data_size)
+{
+ // FIXME: This needs a real implementation.
+ if (wch && data) {
+ *wch = *data;
+ return 1;
+ }
+
+ if (!wch && data) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int wctomb(char*, wchar_t)
+{
+ ASSERT_NOT_REACHED();
+}
+
+size_t wcstombs(char* dest, const wchar_t* src, size_t max)
+{
+ char* originalDest = dest;
+ while ((size_t)(dest - originalDest) < max) {
+ StringView v { (const char*)src, sizeof(wchar_t) };
+
+ // FIXME: dependent on locale, for now utf-8 is supported.
+ Utf8View utf8 { v };
+ if (*utf8.begin() == '\0') {
+ *dest = '\0';
+ return (size_t)(dest - originalDest); // Exclude null character in returned size
+ }
+
+ for (auto byte : utf8) {
+ if (byte != '\0')
+ *dest++ = byte;
+ }
+ ++src;
+ }
+ return max;
+}
+
+long strtol(const char* str, char** endptr, int base)
+{
+ long long value = strtoll(str, endptr, base);
+ if (value < LONG_MIN) {
+ errno = ERANGE;
+ return LONG_MIN;
+ } else if (value > LONG_MAX) {
+ errno = ERANGE;
+ return LONG_MAX;
+ }
+ return value;
+}
+
+unsigned long strtoul(const char* str, char** endptr, int base)
+{
+ unsigned long long value = strtoull(str, endptr, base);
+ if (value > ULONG_MAX) {
+ errno = ERANGE;
+ return ULONG_MAX;
+ }
+ return value;
+}
+
+long long strtoll(const char* str, char** endptr, int base)
+{
+ // Parse spaces and sign
+ char* parse_ptr = const_cast<char*>(str);
+ strtons(parse_ptr, &parse_ptr);
+ const Sign sign = strtosign(parse_ptr, &parse_ptr);
+
+ // Parse base
+ if (base == 0) {
+ if (*parse_ptr == '0') {
+ if (tolower(*(parse_ptr + 1)) == 'x') {
+ base = 16;
+ parse_ptr += 2;
+ } else {
+ base = 8;
+ }
+ } else {
+ base = 10;
+ }
+ }
+
+ // Parse actual digits.
+ LongLongParser digits { sign, base };
+ bool digits_usable = false;
+ bool should_continue = true;
+ bool overflow = false;
+ do {
+ bool is_a_digit;
+ if (overflow) {
+ is_a_digit = digits.parse_digit(*parse_ptr) >= 0;
+ } else {
+ DigitConsumeDecision decision = digits.consume(*parse_ptr);
+ switch (decision) {
+ case DigitConsumeDecision::Consumed:
+ is_a_digit = true;
+ // The very first actual digit must pass here:
+ digits_usable = true;
+ break;
+ case DigitConsumeDecision::PosOverflow:
+ case DigitConsumeDecision::NegOverflow:
+ is_a_digit = true;
+ overflow = true;
+ break;
+ case DigitConsumeDecision::Invalid:
+ is_a_digit = false;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ should_continue = is_a_digit;
+ parse_ptr += should_continue;
+ } while (should_continue);
+
+ if (!digits_usable) {
+ // No actual number value available.
+ if (endptr)
+ *endptr = const_cast<char*>(str);
+ return 0;
+ }
+
+ if (endptr)
+ *endptr = parse_ptr;
+
+ if (overflow) {
+ errno = ERANGE;
+ if (sign != Sign::Negative) {
+ return LONG_LONG_MAX;
+ } else {
+ return LONG_LONG_MIN;
+ }
+ }
+
+ return digits.number();
+}
+
+unsigned long long strtoull(const char* str, char** endptr, int base)
+{
+ // Parse spaces and sign
+ char* parse_ptr = const_cast<char*>(str);
+ strtons(parse_ptr, &parse_ptr);
+
+ // Parse base
+ if (base == 0) {
+ if (*parse_ptr == '0') {
+ if (tolower(*(parse_ptr + 1)) == 'x') {
+ base = 16;
+ parse_ptr += 2;
+ } else {
+ base = 8;
+ }
+ } else {
+ base = 10;
+ }
+ }
+
+ // Parse actual digits.
+ ULongLongParser digits { Sign::Positive, base };
+ bool digits_usable = false;
+ bool should_continue = true;
+ bool overflow = false;
+ do {
+ bool is_a_digit;
+ if (overflow) {
+ is_a_digit = digits.parse_digit(*parse_ptr) >= 0;
+ } else {
+ DigitConsumeDecision decision = digits.consume(*parse_ptr);
+ switch (decision) {
+ case DigitConsumeDecision::Consumed:
+ is_a_digit = true;
+ // The very first actual digit must pass here:
+ digits_usable = true;
+ break;
+ case DigitConsumeDecision::PosOverflow:
+ case DigitConsumeDecision::NegOverflow:
+ is_a_digit = true;
+ overflow = true;
+ break;
+ case DigitConsumeDecision::Invalid:
+ is_a_digit = false;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ should_continue = is_a_digit;
+ parse_ptr += should_continue;
+ } while (should_continue);
+
+ if (!digits_usable) {
+ // No actual number value available.
+ if (endptr)
+ *endptr = const_cast<char*>(str);
+ return 0;
+ }
+
+ if (endptr)
+ *endptr = parse_ptr;
+
+ if (overflow) {
+ errno = ERANGE;
+ return LONG_LONG_MAX;
+ }
+
+ return digits.number();
+}
+
+// Serenity's PRNG is not cryptographically secure. Do not rely on this for
+// any real crypto! These functions (for now) are for compatibility.
+// TODO: In the future, rand can be made deterministic and this not.
+uint32_t arc4random(void)
+{
+ char buf[4];
+ syscall(SC_getrandom, buf, 4, 0);
+ return *(uint32_t*)buf;
+}
+
+void arc4random_buf(void* buffer, size_t buffer_size)
+{
+ // arc4random_buf should never fail, but user supplied buffers could fail.
+ // However, if the user passes a garbage buffer, that's on them.
+ syscall(SC_getrandom, buffer, buffer_size, 0);
+}
+
+uint32_t arc4random_uniform(uint32_t max_bounds)
+{
+ // XXX: Should actually apply special rules for uniformity; avoid what is
+ // called "modulo bias".
+ return arc4random() % max_bounds;
+}
+
+char* realpath(const char* pathname, char* buffer)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return nullptr;
+ }
+ size_t size = PATH_MAX;
+ if (buffer == nullptr)
+ buffer = (char*)malloc(size);
+ Syscall::SC_realpath_params params { { pathname, strlen(pathname) }, { buffer, size } };
+ int rc = syscall(SC_realpath, &params);
+ if (rc < 0) {
+ errno = -rc;
+ return nullptr;
+ }
+ errno = 0;
+ return buffer;
+}
+
+int posix_openpt(int flags)
+{
+ if (flags & ~(O_RDWR | O_NOCTTY | O_CLOEXEC)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return open("/dev/ptmx", flags);
+}
+
+int grantpt([[maybe_unused]] int fd)
+{
+ return 0;
+}
+
+int unlockpt([[maybe_unused]] int fd)
+{
+ return 0;
+}
+}
diff --git a/Userland/Libraries/LibC/stdlib.h b/Userland/Libraries/LibC/stdlib.h
new file mode 100644
index 0000000000..735e62e36a
--- /dev/null
+++ b/Userland/Libraries/LibC/stdlib.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__attribute__((warn_unused_result)) int __generate_unique_filename(char* pattern);
+
+__BEGIN_DECLS
+
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+#define MB_CUR_MAX 1
+
+__attribute__((malloc)) __attribute__((alloc_size(1))) void* malloc(size_t);
+__attribute__((malloc)) __attribute__((alloc_size(1, 2))) void* calloc(size_t nmemb, size_t);
+size_t malloc_size(void*);
+void serenity_dump_malloc_stats(void);
+void free(void*);
+__attribute__((alloc_size(2))) void* realloc(void* ptr, size_t);
+char* getenv(const char* name);
+int putenv(char*);
+int unsetenv(const char*);
+int clearenv(void);
+int setenv(const char* name, const char* value, int overwrite);
+int atoi(const char*);
+long atol(const char*);
+long long atoll(const char*);
+double strtod(const char*, char** endptr);
+long double strtold(const char*, char** endptr);
+float strtof(const char*, char** endptr);
+long strtol(const char*, char** endptr, int base);
+long long strtoll(const char*, char** endptr, int base);
+unsigned long long strtoull(const char*, char** endptr, int base);
+unsigned long strtoul(const char*, char** endptr, int base);
+void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
+void qsort_r(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void* arg);
+int atexit(void (*function)());
+__attribute__((noreturn)) void exit(int status);
+__attribute__((noreturn)) void abort();
+char* ptsname(int fd);
+int ptsname_r(int fd, char* buffer, size_t);
+int abs(int);
+long labs(long);
+double atof(const char*);
+int system(const char* command);
+char* mktemp(char*);
+int mkstemp(char*);
+char* mkdtemp(char*);
+void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
+size_t mbstowcs(wchar_t*, const char*, size_t);
+int mbtowc(wchar_t*, const char*, size_t);
+int wctomb(char*, wchar_t);
+size_t wcstombs(char*, const wchar_t*, size_t);
+char* realpath(const char* pathname, char* buffer);
+
+#define RAND_MAX 32767
+int rand();
+void srand(unsigned seed);
+
+long int random();
+void srandom(unsigned seed);
+
+uint32_t arc4random(void);
+void arc4random_buf(void*, size_t);
+uint32_t arc4random_uniform(uint32_t);
+
+typedef struct {
+ int quot;
+ int rem;
+} div_t;
+div_t div(int, int);
+typedef struct {
+ long quot;
+ long rem;
+} ldiv_t;
+ldiv_t ldiv(long, long);
+
+int posix_openpt(int flags);
+int grantpt(int fd);
+int unlockpt(int fd);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/string.cpp b/Userland/Libraries/LibC/string.cpp
new file mode 100644
index 0000000000..86a72b72a9
--- /dev/null
+++ b/Userland/Libraries/LibC/string.cpp
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/MemMem.h>
+#include <AK/Platform.h>
+#include <AK/StdLibExtras.h>
+#include <AK/Types.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+
+size_t strspn(const char* s, const char* accept)
+{
+ const char* p = s;
+cont:
+ char ch = *p++;
+ char ac;
+ for (const char* ap = accept; (ac = *ap++) != '\0';) {
+ if (ac == ch)
+ goto cont;
+ }
+ return p - 1 - s;
+}
+
+size_t strcspn(const char* s, const char* reject)
+{
+ for (auto* p = s;;) {
+ char c = *p++;
+ auto* rp = reject;
+ char rc;
+ do {
+ if ((rc = *rp++) == c)
+ return p - 1 - s;
+ } while (rc);
+ }
+}
+
+size_t strlen(const char* str)
+{
+ size_t len = 0;
+ while (*(str++))
+ ++len;
+ return len;
+}
+
+size_t strnlen(const char* str, size_t maxlen)
+{
+ size_t len = 0;
+ for (; len < maxlen && *str; str++)
+ len++;
+ return len;
+}
+
+char* strdup(const char* str)
+{
+ size_t len = strlen(str);
+ char* new_str = (char*)malloc(len + 1);
+ memcpy(new_str, str, len);
+ new_str[len] = '\0';
+ return new_str;
+}
+
+char* strndup(const char* str, size_t maxlen)
+{
+ size_t len = strnlen(str, maxlen);
+ char* new_str = (char*)malloc(len + 1);
+ memcpy(new_str, str, len);
+ new_str[len] = 0;
+ return new_str;
+}
+
+int strcmp(const char* s1, const char* s2)
+{
+ while (*s1 == *s2++)
+ if (*s1++ == 0)
+ return 0;
+ return *(const unsigned char*)s1 - *(const unsigned char*)--s2;
+}
+
+int strncmp(const char* s1, const char* s2, size_t n)
+{
+ if (!n)
+ return 0;
+ do {
+ if (*s1 != *s2++)
+ return *(const unsigned char*)s1 - *(const unsigned char*)--s2;
+ if (*s1++ == 0)
+ break;
+ } while (--n);
+ return 0;
+}
+
+int memcmp(const void* v1, const void* v2, size_t n)
+{
+ auto* s1 = (const uint8_t*)v1;
+ auto* s2 = (const uint8_t*)v2;
+ while (n-- > 0) {
+ if (*s1++ != *s2++)
+ return s1[-1] < s2[-1] ? -1 : 1;
+ }
+ return 0;
+}
+
+#if ARCH(I386)
+void* memcpy(void* dest_ptr, const void* src_ptr, size_t n)
+{
+ void* original_dest = dest_ptr;
+ asm volatile(
+ "rep movsb"
+ : "+D"(dest_ptr), "+S"(src_ptr), "+c"(n)::"memory");
+ return original_dest;
+}
+
+void* memset(void* dest_ptr, int c, size_t n)
+{
+ void* original_dest = dest_ptr;
+ asm volatile(
+ "rep stosb\n"
+ : "=D"(dest_ptr), "=c"(n)
+ : "0"(dest_ptr), "1"(n), "a"(c)
+ : "memory");
+ return original_dest;
+}
+#else
+void* memcpy(void* dest_ptr, const void* src_ptr, size_t n)
+{
+ auto* dest = (u8*)dest_ptr;
+ auto* src = (const u8*)src_ptr;
+ for (size_t i = 0; i < n; ++i)
+ dest[i] = src[i];
+ return dest_ptr;
+}
+
+void* memset(void* dest_ptr, int c, size_t n)
+{
+ auto* dest = (u8*)dest_ptr;
+ for (size_t i = 0; i < n; ++i)
+ dest[i] = (u8)c;
+ return dest_ptr;
+}
+#endif
+
+void* memmove(void* dest, const void* src, size_t n)
+{
+ if (dest < src)
+ return memcpy(dest, src, n);
+
+ u8* pd = (u8*)dest;
+ const u8* ps = (const u8*)src;
+ for (pd += n, ps += n; n--;)
+ *--pd = *--ps;
+ return dest;
+}
+
+const void* memmem(const void* haystack, size_t haystack_length, const void* needle, size_t needle_length)
+{
+ return AK::memmem(haystack, haystack_length, needle, needle_length);
+}
+
+char* strcpy(char* dest, const char* src)
+{
+ char* originalDest = dest;
+ while ((*dest++ = *src++) != '\0')
+ ;
+ return originalDest;
+}
+
+char* strncpy(char* dest, const char* src, size_t n)
+{
+ size_t i;
+ for (i = 0; i < n && src[i] != '\0'; ++i)
+ dest[i] = src[i];
+ for (; i < n; ++i)
+ dest[i] = '\0';
+ return dest;
+}
+
+size_t strlcpy(char* dest, const char* src, size_t n)
+{
+ size_t i;
+ // Would like to test i < n - 1 here, but n might be 0.
+ for (i = 0; i + 1 < n && src[i] != '\0'; ++i)
+ dest[i] = src[i];
+ if (n)
+ dest[i] = '\0';
+ for (; src[i] != '\0'; ++i)
+ ; // Determine the length of src, don't copy.
+ return i;
+}
+
+char* strchr(const char* str, int c)
+{
+ char ch = c;
+ for (;; ++str) {
+ if (*str == ch)
+ return const_cast<char*>(str);
+ if (!*str)
+ return nullptr;
+ }
+}
+
+char* strchrnul(const char* str, int c)
+{
+ char ch = c;
+ for (;; ++str) {
+ if (*str == ch || !*str)
+ return const_cast<char*>(str);
+ }
+}
+
+void* memchr(const void* ptr, int c, size_t size)
+{
+ char ch = c;
+ auto* cptr = (const char*)ptr;
+ for (size_t i = 0; i < size; ++i) {
+ if (cptr[i] == ch)
+ return const_cast<char*>(cptr + i);
+ }
+ return nullptr;
+}
+
+char* strrchr(const char* str, int ch)
+{
+ char* last = nullptr;
+ char c;
+ for (; (c = *str); ++str) {
+ if (c == ch)
+ last = const_cast<char*>(str);
+ }
+ return last;
+}
+
+char* strcat(char* dest, const char* src)
+{
+ size_t dest_length = strlen(dest);
+ size_t i;
+ for (i = 0; src[i] != '\0'; i++)
+ dest[dest_length + i] = src[i];
+ dest[dest_length + i] = '\0';
+ return dest;
+}
+
+char* strncat(char* dest, const char* src, size_t n)
+{
+ size_t dest_length = strlen(dest);
+ size_t i;
+ for (i = 0; i < n && src[i] != '\0'; i++)
+ dest[dest_length + i] = src[i];
+ dest[dest_length + i] = '\0';
+ return dest;
+}
+
+const char* const sys_errlist[] = {
+ "Success (not an error)",
+ "Operation not permitted",
+ "No such file or directory",
+ "No such process",
+ "Interrupted syscall",
+ "I/O error",
+ "No such device or address",
+ "Argument list too long",
+ "Exec format error",
+ "Bad fd number",
+ "No child processes",
+ "Try again",
+ "Out of memory",
+ "Permission denied",
+ "Bad address",
+ "Block device required",
+ "Device or resource busy",
+ "File already exists",
+ "Cross-device link",
+ "No such device",
+ "Not a directory",
+ "Is a directory",
+ "Invalid argument",
+ "File table overflow",
+ "Too many open files",
+ "Not a TTY",
+ "Text file busy",
+ "File too large",
+ "No space left on device",
+ "Illegal seek",
+ "Read-only filesystem",
+ "Too many links",
+ "Broken pipe",
+ "Range error",
+ "Name too long",
+ "Too many symlinks",
+ "Overflow",
+ "Operation not supported",
+ "No such syscall",
+ "Not implemented",
+ "Address family not supported",
+ "Not a socket",
+ "Address in use",
+ "Failed without setting an error code (bug!)",
+ "Directory not empty",
+ "Math argument out of domain",
+ "Connection refused",
+ "Address not available",
+ "Already connected",
+ "Connection aborted",
+ "Connection already in progress",
+ "Connection reset",
+ "Destination address required",
+ "Host unreachable",
+ "Illegal byte sequence",
+ "Message size",
+ "Network down",
+ "Network unreachable",
+ "Network reset",
+ "No buffer space",
+ "No lock available",
+ "No message",
+ "No protocol option",
+ "Not connected",
+ "Operation would block",
+ "Protocol not supported",
+ "Resource deadlock would occur",
+ "Timed out",
+ "Wrong protocol type",
+ "Operation in progress",
+ "No such thread",
+ "Protocol error",
+ "Not supported",
+ "Protocol family not supported",
+ "Cannot make directory a subdirectory of itself",
+ "The highest errno +1 :^)",
+};
+
+int sys_nerr = EMAXERRNO;
+
+char* strerror(int errnum)
+{
+ if (errnum < 0 || errnum >= EMAXERRNO) {
+ printf("strerror() missing string for errnum=%d\n", errnum);
+ return const_cast<char*>("Unknown error");
+ }
+ return const_cast<char*>(sys_errlist[errnum]);
+}
+
+char* strsignal(int signum)
+{
+ if (signum >= NSIG) {
+ printf("strsignal() missing string for signum=%d\n", signum);
+ return const_cast<char*>("Unknown signal");
+ }
+ return const_cast<char*>(sys_siglist[signum]);
+}
+
+char* strstr(const char* haystack, const char* needle)
+{
+ char nch;
+ char hch;
+
+ if ((nch = *needle++) != 0) {
+ size_t len = strlen(needle);
+ do {
+ do {
+ if ((hch = *haystack++) == 0)
+ return nullptr;
+ } while (hch != nch);
+ } while (strncmp(haystack, needle, len) != 0);
+ --haystack;
+ }
+ return const_cast<char*>(haystack);
+}
+
+char* strpbrk(const char* s, const char* accept)
+{
+ while (*s)
+ if (strchr(accept, *s++))
+ return const_cast<char*>(--s);
+ return nullptr;
+}
+
+char* strtok_r(char* str, const char* delim, char** saved_str)
+{
+ if (!str) {
+ if (!saved_str)
+ return nullptr;
+ str = *saved_str;
+ }
+
+ size_t token_start = 0;
+ size_t token_end = 0;
+ size_t str_len = strlen(str);
+ size_t delim_len = strlen(delim);
+
+ for (size_t i = 0; i < str_len; ++i) {
+ bool is_proper_delim = false;
+
+ for (size_t j = 0; j < delim_len; ++j) {
+ if (str[i] == delim[j]) {
+ // Skip beginning delimiters
+ if (token_end - token_start == 0) {
+ ++token_start;
+ break;
+ }
+
+ is_proper_delim = true;
+ }
+ }
+
+ ++token_end;
+ if (is_proper_delim && token_end > 0) {
+ --token_end;
+ break;
+ }
+ }
+
+ if (str[token_start] == '\0')
+ return nullptr;
+
+ if (token_end == 0) {
+ *saved_str = nullptr;
+ return &str[token_start];
+ }
+
+ if (str[token_end] == '\0')
+ *saved_str = &str[token_end];
+ else
+ *saved_str = &str[token_end + 1];
+
+ str[token_end] = '\0';
+ return &str[token_start];
+}
+
+char* strtok(char* str, const char* delim)
+{
+ static char* saved_str;
+ return strtok_r(str, delim, &saved_str);
+}
+
+int strcoll(const char* s1, const char* s2)
+{
+ return strcmp(s1, s2);
+}
+
+size_t strxfrm(char* dest, const char* src, size_t n)
+{
+ size_t i;
+ for (i = 0; i < n && src[i] != '\0'; ++i)
+ dest[i] = src[i];
+ for (; i < n; ++i)
+ dest[i] = '\0';
+ return i;
+}
+
+void explicit_bzero(void* ptr, size_t size)
+{
+ memset(ptr, 0, size);
+ asm volatile("" ::
+ : "memory");
+}
+}
diff --git a/Userland/Libraries/LibC/string.h b/Userland/Libraries/LibC/string.h
new file mode 100644
index 0000000000..40a2aabe7d
--- /dev/null
+++ b/Userland/Libraries/LibC/string.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+size_t strlen(const char*);
+size_t strnlen(const char*, size_t maxlen);
+
+int strcmp(const char*, const char*);
+int strncmp(const char*, const char*, size_t);
+
+int memcmp(const void*, const void*, size_t);
+void* memcpy(void*, const void*, size_t);
+void* memmove(void*, const void*, size_t);
+void* memchr(const void*, int c, size_t);
+const void* memmem(const void* haystack, size_t, const void* needle, size_t);
+
+void* memset(void*, int, size_t);
+void explicit_bzero(void*, size_t) __attribute__((nonnull(1)));
+
+__attribute__((malloc)) char* strdup(const char*);
+__attribute__((malloc)) char* strndup(const char*, size_t);
+
+__attribute__((deprecated("use strlcpy or String::copy_characters_to_buffer"))) char* strcpy(char* dest, const char* src);
+__attribute__((deprecated("use strlcpy or String::copy_characters_to_buffer"))) char* strncpy(char* dest, const char* src, size_t);
+__attribute__((warn_unused_result)) size_t strlcpy(char* dest, const char* src, size_t);
+
+char* strchr(const char*, int c);
+char* strchrnul(const char*, int c);
+char* strstr(const char* haystack, const char* needle);
+char* strrchr(const char*, int c);
+
+__attribute__((deprecated("use strncat"))) char* strcat(char* dest, const char* src);
+char* strncat(char* dest, const char* src, size_t);
+
+size_t strspn(const char*, const char* accept);
+size_t strcspn(const char*, const char* reject);
+char* strerror(int errnum);
+char* strsignal(int signum);
+char* strpbrk(const char*, const char* accept);
+char* strtok_r(char* str, const char* delim, char** saved_str);
+char* strtok(char* str, const char* delim);
+int strcoll(const char* s1, const char* s2);
+size_t strxfrm(char* dest, const char* src, size_t n);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/strings.cpp b/Userland/Libraries/LibC/strings.cpp
new file mode 100644
index 0000000000..b5f6579f89
--- /dev/null
+++ b/Userland/Libraries/LibC/strings.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+
+extern "C" {
+
+void bzero(void* dest, size_t n)
+{
+ memset(dest, 0, n);
+}
+
+void bcopy(const void* src, void* dest, size_t n)
+{
+ memmove(dest, src, n);
+}
+
+static char foldcase(char ch)
+{
+ if (isalpha(ch))
+ return tolower(ch);
+ return ch;
+}
+
+int strcasecmp(const char* s1, const char* s2)
+{
+ for (; foldcase(*s1) == foldcase(*s2); ++s1, ++s2) {
+ if (*s1 == 0)
+ return 0;
+ }
+ return foldcase(*(const unsigned char*)s1) < foldcase(*(const unsigned char*)s2) ? -1 : 1;
+}
+
+int strncasecmp(const char* s1, const char* s2, size_t n)
+{
+ if (!n)
+ return 0;
+ do {
+ if (foldcase(*s1) != foldcase(*s2++))
+ return foldcase(*(const unsigned char*)s1) - foldcase(*(const unsigned char*)--s2);
+ if (*s1++ == 0)
+ break;
+ } while (--n);
+ return 0;
+}
+}
diff --git a/Userland/Libraries/LibC/strings.h b/Userland/Libraries/LibC/strings.h
new file mode 100644
index 0000000000..b157e30489
--- /dev/null
+++ b/Userland/Libraries/LibC/strings.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+int strcasecmp(const char*, const char*);
+int strncasecmp(const char*, const char*, size_t);
+void bzero(void*, size_t);
+void bcopy(const void*, void*, size_t);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/arch/i386/regs.h b/Userland/Libraries/LibC/sys/arch/i386/regs.h
new file mode 100644
index 0000000000..d15d0fdd86
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/arch/i386/regs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <AK/Types.h>
+
+struct [[gnu::packed]] PtraceRegisters {
+ u32 eax;
+ u32 ecx;
+ u32 edx;
+ u32 ebx;
+ u32 esp;
+ u32 ebp;
+ u32 esi;
+ u32 edi;
+ u32 eip;
+ u32 eflags;
+ u32 cs;
+ u32 ss;
+ u32 ds;
+ u32 es;
+ u32 fs;
+ u32 gs;
+};
diff --git a/Userland/Libraries/LibC/sys/cdefs.h b/Userland/Libraries/LibC/sys/cdefs.h
new file mode 100644
index 0000000000..4b7edc0cae
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/cdefs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define _POSIX_VERSION 200809L
+
+#ifndef ALWAYS_INLINE
+# define ALWAYS_INLINE inline __attribute__((always_inline))
+#endif
+
+#ifdef __cplusplus
+# ifndef __BEGIN_DECLS
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+# endif
+#else
+# ifndef __BEGIN_DECLS
+# define __BEGIN_DECLS
+# define __END_DECLS
+# endif
+#endif
+
+#undef __P
+#define __P(a) a
+
+#define offsetof(type, member) __builtin_offsetof(type, member)
+
+#ifdef __cplusplus
+//extern "C" int main(int, char**);
+#endif
diff --git a/Userland/Libraries/LibC/sys/file.h b/Userland/Libraries/LibC/sys/file.h
new file mode 100644
index 0000000000..2bf8abd099
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/file.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
diff --git a/Userland/Libraries/LibC/sys/internals.h b/Userland/Libraries/LibC/sys/internals.h
new file mode 100644
index 0000000000..c23785a02e
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/internals.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef void (*AtExitFunction)(void*);
+
+extern void __libc_init();
+extern void __malloc_init();
+extern void __stdio_init();
+extern void _init();
+extern bool __environ_is_malloced;
+extern bool __stdio_is_initialized;
+
+int __cxa_atexit(AtExitFunction exit_function, void* parameter, void* dso_handle);
+void __cxa_finalize(void* dso_handle);
+[[noreturn]] void __cxa_pure_virtual() __attribute__((weak));
+[[noreturn]] void __stack_chk_fail();
+[[noreturn]] void __stack_chk_fail_local();
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/ioctl.h b/Userland/Libraries/LibC/sys/ioctl.h
new file mode 100644
index 0000000000..e29ea315ad
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/ioctl.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/ioctl_numbers.h>
+
+__BEGIN_DECLS
+
+int ioctl(int fd, unsigned request, ...);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/ioctl_numbers.h b/Userland/Libraries/LibC/sys/ioctl_numbers.h
new file mode 100644
index 0000000000..2492349060
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/ioctl_numbers.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+struct FBResolution {
+ unsigned pitch;
+ unsigned width;
+ unsigned height;
+};
+
+__END_DECLS
+
+enum IOCtlNumber {
+ TIOCGPGRP,
+ TIOCSPGRP,
+ TCGETS,
+ TCSETS,
+ TCSETSW,
+ TCSETSF,
+ TCFLSH,
+ TIOCGWINSZ,
+ TIOCSCTTY,
+ TIOCNOTTY,
+ TIOCSWINSZ,
+ FB_IOCTL_GET_SIZE_IN_BYTES,
+ FB_IOCTL_GET_RESOLUTION,
+ FB_IOCTL_SET_RESOLUTION,
+ FB_IOCTL_GET_BUFFER,
+ FB_IOCTL_SET_BUFFER,
+ SIOCSIFADDR,
+ SIOCGIFADDR,
+ SIOCGIFHWADDR,
+ SIOCSIFNETMASK,
+ SIOCADDRT,
+ SIOCDELRT
+};
+
+#define TIOCGPGRP TIOCGPGRP
+#define TIOCSPGRP TIOCSPGRP
+#define TCGETS TCGETS
+#define TCSETS TCSETS
+#define TCSETSW TCSETSW
+#define TCSETSF TCSETSF
+#define TCFLSH TCFLSH
+#define TIOCGWINSZ TIOCGWINSZ
+#define TIOCSCTTY TIOCSCTTY
+#define TIOCNOTTY TIOCNOTTY
+#define TIOCSWINSZ TIOCSWINSZ
+#define FB_IOCTL_GET_SIZE_IN_BYTES FB_IOCTL_GET_SIZE_IN_BYTES
+#define FB_IOCTL_GET_RESOLUTION FB_IOCTL_GET_RESOLUTION
+#define FB_IOCTL_SET_RESOLUTION FB_IOCTL_SET_RESOLUTION
+#define FB_IOCTL_GET_BUFFER FB_IOCTL_GET_BUFFER
+#define FB_IOCTL_SET_BUFFER FB_IOCTL_SET_BUFFER
+#define SIOCSIFADDR SIOCSIFADDR
+#define SIOCGIFADDR SIOCGIFADDR
+#define SIOCGIFHWADDR SIOCGIFHWADDR
+#define SIOCSIFNETMASK SIOCSIFNETMASK
+#define SIOCADDRT SIOCADDRT
+#define SIOCDELRT SIOCDELRT
diff --git a/Userland/Libraries/LibC/sys/mman.h b/Userland/Libraries/LibC/sys/mman.h
new file mode 100644
index 0000000000..4068ce8dd6
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/mman.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <mman.h>
diff --git a/Userland/Libraries/LibC/sys/param.h b/Userland/Libraries/LibC/sys/param.h
new file mode 100644
index 0000000000..5258ac11ca
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/param.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <endian.h>
+#include <limits.h>
diff --git a/Userland/Libraries/LibC/sys/prctl.cpp b/Userland/Libraries/LibC/sys/prctl.cpp
new file mode 100644
index 0000000000..d7aa35486b
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/prctl.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+
+extern "C" {
+
+int prctl(int option, uintptr_t arg1, uintptr_t arg2)
+{
+ int rc = syscall(SC_prctl, option, arg1, arg2);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/sys/prctl.h b/Userland/Libraries/LibC/sys/prctl.h
new file mode 100644
index 0000000000..ea6b8ed47d
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/prctl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/prctl_numbers.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+int prctl(int option, uintptr_t arg1, uintptr_t arg2);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/prctl_numbers.h b/Userland/Libraries/LibC/sys/prctl_numbers.h
new file mode 100644
index 0000000000..36ecc75bb6
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/prctl_numbers.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define PR_SET_DUMPABLE 1
+#define PR_GET_DUMPABLE 2
diff --git a/Userland/Libraries/LibC/sys/ptrace.cpp b/Userland/Libraries/LibC/sys/ptrace.cpp
new file mode 100644
index 0000000000..9e7eb60c2a
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/ptrace.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/LogStream.h>
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+
+extern "C" {
+
+int ptrace(int request, pid_t tid, void* addr, int data)
+{
+
+ // PT_PEEK needs special handling since the syscall wrapper
+ // returns the peeked value as an int, which can be negative because of the cast.
+ // When using PT_PEEK, the user can check if an error occurred
+ // by looking at errno rather than the return value.
+
+ u32 out_data;
+ Syscall::SC_ptrace_peek_params peek_params;
+ if (request == PT_PEEK) {
+ peek_params.address = reinterpret_cast<u32*>(addr);
+ peek_params.out_data = &out_data;
+ addr = &peek_params;
+ }
+
+ Syscall::SC_ptrace_params params {
+ request,
+ tid,
+ reinterpret_cast<u8*>(addr),
+ data
+ };
+ int rc = syscall(SC_ptrace, &params);
+
+ if (request == PT_PEEK) {
+ if (rc < 0) {
+ errno = -rc;
+ return -1;
+ }
+ errno = 0;
+ return static_cast<int>(out_data);
+ }
+
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/sys/ptrace.h b/Userland/Libraries/LibC/sys/ptrace.h
new file mode 100644
index 0000000000..edb45aeec9
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/ptrace.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+#define PT_TRACE_ME 1
+#define PT_ATTACH 2
+#define PT_CONTINUE 3
+#define PT_SYSCALL 4
+#define PT_GETREGS 5
+#define PT_DETACH 6
+#define PT_PEEK 7
+#define PT_POKE 8
+#define PT_SETREGS 9
+
+// FIXME: PID/TID ISSUE
+// Affects the entirety of LibDebug and Userland/strace.cpp.
+// See also Kernel/Ptrace.cpp
+int ptrace(int request, pid_t tid, void* addr, int data);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/resource.h b/Userland/Libraries/LibC/sys/resource.h
new file mode 100644
index 0000000000..82f58f0902
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/resource.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+struct rusage {
+ struct timeval ru_utime;
+ struct timeval ru_stime;
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+};
+
+#define RUSAGE_SELF 1
+#define RUSAGE_CHILDREN 2
+
+int getrusage(int who, struct rusage* usage);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/select.cpp b/Userland/Libraries/LibC/sys/select.cpp
new file mode 100644
index 0000000000..85c5b03d43
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/select.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/time.h>
+
+extern "C" {
+
+int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout_tv)
+{
+ timespec* timeout_ts = nullptr;
+ timespec timeout;
+ if (timeout_tv) {
+ timeout_ts = &timeout;
+ TIMEVAL_TO_TIMESPEC(timeout_tv, timeout_ts);
+ }
+ return pselect(nfds, readfds, writefds, exceptfds, timeout_ts, nullptr);
+}
+
+int pselect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const timespec* timeout, const sigset_t* sigmask)
+{
+ Syscall::SC_select_params params { nfds, readfds, writefds, exceptfds, timeout, sigmask };
+ int rc = syscall(SC_select, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/sys/select.h b/Userland/Libraries/LibC/sys/select.h
new file mode 100644
index 0000000000..9d451eb8ed
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/select.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <fd_set.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
+int pselect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timespec* timeout, const sigset_t* sigmask);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/socket.cpp b/Userland/Libraries/LibC/sys/socket.cpp
new file mode 100644
index 0000000000..95d2a015a7
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/socket.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+extern "C" {
+
+int socket(int domain, int type, int protocol)
+{
+ int rc = syscall(SC_socket, domain, type, protocol);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int bind(int sockfd, const sockaddr* addr, socklen_t addrlen)
+{
+ int rc = syscall(SC_bind, sockfd, addr, addrlen);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int listen(int sockfd, int backlog)
+{
+ int rc = syscall(SC_listen, sockfd, backlog);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int accept(int sockfd, sockaddr* addr, socklen_t* addrlen)
+{
+ int rc = syscall(SC_accept, sockfd, addr, addrlen);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int connect(int sockfd, const sockaddr* addr, socklen_t addrlen)
+{
+ int rc = syscall(SC_connect, sockfd, addr, addrlen);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int shutdown(int sockfd, int how)
+{
+ int rc = syscall(SC_shutdown, sockfd, how);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+ssize_t sendmsg(int sockfd, const struct msghdr* msg, int flags)
+{
+ int rc = syscall(SC_sendmsg, sockfd, msg, flags);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+ssize_t sendto(int sockfd, const void* data, size_t data_length, int flags, const struct sockaddr* addr, socklen_t addr_length)
+{
+ iovec iov = { const_cast<void*>(data), data_length };
+ msghdr msg = { const_cast<struct sockaddr*>(addr), addr_length, &iov, 1, nullptr, 0, 0 };
+ return sendmsg(sockfd, &msg, flags);
+}
+
+ssize_t send(int sockfd, const void* data, size_t data_length, int flags)
+{
+ return sendto(sockfd, data, data_length, flags, nullptr, 0);
+}
+
+ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags)
+{
+ int rc = syscall(SC_recvmsg, sockfd, msg, flags);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+ssize_t recvfrom(int sockfd, void* buffer, size_t buffer_length, int flags, struct sockaddr* addr, socklen_t* addr_length)
+{
+ if (!addr_length && addr) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ sockaddr_storage internal_addr;
+ iovec iov = { buffer, buffer_length };
+ msghdr msg = { addr ? &internal_addr : nullptr, addr ? (socklen_t)sizeof(internal_addr) : 0, &iov, 1, nullptr, 0, 0 };
+ ssize_t rc = recvmsg(sockfd, &msg, flags);
+ if (rc >= 0 && addr) {
+ memcpy(addr, &internal_addr, min(*addr_length, msg.msg_namelen));
+ *addr_length = msg.msg_namelen;
+ }
+ return rc;
+}
+
+ssize_t recv(int sockfd, void* buffer, size_t buffer_length, int flags)
+{
+ return recvfrom(sockfd, buffer, buffer_length, flags, nullptr, nullptr);
+}
+
+int getsockopt(int sockfd, int level, int option, void* value, socklen_t* value_size)
+{
+ Syscall::SC_getsockopt_params params { sockfd, level, option, value, value_size };
+ int rc = syscall(SC_getsockopt, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int setsockopt(int sockfd, int level, int option, const void* value, socklen_t value_size)
+{
+ Syscall::SC_setsockopt_params params { sockfd, level, option, value, value_size };
+ int rc = syscall(SC_setsockopt, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
+{
+ Syscall::SC_getsockname_params params { sockfd, addr, addrlen };
+ int rc = syscall(SC_getsockname, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
+{
+ Syscall::SC_getpeername_params params { sockfd, addr, addrlen };
+ int rc = syscall(SC_getpeername, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int sendfd(int sockfd, int fd)
+{
+ int rc = syscall(SC_sendfd, sockfd, fd);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int recvfd(int sockfd)
+{
+ int rc = syscall(SC_recvfd, sockfd);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/sys/socket.h b/Userland/Libraries/LibC/sys/socket.h
new file mode 100644
index 0000000000..c5a5943041
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/socket.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+__BEGIN_DECLS
+
+#define AF_MASK 0xff
+#define AF_UNSPEC 0
+#define AF_LOCAL 1
+#define AF_UNIX AF_LOCAL
+#define AF_INET 2
+#define AF_MAX 3
+#define PF_LOCAL AF_LOCAL
+#define PF_UNIX PF_LOCAL
+#define PF_INET AF_INET
+#define PF_UNSPEC AF_UNSPEC
+#define PF_MAX AF_MAX
+
+#define SOCK_TYPE_MASK 0xff
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define SOCK_RAW 3
+#define SOCK_NONBLOCK 04000
+#define SOCK_CLOEXEC 02000000
+
+#define SHUT_RD 1
+#define SHUT_WR 2
+#define SHUT_RDWR 3
+
+#define IPPROTO_IP 0
+#define IPPROTO_ICMP 1
+#define IPPROTO_TCP 6
+#define IPPROTO_UDP 17
+
+#define MSG_TRUNC 0x1
+#define MSG_CTRUNC 0x2
+#define MSG_DONTWAIT 0x40
+
+typedef uint16_t sa_family_t;
+
+struct cmsghdr {
+ socklen_t cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+};
+
+struct msghdr {
+ void* msg_name;
+ socklen_t msg_namelen;
+ struct iovec* msg_iov;
+ int msg_iovlen;
+ void* msg_control;
+ socklen_t msg_controllen;
+ int msg_flags;
+};
+
+struct sockaddr {
+ sa_family_t sa_family;
+ char sa_data[14];
+};
+
+struct ucred {
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+};
+
+#define SOL_SOCKET 1
+#define SOMAXCONN 128
+
+enum {
+ SO_RCVTIMEO,
+ SO_SNDTIMEO,
+ SO_TYPE,
+ SO_ERROR,
+ SO_PEERCRED,
+ SO_REUSEADDR,
+ SO_BINDTODEVICE,
+ SO_KEEPALIVE,
+ SO_TIMESTAMP,
+ SO_BROADCAST,
+};
+#define SO_RCVTIMEO SO_RCVTIMEO
+#define SO_SNDTIMEO SO_SNDTIMEO
+#define SO_TYPE SO_TYPE
+#define SO_ERROR SO_ERROR
+#define SO_PEERCRED SO_PEERCRED
+#define SO_REUSEADDR SO_REUSEADDR
+#define SO_BINDTODEVICE SO_BINDTODEVICE
+#define SO_KEEPALIVE SO_KEEPALIVE
+#define SO_TIMESTAMP SO_TIMESTAMP
+#define SO_BROADCAST SO_BROADCAST
+
+enum {
+ SCM_TIMESTAMP,
+ SCM_RIGHTS,
+};
+#define SCM_TIMESTAMP SCM_TIMESTAMP
+#define SCM_RIGHTS SCM_RIGHTS
+
+struct sockaddr_storage {
+ sa_family_t ss_family;
+ union {
+ char data[sizeof(struct sockaddr_un)];
+ void* alignment;
+ };
+};
+
+int socket(int domain, int type, int protocol);
+int bind(int sockfd, const struct sockaddr* addr, socklen_t);
+int listen(int sockfd, int backlog);
+int accept(int sockfd, struct sockaddr*, socklen_t*);
+int connect(int sockfd, const struct sockaddr*, socklen_t);
+int shutdown(int sockfd, int how);
+ssize_t send(int sockfd, const void*, size_t, int flags);
+ssize_t sendmsg(int sockfd, const struct msghdr*, int flags);
+ssize_t sendto(int sockfd, const void*, size_t, int flags, const struct sockaddr*, socklen_t);
+ssize_t recv(int sockfd, void*, size_t, int flags);
+ssize_t recvmsg(int sockfd, struct msghdr*, int flags);
+ssize_t recvfrom(int sockfd, void*, size_t, int flags, struct sockaddr*, socklen_t*);
+int getsockopt(int sockfd, int level, int option, void*, socklen_t*);
+int setsockopt(int sockfd, int level, int option, const void*, socklen_t);
+int getsockname(int sockfd, struct sockaddr*, socklen_t*);
+int getpeername(int sockfd, struct sockaddr*, socklen_t*);
+int sendfd(int sockfd, int fd);
+int recvfd(int sockfd);
+
+// These three are non-POSIX, but common:
+#define CMSG_ALIGN(x) (((x) + sizeof(void*) - 1) & ~(sizeof(void*) - 1))
+#define CMSG_SPACE(x) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(x))
+#define CMSG_LEN(x) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (x))
+
+static inline struct cmsghdr* CMSG_FIRSTHDR(struct msghdr* msg)
+{
+ if (msg->msg_controllen < sizeof(struct cmsghdr))
+ return 0;
+ return (struct cmsghdr*)msg->msg_control;
+}
+
+static inline struct cmsghdr* CMSG_NXTHDR(struct msghdr* msg, struct cmsghdr* cmsg)
+{
+ struct cmsghdr* next = (struct cmsghdr*)((char*)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
+ unsigned offset = (char*)next - (char*)msg->msg_control;
+ if (msg->msg_controllen < offset + sizeof(struct cmsghdr))
+ return NULL;
+ return next;
+}
+
+static inline void* CMSG_DATA(struct cmsghdr* cmsg)
+{
+ return (void*)(cmsg + 1);
+}
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/stat.h b/Userland/Libraries/LibC/sys/stat.h
new file mode 100644
index 0000000000..ed6d84458d
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/stat.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <fcntl.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK)
+#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
+#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO)
+#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK)
+#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK)
+
+struct stat {
+ dev_t st_dev; /* ID of device containing file */
+ ino_t st_ino; /* inode number */
+ mode_t st_mode; /* protection */
+ nlink_t st_nlink; /* number of hard links */
+ uid_t st_uid; /* user ID of owner */
+ gid_t st_gid; /* group ID of owner */
+ dev_t st_rdev; /* device ID (if special file) */
+ off_t st_size; /* total size, in bytes */
+ blksize_t st_blksize; /* blocksize for file system I/O */
+ blkcnt_t st_blocks; /* number of 512B blocks allocated */
+ time_t st_atime; /* time of last access */
+ time_t st_mtime; /* time of last modification */
+ time_t st_ctime; /* time of last status change */
+};
+
+mode_t umask(mode_t);
+int chmod(const char* pathname, mode_t);
+int fchmod(int fd, mode_t);
+int mkdir(const char* pathname, mode_t);
+int mkfifo(const char* pathname, mode_t);
+int fstat(int fd, struct stat* statbuf);
+int lstat(const char* path, struct stat* statbuf);
+int stat(const char* path, struct stat* statbuf);
+
+inline dev_t makedev(unsigned int major, unsigned int minor) { return (minor & 0xffu) | (major << 8u) | ((minor & ~0xffu) << 12u); }
+inline unsigned int major(dev_t dev) { return (dev & 0xfff00u) >> 8u; }
+inline unsigned int minor(dev_t dev) { return (dev & 0xffu) | ((dev >> 12u) & 0xfff00u); }
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/sysmacros.h b/Userland/Libraries/LibC/sys/sysmacros.h
new file mode 100644
index 0000000000..2bf8abd099
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/sysmacros.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
diff --git a/Userland/Libraries/LibC/sys/time.h b/Userland/Libraries/LibC/sys/time.h
new file mode 100644
index 0000000000..11faa3bdd4
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/time.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <time.h>
+
+__BEGIN_DECLS
+
+struct timeval {
+ time_t tv_sec;
+ suseconds_t tv_usec;
+};
+
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+
+int adjtime(const struct timeval* delta, struct timeval* old_delta);
+int gettimeofday(struct timeval* __restrict__, void* __restrict__) __attribute__((nonnull(1)));
+int settimeofday(struct timeval* __restrict__, void* __restrict__) __attribute__((nonnull(1)));
+
+static inline void timeradd(const struct timeval* a, const struct timeval* b, struct timeval* out)
+{
+ out->tv_sec = a->tv_sec + b->tv_sec;
+ out->tv_usec = a->tv_usec + b->tv_usec;
+ if (out->tv_usec >= 1000 * 1000) {
+ out->tv_sec++;
+ out->tv_usec -= 1000 * 1000;
+ }
+}
+
+static inline void timersub(const struct timeval* a, const struct timeval* b, struct timeval* out)
+{
+ out->tv_sec = a->tv_sec - b->tv_sec;
+ out->tv_usec = a->tv_usec - b->tv_usec;
+ if (out->tv_usec < 0) {
+ out->tv_sec--;
+ out->tv_usec += 1000 * 1000;
+ }
+}
+
+static inline void timerclear(struct timeval* out)
+{
+ out->tv_sec = out->tv_usec = 0;
+}
+
+static inline int timerisset(const struct timeval* tv)
+{
+ return tv->tv_sec || tv->tv_usec;
+}
+
+#define timeradd timeradd
+#define timersub timersub
+#define timerclear timerclear
+#define timerisset timerisset
+#define timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? ((tvp)->tv_usec cmp(uvp)->tv_usec) : ((tvp)->tv_sec cmp(uvp)->tv_sec))
+
+static inline void timespecadd(const struct timespec* a, const struct timespec* b, struct timespec* out)
+{
+ out->tv_sec = a->tv_sec + b->tv_sec;
+ out->tv_nsec = a->tv_nsec + b->tv_nsec;
+ if (out->tv_nsec >= 1000 * 1000 * 1000) {
+ out->tv_sec++;
+ out->tv_nsec -= 1000 * 1000 * 1000;
+ }
+}
+
+static inline void timespecsub(const struct timespec* a, const struct timespec* b, struct timespec* out)
+{
+ out->tv_sec = a->tv_sec - b->tv_sec;
+ out->tv_nsec = a->tv_nsec - b->tv_nsec;
+ if (out->tv_nsec < 0) {
+ out->tv_sec--;
+ out->tv_nsec += 1000 * 1000 * 1000;
+ }
+}
+
+static inline void timespecclear(struct timespec* out)
+{
+ out->tv_sec = out->tv_nsec = 0;
+}
+
+static inline int timespecisset(const struct timespec* ts)
+{
+ return ts->tv_sec || ts->tv_nsec;
+}
+
+static inline void TIMEVAL_TO_TIMESPEC(const struct timeval* tv, struct timespec* ts)
+{
+ ts->tv_sec = tv->tv_sec;
+ ts->tv_nsec = tv->tv_usec * 1000;
+}
+
+static inline void TIMESPEC_TO_TIMEVAL(struct timeval* tv, const struct timespec* ts)
+{
+ tv->tv_sec = ts->tv_sec;
+ tv->tv_usec = ts->tv_nsec / 1000;
+}
+
+#define timespecadd timespecadd
+#define timespecsub timespecsub
+#define timespecclear timespecclear
+#define timespecisset timespecisset
+#define timespeccmp(ts, us, cmp) \
+ (((ts)->tv_sec == (us)->tv_sec) ? ((ts)->vf_nsec cmp(us)->tv_nsec) : ((ts)->tv_sec cmp(us)->tv_sec))
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/times.h b/Userland/Libraries/LibC/sys/times.h
new file mode 100644
index 0000000000..3b677d18dc
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/times.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct tms {
+ clock_t tms_utime;
+ clock_t tms_stime;
+ clock_t tms_cutime;
+ clock_t tms_cstime;
+};
+
+clock_t times(struct tms*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/types.h b/Userland/Libraries/LibC/sys/types.h
new file mode 100644
index 0000000000..6de6b1feb1
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/types.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <bits/stdint.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* There is no __SSIZE_TYPE__ but we can trick the preprocessor into defining it for us anyway! */
+#define unsigned signed
+typedef __SIZE_TYPE__ ssize_t;
+#undef unsigned
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+typedef uint32_t uid_t;
+typedef uint32_t gid_t;
+
+typedef int __pid_t;
+#define pid_t __pid_t
+
+typedef char* caddr_t;
+
+typedef int id_t;
+
+typedef __WINT_TYPE__ wint_t;
+
+typedef uint32_t ino_t;
+typedef ssize_t off_t;
+
+typedef uint32_t dev_t;
+typedef uint16_t mode_t;
+typedef uint32_t nlink_t;
+typedef uint32_t blksize_t;
+typedef uint32_t blkcnt_t;
+typedef int64_t time_t;
+typedef uint32_t useconds_t;
+typedef int32_t suseconds_t;
+typedef uint32_t clock_t;
+
+#define __socklen_t_defined
+#define __socklen_t uint32_t
+typedef __socklen_t socklen_t;
+
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+
+typedef int pthread_t;
+typedef int pthread_key_t;
+typedef int32_t pthread_once_t;
+
+typedef struct __pthread_mutex_t {
+ uint32_t lock;
+ pthread_t owner;
+ int level;
+ int type;
+} pthread_mutex_t;
+
+typedef void* pthread_attr_t;
+typedef struct __pthread_mutexattr_t {
+ int type;
+} pthread_mutexattr_t;
+
+typedef struct __pthread_cond_t {
+ int32_t value;
+ uint32_t previous;
+ int clockid; // clockid_t
+} pthread_cond_t;
+
+typedef void* pthread_rwlock_t;
+typedef void* pthread_rwlockatrr_t;
+typedef void* pthread_spinlock_t;
+typedef struct __pthread_condattr_t {
+ int clockid; // clockid_t
+} pthread_condattr_t;
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/uio.cpp b/Userland/Libraries/LibC/sys/uio.cpp
new file mode 100644
index 0000000000..4aad828c65
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/uio.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <sys/uio.h>
+
+extern "C" {
+
+ssize_t writev(int fd, const struct iovec* iov, int iov_count)
+{
+ int rc = syscall(SC_writev, fd, iov, iov_count);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/sys/uio.h b/Userland/Libraries/LibC/sys/uio.h
new file mode 100644
index 0000000000..be310b38f1
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/uio.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct iovec {
+ void* iov_base;
+ size_t iov_len;
+};
+
+ssize_t writev(int fd, const struct iovec*, int iov_count);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/un.h b/Userland/Libraries/LibC/sys/un.h
new file mode 100644
index 0000000000..e0df306153
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/un.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define UNIX_PATH_MAX 108
+struct sockaddr_un {
+ uint16_t sun_family;
+ char sun_path[UNIX_PATH_MAX];
+};
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/utsname.h b/Userland/Libraries/LibC/sys/utsname.h
new file mode 100644
index 0000000000..1637a6c990
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/utsname.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#define UTSNAME_ENTRY_LEN 65
+
+__BEGIN_DECLS
+
+struct utsname {
+ char sysname[UTSNAME_ENTRY_LEN];
+ char nodename[UTSNAME_ENTRY_LEN];
+ char release[UTSNAME_ENTRY_LEN];
+ char version[UTSNAME_ENTRY_LEN];
+ char machine[UTSNAME_ENTRY_LEN];
+};
+
+int uname(struct utsname*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/sys/wait.cpp b/Userland/Libraries/LibC/sys/wait.cpp
new file mode 100644
index 0000000000..9969a8eec2
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/wait.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <assert.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+extern "C" {
+
+pid_t wait(int* wstatus)
+{
+ return waitpid(-1, wstatus, 0);
+}
+
+pid_t waitpid(pid_t waitee, int* wstatus, int options)
+{
+ siginfo_t siginfo;
+ idtype_t idtype;
+ id_t id;
+
+ if (waitee < -1) {
+ idtype = P_PGID;
+ id = -waitee;
+ } else if (waitee == -1) {
+ idtype = P_ALL;
+ id = 0;
+ } else if (waitee == 0) {
+ idtype = P_PGID;
+ id = getgid();
+ } else {
+ idtype = P_PID;
+ id = waitee;
+ }
+
+ // To be able to detect if a child was found when WNOHANG is set,
+ // we need to clear si_pid, which will only be set if it was found.
+ siginfo.si_pid = 0;
+ int rc = waitid(idtype, id, &siginfo, options | WEXITED);
+
+ if (rc < 0)
+ return rc;
+
+ if (wstatus) {
+ if ((options & WNOHANG) && siginfo.si_pid == 0) {
+ // No child in a waitable state was found. All other fields
+ // in siginfo are undefined
+ *wstatus = 0;
+ return 0;
+ }
+
+ switch (siginfo.si_code) {
+ case CLD_EXITED:
+ *wstatus = siginfo.si_status << 8;
+ break;
+ case CLD_KILLED:
+ *wstatus = siginfo.si_status;
+ break;
+ case CLD_STOPPED:
+ *wstatus = siginfo.si_status << 8 | 0x7f;
+ break;
+ case CLD_CONTINUED:
+ *wstatus = 0;
+ return 0; // return 0 if running
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ return siginfo.si_pid;
+}
+
+int waitid(idtype_t idtype, id_t id, siginfo_t* infop, int options)
+{
+ Syscall::SC_waitid_params params { idtype, id, infop, options };
+ int rc = syscall(SC_waitid, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/sys/wait.h b/Userland/Libraries/LibC/sys/wait.h
new file mode 100644
index 0000000000..825453292a
--- /dev/null
+++ b/Userland/Libraries/LibC/sys/wait.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <signal.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+#define WEXITSTATUS(status) (((status)&0xff00) >> 8)
+#define WSTOPSIG(status) WEXITSTATUS(status)
+#define WTERMSIG(status) ((status)&0x7f)
+#define WIFEXITED(status) (WTERMSIG(status) == 0)
+#define WIFSTOPPED(status) (((status)&0xff) == 0x7f)
+#define WIFSIGNALED(status) (((char)(((status)&0x7f) + 1) >> 1) > 0)
+
+#define WNOHANG 1
+#define WUNTRACED 2
+#define WSTOPPED WUNTRACED
+#define WEXITED 4
+#define WCONTINUED 8
+#define WNOWAIT 0x1000000
+
+typedef enum {
+ P_ALL = 1,
+ P_PID,
+ P_PGID
+} idtype_t;
+
+pid_t waitpid(pid_t, int* wstatus, int options);
+pid_t wait(int* wstatus);
+int waitid(idtype_t idtype, id_t id, siginfo_t* infop, int options);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/syslog.cpp b/Userland/Libraries/LibC/syslog.cpp
new file mode 100644
index 0000000000..650347da96
--- /dev/null
+++ b/Userland/Libraries/LibC/syslog.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Has to be defined before including due to legacy Unices
+#define SYSLOG_NAMES 1
+
+#include <AK/String.h>
+#include <AK/StringBuilder.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+// This implementation doesn't talk to a syslog server. Any options related to
+// that are no-ops.
+
+extern "C" {
+
+// For implementation simplicity, we actually only use the re-entrant version
+// of each function, and the version that isn't just redirects with a static
+// struct to share.
+static struct syslog_data global_log_data = {
+ .ident = nullptr,
+ .logopt = 0,
+ .facility = LOG_USER,
+ .maskpri = LOG_UPTO(LOG_DEBUG)
+};
+
+// Used when ident is null, since syslog traditionally prints the program's
+// own name; the process name will always be the same unless we exec.
+static char program_name_buffer[256];
+static bool program_name_set = false;
+
+// Convenience function for initialization and checking what string to use
+// for the program name.
+static const char* get_syslog_ident(struct syslog_data* data)
+{
+ if (!program_name_set && data->ident == nullptr)
+ program_name_set = get_process_name(program_name_buffer, sizeof(program_name_buffer)) >= 0;
+
+ if (data->ident != nullptr)
+ return data->ident;
+ else if (program_name_set)
+ return program_name_buffer;
+
+ ASSERT_NOT_REACHED();
+}
+
+void openlog_r(const char* ident, int logopt, int facility, struct syslog_data* data)
+{
+ data->ident = ident;
+ data->logopt = logopt;
+ data->facility = facility;
+ // default value
+ data->maskpri = LOG_UPTO(LOG_DEBUG);
+ // would be where we connect to a daemon
+}
+
+void openlog(const char* ident, int logopt, int facility)
+{
+ openlog_r(ident, logopt, facility, &global_log_data);
+}
+
+void closelog_r(struct syslog_data* data)
+{
+ // would be where we disconnect from a daemon
+ // restore defaults
+ data->ident = nullptr;
+ data->logopt = 0;
+ data->facility = LOG_USER;
+ data->maskpri = LOG_UPTO(LOG_DEBUG);
+}
+
+void closelog(void)
+{
+ closelog_r(&global_log_data);
+}
+
+int setlogmask_r(int maskpri, struct syslog_data* data)
+{
+ // Remember, this takes the input of LOG_MASK/LOG_UPTO
+ int old_maskpri = data->maskpri;
+ data->maskpri = maskpri;
+ return old_maskpri;
+}
+
+int setlogmask(int maskpri)
+{
+ return setlogmask_r(maskpri, &global_log_data);
+}
+
+void syslog_r(int priority, struct syslog_data* data, const char* message, ...)
+{
+ va_list ap;
+ va_start(ap, message);
+ vsyslog_r(priority, data, message, ap);
+ va_end(ap);
+}
+
+void syslog(int priority, const char* message, ...)
+{
+ va_list ap;
+ va_start(ap, message);
+ vsyslog_r(priority, &global_log_data, message, ap);
+ va_end(ap);
+}
+
+void vsyslog_r(int priority, struct syslog_data* data, const char* message, va_list args)
+{
+ StringBuilder combined;
+
+ int real_priority = LOG_PRI(priority);
+ // Lots of parens, but it just extracts the priority from combo and masks.
+ if (!(data->maskpri & LOG_MASK(real_priority)))
+ return;
+
+ // Some metadata would be consumed by a syslog daemon, if we had one.
+ if (data->logopt & LOG_PID)
+ combined.appendf("%s[%d]: ", get_syslog_ident(data), getpid());
+ else
+ combined.appendf("%s: ", get_syslog_ident(data));
+
+ combined.appendvf(message, args);
+ String combined_string = combined.build();
+
+ if (data->logopt & LOG_CONS)
+ dbgputstr(combined_string.characters(), combined_string.length());
+ if (data->logopt & LOG_PERROR)
+ fputs(combined_string.characters(), stderr);
+}
+
+void vsyslog(int priority, const char* message, va_list args)
+{
+ vsyslog_r(priority, &global_log_data, message, args);
+}
+}
diff --git a/Userland/Libraries/LibC/syslog.h b/Userland/Libraries/LibC/syslog.h
new file mode 100644
index 0000000000..eedebdc277
--- /dev/null
+++ b/Userland/Libraries/LibC/syslog.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stdarg.h>
+
+__BEGIN_DECLS
+
+struct syslog_data {
+ const char* ident;
+ int logopt;
+ int facility;
+ int maskpri;
+};
+
+/* The severity of the message. This is ordered. */
+#define LOG_EMERG 0
+#define LOG_ALERT 1
+#define LOG_CRIT 2
+#define LOG_ERR 3
+#define LOG_WARNING 4
+#define LOG_NOTICE 5
+#define LOG_INFO 6
+#define LOG_DEBUG 7
+
+/* Macros for masking out the priority of a combined priority */
+#define LOG_PRIMASK (7)
+#define LOG_PRI(priority) ((priority)&LOG_PRIMASK)
+
+/*
+ * Many of these facilities don't really make sense anymore, but we keep them
+ * for compatibility purposes.
+ */
+#define LOG_KERN (0 << 3)
+#define LOG_USER (1 << 3)
+#define LOG_MAIL (2 << 3)
+#define LOG_DAEMON (3 << 3)
+#define LOG_AUTH (4 << 3)
+#define LOG_SYSLOG (5 << 3)
+#define LOG_LPR (6 << 3)
+#define LOG_NEWS (7 << 3)
+#define LOG_UUCP (8 << 3)
+#define LOG_CRON (9 << 3)
+#define LOG_AUTHPRIV (10 << 3)
+#define LOG_FTP (11 << 3)
+/* glibc and OpenBSD reserve 12..15 for future system usage, we will too */
+#define LOG_LOCAL0 (16 << 3)
+#define LOG_LOCAL1 (17 << 3)
+#define LOG_LOCAL2 (18 << 3)
+#define LOG_LOCAL3 (19 << 3)
+#define LOG_LOCAL4 (20 << 3)
+#define LOG_LOCAL5 (21 << 3)
+#define LOG_LOCAL6 (22 << 3)
+#define LOG_LOCAL7 (23 << 3)
+
+#define LOG_NFACILITIES 24
+
+/* Macros to get the facility from a combined priority. */
+#define LOG_FACMASK (~7)
+#define LOG_FAC(priority) (((priority)&LOG_FACMASK) >> 3)
+
+/* For masking logs, we use these macros with just the priority. */
+#define LOG_MASK(priority) (1 << (priority))
+#define LOG_UPTO(priority) (LOG_MASK(priority) + (LOG_MASK(priority) - 1))
+
+/* Macro to make a combined priority. */
+#define LOG_MAKEPRI(facility, priority) ((facility) | (priority))
+
+/* Include a PID with the message. */
+#define LOG_PID (1 << 0)
+/* Log on the console. */
+#define LOG_CONS (1 << 1)
+/* Open the syslogd connection at the first call. (not implemented, default) */
+#define LOG_ODELAY (1 << 2)
+/* Open the syslogd connection immediately. (not implemented) */
+#define LOG_NDELAY (1 << 3)
+/* Log to stderr as well. */
+#define LOG_PERROR (1 << 4)
+
+/* This is useful to have, but has to be stored weirdly for compatibility. */
+#ifdef SYSLOG_NAMES
+/* Used for marking the fallback; some applications check for these defines. */
+# define INTERNAL_NOPRI 0x10
+# define INTERNAL_MARK LOG_MAKEPRI(LOG_NFACILITIES << 3, 0)
+
+typedef struct _code {
+ /*
+ * Most Unices define this as char*, but in C++, we have to define it as a
+ * const char* if we want to use string constants.
+ */
+ const char* c_name;
+ int c_val;
+} CODE;
+
+/*
+ * The names we use are the same as what glibc and OpenBSD use. We omit
+ * deprecated values in the hope that no one uses them. Sorted, as well.
+ */
+
+CODE prioritynames[] = {
+ { "alert", LOG_ALERT },
+ { "crit", LOG_CRIT },
+ { "debug", LOG_DEBUG },
+ { "emerg", LOG_EMERG },
+ { "err", LOG_ERR },
+ { "info", LOG_INFO },
+ /* Fallback */
+ { "none", INTERNAL_NOPRI },
+ { "notice", LOG_NOTICE },
+ { "warning", LOG_WARNING },
+ { NULL, -1 },
+};
+
+CODE facilitynames[] = {
+ { "auth", LOG_AUTH },
+ { "authpriv", LOG_AUTHPRIV },
+ { "cron", LOG_CRON },
+ { "daemon", LOG_DAEMON },
+ { "ftp", LOG_FTP },
+ { "kern", LOG_KERN },
+ { "local0", LOG_LOCAL0 },
+ { "local1", LOG_LOCAL1 },
+ { "local2", LOG_LOCAL2 },
+ { "local3", LOG_LOCAL3 },
+ { "local4", LOG_LOCAL4 },
+ { "local5", LOG_LOCAL5 },
+ { "local6", LOG_LOCAL6 },
+ { "local7", LOG_LOCAL7 },
+ { "lpr", LOG_LPR },
+ { "mail", LOG_MAIL },
+ /* Fallback */
+ { "mark", INTERNAL_MARK },
+ { "news", LOG_NEWS },
+ { "syslog", LOG_SYSLOG },
+ { "user", LOG_USER },
+ { "uucp", LOG_UUCP },
+ { NULL, -1 },
+};
+#endif
+
+/* The re-entrant versions are an OpenBSD extension we also implement. */
+void syslog(int, const char*, ...);
+void syslog_r(int, struct syslog_data*, const char*, ...);
+void vsyslog(int, const char* message, va_list);
+void vsyslog_r(int, struct syslog_data* data, const char* message, va_list);
+void openlog(const char*, int, int);
+void openlog_r(const char*, int, int, struct syslog_data*);
+void closelog(void);
+void closelog_r(struct syslog_data*);
+int setlogmask(int);
+int setlogmask_r(int, struct syslog_data*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/termcap.cpp b/Userland/Libraries/LibC/termcap.cpp
new file mode 100644
index 0000000000..1dcc73df68
--- /dev/null
+++ b/Userland/Libraries/LibC/termcap.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/HashMap.h>
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <termcap.h>
+
+//#define TERMCAP_DEBUG
+
+extern "C" {
+
+char PC;
+char* UP;
+char* BC;
+
+int tgetent([[maybe_unused]] char* bp, [[maybe_unused]] const char* name)
+{
+#ifdef TERMCAP_DEBUG
+ fprintf(stderr, "tgetent: bp=%p, name='%s'\n", bp, name);
+#endif
+ PC = '\0';
+ BC = const_cast<char*>("\033[D");
+ UP = const_cast<char*>("\033[A");
+ return 1;
+}
+
+static HashMap<String, const char*>* caps = nullptr;
+
+static void ensure_caps()
+{
+ if (caps)
+ return;
+ caps = new HashMap<String, const char*>;
+ caps->set("DC", "\033[%p1%dP");
+ caps->set("IC", "\033[%p1%d@");
+ caps->set("ce", "\033[K");
+ caps->set("cl", "\033[H\033[J");
+ caps->set("cr", "\015");
+ caps->set("dc", "\033[P");
+ caps->set("ei", "");
+ caps->set("ic", "");
+ caps->set("im", "");
+ caps->set("kd", "\033[B");
+ caps->set("kl", "\033[D");
+ caps->set("kr", "\033[C");
+ caps->set("ku", "\033[A");
+ caps->set("ks", "");
+ caps->set("ke", "");
+ caps->set("le", "\033[D");
+ caps->set("mm", "");
+ caps->set("mo", "");
+ caps->set("pc", "");
+ caps->set("up", "\033[A");
+ caps->set("vb", "");
+ caps->set("am", "");
+ caps->set("@7", "");
+ caps->set("kH", "");
+ caps->set("kI", "\033[L");
+ caps->set("kh", "\033[H");
+ caps->set("vs", "");
+ caps->set("ve", "");
+ caps->set("E3", "");
+ caps->set("kD", "");
+ caps->set("nd", "\033[C");
+
+ caps->set("co", "80");
+ caps->set("li", "25");
+}
+
+// Unfortunately, tgetstr() doesn't accept a size argument for the buffer
+// pointed to by area, so we have to use bare strcpy().
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+char* tgetstr(const char* id, char** area)
+{
+ ensure_caps();
+#ifdef TERMCAP_DEBUG
+ fprintf(stderr, "tgetstr: id='%s'\n", id);
+#endif
+ auto it = caps->find(id);
+ if (it != caps->end()) {
+ char* ret = *area;
+ const char* val = (*it).value;
+ strcpy(*area, val);
+ *area += strlen(val) + 1;
+ return ret;
+ }
+ fprintf(stderr, "tgetstr: missing cap id='%s'\n", id);
+ return nullptr;
+}
+
+#pragma GCC diagnostic pop
+
+int tgetflag([[maybe_unused]] const char* id)
+{
+#ifdef TERMCAP_DEBUG
+ fprintf(stderr, "tgetflag: '%s'\n", id);
+#endif
+ auto it = caps->find(id);
+ if (it != caps->end())
+ return 1;
+ return 0;
+}
+
+int tgetnum(const char* id)
+{
+#ifdef TERMCAP_DEBUG
+ fprintf(stderr, "tgetnum: '%s'\n", id);
+#endif
+ auto it = caps->find(id);
+ if (it != caps->end())
+ return atoi((*it).value);
+ ASSERT_NOT_REACHED();
+}
+
+static Vector<char> s_tgoto_buffer;
+char* tgoto([[maybe_unused]] const char* cap, [[maybe_unused]] int col, [[maybe_unused]] int row)
+{
+ auto cap_str = String(cap);
+ cap_str.replace("%p1%d", String::format("%d", col));
+ cap_str.replace("%p2%d", String::format("%d", row));
+
+ s_tgoto_buffer.clear_with_capacity();
+ s_tgoto_buffer.ensure_capacity(cap_str.length());
+ (void)cap_str.copy_characters_to_buffer(s_tgoto_buffer.data(), cap_str.length());
+ return s_tgoto_buffer.data();
+}
+
+int tputs(const char* str, [[maybe_unused]] int affcnt, int (*putc)(int))
+{
+ size_t len = strlen(str);
+ for (size_t i = 0; i < len; ++i)
+ putc(str[i]);
+ return 0;
+}
+}
diff --git a/Userland/Libraries/LibC/termcap.h b/Userland/Libraries/LibC/termcap.h
new file mode 100644
index 0000000000..b018cf14cb
--- /dev/null
+++ b/Userland/Libraries/LibC/termcap.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern char PC;
+extern char* UP;
+extern char* BC;
+
+int tgetent(char* bp, const char* name);
+int tgetflag(const char* id);
+int tgetnum(const char* id);
+char* tgetstr(const char* id, char** area);
+char* tgoto(const char* cap, int col, int row);
+int tputs(const char* str, int affcnt, int (*putc)(int));
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/termios.cpp b/Userland/Libraries/LibC/termios.cpp
new file mode 100644
index 0000000000..1037b0ab61
--- /dev/null
+++ b/Userland/Libraries/LibC/termios.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+extern "C" {
+
+int tcgetattr(int fd, struct termios* t)
+{
+ return ioctl(fd, TCGETS, t);
+}
+
+int tcsetattr(int fd, int optional_actions, const struct termios* t)
+{
+ switch (optional_actions) {
+ case TCSANOW:
+ return ioctl(fd, TCSETS, t);
+ case TCSADRAIN:
+ return ioctl(fd, TCSETSW, t);
+ case TCSAFLUSH:
+ return ioctl(fd, TCSETSF, t);
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+int tcflow([[maybe_unused]] int fd, [[maybe_unused]] int action)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int tcflush(int fd, int queue_selector)
+{
+ return ioctl(fd, TCFLSH, queue_selector);
+}
+
+speed_t cfgetispeed(const struct termios* tp)
+{
+ return tp->c_ispeed;
+}
+
+speed_t cfgetospeed(const struct termios* tp)
+{
+ return tp->c_ospeed;
+}
+
+static int baud_rate_from_speed(speed_t speed)
+{
+ int rate = -EINVAL;
+ switch (speed) {
+ case B0:
+ rate = 0;
+ break;
+ case B50:
+ rate = 50;
+ break;
+ case B75:
+ rate = 75;
+ break;
+ case B110:
+ rate = 110;
+ break;
+ case B134:
+ rate = 134;
+ break;
+ case B150:
+ rate = 150;
+ break;
+ case B200:
+ rate = 200;
+ break;
+ case B300:
+ rate = 300;
+ break;
+ case B600:
+ rate = 600;
+ break;
+ case B1200:
+ rate = 1200;
+ break;
+ case B1800:
+ rate = 1800;
+ break;
+ case B2400:
+ rate = 2400;
+ break;
+ case B4800:
+ rate = 4800;
+ break;
+ case B9600:
+ rate = 9600;
+ break;
+ case B19200:
+ rate = 19200;
+ break;
+ case B38400:
+ rate = 38400;
+ break;
+ }
+
+ return rate;
+}
+
+int cfsetispeed(struct termios* tp, speed_t speed)
+{
+ auto ispeed = baud_rate_from_speed(speed);
+ if (ispeed > 0) {
+ tp->c_ispeed = ispeed;
+ }
+ __RETURN_WITH_ERRNO(ispeed, 0, -1);
+}
+
+int cfsetospeed(struct termios* tp, speed_t speed)
+{
+ auto ospeed = baud_rate_from_speed(speed);
+ if (ospeed > 0) {
+ tp->c_ispeed = ospeed;
+ }
+ __RETURN_WITH_ERRNO(ospeed, 0, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/termios.h b/Userland/Libraries/LibC/termios.h
new file mode 100644
index 0000000000..028ddc06a5
--- /dev/null
+++ b/Userland/Libraries/LibC/termios.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+#define NCCS 32
+
+typedef uint32_t tcflag_t;
+typedef uint8_t cc_t;
+typedef uint32_t speed_t;
+
+struct termios {
+ tcflag_t c_iflag;
+ tcflag_t c_oflag;
+ tcflag_t c_cflag;
+ tcflag_t c_lflag;
+ cc_t c_cc[NCCS];
+ speed_t c_ispeed;
+ speed_t c_ospeed;
+};
+
+int tcgetattr(int fd, struct termios*);
+int tcsetattr(int fd, int optional_actions, const struct termios*);
+int tcflow(int fd, int action);
+int tcflush(int fd, int queue_selector);
+
+speed_t cfgetispeed(const struct termios*);
+speed_t cfgetospeed(const struct termios*);
+int cfsetispeed(struct termios*, speed_t);
+int cfsetospeed(struct termios*, speed_t);
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK 0000020
+#define ISTRIP 0000040
+#define INLCR 0000100
+#define IGNCR 0000200
+#define ICRNL 0000400
+#define IUCLC 0001000
+#define IXON 0002000
+#define IXANY 0004000
+#define IXOFF 0010000
+#define IMAXBEL 0020000
+#define IUTF8 0040000
+
+/* c_oflag bits */
+#define OPOST 0000001
+#define OLCUC 0000002
+#define ONLCR 0000004
+#define OCRNL 0000010
+#define ONOCR 0000020
+#define ONLRET 0000040
+#define OFILL 0000100
+#define OFDEL 0000200
+#if defined __USE_MISC || defined __USE_XOPEN
+# define NLDLY 0000400
+# define NL0 0000000
+# define NL1 0000400
+# define CRDLY 0003000
+# define CR0 0000000
+# define CR1 0001000
+# define CR2 0002000
+# define CR3 0003000
+# define TABDLY 0014000
+# define TAB0 0000000
+# define TAB1 0004000
+# define TAB2 0010000
+# define TAB3 0014000
+# define BSDLY 0020000
+# define BS0 0000000
+# define BS1 0020000
+# define FFDLY 0100000
+# define FF0 0000000
+# define FF1 0100000
+#endif
+
+#define VTDLY 0040000
+#define VT0 0000000
+#define VT1 0040000
+
+#ifdef __USE_MISC
+# define XTABS 0014000
+#endif
+
+/* c_cflag bit meaning */
+#ifdef __USE_MISC
+# define CBAUD 0010017
+#endif
+#define B0 0000000 /* hang up */
+#define B50 0000001
+#define B75 0000002
+#define B110 0000003
+#define B134 0000004
+#define B150 0000005
+#define B200 0000006
+#define B300 0000007
+#define B600 0000010
+#define B1200 0000011
+#define B1800 0000012
+#define B2400 0000013
+#define B4800 0000014
+#define B9600 0000015
+#define B19200 0000016
+#define B38400 0000017
+#ifdef __USE_MISC
+# define EXTA B19200
+# define EXTB B38400
+#endif
+#define CSIZE 0000060
+#define CS5 0000000
+#define CS6 0000020
+#define CS7 0000040
+#define CS8 0000060
+#define CSTOPB 0000100
+#define CREAD 0000200
+#define PARENB 0000400
+#define PARODD 0001000
+#define HUPCL 0002000
+#define CLOCAL 0004000
+#ifdef __USE_MISC
+# define CBAUDEX 0010000
+#endif
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
+#define __MAX_BAUD B4000000
+#ifdef __USE_MISC
+# define CIBAUD 002003600000 /* input baud rate (not used) */
+# define CMSPAR 010000000000 /* mark or space (stick) parity */
+# define CRTSCTS 020000000000 /* flow control */
+#endif
+
+/* c_lflag bits */
+#define ISIG 0000001
+#define ICANON 0000002
+#if defined __USE_MISC || (defined __USE_XOPEN && !defined __USE_XOPEN2K)
+# define XCASE 0000004
+#endif
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#ifdef __USE_MISC
+# define ECHOCTL 0001000
+# define ECHOPRT 0002000
+# define ECHOKE 0004000
+# define FLUSHO 0010000
+# define PENDIN 0040000
+#endif
+#define IEXTEN 0100000
+#ifdef __USE_MISC
+# define EXTPROC 0200000
+#endif
+
+/* tcflow() and TCXONC use these */
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
+/* tcflush() and TCFLSH use these */
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+
+/* tcsetattr uses these */
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/time.cpp b/Userland/Libraries/LibC/time.cpp
new file mode 100644
index 0000000000..73f1a4234d
--- /dev/null
+++ b/Userland/Libraries/LibC/time.cpp
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/String.h>
+#include <AK/StringBuilder.h>
+#include <AK/Time.h>
+#include <Kernel/API/Syscall.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <time.h>
+
+extern "C" {
+
+time_t time(time_t* tloc)
+{
+ struct timeval tv;
+ struct timezone tz;
+ if (gettimeofday(&tv, &tz) < 0)
+ return (time_t)-1;
+ if (tloc)
+ *tloc = tv.tv_sec;
+ return tv.tv_sec;
+}
+
+int adjtime(const struct timeval* delta, struct timeval* old_delta)
+{
+ int rc = syscall(SC_adjtime, delta, old_delta);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int gettimeofday(struct timeval* __restrict__ tv, void* __restrict__)
+{
+ int rc = syscall(SC_gettimeofday, tv);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int settimeofday(struct timeval* __restrict__ tv, void* __restrict__)
+{
+ timespec ts;
+ TIMEVAL_TO_TIMESPEC(tv, &ts);
+ return clock_settime(CLOCK_REALTIME, &ts);
+}
+
+char* ctime(const time_t* t)
+{
+ return asctime(localtime(t));
+}
+
+static const int __seconds_per_day = 60 * 60 * 24;
+
+static void time_to_tm(struct tm* tm, time_t t)
+{
+ int year = 1970;
+ for (; t >= days_in_year(year) * __seconds_per_day; ++year)
+ t -= days_in_year(year) * __seconds_per_day;
+ for (; t < 0; --year)
+ t += days_in_year(year - 1) * __seconds_per_day;
+ tm->tm_year = year - 1900;
+
+ ASSERT(t >= 0);
+ int days = t / __seconds_per_day;
+ tm->tm_yday = days;
+ int remaining = t % __seconds_per_day;
+ tm->tm_sec = remaining % 60;
+ remaining /= 60;
+ tm->tm_min = remaining % 60;
+ tm->tm_hour = remaining / 60;
+
+ int month;
+ for (month = 1; month < 12 && days >= days_in_month(year, month); ++month)
+ days -= days_in_month(year, month);
+
+ tm->tm_mday = days + 1;
+ tm->tm_wday = day_of_week(year, month, tm->tm_mday);
+ tm->tm_mon = month - 1;
+}
+
+static time_t tm_to_time(struct tm* tm, long timezone_adjust_seconds)
+{
+ // "The original values of the tm_wday and tm_yday components of the structure are ignored,
+ // and the original values of the other components are not restricted to the ranges described in <time.h>.
+ // [...]
+ // Upon successful completion, the values of the tm_wday and tm_yday components of the structure shall be set appropriately,
+ // and the other components are set to represent the specified time since the Epoch,
+ // but with their values forced to the ranges indicated in the <time.h> entry;
+ // the final value of tm_mday shall not be set until tm_mon and tm_year are determined."
+
+ // FIXME: Handle tm_isdst eventually.
+
+ tm->tm_year += tm->tm_mon / 12;
+ tm->tm_mon %= 12;
+ if (tm->tm_mon < 0) {
+ tm->tm_year--;
+ tm->tm_mon += 12;
+ }
+
+ tm->tm_yday = day_of_year(1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
+ time_t days_since_epoch = years_to_days_since_epoch(1900 + tm->tm_year) + tm->tm_yday;
+ auto timestamp = ((days_since_epoch * 24 + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec + timezone_adjust_seconds;
+ time_to_tm(tm, timestamp);
+ return timestamp;
+}
+
+time_t mktime(struct tm* tm)
+{
+ return tm_to_time(tm, timezone);
+}
+
+struct tm* localtime(const time_t* t)
+{
+ static struct tm tm_buf;
+ return localtime_r(t, &tm_buf);
+}
+
+struct tm* localtime_r(const time_t* t, struct tm* tm)
+{
+ if (!t)
+ return nullptr;
+ time_to_tm(tm, (*t) - timezone);
+ return tm;
+}
+
+time_t timegm(struct tm* tm)
+{
+ return tm_to_time(tm, 0);
+}
+
+struct tm* gmtime(const time_t* t)
+{
+ static struct tm tm_buf;
+ return gmtime_r(t, &tm_buf);
+}
+
+struct tm* gmtime_r(const time_t* t, struct tm* tm)
+{
+ if (!t)
+ return nullptr;
+ time_to_tm(tm, *t);
+ return tm;
+}
+
+char* asctime(const struct tm* tm)
+{
+ static char buffer[69];
+ strftime(buffer, sizeof buffer, "%a %b %e %T %Y", tm);
+ return buffer;
+}
+
+//FIXME: Some formats are not supported.
+size_t strftime(char* destination, size_t max_size, const char* format, const struct tm* tm)
+{
+ const char wday_short_names[7][4] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ const char wday_long_names[7][10] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ };
+ const char mon_short_names[12][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ const char mon_long_names[12][10] = {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ };
+
+ StringBuilder builder { max_size };
+
+ const int format_len = strlen(format);
+ for (int i = 0; i < format_len; ++i) {
+ if (format[i] != '%') {
+ builder.append(format[i]);
+ } else {
+ if (++i >= format_len)
+ return 0;
+
+ switch (format[i]) {
+ case 'a':
+ builder.append(wday_short_names[tm->tm_wday]);
+ break;
+ case 'A':
+ builder.append(wday_long_names[tm->tm_wday]);
+ break;
+ case 'b':
+ builder.append(mon_short_names[tm->tm_mon]);
+ break;
+ case 'B':
+ builder.append(mon_long_names[tm->tm_mon]);
+ break;
+ case 'C':
+ builder.appendf("%02d", (tm->tm_year + 1900) / 100);
+ break;
+ case 'd':
+ builder.appendf("%02d", tm->tm_mday);
+ break;
+ case 'D':
+ builder.appendf("%02d/%02d/%02d", tm->tm_mon + 1, tm->tm_mday, (tm->tm_year + 1900) % 100);
+ break;
+ case 'e':
+ builder.appendf("%2d", tm->tm_mday);
+ break;
+ case 'h':
+ builder.append(mon_short_names[tm->tm_mon]);
+ break;
+ case 'H':
+ builder.appendf("%02d", tm->tm_hour);
+ break;
+ case 'I':
+ builder.appendf("%02d", tm->tm_hour % 12);
+ break;
+ case 'j':
+ builder.appendf("%03d", tm->tm_yday + 1);
+ break;
+ case 'm':
+ builder.appendf("%02d", tm->tm_mon + 1);
+ break;
+ case 'M':
+ builder.appendf("%02d", tm->tm_min);
+ break;
+ case 'n':
+ builder.append('\n');
+ break;
+ case 'p':
+ builder.append(tm->tm_hour < 12 ? "a.m." : "p.m.");
+ break;
+ case 'r':
+ builder.appendf("%02d:%02d:%02d %s", tm->tm_hour % 12, tm->tm_min, tm->tm_sec, tm->tm_hour < 12 ? "a.m." : "p.m.");
+ break;
+ case 'R':
+ builder.appendf("%02d:%02d", tm->tm_hour, tm->tm_min);
+ break;
+ case 'S':
+ builder.appendf("%02d", tm->tm_sec);
+ break;
+ case 't':
+ builder.append('\t');
+ break;
+ case 'T':
+ builder.appendf("%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
+ break;
+ case 'u':
+ builder.appendf("%d", tm->tm_wday ? tm->tm_wday : 7);
+ break;
+ case 'U': {
+ const int wday_of_year_beginning = (tm->tm_wday + 6 * tm->tm_yday) % 7;
+ const int week_number = (tm->tm_yday + wday_of_year_beginning) / 7;
+ builder.appendf("%02d", week_number);
+ break;
+ }
+ case 'V': {
+ const int wday_of_year_beginning = (tm->tm_wday + 6 + 6 * tm->tm_yday) % 7;
+ int week_number = (tm->tm_yday + wday_of_year_beginning) / 7 + 1;
+ if (wday_of_year_beginning > 3) {
+ if (tm->tm_yday >= 7 - wday_of_year_beginning)
+ --week_number;
+ else {
+ const int days_of_last_year = days_in_year(tm->tm_year + 1900 - 1);
+ const int wday_of_last_year_beginning = (wday_of_year_beginning + 6 * days_of_last_year) % 7;
+ week_number = (days_of_last_year + wday_of_last_year_beginning) / 7 + 1;
+ if (wday_of_last_year_beginning > 3)
+ --week_number;
+ }
+ }
+ builder.appendf("%02d", week_number);
+ break;
+ }
+ case 'w':
+ builder.appendf("%d", tm->tm_wday);
+ break;
+ case 'W': {
+ const int wday_of_year_beginning = (tm->tm_wday + 6 + 6 * tm->tm_yday) % 7;
+ const int week_number = (tm->tm_yday + wday_of_year_beginning) / 7;
+ builder.appendf("%02d", week_number);
+ break;
+ }
+ case 'y':
+ builder.appendf("%02d", (tm->tm_year + 1900) % 100);
+ break;
+ case 'Y':
+ builder.appendf("%d", tm->tm_year + 1900);
+ break;
+ case '%':
+ builder.append('%');
+ break;
+ default:
+ return 0;
+ }
+ }
+ if (builder.length() + 1 > max_size)
+ return 0;
+ }
+
+ auto str = builder.build();
+ bool fits = str.copy_characters_to_buffer(destination, max_size);
+ return fits ? str.length() : 0;
+}
+
+long timezone = 0;
+long altzone;
+char* tzname[2];
+int daylight;
+
+void tzset()
+{
+ //FIXME: Here we prepend we are in UTC+0.
+ timezone = 0;
+}
+
+clock_t clock()
+{
+ struct tms tms;
+ times(&tms);
+ return tms.tms_utime + tms.tms_stime;
+}
+
+int clock_gettime(clockid_t clock_id, struct timespec* ts)
+{
+ int rc = syscall(SC_clock_gettime, clock_id, ts);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int clock_settime(clockid_t clock_id, struct timespec* ts)
+{
+ int rc = syscall(SC_clock_settime, clock_id, ts);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* requested_sleep, struct timespec* remaining_sleep)
+{
+ Syscall::SC_clock_nanosleep_params params { clock_id, flags, requested_sleep, remaining_sleep };
+ int rc = syscall(SC_clock_nanosleep, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int nanosleep(const struct timespec* requested_sleep, struct timespec* remaining_sleep)
+{
+ return clock_nanosleep(CLOCK_REALTIME, 0, requested_sleep, remaining_sleep);
+}
+
+int clock_getres(clockid_t, struct timespec*)
+{
+ ASSERT_NOT_REACHED();
+}
+
+double difftime(time_t t1, time_t t0)
+{
+ return (double)(t1 - t0);
+}
+}
diff --git a/Userland/Libraries/LibC/time.h b/Userland/Libraries/LibC/time.h
new file mode 100644
index 0000000000..74cf7f8de6
--- /dev/null
+++ b/Userland/Libraries/LibC/time.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct tm {
+ int tm_sec; /* Seconds (0-60) */
+ int tm_min; /* Minutes (0-59) */
+ int tm_hour; /* Hours (0-23) */
+ int tm_mday; /* Day of the month (1-31) */
+ int tm_mon; /* Month (0-11) */
+ int tm_year; /* Year - 1900 */
+ int tm_wday; /* Day of the week (0-6, Sunday = 0) */
+ int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
+ int tm_isdst; /* Daylight saving time */
+};
+
+extern long timezone; /* The difference in seconds between UTC and local time */
+extern long altzone;
+extern char* tzname[2];
+extern int daylight;
+
+typedef uint32_t clock_t;
+typedef int64_t time_t;
+
+struct tm* localtime(const time_t*);
+struct tm* gmtime(const time_t*);
+time_t mktime(struct tm*);
+time_t timegm(struct tm*);
+time_t time(time_t*);
+char* ctime(const time_t*);
+void tzset();
+char* asctime(const struct tm*);
+
+#define CLOCKS_PER_SEC 1000
+clock_t clock();
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+typedef int clockid_t;
+
+#define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 1
+#define CLOCK_MONOTONIC_RAW 4
+#define CLOCK_REALTIME_COARSE 5
+#define CLOCK_MONOTONIC_COARSE 6
+#define TIMER_ABSTIME 99
+
+int clock_gettime(clockid_t, struct timespec*);
+int clock_settime(clockid_t, struct timespec*);
+int clock_nanosleep(clockid_t, int flags, const struct timespec* requested_sleep, struct timespec* remaining_sleep);
+int clock_getres(clockid_t, struct timespec* result);
+int nanosleep(const struct timespec* requested_sleep, struct timespec* remaining_sleep);
+struct tm* gmtime_r(const time_t* timep, struct tm* result);
+struct tm* localtime_r(const time_t* timep, struct tm* result);
+
+double difftime(time_t, time_t);
+size_t strftime(char* s, size_t max, const char* format, const struct tm*) __attribute__((format(strftime, 3, 0)));
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/times.cpp b/Userland/Libraries/LibC/times.cpp
new file mode 100644
index 0000000000..012dfc7d70
--- /dev/null
+++ b/Userland/Libraries/LibC/times.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <sys/times.h>
+
+clock_t times(struct tms* buf)
+{
+ int rc = syscall(SC_times, buf);
+ __RETURN_WITH_ERRNO(rc, rc, (clock_t)-1);
+}
diff --git a/Userland/Libraries/LibC/ulimit.cpp b/Userland/Libraries/LibC/ulimit.cpp
new file mode 100644
index 0000000000..1ab9b7dc3a
--- /dev/null
+++ b/Userland/Libraries/LibC/ulimit.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/LogStream.h>
+#include <assert.h>
+#include <sys/resource.h>
+#include <ulimit.h>
+
+extern "C" {
+
+long ulimit([[maybe_unused]] int cmd, [[maybe_unused]] long newlimit)
+{
+ ASSERT_NOT_REACHED();
+ return -1;
+}
+
+int getrusage([[maybe_unused]] int who, [[maybe_unused]] struct rusage* usage)
+{
+ dbgln("LibC: getrusage is not implemented");
+ return -1;
+}
+}
diff --git a/Userland/Libraries/LibC/ulimit.h b/Userland/Libraries/LibC/ulimit.h
new file mode 100644
index 0000000000..dd48401c6e
--- /dev/null
+++ b/Userland/Libraries/LibC/ulimit.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+long ulimit(int cmd, long newlimit);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/unistd.cpp b/Userland/Libraries/LibC/unistd.cpp
new file mode 100644
index 0000000000..b35f011289
--- /dev/null
+++ b/Userland/Libraries/LibC/unistd.cpp
@@ -0,0 +1,725 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/ScopedValueRollback.h>
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <Kernel/API/Syscall.h>
+#include <alloca.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+extern "C" {
+
+#ifdef NO_TLS
+static int s_cached_tid = 0;
+#else
+static __thread int s_cached_tid = 0;
+#endif
+
+static int s_cached_pid = 0;
+
+int chown(const char* pathname, uid_t uid, gid_t gid)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_chown_params params { { pathname, strlen(pathname) }, uid, gid };
+ int rc = syscall(SC_chown, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int fchown(int fd, uid_t uid, gid_t gid)
+{
+ int rc = syscall(SC_fchown, fd, uid, gid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+pid_t fork()
+{
+ int rc = syscall(SC_fork);
+ if (rc == 0) {
+ s_cached_tid = 0;
+ s_cached_pid = 0;
+ }
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int execv(const char* path, char* const argv[])
+{
+ return execve(path, argv, environ);
+}
+
+int execve(const char* filename, char* const argv[], char* const envp[])
+{
+ size_t arg_count = 0;
+ for (size_t i = 0; argv[i]; ++i)
+ ++arg_count;
+
+ size_t env_count = 0;
+ for (size_t i = 0; envp[i]; ++i)
+ ++env_count;
+
+ auto copy_strings = [&](auto& vec, size_t count, auto& output) {
+ output.length = count;
+ for (size_t i = 0; vec[i]; ++i) {
+ output.strings[i].characters = vec[i];
+ output.strings[i].length = strlen(vec[i]);
+ }
+ };
+
+ Syscall::SC_execve_params params;
+ params.arguments.strings = (Syscall::StringArgument*)alloca(arg_count * sizeof(Syscall::StringArgument));
+ params.environment.strings = (Syscall::StringArgument*)alloca(env_count * sizeof(Syscall::StringArgument));
+
+ params.path = { filename, strlen(filename) };
+ copy_strings(argv, arg_count, params.arguments);
+ copy_strings(envp, env_count, params.environment);
+
+ int rc = syscall(SC_execve, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int execvpe(const char* filename, char* const argv[], char* const envp[])
+{
+ if (strchr(filename, '/'))
+ return execve(filename, argv, envp);
+
+ ScopedValueRollback errno_rollback(errno);
+ String path = getenv("PATH");
+ if (path.is_empty())
+ path = "/bin:/usr/bin";
+ auto parts = path.split(':');
+ for (auto& part : parts) {
+ auto candidate = String::format("%s/%s", part.characters(), filename);
+ int rc = execve(candidate.characters(), argv, envp);
+ if (rc < 0 && errno != ENOENT) {
+ errno_rollback.set_override_rollback_value(errno);
+ dbgln("execvpe() failed on attempt ({}) with {}", candidate, strerror(errno));
+ return rc;
+ }
+ }
+ errno_rollback.set_override_rollback_value(ENOENT);
+ dbgln("execvpe() leaving :(");
+ return -1;
+}
+
+int execvp(const char* filename, char* const argv[])
+{
+ int rc = execvpe(filename, argv, environ);
+ int saved_errno = errno;
+ dbgln("execvp() about to return {} with errno={}", rc, saved_errno);
+ errno = saved_errno;
+ return rc;
+}
+
+int execl(const char* filename, const char* arg0, ...)
+{
+ Vector<const char*, 16> args;
+ args.append(arg0);
+
+ va_list ap;
+ va_start(ap, arg0);
+ for (;;) {
+ const char* arg = va_arg(ap, const char*);
+ if (!arg)
+ break;
+ args.append(arg);
+ }
+ va_end(ap);
+ args.append(nullptr);
+ return execve(filename, const_cast<char* const*>(args.data()), environ);
+}
+
+int execlp(const char* filename, const char* arg0, ...)
+{
+ Vector<const char*, 16> args;
+ args.append(arg0);
+
+ va_list ap;
+ va_start(ap, arg0);
+ for (;;) {
+ const char* arg = va_arg(ap, const char*);
+ if (!arg)
+ break;
+ args.append(arg);
+ }
+ va_end(ap);
+ args.append(nullptr);
+ return execvpe(filename, const_cast<char* const*>(args.data()), environ);
+}
+
+uid_t geteuid()
+{
+ return syscall(SC_geteuid);
+}
+
+gid_t getegid()
+{
+ return syscall(SC_getegid);
+}
+
+uid_t getuid()
+{
+ return syscall(SC_getuid);
+}
+
+gid_t getgid()
+{
+ return syscall(SC_getgid);
+}
+
+pid_t getpid()
+{
+ int cached_pid = s_cached_pid;
+ if (!cached_pid) {
+ cached_pid = syscall(SC_getpid);
+ s_cached_pid = cached_pid;
+ }
+ return cached_pid;
+}
+
+pid_t getppid()
+{
+ return syscall(SC_getppid);
+}
+
+int getresuid(uid_t* ruid, uid_t* euid, uid_t* suid)
+{
+ return syscall(SC_getresuid, ruid, euid, suid);
+}
+
+int getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid)
+{
+ return syscall(SC_getresgid, rgid, egid, sgid);
+}
+
+pid_t getsid(pid_t pid)
+{
+ int rc = syscall(SC_getsid, pid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+pid_t setsid()
+{
+ int rc = syscall(SC_setsid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+pid_t tcgetpgrp(int fd)
+{
+ return ioctl(fd, TIOCGPGRP);
+}
+
+int tcsetpgrp(int fd, pid_t pgid)
+{
+ return ioctl(fd, TIOCSPGRP, pgid);
+}
+
+int setpgid(pid_t pid, pid_t pgid)
+{
+ int rc = syscall(SC_setpgid, pid, pgid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+pid_t getpgid(pid_t pid)
+{
+ int rc = syscall(SC_getpgid, pid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+pid_t getpgrp()
+{
+ int rc = syscall(SC_getpgrp);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+ssize_t read(int fd, void* buf, size_t count)
+{
+ int rc = syscall(SC_read, fd, buf, count);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+ssize_t write(int fd, const void* buf, size_t count)
+{
+ int rc = syscall(SC_write, fd, buf, count);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int ttyname_r(int fd, char* buffer, size_t size)
+{
+ int rc = syscall(SC_ttyname, fd, buffer, size);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+static char ttyname_buf[32];
+char* ttyname(int fd)
+{
+ if (ttyname_r(fd, ttyname_buf, sizeof(ttyname_buf)) < 0)
+ return nullptr;
+ return ttyname_buf;
+}
+
+int close(int fd)
+{
+ int rc = syscall(SC_close, fd);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int chdir(const char* path)
+{
+ if (!path) {
+ errno = EFAULT;
+ return -1;
+ }
+ int rc = syscall(SC_chdir, path, strlen(path));
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int fchdir(int fd)
+{
+ int rc = syscall(SC_fchdir, fd);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+char* getcwd(char* buffer, size_t size)
+{
+ if (!buffer) {
+ size = size ? size : PATH_MAX;
+ buffer = (char*)malloc(size);
+ }
+ int rc = syscall(SC_getcwd, buffer, size);
+ __RETURN_WITH_ERRNO(rc, buffer, nullptr);
+}
+
+char* getwd(char* buf)
+{
+ auto* p = getcwd(buf, PATH_MAX);
+ return p;
+}
+
+int sleep(unsigned seconds)
+{
+ struct timespec ts = { seconds, 0 };
+ if (clock_nanosleep(CLOCK_MONOTONIC_COARSE, 0, &ts, nullptr) < 0)
+ return ts.tv_sec;
+ return 0;
+}
+
+int usleep(useconds_t usec)
+{
+ struct timespec ts = { (long)(usec / 1000000), (long)(usec % 1000000) * 1000 };
+ return clock_nanosleep(CLOCK_MONOTONIC_COARSE, 0, &ts, nullptr);
+}
+
+int gethostname(char* buffer, size_t size)
+{
+ int rc = syscall(SC_gethostname, buffer, size);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int sethostname(const char* hostname, ssize_t size)
+{
+ int rc = syscall(SC_sethostname, hostname, size);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+ssize_t readlink(const char* path, char* buffer, size_t size)
+{
+ Syscall::SC_readlink_params params { { path, strlen(path) }, { buffer, size } };
+ int rc = syscall(SC_readlink, &params);
+ // Return the number of bytes placed in the buffer, not the full path size.
+ __RETURN_WITH_ERRNO(rc, min((size_t)rc, size), -1);
+}
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+ int rc = syscall(SC_lseek, fd, offset, whence);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int link(const char* old_path, const char* new_path)
+{
+ if (!old_path || !new_path) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_link_params params { { old_path, strlen(old_path) }, { new_path, strlen(new_path) } };
+ int rc = syscall(SC_link, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int unlink(const char* pathname)
+{
+ int rc = syscall(SC_unlink, pathname, strlen(pathname));
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int symlink(const char* target, const char* linkpath)
+{
+ if (!target || !linkpath) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_symlink_params params { { target, strlen(target) }, { linkpath, strlen(linkpath) } };
+ int rc = syscall(SC_symlink, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int rmdir(const char* pathname)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ int rc = syscall(SC_rmdir, pathname, strlen(pathname));
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int isatty(int fd)
+{
+ return fcntl(fd, F_ISTTY);
+}
+
+int dup(int old_fd)
+{
+ return fcntl(old_fd, F_DUPFD, 0);
+}
+
+int dup2(int old_fd, int new_fd)
+{
+ int rc = syscall(SC_dup2, old_fd, new_fd);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int setgroups(size_t size, const gid_t* list)
+{
+ int rc = syscall(SC_setgroups, size, list);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int getgroups(int size, gid_t list[])
+{
+ int rc = syscall(SC_getgroups, size, list);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int pipe(int pipefd[2])
+{
+ return pipe2(pipefd, 0);
+}
+
+int pipe2(int pipefd[2], int flags)
+{
+ int rc = syscall(SC_pipe, pipefd, flags);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+unsigned int alarm(unsigned int seconds)
+{
+ return syscall(SC_alarm, seconds);
+}
+
+int seteuid(uid_t euid)
+{
+ int rc = syscall(SC_seteuid, euid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int setegid(gid_t egid)
+{
+ int rc = syscall(SC_setegid, egid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int setuid(uid_t uid)
+{
+ int rc = syscall(SC_setuid, uid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int setgid(gid_t gid)
+{
+ int rc = syscall(SC_setgid, gid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+ int rc = syscall(SC_setresuid, ruid, euid, suid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+ int rc = syscall(SC_setresgid, rgid, egid, sgid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int access(const char* pathname, int mode)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ int rc = syscall(SC_access, pathname, strlen(pathname), mode);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int mknod(const char* pathname, mode_t mode, dev_t dev)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_mknod_params params { { pathname, strlen(pathname) }, mode, dev };
+ int rc = syscall(SC_mknod, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+long fpathconf([[maybe_unused]] int fd, [[maybe_unused]] int name)
+{
+ switch (name) {
+ case _PC_PATH_MAX:
+ return PATH_MAX;
+ case _PC_VDISABLE:
+ return _POSIX_VDISABLE;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+long pathconf([[maybe_unused]] const char* path, int name)
+{
+ switch (name) {
+ case _PC_PATH_MAX:
+ return PATH_MAX;
+ case _PC_PIPE_BUF:
+ return PIPE_BUF;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+void _exit(int status)
+{
+ syscall(SC_exit, status);
+ ASSERT_NOT_REACHED();
+}
+
+void sync()
+{
+ syscall(SC_sync);
+}
+
+static String getlogin_buffer;
+
+char* getlogin()
+{
+ if (getlogin_buffer.is_null()) {
+ if (auto* passwd = getpwuid(getuid())) {
+ getlogin_buffer = String(passwd->pw_name);
+ }
+ endpwent();
+ }
+ return const_cast<char*>(getlogin_buffer.characters());
+}
+
+int ftruncate(int fd, off_t length)
+{
+ int rc = syscall(SC_ftruncate, fd, length);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int truncate(const char* path, off_t length)
+{
+ int fd = open(path, O_RDWR | O_CREAT, 0666);
+ if (fd < 0)
+ return fd;
+ int rc = ftruncate(fd, length);
+ int saved_errno = errno;
+ if (int close_rc = close(fd); close_rc < 0)
+ return close_rc;
+ errno = saved_errno;
+ return rc;
+}
+
+int gettid()
+{
+ int cached_tid = s_cached_tid;
+ if (!cached_tid) {
+ cached_tid = syscall(SC_gettid);
+ s_cached_tid = cached_tid;
+ }
+ return cached_tid;
+}
+
+int donate(int tid)
+{
+ int rc = syscall(SC_donate, tid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+void sysbeep()
+{
+ syscall(SC_beep);
+}
+
+int fsync([[maybe_unused]] int fd)
+{
+ dbgprintf("FIXME: Implement fsync()\n");
+ return 0;
+}
+
+int halt()
+{
+ int rc = syscall(SC_halt);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int reboot()
+{
+ int rc = syscall(SC_reboot);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int mount(int source_fd, const char* target, const char* fs_type, int flags)
+{
+ if (!target || !fs_type) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ Syscall::SC_mount_params params {
+ source_fd,
+ { target, strlen(target) },
+ { fs_type, strlen(fs_type) },
+ flags
+ };
+ int rc = syscall(SC_mount, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int umount(const char* mountpoint)
+{
+ int rc = syscall(SC_umount, mountpoint, strlen(mountpoint));
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+void dump_backtrace()
+{
+ syscall(SC_dump_backtrace);
+}
+
+int get_process_name(char* buffer, int buffer_size)
+{
+ int rc = syscall(SC_get_process_name, buffer, buffer_size);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int set_process_name(const char* name, size_t name_length)
+{
+ int rc = syscall(SC_set_process_name, name, name_length);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int chroot(const char* path)
+{
+ return chroot_with_mount_flags(path, -1);
+}
+
+int chroot_with_mount_flags(const char* path, int mount_flags)
+{
+ if (!path) {
+ errno = EFAULT;
+ return -1;
+ }
+ int rc = syscall(SC_chroot, path, strlen(path), mount_flags);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int pledge(const char* promises, const char* execpromises)
+{
+ Syscall::SC_pledge_params params {
+ { promises, promises ? strlen(promises) : 0 },
+ { execpromises, execpromises ? strlen(execpromises) : 0 }
+ };
+ int rc = syscall(SC_pledge, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int unveil(const char* path, const char* permissions)
+{
+ Syscall::SC_unveil_params params {
+ { path, path ? strlen(path) : 0 },
+ { permissions, permissions ? strlen(permissions) : 0 }
+ };
+ int rc = syscall(SC_unveil, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+ssize_t pread(int fd, void* buf, size_t count, off_t offset)
+{
+ // FIXME: This is not thread safe and should be implemented in the kernel instead.
+ off_t old_offset = lseek(fd, 0, SEEK_CUR);
+ lseek(fd, offset, SEEK_SET);
+ ssize_t nread = read(fd, buf, count);
+ lseek(fd, old_offset, SEEK_SET);
+ return nread;
+}
+
+char* getpass(const char* prompt)
+{
+ dbgln("FIXME: getpass('{}')", prompt);
+ ASSERT_NOT_REACHED();
+}
+
+long sysconf(int name)
+{
+ int rc = syscall(SC_sysconf, name);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int getpagesize()
+{
+ return PAGE_SIZE;
+}
+}
diff --git a/Userland/Libraries/LibC/unistd.h b/Userland/Libraries/LibC/unistd.h
new file mode 100644
index 0000000000..483a690011
--- /dev/null
+++ b/Userland/Libraries/LibC/unistd.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* standard symbolic constants and types
+ *
+ * values from POSIX standard unix specification
+ *
+ * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html
+ */
+
+#pragma once
+
+#include <errno.h>
+#include <limits.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+#define HZ 1000
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+/* lseek whence values */
+#ifndef _STDIO_H /* also defined in stdio.h */
+# define SEEK_SET 0 /* from beginning of file. */
+# define SEEK_CUR 1 /* from current position in file. */
+# define SEEK_END 2 /* from the end of the file. */
+#endif
+
+extern char** environ;
+
+int get_process_name(char* buffer, int buffer_size);
+int set_process_name(const char* name, size_t name_length);
+void dump_backtrace();
+int fsync(int fd);
+void sysbeep();
+int gettid();
+int donate(int tid);
+int getpagesize();
+pid_t fork();
+int execv(const char* path, char* const argv[]);
+int execve(const char* filename, char* const argv[], char* const envp[]);
+int execvpe(const char* filename, char* const argv[], char* const envp[]);
+int execvp(const char* filename, char* const argv[]);
+int execl(const char* filename, const char* arg, ...);
+int execlp(const char* filename, const char* arg, ...);
+int chroot(const char* path);
+int chroot_with_mount_flags(const char* path, int mount_flags);
+void sync();
+__attribute__((noreturn)) void _exit(int status);
+pid_t getsid(pid_t);
+pid_t setsid();
+int setpgid(pid_t pid, pid_t pgid);
+pid_t getpgid(pid_t);
+pid_t getpgrp();
+uid_t geteuid();
+gid_t getegid();
+uid_t getuid();
+gid_t getgid();
+pid_t getpid();
+pid_t getppid();
+int getresuid(uid_t*, uid_t*, uid_t*);
+int getresgid(gid_t*, gid_t*, gid_t*);
+int getgroups(int size, gid_t list[]);
+int setgroups(size_t, const gid_t*);
+int seteuid(uid_t);
+int setegid(gid_t);
+int setuid(uid_t);
+int setgid(gid_t);
+int setresuid(uid_t, uid_t, uid_t);
+int setresgid(gid_t, gid_t, gid_t);
+pid_t tcgetpgrp(int fd);
+int tcsetpgrp(int fd, pid_t pgid);
+ssize_t read(int fd, void* buf, size_t count);
+ssize_t pread(int fd, void* buf, size_t count, off_t);
+ssize_t write(int fd, const void* buf, size_t count);
+int close(int fd);
+int chdir(const char* path);
+int fchdir(int fd);
+char* getcwd(char* buffer, size_t size);
+char* getwd(char* buffer);
+int sleep(unsigned seconds);
+int usleep(useconds_t);
+int gethostname(char*, size_t);
+int sethostname(const char*, ssize_t);
+ssize_t readlink(const char* path, char* buffer, size_t);
+char* ttyname(int fd);
+int ttyname_r(int fd, char* buffer, size_t);
+off_t lseek(int fd, off_t, int whence);
+int link(const char* oldpath, const char* newpath);
+int unlink(const char* pathname);
+int symlink(const char* target, const char* linkpath);
+int rmdir(const char* pathname);
+int dup(int old_fd);
+int dup2(int old_fd, int new_fd);
+int pipe(int pipefd[2]);
+int pipe2(int pipefd[2], int flags);
+unsigned int alarm(unsigned int seconds);
+int access(const char* pathname, int mode);
+int isatty(int fd);
+int mknod(const char* pathname, mode_t, dev_t);
+long fpathconf(int fd, int name);
+long pathconf(const char* path, int name);
+char* getlogin();
+int chown(const char* pathname, uid_t, gid_t);
+int fchown(int fd, uid_t, gid_t);
+int ftruncate(int fd, off_t length);
+int truncate(const char* path, off_t length);
+int halt();
+int reboot();
+int mount(int source_fd, const char* target, const char* fs_type, int flags);
+int umount(const char* mountpoint);
+int pledge(const char* promises, const char* execpromises);
+int unveil(const char* path, const char* permissions);
+char* getpass(const char* prompt);
+
+enum {
+ _PC_NAME_MAX,
+ _PC_PATH_MAX,
+ _PC_PIPE_BUF,
+ _PC_VDISABLE
+};
+
+#define HOST_NAME_MAX 64
+
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#define F_OK 0
+
+#define MS_NODEV (1 << 0)
+#define MS_NOEXEC (1 << 1)
+#define MS_NOSUID (1 << 2)
+#define MS_BIND (1 << 3)
+#define MS_RDONLY (1 << 4)
+#define MS_REMOUNT (1 << 5)
+
+#define _POSIX_SAVED_IDS
+
+/*
+ * We aren't fully compliant (don't support policies, and don't have a wide
+ * range of values), but we do have process priorities.
+ */
+#define _POSIX_PRIORITY_SCHEDULING
+#define _POSIX_VDISABLE '\0'
+
+enum {
+ _SC_NPROCESSORS_CONF,
+ _SC_NPROCESSORS_ONLN,
+ _SC_PAGESIZE,
+ _SC_OPEN_MAX,
+};
+
+#define _SC_NPROCESSORS_CONF _SC_NPROCESSORS_CONF
+#define _SC_NPROCESSORS_ONLN _SC_NPROCESSORS_ONLN
+#define _SC_PAGESIZE _SC_PAGESIZE
+#define _SC_OPEN_MAX _SC_OPEN_MAX
+
+long sysconf(int name);
+
+struct crypt_data {
+ int initialized;
+ char result[65];
+};
+
+char* crypt(const char* key, const char* salt);
+char* crypt_r(const char* key, const char* salt, struct crypt_data* data);
+
+// If opterr is set (the default), print error messages to stderr.
+extern int opterr;
+// On errors, optopt is set to the erroneous *character*.
+extern int optopt;
+// Index of the next argument to process upon a getopt*() call.
+extern int optind;
+// If set, reset the internal state kept by getopt*(). You may also want to set
+// optind to 1 in that case. Alternatively, setting optind to 0 is treated like
+// doing both of the above.
+extern int optreset;
+// After parsing an option that accept an argument, set to point to the argument
+// value.
+extern char* optarg;
+
+int getopt(int argc, char** argv, const char* short_options);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/utime.cpp b/Userland/Libraries/LibC/utime.cpp
new file mode 100644
index 0000000000..501d7f06c2
--- /dev/null
+++ b/Userland/Libraries/LibC/utime.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <string.h>
+#include <utime.h>
+
+extern "C" {
+
+int utime(const char* pathname, const struct utimbuf* buf)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ int rc = syscall(SC_utime, pathname, strlen(pathname), buf);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/utime.h b/Userland/Libraries/LibC/utime.h
new file mode 100644
index 0000000000..073caa3655
--- /dev/null
+++ b/Userland/Libraries/LibC/utime.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+int utime(const char* pathname, const struct utimbuf*);
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/utmp.h b/Userland/Libraries/LibC/utmp.h
new file mode 100644
index 0000000000..0b0ca85946
--- /dev/null
+++ b/Userland/Libraries/LibC/utmp.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+struct exit_status { /* Type for ut_exit, below */
+ short int e_termination; /* Process termination status */
+ short int e_exit; /* Process exit status */
+};
+
+#define USER_PROCESS 7
+#define DEAD_PROCESS 8
+
+#define UT_NAMESIZE 32
+#define UT_LINESIZE 32
+#define UT_HOSTSIZE 256
+
+struct utmp {
+ short ut_type; /* Type of record */
+ pid_t ut_pid; /* PID of login process */
+ char ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */
+ char ut_id[4]; /* Terminal name suffix,
+ or inittab(5) ID */
+ char ut_user[UT_NAMESIZE]; /* Username */
+ char ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or
+ kernel version for run-level
+ messages */
+ struct exit_status ut_exit; /* Exit status of a process
+ marked as DEAD_PROCESS; not
+ used by Linux init (1 */
+
+ long ut_session; /* Session ID */
+ struct timeval ut_tv; /* Time entry was made */
+
+ int32_t ut_addr_v6[4]; /* Internet address of remote
+ host; IPv4 address uses
+ just ut_addr_v6[0] */
+
+ char __unused[20]; /* Reserved for future use */
+};
+
+/* Backward compatibility hacks */
+#define ut_name ut_user
+#ifndef _NO_UT_TIME
+# define ut_time ut_tv.tv_sec
+#endif
+#define ut_xtime ut_tv.tv_sec
+#define ut_addr ut_addr_v6[0]
+
+__END_DECLS
diff --git a/Userland/Libraries/LibC/utsname.cpp b/Userland/Libraries/LibC/utsname.cpp
new file mode 100644
index 0000000000..23d10ee7e9
--- /dev/null
+++ b/Userland/Libraries/LibC/utsname.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <Kernel/API/Syscall.h>
+#include <errno.h>
+#include <sys/utsname.h>
+
+extern "C" {
+
+int uname(struct utsname* buf)
+{
+ int rc = syscall(SC_uname, buf);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+}
diff --git a/Userland/Libraries/LibC/wchar.cpp b/Userland/Libraries/LibC/wchar.cpp
new file mode 100644
index 0000000000..54cfdacda4
--- /dev/null
+++ b/Userland/Libraries/LibC/wchar.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Assertions.h>
+#include <wchar.h>
+
+extern "C" {
+
+size_t wcslen(const wchar_t* str)
+{
+ size_t len = 0;
+ while (*(str++))
+ ++len;
+ return len;
+}
+
+wchar_t* wcscpy(wchar_t* dest, const wchar_t* src)
+{
+ wchar_t* originalDest = dest;
+ while ((*dest++ = *src++) != '\0')
+ ;
+ return originalDest;
+}
+
+wchar_t* wcsncpy(wchar_t* dest, const wchar_t* src, size_t num)
+{
+ wchar_t* originalDest = dest;
+ while (((*dest++ = *src++) != '\0') && ((size_t)(dest - originalDest) < num))
+ ;
+ return originalDest;
+}
+
+int wcscmp(const wchar_t* s1, const wchar_t* s2)
+{
+ while (*s1 == *s2++)
+ if (*s1++ == 0)
+ return 0;
+ return *(const wchar_t*)s1 - *(const wchar_t*)--s2;
+}
+
+wchar_t* wcschr(const wchar_t* str, int c)
+{
+ wchar_t ch = c;
+ for (;; ++str) {
+ if (*str == ch)
+ return const_cast<wchar_t*>(str);
+ if (!*str)
+ return nullptr;
+ }
+}
+
+const wchar_t* wcsrchr(const wchar_t* str, wchar_t wc)
+{
+ wchar_t* last = nullptr;
+ wchar_t c;
+ for (; (c = *str); ++str) {
+ if (c == wc)
+ last = const_cast<wchar_t*>(str);
+ }
+ return last;
+}
+
+wchar_t* wcscat(wchar_t* dest, const wchar_t* src)
+{
+ size_t dest_length = wcslen(dest);
+ size_t i;
+ for (i = 0; src[i] != '\0'; i++)
+ dest[dest_length + i] = src[i];
+ dest[dest_length + i] = '\0';
+ return dest;
+}
+
+wchar_t* wcstok(wchar_t* str, const wchar_t* delim, wchar_t** ptr)
+{
+ wchar_t* used_str = str;
+ if (!used_str) {
+ used_str = *ptr;
+ }
+
+ size_t token_start = 0;
+ size_t token_end = 0;
+ size_t str_len = wcslen(used_str);
+ size_t delim_len = wcslen(delim);
+
+ for (size_t i = 0; i < str_len; ++i) {
+ bool is_proper_delim = false;
+
+ for (size_t j = 0; j < delim_len; ++j) {
+ if (used_str[i] == delim[j]) {
+ // Skip beginning delimiters
+ if (token_end - token_start == 0) {
+ ++token_start;
+ break;
+ }
+
+ is_proper_delim = true;
+ }
+ }
+
+ ++token_end;
+ if (is_proper_delim && token_end > 0) {
+ --token_end;
+ break;
+ }
+ }
+
+ if (used_str[token_start] == '\0')
+ return nullptr;
+
+ if (token_end == 0) {
+ return &used_str[token_start];
+ }
+
+ used_str[token_end] = '\0';
+ return &used_str[token_start];
+}
+
+wchar_t* wcsncat(wchar_t* dest, const wchar_t* src, size_t n)
+{
+ size_t dest_length = wcslen(dest);
+ size_t i;
+ for (i = 0; i < n && src[i] != '\0'; i++)
+ dest[dest_length + i] = src[i];
+ dest[dest_length + i] = '\0';
+ return dest;
+}
+}
diff --git a/Userland/Libraries/LibC/wchar.h b/Userland/Libraries/LibC/wchar.h
new file mode 100644
index 0000000000..c6ab5b2965
--- /dev/null
+++ b/Userland/Libraries/LibC/wchar.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#ifndef WEOF
+# define WEOF (0xffffffffu)
+#endif
+
+size_t wcslen(const wchar_t*);
+wchar_t* wcscpy(wchar_t*, const wchar_t*);
+wchar_t* wcsncpy(wchar_t*, const wchar_t*, size_t);
+int wcscmp(const wchar_t*, const wchar_t*);
+wchar_t* wcschr(const wchar_t*, int);
+const wchar_t* wcsrchr(const wchar_t*, wchar_t);
+wchar_t* wcscat(wchar_t*, const wchar_t*);
+wchar_t* wcstok(wchar_t*, const wchar_t*, wchar_t**);
+wchar_t* wcsncat(wchar_t*, const wchar_t*, size_t);
+
+__END_DECLS