authorgravatar for jo.sh@tutanota.comJosh Megnauth <jo.sh@tutanota.com> 2026-04-09 14:53:40-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-17 23:13:39+02:00
logff612334fa8af05c42b71f784dff521899026f97
treecc89f0c97619c35f704842d5913a4b435fd23d24
parent6e987a1d04e5d9eb41a10110a5343384f0a9a57b

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

4 files changed, 27 insertions(+), 48 deletions(-)

lib/c/unistd.zig+27
...@@ -21,6 +21,8 @@ comptime {...@@ -21,6 +21,8 @@ comptime {
21 symbol(&chrootLinux, "chroot");21 symbol(&chrootLinux, "chroot");
22 symbol(&ctermidLinux, "ctermid");22 symbol(&ctermidLinux, "ctermid");
23 symbol(&dupLinux, "dup");23 symbol(&dupLinux, "dup");
24 symbol(&dup2Linux, "dup2");
25 symbol(&dup3Linux, "dup3");
2426
25 symbol(&getegidLinux, "getegid");27 symbol(&getegidLinux, "getegid");
26 symbol(&geteuidLinux, "geteuid");28 symbol(&geteuidLinux, "geteuid");
...@@ -101,6 +103,31 @@ fn dupLinux(fd: c_int) callconv(.c) c_int {...@@ -101,6 +103,31 @@ fn dupLinux(fd: c_int) callconv(.c) c_int {
101 return errno(linux.dup(fd));103 return errno(linux.dup(fd));
102}104}
103105
106fn dup2Linux(old: c_int, new: c_int) callconv(.c) c_int {
107 const busy: usize = @bitCast(-@as(isize, @intFromEnum(linux.E.BUSY)));
108 var res = busy;
109 while (res == busy) res = linux.dup2(old, new);
110 return errno(res);
111}
112
113fn dup3Linux(old: c_int, new: c_int, flags: c_int) callconv(.c) c_int {
114 const busy: usize = @bitCast(-@as(isize, @intFromEnum(linux.E.BUSY)));
115 var res = busy;
116
117 if (@hasField(linux.SYS, "dup3")) {
118 while (res == busy) res = linux.dup3(old, new, @intCast(flags));
119 } else if (@hasField(linux.SYS, "dup2")) {
120 const cloexec: c_int = @bitCast(linux.O{ .CLOEXEC = true });
121 const inval: usize = @bitCast(-@as(isize, @intFromEnum(linux.E.INVAL)));
122 if (old == new or (flags & ~cloexec != 0)) return errno(inval);
123 while (res == busy) res = linux.dup2(old, new);
124 _ = if (res >= 0 and (flags & cloexec == cloexec)) linux.fcntl(new, linux.F.SETFD, linux.FD_CLOEXEC);
125 } else {
126 return errno(@bitCast(-@as(isize, @intFromEnum(linux.E.NOSYS))));
127 }
128 return errno(res);
129}
130
104fn getegidLinux() callconv(.c) linux.gid_t {131fn getegidLinux() callconv(.c) linux.gid_t {
105 return linux.getegid();132 return linux.getegid();
106}133}
lib/libc/musl/src/unistd/dup2.c deleted-20
...@@ -1,20 +0,0 @@
1#include <unistd.h>
2#include <errno.h>
3#include <fcntl.h>
4#include "syscall.h"
5
6int dup2(int old, int new)
7{
8 int r;
9#ifdef SYS_dup2
10 while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
11#else
12 if (old==new) {
13 r = __syscall(SYS_fcntl, old, F_GETFD);
14 if (r >= 0) return old;
15 } else {
16 while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY);
17 }
18#endif
19 return __syscall_ret(r);
20}
lib/libc/musl/src/unistd/dup3.c deleted-26
...@@ -1,26 +0,0 @@
1#define _GNU_SOURCE
2#include <unistd.h>
3#include <errno.h>
4#include <fcntl.h>
5#include "syscall.h"
6
7int __dup3(int old, int new, int flags)
8{
9 int r;
10#ifdef SYS_dup2
11 if (old==new) return __syscall_ret(-EINVAL);
12 if (flags) {
13 while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
14 if (r!=-ENOSYS) return __syscall_ret(r);
15 if (flags & ~O_CLOEXEC) return __syscall_ret(-EINVAL);
16 }
17 while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
18 if (r >= 0 && (flags & O_CLOEXEC))
19 __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
20#else
21 while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
22#endif
23 return __syscall_ret(r);
24}
25
26weak_alias(__dup3, dup3);
src/libs/musl.zig-2
...@@ -1758,8 +1758,6 @@ const src_files = [_][]const u8{...@@ -1758,8 +1758,6 @@ const src_files = [_][]const u8{
1758 "musl/src/time/wcsftime.c",1758 "musl/src/time/wcsftime.c",
1759 "musl/src/time/__year_to_secs.c",1759 "musl/src/time/__year_to_secs.c",
1760 "musl/src/unistd/alarm.c",1760 "musl/src/unistd/alarm.c",
1761 "musl/src/unistd/dup2.c",
1762 "musl/src/unistd/dup3.c",
1763 "musl/src/unistd/faccessat.c",1761 "musl/src/unistd/faccessat.c",
1764 "musl/src/unistd/fchdir.c",1762 "musl/src/unistd/fchdir.c",
1765 "musl/src/unistd/fchown.c",1763 "musl/src/unistd/fchown.c",