1const builtin = @import("builtin");
2
3const std = @import("std");
4const linux = std.os.linux;
5
6const symbol = @import("../c.zig").symbol;
7const errno = @import("../c.zig").errno;
8
9comptime {
10 if (builtin.target.isMuslLibC()) {
11 symbol(&_exit, "_exit");
12
13 symbol(&accessLinux, "access");
14 symbol(&acctLinux, "acct");
15 symbol(&chdirLinux, "chdir");
16 symbol(&chownLinux, "chown");
17 symbol(&close, "close");
18 symbol(&posix_close, "posix_close");
19 symbol(&fchownatLinux, "fchownat");
20 symbol(&lchownLinux, "lchown");
21 symbol(&chrootLinux, "chroot");
22 symbol(&ctermidLinux, "ctermid");
23 symbol(&dupLinux, "dup");
24 symbol(&dup2Linux, "dup2");
25 symbol(&dup3Linux, "dup3");
26 symbol(&dup3Linux, "__dup3");
27
28 symbol(&getegidLinux, "getegid");
29 symbol(&geteuidLinux, "geteuid");
30 symbol(&getgidLinux, "getgid");
31 symbol(&getgroupsLinux, "getgroups");
32 symbol(&getpgidLinux, "getpgid");
33 symbol(&getpgrpLinux, "getpgrp");
34 symbol(&setpgidLinux, "setpgid");
35 symbol(&setpgrpLinux, "setpgrp");
36 symbol(&getsidLinux, "getsid");
37 symbol(&getpidLinux, "getpid");
38 symbol(&getppidLinux, "getppid");
39 symbol(&getuidLinux, "getuid");
40
41 symbol(&rmdirLinux, "rmdir");
42 symbol(&linkLinux, "link");
43 symbol(&linkatLinux, "linkat");
44 symbol(&pipeLinux, "pipe");
45 symbol(&renameatLinux, "renameat");
46 symbol(&symlinkLinux, "symlink");
47 symbol(&symlinkatLinux, "symlinkat");
48 symbol(&syncLinux, "sync");
49 symbol(&unlinkLinux, "unlink");
50 symbol(&unlinkatLinux, "unlinkat");
51
52 symbol(&execveLinux, "execve");
53 }
54 if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
55 symbol(&swab, "swab");
56 }
57 if (builtin.target.isWasiLibC()) {
58 symbol(&closeWasi, "close");
59 }
60}
61
62fn _exit(exit_code: c_int) callconv(.c) noreturn {
63 std.c._Exit(exit_code);
64}
65
66fn accessLinux(path: [*:0]const c_char, amode: c_int) callconv(.c) c_int {
67 return errno(linux.access(@ptrCast(path), @bitCast(amode)));
68}
69
70fn acctLinux(path: [*:0]const c_char) callconv(.c) c_int {
71 return errno(linux.acct(@ptrCast(path)));
72}
73
74fn chdirLinux(path: [*:0]const c_char) callconv(.c) c_int {
75 return errno(linux.chdir(@ptrCast(path)));
76}
77
78fn chownLinux(path: [*:0]const c_char, uid: linux.uid_t, gid: linux.gid_t) callconv(.c) c_int {
79 return errno(linux.chown(@ptrCast(path), uid, gid));
80}
81
82fn fchownatLinux(fd: c_int, path: [*:0]const c_char, uid: linux.uid_t, gid: linux.gid_t, flags: c_int) callconv(.c) c_int {
83 return errno(linux.fchownat(fd, @ptrCast(path), uid, gid, @bitCast(flags)));
84}
85
86fn lchownLinux(path: [*:0]const c_char, uid: linux.uid_t, gid: linux.gid_t) callconv(.c) c_int {
87 return errno(linux.lchown(@ptrCast(path), uid, gid));
88}
89
90fn chrootLinux(path: [*:0]const c_char) callconv(.c) c_int {
91 return errno(linux.chroot(@ptrCast(path)));
92}
93
94fn ctermidLinux(maybe_path: ?[*]c_char) callconv(.c) [*:0]c_char {
95 const default_tty = "/dev/tty";
96
97 return if (maybe_path) |path| blk: {
98 path[0..(default_tty.len + 1)].* = @bitCast(default_tty.*);
99 break :blk path[0..default_tty.len :0].ptr;
100 } else @ptrCast(@constCast(default_tty));
101}
102
103fn dupLinux(fd: c_int) callconv(.c) c_int {
104 return errno(linux.dup(fd));
105}
106
107fn dup2Linux(old: c_int, new: c_int) callconv(.c) c_int {
108 const busy: usize = @bitCast(-@as(isize, @backingInt(linux.E.BUSY)));
109 var res = busy;
110 while (res == busy) res = linux.dup2(old, new);
111 return errno(res);
112}
113
114fn dup3Linux(old: c_int, new: c_int, flags: c_int) callconv(.c) c_int {
115 const busy: usize = @bitCast(-@as(isize, @backingInt(linux.E.BUSY)));
116 var res = busy;
117
118 if (@hasField(linux.SYS, "dup3")) {
119 while (res == busy) res = linux.dup3(old, new, @intCast(flags));
120 } else if (@hasField(linux.SYS, "dup2")) {
121 const cloexec: c_int = @bitCast(linux.O{ .CLOEXEC = true });
122 const inval: usize = @bitCast(-@as(isize, @backingInt(linux.E.INVAL)));
123 if (old == new or (flags & ~cloexec != 0)) return errno(inval);
124 while (res == busy) res = linux.dup2(old, new);
125 _ = if (res >= 0 and (flags & cloexec == cloexec)) linux.fcntl(new, linux.F.SETFD, linux.FD_CLOEXEC);
126 } else {
127 return errno(@bitCast(-@as(isize, @backingInt(linux.E.NOSYS))));
128 }
129 return errno(res);
130}
131
132fn getegidLinux() callconv(.c) linux.gid_t {
133 return linux.getegid();
134}
135
136fn geteuidLinux() callconv(.c) linux.uid_t {
137 return linux.geteuid();
138}
139
140fn getgidLinux() callconv(.c) linux.gid_t {
141 return linux.getgid();
142}
143
144fn getgroupsLinux(size: c_int, list: ?[*]linux.gid_t) callconv(.c) c_int {
145 return errno(linux.getgroups(@intCast(size), list));
146}
147
148fn getpgidLinux(pid: linux.pid_t) callconv(.c) linux.pid_t {
149 return errno(linux.getpgid(pid));
150}
151
152fn getpgrpLinux() callconv(.c) linux.pid_t {
153 return @intCast(linux.getpgid(0)); // @intCast as it cannot fail
154}
155
156fn setpgidLinux(pid: linux.pid_t, pgid: linux.pid_t) callconv(.c) c_int {
157 return errno(linux.setpgid(pid, pgid));
158}
159
160fn setpgrpLinux() callconv(.c) linux.pid_t {
161 return @intCast(linux.setpgid(0, 0)); // @intCast as it cannot fail
162}
163
164fn getpidLinux() callconv(.c) linux.pid_t {
165 return linux.getpid();
166}
167
168fn getppidLinux() callconv(.c) linux.pid_t {
169 return linux.getppid();
170}
171
172fn getsidLinux(pid: linux.pid_t) callconv(.c) linux.pid_t {
173 return errno(linux.getsid(pid));
174}
175
176fn getuidLinux() callconv(.c) linux.uid_t {
177 return linux.getuid();
178}
179
180fn linkLinux(old: [*:0]const c_char, new: [*:0]const c_char) callconv(.c) c_int {
181 return errno(linux.link(@ptrCast(old), @ptrCast(new)));
182}
183
184fn linkatLinux(old_fd: c_int, old: [*:0]const c_char, new_fd: c_int, new: [*:0]const c_char, flags: c_int) callconv(.c) c_int {
185 return errno(linux.linkat(old_fd, @ptrCast(old), new_fd, @ptrCast(new), @bitCast(flags)));
186}
187
188fn pipeLinux(fd: *[2]c_int) callconv(.c) c_int {
189 return errno(linux.pipe(@ptrCast(fd)));
190}
191
192fn renameatLinux(old_fd: c_int, old: [*:0]const c_char, new_fd: c_int, new: [*:0]const c_char) callconv(.c) c_int {
193 return errno(linux.renameat(old_fd, @ptrCast(old), new_fd, @ptrCast(new)));
194}
195
196fn rmdirLinux(path: [*:0]const c_char) callconv(.c) c_int {
197 return errno(linux.rmdir(@ptrCast(path)));
198}
199
200fn symlinkLinux(existing: [*:0]const c_char, new: [*:0]const c_char) callconv(.c) c_int {
201 return errno(linux.symlink(@ptrCast(existing), @ptrCast(new)));
202}
203
204fn symlinkatLinux(existing: [*:0]const c_char, fd: c_int, new: [*:0]const c_char) callconv(.c) c_int {
205 return errno(linux.symlinkat(@ptrCast(existing), fd, @ptrCast(new)));
206}
207
208fn syncLinux() callconv(.c) void {
209 linux.sync();
210}
211
212fn unlinkLinux(path: [*:0]const c_char) callconv(.c) c_int {
213 return errno(linux.unlink(@ptrCast(path)));
214}
215
216fn unlinkatLinux(fd: c_int, path: [*:0]const c_char, flags: c_int) callconv(.c) c_int {
217 return errno(linux.unlinkat(fd, @ptrCast(path), @bitCast(flags)));
218}
219
220fn execveLinux(path: [*:0]const c_char, argv: [*:null]const ?[*:0]c_char, envp: [*:null]const ?[*:0]c_char) callconv(.c) c_int {
221 return errno(linux.execve(@ptrCast(path), @ptrCast(argv), @ptrCast(envp)));
222}
223
224fn swab(noalias src_ptr: *const anyopaque, noalias dest_ptr: *anyopaque, n: isize) callconv(.c) void {
225 var src: [*]const u8 = @ptrCast(src_ptr);
226 var dest: [*]u8 = @ptrCast(dest_ptr);
227 var i = n;
228
229 while (i > 1) : (i -= 2) {
230 dest[0] = src[1];
231 dest[1] = src[0];
232 dest += 2;
233 src += 2;
234 }
235}
236
237fn close(fd: std.c.fd_t) callconv(.c) c_int {
238 const signed: isize = @bitCast(linux.close(fd));
239 if (signed < 0) {
240 @branchHint(.unlikely);
241 if (-signed == @backingInt(linux.E.INTR)) return 0;
242 std.c._errno().* = @intCast(-signed);
243 return -1;
244 }
245 return 0;
246}
247
248fn posix_close(fd: std.c.fd_t, _: c_int) callconv(.c) c_int {
249 return close(fd);
250}
251
252fn closeWasi(fd: std.c.fd_t) callconv(.c) c_int {
253 switch (std.os.wasi.fd_close(fd)) {
254 .SUCCESS => return 0,
255 else => |e| {
256 std.c._errno().* = @backingInt(e);
257 return -1;
258 },
259 }
260}