| 1 | const builtin = @import("builtin"); |
| 2 | |
| 3 | const std = @import("std"); |
| 4 | const linux = std.os.linux; |
| 5 | |
| 6 | const symbol = @import("../c.zig").symbol; |
| 7 | const errno = @import("../c.zig").errno; |
| 8 | |
| 9 | comptime { |
| 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 | |
| 62 | fn _exit(exit_code: c_int) callconv(.c) noreturn { |
| 63 | std.c._Exit(exit_code); |
| 64 | } |
| 65 | |
| 66 | fn accessLinux(path: [*:0]const c_char, amode: c_int) callconv(.c) c_int { |
| 67 | return errno(linux.access(@ptrCast(path), @bitCast(amode))); |
| 68 | } |
| 69 | |
| 70 | fn acctLinux(path: [*:0]const c_char) callconv(.c) c_int { |
| 71 | return errno(linux.acct(@ptrCast(path))); |
| 72 | } |
| 73 | |
| 74 | fn chdirLinux(path: [*:0]const c_char) callconv(.c) c_int { |
| 75 | return errno(linux.chdir(@ptrCast(path))); |
| 76 | } |
| 77 | |
| 78 | fn 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 | |
| 82 | fn 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 | |
| 86 | fn 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 | |
| 90 | fn chrootLinux(path: [*:0]const c_char) callconv(.c) c_int { |
| 91 | return errno(linux.chroot(@ptrCast(path))); |
| 92 | } |
| 93 | |
| 94 | fn 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 | |
| 103 | fn dupLinux(fd: c_int) callconv(.c) c_int { |
| 104 | return errno(linux.dup(fd)); |
| 105 | } |
| 106 | |
| 107 | fn 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 | |
| 114 | fn 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 | |
| 132 | fn getegidLinux() callconv(.c) linux.gid_t { |
| 133 | return linux.getegid(); |
| 134 | } |
| 135 | |
| 136 | fn geteuidLinux() callconv(.c) linux.uid_t { |
| 137 | return linux.geteuid(); |
| 138 | } |
| 139 | |
| 140 | fn getgidLinux() callconv(.c) linux.gid_t { |
| 141 | return linux.getgid(); |
| 142 | } |
| 143 | |
| 144 | fn getgroupsLinux(size: c_int, list: ?[*]linux.gid_t) callconv(.c) c_int { |
| 145 | return errno(linux.getgroups(@intCast(size), list)); |
| 146 | } |
| 147 | |
| 148 | fn getpgidLinux(pid: linux.pid_t) callconv(.c) linux.pid_t { |
| 149 | return errno(linux.getpgid(pid)); |
| 150 | } |
| 151 | |
| 152 | fn getpgrpLinux() callconv(.c) linux.pid_t { |
| 153 | return @intCast(linux.getpgid(0)); // @intCast as it cannot fail |
| 154 | } |
| 155 | |
| 156 | fn setpgidLinux(pid: linux.pid_t, pgid: linux.pid_t) callconv(.c) c_int { |
| 157 | return errno(linux.setpgid(pid, pgid)); |
| 158 | } |
| 159 | |
| 160 | fn setpgrpLinux() callconv(.c) linux.pid_t { |
| 161 | return @intCast(linux.setpgid(0, 0)); // @intCast as it cannot fail |
| 162 | } |
| 163 | |
| 164 | fn getpidLinux() callconv(.c) linux.pid_t { |
| 165 | return linux.getpid(); |
| 166 | } |
| 167 | |
| 168 | fn getppidLinux() callconv(.c) linux.pid_t { |
| 169 | return linux.getppid(); |
| 170 | } |
| 171 | |
| 172 | fn getsidLinux(pid: linux.pid_t) callconv(.c) linux.pid_t { |
| 173 | return errno(linux.getsid(pid)); |
| 174 | } |
| 175 | |
| 176 | fn getuidLinux() callconv(.c) linux.uid_t { |
| 177 | return linux.getuid(); |
| 178 | } |
| 179 | |
| 180 | fn 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 | |
| 184 | fn 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 | |
| 188 | fn pipeLinux(fd: *[2]c_int) callconv(.c) c_int { |
| 189 | return errno(linux.pipe(@ptrCast(fd))); |
| 190 | } |
| 191 | |
| 192 | fn 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 | |
| 196 | fn rmdirLinux(path: [*:0]const c_char) callconv(.c) c_int { |
| 197 | return errno(linux.rmdir(@ptrCast(path))); |
| 198 | } |
| 199 | |
| 200 | fn 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 | |
| 204 | fn 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 | |
| 208 | fn syncLinux() callconv(.c) void { |
| 209 | linux.sync(); |
| 210 | } |
| 211 | |
| 212 | fn unlinkLinux(path: [*:0]const c_char) callconv(.c) c_int { |
| 213 | return errno(linux.unlink(@ptrCast(path))); |
| 214 | } |
| 215 | |
| 216 | fn 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 | |
| 220 | fn 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 | |
| 224 | fn 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 | |
| 237 | fn 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 | |
| 248 | fn posix_close(fd: std.c.fd_t, _: c_int) callconv(.c) c_int { |
| 249 | return close(fd); |
| 250 | } |
| 251 | |
| 252 | fn 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 | } |