diff --git a/libc-bottom-half/cloudlibc/src/libc/fcntl/fcntl.c b/libc-bottom-half/cloudlibc/src/libc/fcntl/fcntl.c index f8673576b..06b728836 100644 --- a/libc-bottom-half/cloudlibc/src/libc/fcntl/fcntl.c +++ b/libc-bottom-half/cloudlibc/src/libc/fcntl/fcntl.c @@ -9,12 +9,30 @@ int fcntl(int fildes, int cmd, ...) { switch (cmd) { - case F_GETFD: - // Act as if the close-on-exec flag is always set. - return FD_CLOEXEC; - case F_SETFD: - // The close-on-exec flag is ignored. + case F_GETFD: { + __wasi_fdflagsext_t flags; + __wasi_errno_t error = __wasi_fd_fdflags_get(fildes, &flags); + if (error != 0) { + errno = error; + return -1; + } + return flags & __WASI_FDFLAGSEXT_CLOEXEC ? FD_CLOEXEC : 0; + } + case F_SETFD: { + va_list ap; + va_start(ap, cmd); + int flags = va_arg(ap, int); + va_end(ap); + + __wasi_fdflagsext_t fd_flags = flags | FD_CLOEXEC ? __WASI_FDFLAGSEXT_CLOEXEC : 0; + __wasi_errno_t error = + __wasi_fd_fdflags_set(fildes, fd_flags); + if (error != 0) { + errno = error; + return -1; + } return 0; + } case F_GETFL: { // Obtain the flags and the rights of the descriptor. __wasi_fdstat_t fds; @@ -57,8 +75,14 @@ int fcntl(int fildes, int cmd, ...) { } case F_DUPFD: case F_DUPFD_CLOEXEC: { + va_list ap; + va_start(ap, cmd); + int min_res_fd = va_arg(ap, int); + va_end(ap); + int fd; - __wasi_errno_t error = __wasi_fd_dup(fildes, &fd); + __wasi_bool_t cloexec = cmd == F_DUPFD_CLOEXEC; + __wasi_errno_t error = __wasi_fd_dup2(fildes, min_res_fd, cloexec, &fd); if (error != 0) { errno = error; return -1; diff --git a/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c b/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c index 09cbbf800..4263481c3 100644 --- a/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c +++ b/libc-bottom-half/cloudlibc/src/libc/fcntl/openat.c @@ -20,6 +20,8 @@ static_assert(O_DIRECTORY >> 12 == __WASI_OFLAGS_DIRECTORY, "Value mismatch"); static_assert(O_EXCL >> 12 == __WASI_OFLAGS_EXCL, "Value mismatch"); static_assert(O_TRUNC >> 12 == __WASI_OFLAGS_TRUNC, "Value mismatch"); +static_assert(O_CLOEXEC >> 24 == __WASI_FDFLAGSEXT_CLOEXEC, "Value mismatch"); + int __wasilibc_nocwd_openat_nomode(int fd, const char *path, int oflag) { // Compute rights corresponding with the access modes provided. // Attempt to obtain all rights, except the ones that contradict the @@ -65,13 +67,14 @@ int __wasilibc_nocwd_openat_nomode(int fd, const char *path, int oflag) { // Open file with appropriate rights. __wasi_fdflags_t fs_flags = oflag & 0xfff; + __wasi_fdflagsext_t fd_flags = oflag >> 24 & 0xff; __wasi_rights_t fs_rights_base = max & fsb_cur.fs_rights_inheriting; __wasi_rights_t fs_rights_inheriting = fsb_cur.fs_rights_inheriting; __wasi_fd_t newfd; - error = __wasi_path_open(fd, lookup_flags, path, + error = __wasi_path_open2(fd, lookup_flags, path, (oflag >> 12) & 0xfff, fs_rights_base, fs_rights_inheriting, fs_flags, - &newfd); + fd_flags, &newfd); if (error != 0) { errno = error; return -1; diff --git a/libc-bottom-half/headers/public/__header_fcntl.h b/libc-bottom-half/headers/public/__header_fcntl.h index 9f0fcbf8f..c184681ee 100644 --- a/libc-bottom-half/headers/public/__header_fcntl.h +++ b/libc-bottom-half/headers/public/__header_fcntl.h @@ -21,10 +21,7 @@ #define O_SEARCH (0x08000000) #define O_WRONLY (0x10000000) -/* - * O_CLOEXEC is defined to be zero, as WASI has no exec-style functions. - */ -#define O_CLOEXEC (0) +#define O_CLOEXEC (__WASI_FDFLAGSEXT_CLOEXEC << 24) /* * O_TTY_INIT is defined to be zero, meaning that WASI implementations are diff --git a/libc-bottom-half/headers/public/wasi/api_wasix.h b/libc-bottom-half/headers/public/wasi/api_wasix.h index 5d053df9c..7977184a9 100644 --- a/libc-bottom-half/headers/public/wasi/api_wasix.h +++ b/libc-bottom-half/headers/public/wasi/api_wasix.h @@ -1606,6 +1606,18 @@ typedef uint16_t __wasi_eventfdflags_t; */ #define __WASI_EVENTFDFLAGS_SEMAPHORE ((__wasi_eventfdflags_t)(1 << 0)) +/** + * Actual file descriptor flags. The fdflags type from WASI corresponds to + * file status flags, which is why we had to come up with a weird name for + * this type. + */ +typedef uint16_t __wasi_fdflagsext_t; + +/** + * Close this file in the child process when spawning one. + */ +#define __WASI_FDFLAGSEXT_CLOEXEC ((__wasi_fdflagsext_t)(1 << 0)) + /** * Rect that represents the TTY. */ @@ -3631,6 +3643,15 @@ __wasi_errno_t __wasi_fd_dup( __wasi_fd_t fd, __wasi_fd_t *retptr0 ) __attribute__((__warn_unused_result__)); +/** + * Atomically duplicate a file handle. + */ +__wasi_errno_t __wasi_fd_dup2( + __wasi_fd_t fd, + __wasi_fd_t min_result_fd, + __wasi_bool_t cloexec, + __wasi_fd_t *retptr0 +) __attribute__((__warn_unused_result__)); /** * Creates a file handle for event notifications * @@ -3849,6 +3870,70 @@ _Noreturn void __wasi_stack_restore( */ __wasi_longsize_t val ); +/** + * Open a file or directory. + * The returned file descriptor is not guaranteed to be the lowest-numbered + * file descriptor not currently open; it is randomized to prevent + * applications from depending on making assumptions about indexes, since this + * is error-prone in multi-threaded contexts. The returned file descriptor is + * guaranteed to be less than 2**31. + * Note: This is similar to `openat` in POSIX. + * Recreated in WASIX from the original WASI function to add support for + * fdflagsext. + * @return + * The file descriptor of the file that has been opened. + */ +__wasi_errno_t __wasi_path_open2( + __wasi_fd_t fd, + /** + * Flags determining the method of how the path is resolved. + */ + __wasi_lookupflags_t dirflags, + /** + * The relative path of the file or directory to open, relative to the + * `path_open::fd` directory. + */ + const char *path, + /** + * The method by which to open the file. + */ + __wasi_oflags_t oflags, + /** + * The initial rights of the newly created file descriptor. The + * implementation is allowed to return a file descriptor with fewer rights + * than specified, if and only if those rights do not apply to the type of + * file being opened. + * The *base* rights are rights that will apply to operations using the file + * descriptor itself, while the *inheriting* rights are rights that apply to + * file descriptors derived from it. + */ + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, + __wasi_fdflags_t fdflags, + __wasi_fdflagsext_t fdflagsext, + __wasi_fd_t *retptr0 +) __attribute__((__warn_unused_result__)); +/** + * Get the FD flags of a file descriptor (fdflagsext). + * Note: This returns similar flags to `fsync(fd, F_GETFD)` in POSIX. + * @return + * The buffer where the file descriptor's attributes are stored. + */ +__wasi_errno_t __wasi_fd_fdflags_get( + __wasi_fd_t fd, + __wasi_fdflagsext_t *retptr0 +) __attribute__((__warn_unused_result__)); +/** + * Adjust the FD flags associated with a file descriptor. + * Note: This is similar to `fcntl(fd, F_SETFD, flags)` in POSIX. + */ +__wasi_errno_t __wasi_fd_fdflags_set( + __wasi_fd_t fd, + /** + * The desired values of the file descriptor flags. + */ + __wasi_fdflagsext_t flags +) __attribute__((__warn_unused_result__)); /** * Send a signal to the process of the calling thread on a regular basis * Note: This is similar to `setitimer` in POSIX. diff --git a/libc-bottom-half/sources/__wasixlibc_real.c b/libc-bottom-half/sources/__wasixlibc_real.c index 5c265a80c..20b986312 100644 --- a/libc-bottom-half/sources/__wasixlibc_real.c +++ b/libc-bottom-half/sources/__wasixlibc_real.c @@ -39,6 +39,21 @@ __wasi_errno_t __wasi_fd_dup( return (uint16_t) ret; } +int32_t __imported_wasix_32v1_fd_dup2(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) __attribute__(( + __import_module__("wasix_32v1"), + __import_name__("fd_dup2") +)); + +__wasi_errno_t __wasi_fd_dup2( + __wasi_fd_t fd, + __wasi_fd_t min_result_fd, + __wasi_bool_t cloexec, + __wasi_fd_t *retptr0 +){ + int32_t ret = __imported_wasix_32v1_fd_dup2((int32_t) fd, (int32_t) min_result_fd, (int32_t) cloexec, (intptr_t) retptr0); + return (uint16_t) ret; +} + int32_t __imported_wasix_32v1_fd_event(int64_t arg0, int32_t arg1, int32_t arg2) __attribute__(( __import_module__("wasix_32v1"), __import_name__("fd_event") @@ -279,6 +294,53 @@ _Noreturn void __wasi_stack_restore( __imported_wasix_32v1_stack_restore((int32_t) snapshot, (int64_t) val); } +int32_t __imported_wasix_32v1_path_open2(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int64_t arg5, int64_t arg6, int32_t arg7, int32_t arg8, int32_t arg9) __attribute__(( + __import_module__("wasix_32v1"), + __import_name__("path_open2") +)); + +__wasi_errno_t __wasi_path_open2( + __wasi_fd_t fd, + __wasi_lookupflags_t dirflags, + const char *path, + __wasi_oflags_t oflags, + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, + __wasi_fdflags_t fdflags, + __wasi_fdflagsext_t fdflagsext, + __wasi_fd_t *retptr0 +){ + size_t path_len = strlen(path); + int32_t ret = __imported_wasix_32v1_path_open2((int32_t) fd, dirflags, (intptr_t) path, (intptr_t) path_len, oflags, fs_rights_base, fs_rights_inheriting, fdflags, fdflagsext, (intptr_t) retptr0); + return (uint16_t) ret; +} + +int32_t __imported_wasix_32v1_fd_fdflags_get(int32_t arg0, int32_t arg1) __attribute__(( + __import_module__("wasix_32v1"), + __import_name__("fd_fdflags_get") +)); + +__wasi_errno_t __wasi_fd_fdflags_get( + __wasi_fd_t fd, + __wasi_fdflagsext_t *retptr0 +){ + int32_t ret = __imported_wasix_32v1_fd_fdflags_get((int32_t) fd, (intptr_t) retptr0); + return (uint16_t) ret; +} + +int32_t __imported_wasix_32v1_fd_fdflags_set(int32_t arg0, int32_t arg1) __attribute__(( + __import_module__("wasix_32v1"), + __import_name__("fd_fdflags_set") +)); + +__wasi_errno_t __wasi_fd_fdflags_set( + __wasi_fd_t fd, + __wasi_fdflagsext_t flags +){ + int32_t ret = __imported_wasix_32v1_fd_fdflags_set((int32_t) fd, flags); + return (uint16_t) ret; +} + int32_t __imported_wasix_32v1_proc_raise_interval(int32_t arg0, int64_t arg1, int32_t arg2) __attribute__(( __import_module__("wasix_32v1"), __import_name__("proc_raise_interval") diff --git a/libc-top-half/musl/src/thread/thrd_create.c b/libc-top-half/musl/src/thread/thrd_create.c index 76a683dbf..d6f787934 100644 --- a/libc-top-half/musl/src/thread/thrd_create.c +++ b/libc-top-half/musl/src/thread/thrd_create.c @@ -3,7 +3,7 @@ int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { - int ret = __pthread_create(thr, __ATTRP_C11_THREAD, (void *(*)(void *))func, arg); + int ret = __pthread_create(thr, __ATTRP_C11_THREAD, (void *(*)(void *))(void *)func, arg); switch (ret) { case 0: return thrd_success; case EAGAIN: return thrd_nomem;