| ... | ... | @@ -1,6 +1,12 @@ |
| 1 | 1 | const std = @import("../std.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | pub const fd_t = i32; |
| 5 | |
| 6 | pub const STDIN_FILENO = 0; |
| 7 | pub const STDOUT_FILENO = 1; |
| 8 | pub const STDERR_FILENO = 2; |
| 9 | pub const PATH_MAX = 1023; |
| 4 | 10 | pub const syscall_bits = switch (builtin.cpu.arch) { |
| 5 | 11 | .x86_64 => @import("plan9/x86_64.zig"), |
| 6 | 12 | else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"), |
| ... | ... | @@ -57,7 +63,8 @@ pub const SIG = struct { |
| 57 | 63 | }; |
| 58 | 64 | pub const sigset_t = c_long; |
| 59 | 65 | pub const empty_sigset = 0; |
| 60 | | pub const siginfo_t = c_long; // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible. |
| 66 | pub const siginfo_t = c_long; |
| 67 | // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible. |
| 61 | 68 | pub const Sigaction = extern struct { |
| 62 | 69 | pub const handler_fn = *const fn (c_int) callconv(.C) void; |
| 63 | 70 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| ... | ... | @@ -69,6 +76,9 @@ pub const Sigaction = extern struct { |
| 69 | 76 | mask: sigset_t, |
| 70 | 77 | flags: c_int, |
| 71 | 78 | }; |
| 79 | pub const AT = struct { |
| 80 | pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9 |
| 81 | }; |
| 72 | 82 | // TODO implement sigaction |
| 73 | 83 | // right now it is just a shim to allow using start.zig code |
| 74 | 84 | pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize { |
| ... | ... | @@ -132,20 +142,47 @@ pub const SYS = enum(usize) { |
| 132 | 142 | _NSEC = 53, |
| 133 | 143 | }; |
| 134 | 144 | |
| 135 | | pub fn pwrite(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize { |
| 136 | | return syscall_bits.syscall4(.PWRITE, fd, @intFromPtr(buf), count, offset); |
| 145 | pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { |
| 146 | return syscall_bits.syscall3(._WRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count); |
| 147 | } |
| 148 | pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { |
| 149 | return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, offset); |
| 137 | 150 | } |
| 138 | 151 | |
| 139 | | pub fn pread(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize { |
| 140 | | return syscall_bits.syscall4(.PREAD, fd, @intFromPtr(buf), count, offset); |
| 152 | pub fn read(fd: i32, buf: [*]const u8, count: usize) usize { |
| 153 | return syscall_bits.syscall3(._READ, @bitCast(@as(isize, fd)), @intFromPtr(buf), count); |
| 154 | } |
| 155 | pub fn pread(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { |
| 156 | return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, offset); |
| 157 | } |
| 158 | |
| 159 | pub fn open(path: [*:0]const u8, omode: mode_t) usize { |
| 160 | return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @bitCast(@as(isize, omode))); |
| 161 | } |
| 162 | |
| 163 | pub fn openat(dirfd: i32, path: [*:0]const u8, _: u32, omode: mode_t) usize { |
| 164 | if (dirfd == AT.FDCWD) { // openat(AT_FDCWD, ...) == open(...) |
| 165 | return open(path, omode); |
| 166 | } |
| 167 | var dir_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 168 | var total_path_buf: [std.fs.MAX_PATH_BYTES + 1]u8 = undefined; |
| 169 | const rc = fd2path(dirfd, &dir_path_buf, std.fs.MAX_PATH_BYTES); |
| 170 | if (rc != 0) return rc; |
| 171 | var fba = std.heap.FixedBufferAllocator.init(&total_path_buf); |
| 172 | var alloc = fba.allocator(); |
| 173 | const dir_path = std.mem.span(@as([*:0]u8, @ptrCast(&dir_path_buf))); |
| 174 | const total_path = std.fs.path.join(alloc, &.{ dir_path, std.mem.span(path) }) catch unreachable; // the allocation shouldn't fail because it should not exceed MAX_PATH_BYTES |
| 175 | fba.reset(); |
| 176 | const total_path_z = alloc.dupeZ(u8, total_path) catch unreachable; // should not exceed MAX_PATH_BYTES + 1 |
| 177 | return open(total_path_z.ptr, omode); |
| 141 | 178 | } |
| 142 | 179 | |
| 143 | | pub fn open(path: [*:0]const u8, omode: OpenMode) usize { |
| 144 | | return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @intFromEnum(omode)); |
| 180 | pub fn fd2path(fd: i32, buf: [*]u8, nbuf: usize) usize { |
| 181 | return syscall_bits.syscall3(.FD2PATH, @bitCast(@as(isize, fd)), @intFromPtr(buf), nbuf); |
| 145 | 182 | } |
| 146 | 183 | |
| 147 | | pub fn create(path: [*:0]const u8, omode: OpenMode, perms: usize) usize { |
| 148 | | return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @intFromEnum(omode), perms); |
| 184 | pub fn create(path: [*:0]const u8, omode: mode_t, perms: usize) usize { |
| 185 | return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @bitCast(@as(isize, omode)), perms); |
| 149 | 186 | } |
| 150 | 187 | |
| 151 | 188 | pub fn exit(status: u8) noreturn { |
| ... | ... | @@ -163,16 +200,19 @@ pub fn exits(status: ?[*:0]const u8) noreturn { |
| 163 | 200 | unreachable; |
| 164 | 201 | } |
| 165 | 202 | |
| 166 | | pub fn close(fd: usize) usize { |
| 167 | | return syscall_bits.syscall1(.CLOSE, fd); |
| 203 | pub fn close(fd: i32) usize { |
| 204 | return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd))); |
| 168 | 205 | } |
| 169 | | pub const OpenMode = enum(usize) { |
| 170 | | OREAD = 0, //* open for read |
| 171 | | OWRITE = 1, //* write |
| 172 | | ORDWR = 2, //* read and write |
| 173 | | OEXEC = 3, //* execute, == read but check execute permission |
| 174 | | OTRUNC = 16, //* or'ed in (except for exec), truncate file first |
| 175 | | OCEXEC = 32, //* or'ed in (per file descriptor), close on exec |
| 176 | | ORCLOSE = 64, //* or'ed in, remove on close |
| 177 | | OEXCL = 0x1000, //* or'ed in, exclusive create |
| 206 | pub const mode_t = i32; |
| 207 | pub const O = struct { |
| 208 | pub const READ = 0; // open for read |
| 209 | pub const RDONLY = 0; |
| 210 | pub const WRITE = 1; // write |
| 211 | pub const WRONLY = 1; |
| 212 | pub const RDWR = 2; // read and write |
| 213 | pub const EXEC = 3; // execute, == read but check execute permission |
| 214 | pub const TRUNC = 16; // or'ed in (except for exec), truncate file first |
| 215 | pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec |
| 216 | pub const RCLOSE = 64; // or'ed in, remove on close |
| 217 | pub const EXCL = 0x1000; // or'ed in, exclusive create |
| 178 | 218 | }; |