libzigc: dup2 and dup3

This commit adds `dup2` and `dup3` based on musl. Zig already has
wrappers for the syscalls, but musl's implementation checks for a rare,
temporary race condition with dup2/3 and `open`. Like musl, this
implementation adds a fallback for dup3 if the syscall isn't available.

Contributes to: #30978
This commit is contained in:
Josh Megnauth
2026-04-09 14:53:40 -04:00
committed by Andrew Kelley
parent 6e987a1d04
commit ff612334fa
4 changed files with 27 additions and 48 deletions
+27
View File
@@ -21,6 +21,8 @@ comptime {
symbol(&chrootLinux, "chroot");
symbol(&ctermidLinux, "ctermid");
symbol(&dupLinux, "dup");
symbol(&dup2Linux, "dup2");
symbol(&dup3Linux, "dup3");
symbol(&getegidLinux, "getegid");
symbol(&geteuidLinux, "geteuid");
@@ -101,6 +103,31 @@ fn dupLinux(fd: c_int) callconv(.c) c_int {
return errno(linux.dup(fd));
}
fn dup2Linux(old: c_int, new: c_int) callconv(.c) c_int {
const busy: usize = @bitCast(-@as(isize, @intFromEnum(linux.E.BUSY)));
var res = busy;
while (res == busy) res = linux.dup2(old, new);
return errno(res);
}
fn dup3Linux(old: c_int, new: c_int, flags: c_int) callconv(.c) c_int {
const busy: usize = @bitCast(-@as(isize, @intFromEnum(linux.E.BUSY)));
var res = busy;
if (@hasField(linux.SYS, "dup3")) {
while (res == busy) res = linux.dup3(old, new, @intCast(flags));
} else if (@hasField(linux.SYS, "dup2")) {
const cloexec: c_int = @bitCast(linux.O{ .CLOEXEC = true });
const inval: usize = @bitCast(-@as(isize, @intFromEnum(linux.E.INVAL)));
if (old == new or (flags & ~cloexec != 0)) return errno(inval);
while (res == busy) res = linux.dup2(old, new);
_ = if (res >= 0 and (flags & cloexec == cloexec)) linux.fcntl(new, linux.F.SETFD, linux.FD_CLOEXEC);
} else {
return errno(@bitCast(-@as(isize, @intFromEnum(linux.E.NOSYS))));
}
return errno(res);
}
fn getegidLinux() callconv(.c) linux.gid_t {
return linux.getegid();
}
-20
View File
@@ -1,20 +0,0 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "syscall.h"
int dup2(int old, int new)
{
int r;
#ifdef SYS_dup2
while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
#else
if (old==new) {
r = __syscall(SYS_fcntl, old, F_GETFD);
if (r >= 0) return old;
} else {
while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY);
}
#endif
return __syscall_ret(r);
}
-26
View File
@@ -1,26 +0,0 @@
#define _GNU_SOURCE
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "syscall.h"
int __dup3(int old, int new, int flags)
{
int r;
#ifdef SYS_dup2
if (old==new) return __syscall_ret(-EINVAL);
if (flags) {
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
if (r!=-ENOSYS) return __syscall_ret(r);
if (flags & ~O_CLOEXEC) return __syscall_ret(-EINVAL);
}
while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
if (r >= 0 && (flags & O_CLOEXEC))
__syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
#else
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
#endif
return __syscall_ret(r);
}
weak_alias(__dup3, dup3);
-2
View File
@@ -1758,8 +1758,6 @@ const src_files = [_][]const u8{
"musl/src/time/wcsftime.c",
"musl/src/time/__year_to_secs.c",
"musl/src/unistd/alarm.c",
"musl/src/unistd/dup2.c",
"musl/src/unistd/dup3.c",
"musl/src/unistd/faccessat.c",
"musl/src/unistd/fchdir.c",
"musl/src/unistd/fchown.c",