1const std = @import("std");
2const builtin = @import("builtin");
3const sys_linux = @import("sys-linux");
4const nio = @import("nio");
5
6pub const Dir = @import("./Dir.zig");
7pub const File = @import("./File.zig");
8
9const os = builtin.target.os.tag;
10
11const sys = switch (os) {
12 .linux => sys_linux,
13 .macos => @import("sys-darwin"),
14 .freebsd => @import("sys-freebsd"),
15 .netbsd => @import("sys-netbsd"),
16 .openbsd => @import("sys-openbsd"),
17 else => unreachable,
18};
19
20pub const Handle = enum(c_int) {
21 _,
22};
23
24pub const Error = sys.errno.Error;
25pub const PATH_MAX = sys.PATH_MAX;
26pub const NAME_MAX = sys.NAME_MAX;
27
28pub fn cwd() Dir {
29 return .{ .fd = @enumFromInt(sys.AT.FDCWD) };
30}
31
32pub fn cwdpath(buf: []u8) ![:0]u8 {
33 const ptr = try sys.getcwd(buf);
34 const str = std.mem.sliceTo(ptr, 0);
35 return str;
36}
37
38pub fn stdin() File {
39 return .{ .fd = @enumFromInt(0) };
40}
41
42pub fn stdout() File {
43 return .{ .fd = @enumFromInt(1) };
44}
45
46pub fn stderr() File {
47 return .{ .fd = @enumFromInt(2) };
48}
49
50pub fn memfd_create(name: [*:0]const u8, flags: c_uint) !File {
51 return .{ .fd = @enumFromInt(try sys.memfd_create(name, flags)) };
52}
53
54/// Free a region of memory allocated with mmap.
55/// Any error calling munmap is ignored.
56pub fn munmap(region: []const u8) void {
57 return sys.munmap(region.ptr, region.len) catch {};
58}
59
60pub fn mktemp_buf() [19:0]u8 {
61 var template: [19:0]u8 = "/tmp/tmp.XXXXXXXXXX".*;
62 const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
63 const rand = nio.randomBytes(10);
64 for (template[9..][0..10], rand) |*a, b| a.* = letters[b % 62];
65 return template;
66}
67
68pub fn mkdtemp() !Dir {
69 const path = &mktemp_buf();
70 return cwd().makeOpenPath(path, .{});
71}
72
73pub fn mktemp(flags: Dir.CreateFlags) !File {
74 const path = &mktemp_buf();
75 var _flags = flags;
76 _flags.exclusive = true;
77 return cwd().createFile(path, _flags);
78}
79
80pub fn pipe2(flag: c_int) ![2]File {
81 const fds = try sys.pipe2(flag);
82 return .{
83 .{ .fd = @enumFromInt(fds[0]) },
84 .{ .fd = @enumFromInt(fds[1]) },
85 };
86}
87
88pub fn dup2(fd1: Handle, fd2: Handle) !void {
89 return sys.dup2(@intFromEnum(fd1), @intFromEnum(fd2));
90}
91
92pub fn realdpath(fd: Handle, buf: *[sys.PATH_MAX]u8) ![:0]u8 {
93 if (os == .linux) {
94 var dbuf: [64]u8 = undefined;
95 const str = nio.fmt.bufPrintZ(&dbuf, "/proc/self/fd/{d}", .{@intFromEnum(fd)}) catch unreachable;
96 return sys.readlinkat(@intFromEnum(cwd().fd), str, buf);
97 }
98 if (os == .macos or os == .netbsd) {
99 @memset(buf, 0);
100 const rc = sys.libc.fcntl(@intFromEnum(fd), sys.F.GETPATH, buf.ptr);
101 if (rc == -1) return sys.errno.fromInt(sys.errno.fromLibC());
102 const idx = std.mem.indexOfScalar(u8, buf, 0).?;
103 return buf[0..idx :0];
104 }
105 if (os == .freebsd) {
106 // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198570
107 comptime unreachable; // TODO
108 }
109 if (os == .openbsd) {
110 comptime unreachable;
111 }
112}