155 lines
4.1 KiB
Plaintext
155 lines
4.1 KiB
Plaintext
include "std/posix.zr"
|
|
include "std/linux_syscalls.zr"
|
|
include "std/str.zr"
|
|
include "std/containers.zr"
|
|
|
|
func os.exit[code: i64] : void
|
|
_builtin_syscall(SYS_exit, code)
|
|
|
|
func os.getpid[] : i64
|
|
return _builtin_syscall(SYS_getpid)
|
|
|
|
func os.arg[argv: ptr, n: i64] : str
|
|
return mem.read64(argv + n * 8) as str
|
|
|
|
func os.getenv[name: str] : str, bool
|
|
name_len := name->len()
|
|
i := 0
|
|
while true
|
|
entry := mem.read64(_builtin_environ() + i * 8) as str
|
|
if entry as ptr == 0
|
|
break
|
|
if entry->equal_n(name, name_len) && entry[name_len] == '='
|
|
return (entry as ptr + name_len + 1) as str, true
|
|
i += 1
|
|
return 0 as str, false
|
|
|
|
func os.basename[path: str] : str
|
|
len := path->len()
|
|
end := len
|
|
while end > 0 && path[end - 1] == '/'
|
|
end -= 1
|
|
|
|
if end == 0
|
|
return "/"
|
|
|
|
i := end - 1
|
|
while i >= 0 && path[i] != '/'
|
|
i -= 1
|
|
|
|
return path->substr_n(i + 1, end - i - 1)
|
|
|
|
struct os.Timespec
|
|
tv_sec: i64
|
|
tv_nsec: i64
|
|
|
|
func os.sleep[ms: i64] : void
|
|
if ms < 0
|
|
panic("negative time passed to os.sleep")
|
|
req := new os.Timespec
|
|
req->tv_sec = ms / 1000
|
|
req->tv_nsec = (ms % 1000) * 1000000
|
|
_builtin_syscall(SYS_nanosleep, req, 0)
|
|
|
|
func os.time[] : i64
|
|
ts := new os.Timespec
|
|
_builtin_syscall(SYS_clock_gettime, CLOCK_REALTIME, ts)
|
|
out := ts->tv_sec * 1000 + ts->tv_nsec / 1000000
|
|
return out
|
|
|
|
func os.urandom_buf[buf: ptr, n: i64] : void
|
|
pos := 0
|
|
while pos < n
|
|
ret := _builtin_syscall(SYS_getrandom, buf + pos, n - pos, 0)
|
|
if ret <= 0
|
|
panic("os.urandom_buf: syscall failed")
|
|
pos += ret
|
|
|
|
func os.urandom[n: i64]: ptr
|
|
buf := mem.alloc(n)
|
|
os.urandom_buf(buf, n)
|
|
return buf
|
|
|
|
func os.urandom_i64[] : i64
|
|
n := 0
|
|
os.urandom_buf(^n, 8)
|
|
return n
|
|
|
|
func os.run_shell_command[command: str] : i64, bool
|
|
pid := _builtin_syscall(SYS_fork)
|
|
if pid < 0
|
|
return -1, false
|
|
|
|
if pid == 0
|
|
argv := ["sh", "-c", command, 0] // gets freed after child process exits
|
|
_builtin_syscall(SYS_execve, "/bin/sh", argv->data, _builtin_environ())
|
|
os.exit(1)
|
|
else
|
|
status := 0
|
|
wp := _builtin_syscall(SYS_wait4, pid, ^status, 0, 0)
|
|
if wp < 0
|
|
return -1, false
|
|
st := status & 0xffffffff
|
|
|
|
if (st & 0x7f) == 0
|
|
return (st >> 8) & 0xff, true
|
|
else
|
|
return -(st & 0x7f), true
|
|
|
|
func os.file_exists[path: str] : bool
|
|
return _builtin_syscall(SYS_faccessat, AT_FDCWD, path, F_OK, 0) == 0
|
|
|
|
func os.get_file_size[path: str] : i64, bool
|
|
st := _stackalloc(256) // it has 21 mixed-size fields so ptr for now
|
|
|
|
rc := _builtin_syscall(SYS_newfstatat, AT_FDCWD, path, st, 0)
|
|
if rc != 0
|
|
return 0, false
|
|
|
|
return mem.read64(st + 48), true
|
|
|
|
func os.is_a_directory[path: str] : bool
|
|
st := _stackalloc(256) // it has 21 mixed-size fields so ptr for now
|
|
|
|
rc := _builtin_syscall(SYS_newfstatat, AT_FDCWD, path, st, 0)
|
|
if rc != 0
|
|
return false
|
|
|
|
return (mem.read32(st + 24) & S_IFMT) == S_IFDIR
|
|
|
|
func os.list_directory[path: str] : Array, bool
|
|
fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_RDONLY, 0)
|
|
if fd < 0
|
|
return 0 as Array, false
|
|
|
|
files := []
|
|
buf := _stackalloc(1024)
|
|
while true
|
|
n := _builtin_syscall(SYS_getdents64, fd, buf, 1024)
|
|
if n < 0
|
|
files->free_with_items()
|
|
_builtin_syscall(SYS_close, fd)
|
|
return 0 as Array, false
|
|
else if n == 0
|
|
break
|
|
|
|
pos := 0
|
|
while pos < n
|
|
len := mem.read16(buf + pos + 16)
|
|
name : ptr = buf + pos + 19
|
|
if name[0]
|
|
skip := false
|
|
// skip if name is exactly '.' or '..'
|
|
if name[0] == '.'
|
|
if name[1] == 0
|
|
skip = true
|
|
else if name[1] == '.'
|
|
if name[2] == 0
|
|
skip = true
|
|
if !skip
|
|
files->push((name as str)->make_copy())
|
|
pos += len
|
|
|
|
_builtin_syscall(SYS_close, fd)
|
|
return files, true
|