diff options
Diffstat (limited to 'Userland/Libraries/LibC')
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, ¶ms); + 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, ¶ms); + __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, ¶ms); + 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, ¶ms); + 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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + 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, ¶ms); + + 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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + // 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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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, ¶ms); + __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 |