hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 0f753c9c828d6073282bb05fac356d62899f029e
parent 2cd92f12d91100d15c76622a69f57d6ca0c76419
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue,  5 Mar 2024 10:59:45 +0100

unix: unify and normalize credentials

This merges all credentials-related Unix semantics into unix/*/creds.ha,
including getuid, setuid, getpid, and so on, adds unix::pid et al type
aliases, and updates everything accordingly.

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mdirs/xdg.ha | 2+-
Mmakefiles/freebsd.aarch64.mk | 4++--
Mmakefiles/freebsd.riscv64.mk | 4++--
Mmakefiles/freebsd.x86_64.mk | 4++--
Mmakefiles/linux.aarch64.mk | 4++--
Mmakefiles/linux.riscv64.mk | 4++--
Mmakefiles/linux.x86_64.mk | 4++--
Mmakefiles/openbsd.aarch64.mk | 4++--
Mmakefiles/openbsd.riscv64.mk | 4++--
Mmakefiles/openbsd.x86_64.mk | 4++--
Mos/exec/+freebsd/exec.ha | 4++--
Mos/exec/+freebsd/process.ha | 15++++++++-------
Mos/exec/+linux/exec.ha | 2+-
Mos/exec/+linux/process.ha | 19++++++++++---------
Mos/exec/+openbsd/process.ha | 26+++++++++++++-------------
Mrt/+freebsd/syscalls.ha | 30+++++++++++++++++++++---------
Mrt/+linux/syscalls.ha | 49++++++++++++++++++++++++++++++++-----------------
Mrt/+openbsd/syscalls.ha | 62+++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Aunix/+freebsd/creds.ha | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dunix/+freebsd/getpid.ha | 7-------
Dunix/+freebsd/getuid.ha | 32--------------------------------
Dunix/+freebsd/groups.ha | 22----------------------
Dunix/+freebsd/setuid.ha | 44--------------------------------------------
Aunix/+linux/creds.ha | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dunix/+linux/getpid.ha | 7-------
Dunix/+linux/getuid.ha | 32--------------------------------
Dunix/+linux/groups.ha | 22----------------------
Dunix/+linux/setuid.ha | 44--------------------------------------------
Aunix/+openbsd/creds.ha | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dunix/+openbsd/getpid.ha | 7-------
Dunix/+openbsd/getuid.ha | 17-----------------
Dunix/+openbsd/groups.ha | 22----------------------
Dunix/+openbsd/setuid.ha | 44--------------------------------------------
Munix/passwd/group.ha | 11++++++-----
Munix/passwd/passwd.ha | 19++++++++++---------
Munix/signal/+freebsd.ha | 5+++--
Munix/signal/+linux.ha | 5+++--
Munix/signal/+openbsd.ha | 5+++--
38 files changed, 610 insertions(+), 408 deletions(-)

diff --git a/dirs/xdg.ha b/dirs/xdg.ha @@ -91,7 +91,7 @@ export fn runtime() (str | fs::error) = { }; const st = os::stat(path)?; - const uid = unix::getuid(); + const uid = unix::getuid(): uint; if (st.uid != uid || fs::mode_perm(st.mode) != fs::mode::USER_RWX) { return errors::noaccess; }; diff --git a/makefiles/freebsd.aarch64.mk b/makefiles/freebsd.aarch64.mk @@ -201,14 +201,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+freebsd/getpid.ha unix/+freebsd/getuid.ha unix/+freebsd/groups.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/setuid.ha unix/+freebsd/umask.ha +unix_ha = unix/+freebsd/creds.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/freebsd.riscv64.mk b/makefiles/freebsd.riscv64.mk @@ -201,14 +201,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+freebsd/getpid.ha unix/+freebsd/getuid.ha unix/+freebsd/groups.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/setuid.ha unix/+freebsd/umask.ha +unix_ha = unix/+freebsd/creds.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/freebsd.x86_64.mk b/makefiles/freebsd.x86_64.mk @@ -201,14 +201,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+freebsd/getpid.ha unix/+freebsd/getuid.ha unix/+freebsd/groups.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/setuid.ha unix/+freebsd/umask.ha +unix_ha = unix/+freebsd/creds.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/linux.aarch64.mk b/makefiles/linux.aarch64.mk @@ -219,14 +219,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+linux/getpid.ha unix/+linux/getuid.ha unix/+linux/groups.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/setuid.ha unix/+linux/umask.ha +unix_ha = unix/+linux/creds.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/linux.riscv64.mk b/makefiles/linux.riscv64.mk @@ -219,14 +219,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+linux/getpid.ha unix/+linux/getuid.ha unix/+linux/groups.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/setuid.ha unix/+linux/umask.ha +unix_ha = unix/+linux/creds.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/linux.x86_64.mk b/makefiles/linux.x86_64.mk @@ -219,14 +219,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+linux/getpid.ha unix/+linux/getuid.ha unix/+linux/groups.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/setuid.ha unix/+linux/umask.ha +unix_ha = unix/+linux/creds.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/openbsd.aarch64.mk b/makefiles/openbsd.aarch64.mk @@ -201,14 +201,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+openbsd/getpid.ha unix/+openbsd/getuid.ha unix/+openbsd/groups.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/setuid.ha unix/+openbsd/umask.ha +unix_ha = unix/+openbsd/creds.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+openbsd.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/openbsd.riscv64.mk b/makefiles/openbsd.riscv64.mk @@ -201,14 +201,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+openbsd/getpid.ha unix/+openbsd/getuid.ha unix/+openbsd/groups.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/setuid.ha unix/+openbsd/umask.ha +unix_ha = unix/+openbsd/creds.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+openbsd.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/makefiles/openbsd.x86_64.mk b/makefiles/openbsd.x86_64.mk @@ -201,14 +201,14 @@ $(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACH @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) -unix_ha = unix/+openbsd/getpid.ha unix/+openbsd/getuid.ha unix/+openbsd/groups.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/setuid.ha unix/+openbsd/umask.ha +unix_ha = unix/+openbsd/creds.ha unix/+openbsd/nice.ha unix/+openbsd/pipe.ha unix/+openbsd/umask.ha $(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha) unix_signal_ha = unix/signal/+openbsd.ha unix/signal/types.ha -$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/unix.td @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha) diff --git a/os/exec/+freebsd/exec.ha b/os/exec/+freebsd/exec.ha @@ -14,7 +14,7 @@ export fn fork() (process | void | error) = { match (rt::fork()) { case let err: rt::errno => return errors::errno(err); - case let i: int => + case let i: rt::pid_t => return i: process; case void => return void; @@ -184,7 +184,7 @@ fn platform_start(cmd: *command) (process | errors::error) = { match (rt::fork()) { case let err: rt::errno => return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => rt::close(pipe[1])!; defer rt::close(pipe[0])!; let errno: int = 0; diff --git a/os/exec/+freebsd/process.ha b/os/exec/+freebsd/process.ha @@ -5,14 +5,15 @@ use errors; use fmt; use rt; use time; +use unix; use unix::signal; // Stores information about a child process. -export type process = int; +export type process = unix::pid; // Returns the currently running [[process]]. export fn self() process = { - return rt::getpid(); + return unix::getpid(); }; // Stores information about an exited process. @@ -73,7 +74,7 @@ export fn wait(proc: *process) (status | error) = { case let err: rt::errno => return errors::errno(err); case let pid: int => - assert(pid == *proc); + assert(pid == *proc: int); }; rusage(&st, &ru); return st; @@ -89,7 +90,7 @@ export fn waitany() ((process, status) | error) = { return errors::errno(err); case let pid: int => rusage(&st, &ru); - return (pid, st); + return (pid: process, st); }; }; @@ -110,7 +111,7 @@ export fn waitall() (uint | error | !(process, exit_status)) = { match (check(&st)) { case void => void; case let es: !exit_status => - return (pid, es); + return (pid: process, es); }; }; }; @@ -128,7 +129,7 @@ export fn peek(proc: *process) (status | void | error) = { case 0 => return; case => - assert(pid == *proc); + assert(pid == *proc: int); }; }; rusage(&st, &ru); @@ -148,7 +149,7 @@ export fn peekany() ((process, status) | void | error) = { case 0 => return; case => - return (pid, st); + return (pid: process, st); }; }; }; diff --git a/os/exec/+linux/exec.ha b/os/exec/+linux/exec.ha @@ -14,7 +14,7 @@ export fn fork() (process | void | error) = { match (rt::fork()) { case let err: rt::errno => return errors::errno(err); - case let i: int => + case let i: rt::pid_t => return i: process; case void => return void; diff --git a/os/exec/+linux/process.ha b/os/exec/+linux/process.ha @@ -5,14 +5,15 @@ use errors; use fmt; use rt; use time; +use unix; use unix::signal; // Stores information about a child process. -export type process = int; +export type process = unix::pid; // Returns the currently running [[process]]. export fn self() process = { - return rt::getpid(); + return unix::getpid(); }; // Stores information about an exited process. @@ -58,8 +59,8 @@ export fn wait(proc: *process) (status | error) = { match (rt::wait4(*proc, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => - assert(pid == *proc); + case let pid: rt::pid_t => + assert(pid == *proc: rt::pid_t); }; rusage(&st, &ru); return st; @@ -73,7 +74,7 @@ export fn waitany() ((process, status) | error) = { match (rt::wait4(-1, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => rusage(&st, &ru); return (pid, st); }; @@ -91,7 +92,7 @@ export fn waitall() (uint | error | !(process, exit_status)) = { return i; }; return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => match (check(&st)) { case void => void; case let es: !exit_status => @@ -108,12 +109,12 @@ export fn peek(proc: *process) (status | void | error) = { match (rt::wait4(*proc, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => switch (pid) { case 0 => return; case => - assert(pid == *proc); + assert(pid == *proc: rt::pid_t); }; }; rusage(&st, &ru); @@ -128,7 +129,7 @@ export fn peekany() ((process, status) | void | error) = { match (rt::wait4(-1, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => switch (pid) { case 0 => return; diff --git a/os/exec/+openbsd/process.ha b/os/exec/+openbsd/process.ha @@ -5,14 +5,15 @@ use errors; use fmt; use rt; use time; +use unix; use unix::signal; // Stores information about a child process. -export type process = int; +export type process = unix::pid; // Returns the currently running [[process]]. export fn self() process = { - return rt::getpid(); + return unix::getpid(); }; // Stores information about an exited process. @@ -72,9 +73,8 @@ export fn wait(proc: *process) (status | error) = { match (rt::wait4(*proc, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => - // TODO: Handle invalid pid? - assert(pid == *proc); + case let pid: rt::pid_t => + assert(pid == *proc: rt::pid_t); }; rusage(&st, &ru); return st; @@ -88,9 +88,9 @@ export fn waitany() ((process, status) | error) = { match (rt::wait4(rt::WAIT_ANY, &st.status, 0, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => rusage(&st, &ru); - return (pid, st); + return (pid: process, st); }; }; @@ -108,11 +108,11 @@ export fn waitall() (uint | error | !(process, exit_status)) = { } else { return errors::errno(err); }; - case let pid: int => + case let pid: rt::pid_t => match (check(&st)) { case void => void; case let es: !exit_status => - return (pid, es); + return (pid: process, es); }; }; }; @@ -126,12 +126,12 @@ export fn peek(proc: *process) (status | void | error) = { match (rt::wait4(*proc, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => switch (pid) { case 0 => return; case => - assert(pid == *proc); + assert(pid == *proc: rt::pid_t); }; }; rusage(&st, &ru); @@ -146,12 +146,12 @@ export fn peekany() ((process, status) | void | error) = { match (rt::wait4(rt::WAIT_ANY, &st.status, rt::WNOHANG, &ru)) { case let err: rt::errno => return errors::errno(err); - case let pid: int => + case let pid: rt::pid_t => switch (pid) { case 0 => return; case => - return (pid, st); + return (pid: process, st); }; }; }; diff --git a/rt/+freebsd/syscalls.ha b/rt/+freebsd/syscalls.ha @@ -283,12 +283,12 @@ export fn exit(status: int) never = { abort(); }; -export fn kill(pid: int, signal: int) (void | errno) = { +export fn kill(pid: pid_t, signal: int) (void | errno) = { wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?; }; -export fn fork() (int | void | errno) = { - let n = wrap_return(syscall0(SYS_fork))?: int; +export fn fork() (pid_t | void | errno) = { + let n = wrap_return(syscall0(SYS_fork))?: pid_t; switch (n) { case 0 => return; @@ -309,7 +309,7 @@ export fn fexecve(fd: int, argv: *[*]nullable *const u8, }; export fn wait4( - pid: int, + pid: pid_t, wstatus: nullable *int, options: int, rusage: nullable *rusage, @@ -326,7 +326,19 @@ export fn wtermsig(status: int) int = status & 0x7f; export fn wifsignaled(status: int) bool = wtermsig(status) != 0o177 && wtermsig(status) != 0 && status != 0x13; -export fn getpid() int = syscall0(SYS_getpid): int; +export fn getpid() pid_t = syscall0(SYS_getpid): pid_t; + +export fn getppid() pid_t = syscall0(SYS_getppid): pid_t; + +export fn getpgrp() pid_t = syscall0(SYS_getpgrp): pid_t; + +export fn getpgid(pid: pid_t) (pid_t | errno) = { + return wrap_return(syscall1(SYS_getpgid, pid))?: pid_t; +}; + +export fn getsid(pid: pid_t) (pid_t | errno) = { + return wrap_return(syscall1(SYS_getsid, pid))?: pid_t; +}; export fn getpriority(which: int, who: id_t) (int | errno) = { return wrap_return(syscall2(SYS_getpriority, @@ -349,14 +361,14 @@ export fn setresgid(gid: gid_t, egid: gid_t, sgid: gid_t) (void | errno) = { wrap_return(syscall3(SYS_setresgid, gid: u64, egid: u64, sgid: u64))?; }; -export fn getgroups(gids: []uint) (uint | errno) = { +export fn getgroups(gids: []gid_t) (uint | errno) = { return wrap_return(syscall2(SYS_getgroups, - len(gids): u64, gids: *[*]uint: uintptr: u64))?: uint; + len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint; }; -export fn setgroups(gids: []uint) (void | errno) = { +export fn setgroups(gids: []gid_t) (void | errno) = { wrap_return(syscall2(SYS_setgroups, - len(gids): u64, gids: *[*]uint: uintptr: u64))?; + len(gids): u64, gids: *[*]gid_t: uintptr: u64))?; }; export fn getresuid(uid: *uid_t, euid: *uid_t, suid: *uid_t) (void | errno) = { diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha @@ -263,23 +263,38 @@ export fn execve(path: path, argv: *[*]nullable *const u8, // Returns the new PID to the parent, void to the child, or errno if something // goes wrong. -export fn fork() (int | void | errno) = clone(null, SIGCHLD, null, null, 0); +export fn fork() (pid_t | void | errno) = { + match (clone(null, SIGCHLD, null, null, 0)?) { + case let id: int => + return id: pid_t; + case void => + return void; + }; +}; + +export fn getpid() pid_t = syscall0(SYS_getpid): pid_t; -export fn getpid() int = syscall0(SYS_getpid): int; +export fn getppid() pid_t = syscall0(SYS_getppid): pid_t; -export fn getpgid(pid: int) (int | errno) = { - return wrap_return(syscall1(SYS_getpgid, pid: u64))?: int; +export fn getpgrp() pid_t = syscall0(SYS_getpgrp): pid_t; + +export fn getpgid(pid: pid_t) (pid_t | errno) = { + return wrap_return(syscall1(SYS_getpgid, pid: u64))?: pid_t; +}; + +export fn setpgid(pid: pid_t, pgid: pid_t) (void | errno) = { + wrap_return(syscall2(SYS_setpgid, pid: u64, pgid: u64))?; }; export fn wait4( - pid: int, + pid: pid_t, wstatus: nullable *int, options: int, rusage: nullable *rusage, -) (int | errno) = { +) (pid_t | errno) = { return wrap_return(syscall4(SYS_wait4, pid: u64, wstatus: uintptr: u64, - options: u64, rusage: uintptr: u64))?: int; + options: u64, rusage: uintptr: u64))?: pid_t; }; export fn sendfile( @@ -295,7 +310,7 @@ export fn exit(status: int) never = { abort(); }; -export fn kill(pid: int, signal: int) (void | errno) = { +export fn kill(pid: pid_t, signal: int) (void | errno) = { wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?; }; @@ -731,14 +746,14 @@ export fn getresgid(gid: *gid_t, egid: *gid_t, sgid: *gid_t) (void | errno) = { sgid: uintptr: u64))?; }; -export fn getgroups(gids: []uint) (uint | errno) = { +export fn getgroups(gids: []gid_t) (uint | errno) = { return wrap_return(syscall2(SYS_getgroups, - len(gids): u64, gids: *[*]uint: uintptr: u64))?: uint; + len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint; }; -export fn setgroups(gids: []uint) (void | errno) = { +export fn setgroups(gids: []gid_t) (void | errno) = { wrap_return(syscall2(SYS_setgroups, - len(gids): u64, gids: *[*]uint: uintptr: u64))?; + len(gids): u64, gids: *[*]gid_t: uintptr: u64))?; }; export fn getpriority(which: int, who: id_t) (int | errno) = { @@ -841,8 +856,8 @@ export fn keyctl( arg2, arg3, arg4, arg5))?: int; }; -export fn getsid(pid: int) (int | errno) = { - return wrap_return(syscall1(SYS_getsid, pid: u64))?: int; +export fn getsid(pid: pid_t) (pid_t | errno) = { + return wrap_return(syscall1(SYS_getsid, pid: u64))?: pid_t; }; export fn setsid() (void | errno) = { @@ -869,7 +884,7 @@ export fn umount2(target: path, flags: int) (void | errno) = { export fn ptrace( request: int, - pid: int, + pid: pid_t, addr: uintptr, data: uintptr, ) (u64 | errno) = { @@ -970,7 +985,7 @@ export fn shmat(id: int, addr: *const opaque, flag: int) *opaque = { }; export fn sched_getaffinity( - pid: int, + pid: pid_t, cpusetsize: size, mask: *cpu_set, ) (void | errno) = { @@ -979,7 +994,7 @@ export fn sched_getaffinity( }; export fn sched_setaffinity( - pid: int, + pid: pid_t, cpusetsize: size, mask: *const cpu_set, ) (void | errno) = { diff --git a/rt/+openbsd/syscalls.ha b/rt/+openbsd/syscalls.ha @@ -123,18 +123,18 @@ export fn close(fd: int) (void | errno) = { // wait4 @symbol("wait4") fn libc_wait4( - wpid: int, + wpid: pid_t, status: nullable *int, options: int, rusage: nullable *rusage -) int; +) pid_t; export fn wait4( - pid: int, + pid: pid_t, wstatus: nullable *int, options: int, rusage: nullable *rusage, -) (int | errno) = { +) (pid_t | errno) = { let res = libc_wait4(pid, wstatus, options, rusage); if (res == -1) { return *__errno(): errno; @@ -174,7 +174,7 @@ export fn fchdir(fd: int) (void | errno) = { // getrusage // getpid -export @symbol("getpid") fn getpid() int; +export @symbol("getpid") fn getpid() pid_t; // mount // unmount @@ -315,7 +315,11 @@ export fn access(path: path, amode: int) (bool | errno) = { // sync // msyscall // stat + // getppid + +export @symbol("getppid") fn getppid() pid_t; + // lstat // dup // fstatat @@ -538,10 +542,10 @@ export fn munmap(addr: *opaque, len_: size) (void | errno) = { // mquery // getgroups -@symbol("getgroups") fn libc_getgroups(gidsetlen: int, gidset: *[*]u32) int; +@symbol("getgroups") fn libc_getgroups(gidsetlen: int, gidset: *[*]gid_t) int; -export fn getgroups(gids: []uint) (uint | errno) = { - let res = libc_getgroups(len(gids): int, gids: *[*]u32); +export fn getgroups(gids: []gid_t) (uint | errno) = { + let res = libc_getgroups(len(gids): int, gids: *[*]gid_t); if (res == -1) { return *__errno(): errno; }; @@ -552,18 +556,31 @@ export fn getgroups(gids: []uint) (uint | errno) = { @symbol("setgroups") fn libc_setgroups( ngroups: int, - gidset: *[*]u32 + gidset: *[*]gid_t, ) int; -export fn setgroups(gids: []uint) (void | errno) = { - let res = libc_setgroups(len(gids): int, gids: *[*]u32); +export fn setgroups(gids: []gid_t) (void | errno) = { + let res = libc_setgroups(len(gids): int, gids: *[*]gid_t); if (res == -1) { return *__errno(): errno; }; }; // getpgrp + +export @symbol("getpgrp") fn getpgrp() pid_t; + // setpgid + +@symbol("setpgid") fn libc_setpgid(pid: pid_t, pgrp: pid_t) int; + +export fn setpgid(pid: pid_t, pgrp: pid_t) (void | errno) = { + let res = libc_setpgid(pid, pgrp); + if (res == -1) { + return *__errno(): errno; + }; +}; + // futex // utimensat // futimens @@ -1027,7 +1044,18 @@ export fn socketpair( // getthrname // setthrname // pinsyscall + // setsid + +@symbol("setsid") fn libc_setsid() pid_t; + +export fn setsid() (void | errno) = { + let res = libc_setsid(); + if (res == -1) { + return *__errno(): errno; + }; +}; + // quotactl // ypconnect // nfssvc @@ -1153,7 +1181,19 @@ export fn getpgid(pid: pid_t) (pid_t | errno) = { // poll // issetugid // lchown + // getsid + +@symbol("getsid") fn libc_getsid(pid: pid_t) pid_t; + +export fn getsid(pid: pid_t) (pid_t | errno) = { + let res = libc_getsid(pid); + if (res == -1) { + return *__errno(): errno; + }; + return res; +}; + // msync // pipe // fhopen diff --git a/unix/+freebsd/creds.ha b/unix/+freebsd/creds.ha @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> +// Unix credentials types & functions; ref credentials(7) + +use errors; +use rt; + +// Process ID. +export type pid = rt::pid_t; + +// User ID. +export type uid = rt::uid_t; + +// Group ID. +export type gid = rt::gid_t; + +// Returns the current process user ID. +export fn getuid() uid = { + let uid = 0u, euid = 0u, suid = 0u; + rt::getresuid(&uid, &euid, &suid) as void; + return uid; +}; + +// Returns the current process effective user ID. +export fn geteuid() uid = { + let uid = 0u, euid = 0u, suid = 0u; + rt::getresuid(&uid, &euid, &suid) as void; + return euid; +}; + +// Returns the current process group ID. +export fn getgid() gid = { + let gid = 0u, egid = 0u, sgid = 0u; + rt::getresgid(&gid, &egid, &sgid) as void; + return gid; +}; + +// Returns the current process effective group ID. +export fn getegid() gid = { + let gid = 0u, egid = 0u, sgid = 0u; + rt::getresgid(&gid, &egid, &sgid) as void; + return egid; +}; + +// Sets the caller's user ID to the specified value. This generally requires +// elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setuid(uid: uid) void = rt::setresuid(uid, -1i: uint, -1i: uint)!; + +// Sets the caller's effective user ID to the specified value. This generally +// requires elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from seteuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn seteuid(uid: uid) void = rt::setresuid(-1i: uint, uid, -1i: uint)!; + +// Sets the caller's group ID to the specified value. This generally requires +// elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setgid(gid: gid) void = rt::setresgid(gid, -1i: uint, -1i: uint)!; + +// Sets the caller's effective group ID to the specified value. This generally +// requires elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setegid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setegid(gid: gid) void = rt::setresgid(-1i: uint, gid, -1i: uint)!; + +// Returns a list of supplementary group IDs for the current process. The +// returned slice is statically allocated. +export fn getgroups() []gid = { + static let gids: [rt::NGROUPS_MAX]rt::gid_t = [0...]; + const n = rt::getgroups(gids)!; + return gids[..n]: []gid; +}; + +// Sets the list of supplementary group IDs which apply to the current process. +// This generally requires elevated permissions. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setgroups is a grave security issue in your program, +// and therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setgroups(gids: []gid) void = rt::setgroups(gids: []rt::gid_t)!; + +// Returns the current process ID. +export fn getpid() pid = rt::getpid(); + +// Returns the parent process ID. +export fn getppid() pid = rt::getppid(); + +// Returns the current process group ID. +export fn getpgrp() pid = rt::getpgrp(); + +// Returns the current process's session ID. +export fn getsid() pid = rt::getsid(0)!; + +// Returns the session ID associated with the given process. +export fn getpsid(pid: pid) (pid | errors::noentry | errors::noaccess) = { + match (rt::getsid(pid)) { + case let pid: rt::pid_t => + return pid; + case let err: rt::errno => + assert(err == rt::ESRCH); + return errors::noentry; + }; +}; diff --git a/unix/+freebsd/getpid.ha b/unix/+freebsd/getpid.ha @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns the current process ID. -export fn getpid() int = rt::getpid(); diff --git a/unix/+freebsd/getuid.ha b/unix/+freebsd/getuid.ha @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns the current process user ID. -export fn getuid() uint = { - let uid = 0u, euid = 0u, suid = 0u; - rt::getresuid(&uid, &euid, &suid) as void; - return uid; -}; - -// Returns the current process effective user ID. -export fn geteuid() uint = { - let uid = 0u, euid = 0u, suid = 0u; - rt::getresuid(&uid, &euid, &suid) as void; - return euid; -}; - -// Returns the current process group ID. -export fn getgid() uint = { - let gid = 0u, egid = 0u, sgid = 0u; - rt::getresgid(&gid, &egid, &sgid) as void; - return gid; -}; - -// Returns the current process effective group ID. -export fn getegid() uint = { - let gid = 0u, egid = 0u, sgid = 0u; - rt::getresgid(&gid, &egid, &sgid) as void; - return egid; -}; diff --git a/unix/+freebsd/groups.ha b/unix/+freebsd/groups.ha @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns a list of supplementary group IDs for the current process. The -// returned slice is statically allocated. -export fn getgroups() []uint = { - static let gids: [rt::NGROUPS_MAX]uint = [0...]; - const n = rt::getgroups(gids)!; - return gids[..n]; -}; - -// Sets the list of supplementary group IDs which apply to the current process. -// This generally requires elevated permissions. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setgroups is a grave security issue in your program, -// and therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setgroups(gids: []uint) void = rt::setgroups(gids)!; diff --git a/unix/+freebsd/setuid.ha b/unix/+freebsd/setuid.ha @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Sets the caller's user ID to the specified value. This generally requires -// elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setuid(uid: uint) void = rt::setresuid(uid, -1i: uint, -1i: uint)!; - -// Sets the caller's effective user ID to the specified value. This generally -// requires elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from seteuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn seteuid(uid: uint) void = rt::setresuid(-1i: uint, uid, -1i: uint)!; - -// Sets the caller's group ID to the specified value. This generally requires -// elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setgid(gid: uint) void = rt::setresgid(gid, -1i: uint, -1i: uint)!; - -// Sets the caller's effective group ID to the specified value. This generally -// requires elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setegid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setegid(gid: uint) void = rt::setresgid(-1i: uint, gid, -1i: uint)!; diff --git a/unix/+linux/creds.ha b/unix/+linux/creds.ha @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> +// Unix credentials types & functions; ref credentials(7) + +use errors; +use rt; + +// Process ID. +export type pid = rt::pid_t; + +// User ID. +export type uid = rt::uid_t; + +// Group ID. +export type gid = rt::gid_t; + +// Returns the current process user ID. +export fn getuid() uid = { + let uid = 0u, euid = 0u, suid = 0u; + rt::getresuid(&uid, &euid, &suid) as void; + return uid; +}; + +// Returns the current process effective user ID. +export fn geteuid() uid = { + let uid = 0u, euid = 0u, suid = 0u; + rt::getresuid(&uid, &euid, &suid) as void; + return euid; +}; + +// Returns the current process group ID. +export fn getgid() gid = { + let gid = 0u, egid = 0u, sgid = 0u; + rt::getresgid(&gid, &egid, &sgid) as void; + return gid; +}; + +// Returns the current process effective group ID. +export fn getegid() gid = { + let gid = 0u, egid = 0u, sgid = 0u; + rt::getresgid(&gid, &egid, &sgid) as void; + return egid; +}; + +// Sets the caller's user ID to the specified value. This generally requires +// elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setuid(uid: uid) void = rt::setresuid(uid, -1i: uint, -1i: uint)!; + +// Sets the caller's effective user ID to the specified value. This generally +// requires elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from seteuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn seteuid(uid: uid) void = rt::setresuid(-1i: uint, uid, -1i: uint)!; + +// Sets the caller's group ID to the specified value. This generally requires +// elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setgid(gid: gid) void = rt::setresgid(gid, -1i: uint, -1i: uint)!; + +// Sets the caller's effective group ID to the specified value. This generally +// requires elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setegid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setegid(gid: gid) void = rt::setresgid(-1i: uint, gid, -1i: uint)!; + +// Returns a list of supplementary group IDs for the current process. The +// returned slice is statically allocated. +export fn getgroups() []gid = { + static let gids: [rt::NGROUPS_MAX]rt::gid_t = [0...]; + const n = rt::getgroups(gids)!; + return gids[..n]: []gid; +}; + +// Sets the list of supplementary group IDs which apply to the current process. +// This generally requires elevated permissions. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setgroups is a grave security issue in your program, +// and therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setgroups(gids: []gid) void = rt::setgroups(gids: []rt::gid_t)!; + +// Returns the current process ID. +export fn getpid() pid = rt::getpid(); + +// Returns the parent process ID. +export fn getppid() pid = rt::getppid(); + +// Returns the current process group ID. +export fn getpgrp() pid = rt::getpgrp(); + +// Returns the process group associated with the given pid. +export fn getpgid(pid: pid) (pid | errors::noentry) = { + match (rt::getpgid(pid)) { + case let pid: rt::pid_t => + return pid; + case let err: rt::errno => + assert(err == rt::ESRCH, "Unexpected getpgid return value"); + return errors::noentry; + }; +}; + +// Sets the process group ID of the specified process. This function is +// error-prone; see the notes in the POSIX specification for its many caveats. +export fn setpgid(targ: pid, pgid: pid) (void | errors::error) = { + match (rt::setpgid(targ, pgid)) { + case let err: rt::errno => + return errors::errno(err); + case void => + return; + }; +}; + +// Returns the current process's session ID. +export fn getsid() pid = rt::getsid(0)!; + +// Returns the session ID associated with the given process. +export fn getpsid(pid: pid) (pid | errors::noentry | errors::noaccess) = { + match (rt::getsid(pid)) { + case let pid: rt::pid_t => + return pid; + case let err: rt::errno => + assert(err == rt::ESRCH, "Unexpected getsid return value"); + return errors::noentry; + }; +}; + +// Creates a new session and sets the current process to the session leader. +// A new process group is also created with its process group ID equal to the +// pid of the current process, and the current process is made the process group +// leader. +// +// Upon return, the new session will have no controlling terminal. To establish +// one, the caller must open a terminal file with [[fs::flag::CTTY]]; this +// opt-in approach differs from the Unix norm where O_NOCTTY is required to +// opt-out of establishing a controlling terminal. +// +// The current process cannot be a process group leader; this is a programmer +// error and will cause a runtime assertion failure. +export fn setsid() void = rt::setsid()!; diff --git a/unix/+linux/getpid.ha b/unix/+linux/getpid.ha @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns the current process ID. -export fn getpid() int = rt::getpid(); diff --git a/unix/+linux/getuid.ha b/unix/+linux/getuid.ha @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns the current process user ID. -export fn getuid() uint = { - let uid = 0u, euid = 0u, suid = 0u; - rt::getresuid(&uid, &euid, &suid) as void; - return uid; -}; - -// Returns the current process effective user ID. -export fn geteuid() uint = { - let uid = 0u, euid = 0u, suid = 0u; - rt::getresuid(&uid, &euid, &suid) as void; - return euid; -}; - -// Returns the current process group ID. -export fn getgid() uint = { - let gid = 0u, egid = 0u, sgid = 0u; - rt::getresgid(&gid, &egid, &sgid) as void; - return gid; -}; - -// Returns the current process effective group ID. -export fn getegid() uint = { - let gid = 0u, egid = 0u, sgid = 0u; - rt::getresgid(&gid, &egid, &sgid) as void; - return egid; -}; diff --git a/unix/+linux/groups.ha b/unix/+linux/groups.ha @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns a list of supplementary group IDs for the current process. The -// returned slice is statically allocated. -export fn getgroups() []uint = { - static let gids: [rt::NGROUPS_MAX]uint = [0...]; - const n = rt::getgroups(gids)!; - return gids[..n]; -}; - -// Sets the list of supplementary group IDs which apply to the current process. -// This generally requires elevated permissions. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setgroups is a grave security issue in your program, -// and therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setgroups(gids: []uint) void = rt::setgroups(gids)!; diff --git a/unix/+linux/setuid.ha b/unix/+linux/setuid.ha @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Sets the caller's user ID to the specified value. This generally requires -// elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setuid(uid: uint) void = rt::setresuid(uid, -1i: uint, -1i: uint)!; - -// Sets the caller's effective user ID to the specified value. This generally -// requires elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from seteuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn seteuid(uid: uint) void = rt::setresuid(-1i: uint, uid, -1i: uint)!; - -// Sets the caller's group ID to the specified value. This generally requires -// elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setgid(gid: uint) void = rt::setresgid(gid, -1i: uint, -1i: uint)!; - -// Sets the caller's effective group ID to the specified value. This generally -// requires elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setegid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setegid(gid: uint) void = rt::setresgid(-1i: uint, gid, -1i: uint)!; diff --git a/unix/+openbsd/creds.ha b/unix/+openbsd/creds.ha @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> +// Unix credentials types & functions; ref credentials(7) + +use errors; +use rt; + +// Process ID. +export type pid = rt::pid_t; + +// User ID. +export type uid = rt::uid_t; + +// Group ID. +export type gid = rt::gid_t; + +// Returns the current process user ID. +export fn getuid() uid = rt::getuid(); + +// Returns the current process effective user ID. +export fn geteuid() uid = rt::geteuid(); + +// Returns the current process group ID. +export fn getgid() uid = rt::getgid(); + +// Returns the current process effective group ID. +export fn getegid() uid = rt::getegid(); + +// Sets the caller's user ID to the specified value. This generally requires +// elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, +// and take extreme care to handle errors correctly. +export fn setuid(uid: uid) void = rt::setuid(uid)!; + +// Sets the caller's effective user ID to the specified value. This generally +// requires elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from seteuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, +// and take extreme care to handle errors correctly. +export fn seteuid(uid: uid) void = rt::seteuid(uid)!; + +// Sets the caller's group ID to the specified value. This generally requires +// elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setuid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, +// and take extreme care to handle errors correctly. +export fn setgid(gid: gid) void = rt::setgid(gid)!; + +// Sets the caller's effective group ID to the specified value. This generally +// requires elevated permissions from the calling process. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setegid is a grave security issue in your program, and +// therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, +// and take extreme care to handle errors correctly. +export fn setegid(gid: gid) void = rt::setegid(gid)!; + +// Returns a list of supplementary group IDs for the current process. The +// returned slice is statically allocated. +export fn getgroups() []gid = { + static let gids: [rt::NGROUPS_MAX]rt::gid_t = [0...]; + const n = rt::getgroups(gids)!; + return gids[..n]: []gid; +}; + +// Sets the list of supplementary group IDs which apply to the current process. +// This generally requires elevated permissions. +// +// If the system returns an error, this function will abort the program. Failing +// to handle errors from setgroups is a grave security issue in your program, +// and therefore we require this function to succeed. If you need to handle the +// error case gracefully, call the appropriate syscall wrapper in [[rt::]] +// yourself, and take extreme care to handle errors correctly. +export fn setgroups(gids: []gid) void = rt::setgroups(gids: []rt::gid_t)!; + +// Returns the current process ID. +export fn getpid() pid = rt::getpid(); + +// Returns the parent process ID. +export fn getppid() pid = rt::getppid(); + +// Returns the current process group ID. +export fn getpgrp() pid = rt::getpgrp(); + +// Returns the process group associated with the given pid. +export fn getpgid(pid: pid) (pid | errors::noentry) = { + match (rt::getpgid(pid)) { + case let pid: rt::pid_t => + return pid; + case let err: rt::errno => + assert(err == rt::ESRCH, "Unexpected getpgid return value"); + return errors::noentry; + }; +}; + +// Sets the process group ID of the specified process. This function is +// error-prone; see the notes in the POSIX specification for its many caveats. +export fn setpgid(targ: pid, pgid: pid) (void | errors::error) = { + match (rt::setpgid(targ, pgid)) { + case let err: rt::errno => + return errors::errno(err); + case void => + return; + }; +}; + +// Returns the current process's session ID. +export fn getsid() pid = rt::getsid(0)!; + +// Returns the session ID associated with the given process. +export fn getpsid(pid: pid) (pid | errors::noentry | errors::noaccess) = { + match (rt::getsid(pid)) { + case let pid: rt::pid_t => + return pid; + case let err: rt::errno => + assert(err == rt::ESRCH, "Unexpected getsid return value"); + return errors::noentry; + }; +}; + +// Creates a new session and sets the current process to the session leader. +// A new process group is also created with its process group ID equal to the +// pid of the current process, and the current process is made the process group +// leader. +// +// Upon return, the new session will have no controlling terminal. To establish +// one, the caller must open a terminal file with [[fs::flag::CTTY]]; this +// opt-in approach differs from the Unix norm where O_NOCTTY is required to +// opt-out of establishing a controlling terminal. +// +// The current process cannot be a process group leader; this is a programmer +// error and will cause a runtime assertion failure. +export fn setsid() void = rt::setsid()!; diff --git a/unix/+openbsd/getpid.ha b/unix/+openbsd/getpid.ha @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns the current process ID. -export fn getpid() int = rt::getpid(); diff --git a/unix/+openbsd/getuid.ha b/unix/+openbsd/getuid.ha @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns the current process user ID. -export fn getuid() uint = rt::getuid(): uint; - -// Returns the current process effective user ID. -export fn geteuid() uint = rt::geteuid(): uint; - -// Returns the current process group ID. -export fn getgid() uint = rt::getgid(): uint; - -// Returns the current process effective group ID. -export fn getegid() uint = rt::getegid(): uint; -\ No newline at end of file diff --git a/unix/+openbsd/groups.ha b/unix/+openbsd/groups.ha @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Returns a list of supplementary group IDs for the current process. The -// returned slice is statically allocated. -export fn getgroups() []uint = { - static let gids: [rt::NGROUPS_MAX]uint = [0...]; - const n = rt::getgroups(gids)!; - return gids[..n]; -}; - -// Sets the list of supplementary group IDs which apply to the current process. -// This generally requires elevated permissions. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setgroups is a grave security issue in your program, -// and therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] -// yourself, and take extreme care to handle errors correctly. -export fn setgroups(gids: []uint) void = rt::setgroups(gids)!; diff --git a/unix/+openbsd/setuid.ha b/unix/+openbsd/setuid.ha @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use rt; - -// Sets the caller's user ID to the specified value. This generally requires -// elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, -// and take extreme care to handle errors correctly. -export fn setuid(uid: uint) void = rt::setuid(uid: rt::uid_t)!; - -// Sets the caller's effective user ID to the specified value. This generally -// requires elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from seteuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, -// and take extreme care to handle errors correctly. -export fn seteuid(uid: uint) void = rt::seteuid(uid: rt::uid_t)!; - -// Sets the caller's group ID to the specified value. This generally requires -// elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setuid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, -// and take extreme care to handle errors correctly. -export fn setgid(gid: uint) void = rt::setgid(gid: rt::gid_t)!; - -// Sets the caller's effective group ID to the specified value. This generally -// requires elevated permissions from the calling process. -// -// If the system returns an error, this function will abort the program. Failing -// to handle errors from setegid is a grave security issue in your program, and -// therefore we require this function to succeed. If you need to handle the -// error case gracefully, call the appropriate syscall wrapper in [[rt::]] yourself, -// and take extreme care to handle errors correctly. -export fn setegid(gid: uint) void = rt::setegid(gid: rt::gid_t)!; diff --git a/unix/passwd/group.ha b/unix/passwd/group.ha @@ -7,6 +7,7 @@ use memio; use os; use strconv; use strings; +use unix; // A Unix-like group file entry. export type grent = struct { @@ -15,7 +16,7 @@ export type grent = struct { // Optional encrypted password password: str, // Numerical group ID - gid: uint, + gid: unix::gid, // List of usernames that are members of this group userlist: []str, }; @@ -43,9 +44,9 @@ export fn nextgr(in: io::handle) (grent | io::EOF | io::error | invalid) = { return invalid; }; - let gid = match (strconv::stou(fields[2])) { - case let u: uint => - yield u; + let gid = match (strconv::stou64(fields[2])) { + case let u: u64 => + yield u: unix::gid; case => return invalid; }; @@ -102,7 +103,7 @@ export fn getgroup(name: str) (grent | void) = { // /etc/group. Aborts if that file doesn't exist or is not properly formatted. // // See [[nextgr]] for low-level parsing API. -export fn getgid(gid: uint) (grent | void) = { +export fn getgid(gid: unix::gid) (grent | void) = { let file = match (os::open("/etc/group")) { case let f: io::file => yield f; diff --git a/unix/passwd/passwd.ha b/unix/passwd/passwd.ha @@ -7,6 +7,7 @@ use memio; use os; use strconv; use strings; +use unix; // A Unix-like password database entry. export type pwent = struct { @@ -15,9 +16,9 @@ export type pwent = struct { // Optional encrypted password password: str, // Numerical user ID - uid: uint, + uid: unix::uid, // Numerical group ID - gid: uint, + gid: unix::gid, // User name or comment field comment: str, // User home directory @@ -49,16 +50,16 @@ export fn nextpw(in: io::handle) (pwent | io::EOF | io::error | invalid) = { return invalid; }; - let uid = match (strconv::stou(fields[2])) { - case let u: uint => - yield u; + let uid = match (strconv::stou64(fields[2])) { + case let u: u64 => + yield u: unix::uid; case => return invalid; }; - let gid = match (strconv::stou(fields[3])) { - case let u: uint => - yield u; + let gid = match (strconv::stou64(fields[3])) { + case let u: u64 => + yield u: unix::gid; case => return invalid; }; @@ -122,7 +123,7 @@ export fn getuser(username: str) (pwent | void) = { // properly formatted. The return value must be freed with [[pwent_finish]]. // // See [[nextpw]] for low-level parsing API. -export fn getuid(uid: uint) (pwent | void) = { +export fn getuid(uid: unix::uid) (pwent | void) = { let file = match (os::open("/etc/passwd")) { case let f: io::file => yield f; diff --git a/unix/signal/+freebsd.ha b/unix/signal/+freebsd.ha @@ -3,6 +3,7 @@ use io; use rt; +use unix; // Configures a new signal handler, returning the old details (which can be // passed to [[restore]] to restore its behavior). @@ -199,9 +200,9 @@ export type siginfo = union { // The signal code, if any. code: code, // Process ID of the sender. - pid: int, + pid: unix::pid, // Real user ID of the sending process. - uid: uint, + uid: unix::uid, // Exit value or signal. status: int, // Address of the faulting instruction. diff --git a/unix/signal/+linux.ha b/unix/signal/+linux.ha @@ -4,6 +4,7 @@ use errors; use io; use rt; +use unix; // Configures a new signal handler, returning the old details (which can be // passed to [[restore]] to restore its behavior). @@ -204,9 +205,9 @@ export type siginfo = union { union { struct { // Process ID of the sender. - pid: int, + pid: unix::pid, // Real user ID of the sending process. - uid: uint, + uid: unix::uid, // Exit value or signal. status: int, }, diff --git a/unix/signal/+openbsd.ha b/unix/signal/+openbsd.ha @@ -3,6 +3,7 @@ use io; use rt; +use unix; // Configures a new signal handler, returning the old details (which can be // passed to [[restore]] to restore its behavior). @@ -200,9 +201,9 @@ export type siginfo = struct { union { struct { // Process ID of the sender. - pid: int, + pid: unix::pid, // Real user ID of the sending process. - uid: uint, + uid: unix::uid, }, struct { // Address of the faulting instruction.