hare

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

commit 029f0b187ae1ed7d2153429a117e76ef30ec91ad
parent 4880c021c1752b24fe2ae63df46e479b31394b38
Author: Mallory Adams <malloryadams@fastmail.com>
Date:   Fri, 24 May 2024 16:26:11 -0400

NetBSD: port Hare to NetBSD/amd64

Note that NetBSD does not include NTP's leap seconds list. That will
need to be installed separately:

```
ftp https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list
doas mv leap-seconds.list /usr/share/zoneinfo/leap-seconds.list
```

Thanks-to: Lorenz (xha) <me@xha.li>
Signed-off-by: Mallory Adams <malloryadams@fastmail.com>

Diffstat:
A.builds/netbsd.yml | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mcmd/hare/build/platform.ha | 4++++
Aconfigs/netbsd.mk | 43+++++++++++++++++++++++++++++++++++++++++++
Acrypto/random/+netbsd.ha | 36++++++++++++++++++++++++++++++++++++
Adebug/+netbsd/+x86_64/ucontext.ha | 22++++++++++++++++++++++
Adebug/+netbsd/translate.ha | 12++++++++++++
Adebug/image/self+netbsd.ha | 48++++++++++++++++++++++++++++++++++++++++++++++++
Aformat/elf/platform+netbsd.ha | 5+++++
Aio/+netbsd/dup.ha | 44++++++++++++++++++++++++++++++++++++++++++++
Aio/+netbsd/mmap.ha | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aio/+netbsd/platform_file.ha | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aio/+netbsd/vector.ha | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Amakefiles/netbsd.aarch64.mk | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amakefiles/netbsd.riscv64.mk | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amakefiles/netbsd.x86_64.mk | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amime/+netbsd.ha | 5+++++
Anet/+netbsd.ha | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anet/ip/+netbsd.ha | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anet/tcp/+netbsd.ha | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anet/udp/+netbsd.ha | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anet/unix/+netbsd.ha | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/+netbsd/dirfdfs.ha | 481+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/+netbsd/exit+test.ha | 7+++++++
Aos/+netbsd/exit.ha | 10++++++++++
Aos/+netbsd/fs.ha | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/+netbsd/platform_environ.ha | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/+netbsd/status.ha | 9+++++++++
Aos/+netbsd/stdfd.ha | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/exec/+netbsd/exec.ha | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/exec/+netbsd/platform_cmd.ha | 23+++++++++++++++++++++++
Aos/exec/+netbsd/process.ha | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apath/+netbsd.ha | 12++++++++++++
Art/+netbsd/+x86_64.ha | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/env.ha | 6++++++
Art/+netbsd/errno.ha | 516+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/hare.sc | 47+++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/initfini.ha | 20++++++++++++++++++++
Art/+netbsd/platform_abort.ha | 23+++++++++++++++++++++++
Art/+netbsd/platformstart-libc.ha | 10++++++++++
Art/+netbsd/segmalloc.ha | 23+++++++++++++++++++++++
Art/+netbsd/signal.ha | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/socket.ha | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/start+test.ha | 16++++++++++++++++
Art/+netbsd/start+x86_64-libc.s | 16++++++++++++++++
Art/+netbsd/start.ha | 16++++++++++++++++
Art/+netbsd/syscall+x86_64.s | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/syscallno.ha | 431+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/syscalls.ha | 614+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/sysctl.ha | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/+netbsd/types.ha | 518+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mscripts/genbootstrap | 2+-
Atemp/+netbsd.ha | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atime/+netbsd/functions.ha | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atime/chrono/+netbsd.ha | 9+++++++++
Aunix/+netbsd/creds.ha | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aunix/+netbsd/nice.ha | 27+++++++++++++++++++++++++++
Aunix/+netbsd/pipe.ha | 26++++++++++++++++++++++++++
Aunix/+netbsd/umask.ha | 9+++++++++
Aunix/hosts/+netbsd.ha | 4++++
Aunix/poll/+netbsd.ha | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Aunix/resolvconf/+netbsd.ha | 4++++
Aunix/signal/+netbsd.ha | 497+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aunix/tty/+netbsd/isatty.ha | 17+++++++++++++++++
Aunix/tty/+netbsd/open.ha | 18++++++++++++++++++
Aunix/tty/+netbsd/pgid.ha | 16++++++++++++++++
Aunix/tty/+netbsd/pty.ha | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aunix/tty/+netbsd/termios.ha | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aunix/tty/+netbsd/winsize.ha | 28++++++++++++++++++++++++++++
68 files changed, 7354 insertions(+), 1 deletion(-)

diff --git a/.builds/netbsd.yml b/.builds/netbsd.yml @@ -0,0 +1,47 @@ +image: netbsd/latest +sources: +- https://git.sr.ht/~sircmpwn/hare +- https://git.sr.ht/~sircmpwn/harec +- git://c9x.me/qbe.git +packages: +- binutils +- scdoc +- git +triggers: +- action: email + condition: failure + to: "<~sircmpwn/hare-dev@lists.sr.ht>" +tasks: +- environment: | + cd hare + if [ "$BUILD_SUBMITTER" = "git.sr.ht" ] + then + if [ "$GIT_REF" != "refs/heads/master" ] + then + complete-build + fi + if [ "$(git remote get-url origin)" != "https://git.sr.ht/~sircmpwn/hare" ] + then + complete-build + fi + fi +- ntp-leapseconds: | + ftp https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list + doas mv leap-seconds.list /var/db/ntpd.leap-seconds.list +- qbe: | + cd qbe + make -j2 PREFIX=/usr + doas make install PREFIX=/usr +- harec: | + cd harec + cp configs/netbsd.mk config.mk + make -j2 + doas make install +- hare: | + cd hare + cp configs/netbsd.mk config.mk + make -j2 + doas make install +- check: | + cd hare + make -j2 check diff --git a/cmd/hare/build/platform.ha b/cmd/hare/build/platform.ha @@ -19,6 +19,10 @@ const platforms: [_]platform = [ ... }, platform { + name = "NetBSD", + ... + }, + platform { name = "OpenBSD", need_libc = true, default_flags = [ diff --git a/configs/netbsd.mk b/configs/netbsd.mk @@ -0,0 +1,43 @@ +# install locations +PREFIX = /usr/local +BINDIR = $(PREFIX)/bin +MANDIR = $(PREFIX)/share/man +SRCDIR = $(PREFIX)/src +STDLIB = $(SRCDIR)/hare/stdlib + +# variables used during build +PLATFORM = netbsd +ARCH = x86_64 +HAREFLAGS = +HARECFLAGS = +QBEFLAGS = +ASFLAGS = +LDLINKFLAGS = --gc-sections -z noexecstack + +# commands used by the build script +HAREC = harec +QBE = qbe +AS = as +LD = ld +SCDOC = scdoc + +# build locations +HARECACHE = .cache +BINOUT = .bin + +# variables that will be embedded in the binary with -D definitions +HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party +VERSION=$$(./scripts/version) + +# For cross-compilation, modify the variables below +AARCH64_AS=as +AARCH64_CC=cc +AARCH64_LD=ld + +RISCV64_AS=as +RISCV64_CC=cc +RISCV64_LD=ld + +X86_64_AS=as +X86_64_CC=cc +X86_64_LD=ld diff --git a/crypto/random/+netbsd.ha b/crypto/random/+netbsd.ha @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use rt; + +// Fills the given buffer with cryptographically random data. If the system is +// unable to provide random data, abort. If you need to handle errors or want to +// use whatever random data the system can provide, even if less than the +// requested amount, use [[stream]] instead. +export fn buffer(buf: []u8) void = { + let n = 0z; + for (n < len(buf)) { + match (rt::getrandom(buf[n..]: *[*]u8, len(buf), 0)) { + case let err: rt::errno => + switch (err) { + case rt::EINTR => void; + case => + abort(); + }; + case let z: size => + n += z; + }; + }; +}; + +fn rand_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { + assert(s == stream); + match (rt::getrandom(buf: *[*]u8, len(buf), 0)) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + return n; + }; +}; diff --git a/debug/+netbsd/+x86_64/ucontext.ha b/debug/+netbsd/+x86_64/ucontext.ha @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use rt; + +// Returns the stack pointer from a ucontext. +fn uctx_sp(uctx: *opaque) uintptr = { + const uctx = uctx: *rt::ucontext; + return uctx.uc_mcontext.mc_rsp: uintptr; +}; + +// Returns the instruction pointer from a ucontext. +fn uctx_ip(uctx: *opaque) uintptr = { + const uctx = uctx: *rt::ucontext; + return uctx.uc_mcontext.mc_rip: uintptr; +}; + +// Returns the current call frame from a ucontext. +fn uctx_frame(uctx: *opaque) stackframe = { + const uctx = uctx: *rt::ucontext; + return *(uctx.uc_mcontext.mc_rbp: uintptr: *stackframe); +}; diff --git a/debug/+netbsd/translate.ha b/debug/+netbsd/translate.ha @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use rt; +use types::c; + +// Tries to translate a pointer into an ELF address of the currently running +// binary. +export fn translate(ptr: uintptr) (uintptr | void) = { + // TODO NetBSD (will break when enabling PIE code) + return ptr; +}; diff --git a/debug/image/self+netbsd.ha b/debug/image/self+netbsd.ha @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use fs; +use io; +use os; +use path; +use rt; +use types::c; + +// Opens the executing process's binary image. +export fn self() (image | io::error | fs::error) = { + // 1: sysctl + let buf: [path::MAX * 2 + 1]u8 = [0...]; + let pathsz = len(buf); + match (rt::sysctl([rt::CTL_KERN, rt::KERN_PROC_PATHNAME], + &buf[0], &pathsz, null, 0)) { + case rt::errno => void; + case void => + const file = os::open(c::tostr(&buf[0]: *const c::char)!)?; + match (open(file)) { + case let img: image => + return img; + case let err: io::error => + return err; + case errors::invalid => + abort("Running program image is not a valid ELF file"); + }; + }; + + // 2. procfs (not mounted by default, but better than step 3) + match (os::open("/proc/curproc/exe")) { + case let file: io::file => + match (open(file)) { + case let img: image => + return img; + case let err: io::error => + return err; + case errors::invalid => + abort("Running program image is not a valid ELF file"); + }; + case => void; + }; + + // 3. Fallback (os::args[0]) + return self_argv(); +}; diff --git a/format/elf/platform+netbsd.ha b/format/elf/platform+netbsd.ha @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// The ABI of the target. +export def TARGET_ABI: ident_abi = ident_abi::SYSV; diff --git a/io/+netbsd/dup.ha b/io/+netbsd/dup.ha @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; + +// Flags for [[dup]] and [[dup2]] operations. +export type dupflag = enum { + NONE = 0, + + // Causes [[dup]] and [[dup2]] not to set the CLOEXEC flag on the + // duplicated file descriptor. By default, CLOEXEC is set. + NOCLOEXEC = rt::FD_CLOEXEC, +}; + +// Duplicates a file descriptor. +export fn dup(old: file, flags: dupflag) (file | error) = { + flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC + + match (rt::dup2(old, -1)) { + case let fd: int => + const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; + rt::fcntl(fd, rt::F_SETFD, fl | rt::FD_CLOEXEC)!; + return fd; + case let e: rt::errno => + return errors::errno(e); + }; +}; + +// Duplicates a file descriptor and stores the new file at a specific file +// descriptor number. If the file indicated by "new" already refers to an open +// file, this file will be closed before the file descriptor is reused. +export fn dup2(old: file, new: file, flags: dupflag) (file | error) = { + flags ^= dupflag::NOCLOEXEC; // Invert CLOEXEC + + match (rt::dup2(old, new)) { + case let fd: int => + const fl = rt::fcntl(fd, rt::F_GETFD, 0)!; + rt::fcntl(fd, rt::F_SETFD, fl | flags)!; + return fd; + case let e: rt::errno => + return errors::errno(e); + }; +}; diff --git a/io/+netbsd/mmap.ha b/io/+netbsd/mmap.ha @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; + +// Values for the [[mmap]] prot parameter. Only the EXEC, READ, WRITE, and NONE +// values are portable. +export type prot = enum uint { + NONE = rt::PROT_NONE, + READ = rt::PROT_READ, + WRITE = rt::PROT_WRITE, + EXEC = rt::PROT_EXEC, +}; + +// Values for the [[mmap]] flags parameter. Only the SHARED, PRIVATE, and FIXED +// values are portable. +export type mflag = enum uint { + SHARED = rt::MAP_SHARED, + PRIVATE = rt::MAP_PRIVATE, + FIXED = rt::MAP_FIXED, + HASSEMAPHORE = rt::MAP_HASSEMAPHORE , + STACK = rt::MAP_STACK, + NOSYNC = rt::MAP_NOSYNC, + FILE = rt::MAP_FILE, + ANON = rt::MAP_ANON, + GUARD = rt::MAP_GUARD, + EXCL = rt::MAP_EXCL, + NOCORE = rt::MAP_NOCORE, + PREFAULT_READ = rt::MAP_PREFAULT_READ, + _32BIT = rt::MAP_32BIT, +}; + +// Performs the mmap syscall. Consult your system for documentation on this +// function. +export fn mmap( + addr: nullable *opaque, + length: size, + prot: prot, + flags: mflag, + fd: file, + offs: size +) (*opaque | errors::error) = { + match (rt::mmap(addr, length, prot, flags, fd, offs)) { + case let ptr: *opaque => + return ptr; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Unmaps memory previously mapped with [[mmap]]. +export fn munmap(addr: *opaque, length: size) (void | errors::error) = { + match (rt::munmap(addr, length)) { + case void => + return; + case let err: rt::errno => + return errors::errno(err); + }; +}; diff --git a/io/+netbsd/platform_file.ha b/io/+netbsd/platform_file.ha @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; + +// This is an opaque type which encloses an OS-level file handle resource. It +// can be used as a [[handle]] in most situations, but there are some APIs which +// require a [[file]] with some OS-level handle backing it - this type is used +// for such APIs. +// +// On NetBSD, [[file]] is a file descriptor. +export type file = int; + +// Opens a Unix file descriptor as a file. This is a low-level interface, to +// open files most programs will use something like [[os::open]]. This function +// is not portable. +export fn fdopen(fd: int) file = fd; + +fn fd_read(fd: file, buf: []u8) (size | EOF | error) = { + match (rt::read(fd, buf: *[*]u8, len(buf))) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + switch (n) { + case 0 => + return EOF; + case => + return n; + }; + }; +}; + +fn fd_write(fd: file, buf: const []u8) (size | error) = { + match (rt::write(fd, buf: *const [*]u8, len(buf))) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + return n; + }; +}; + +fn fd_close(fd: file) (void | error) = { + match (rt::close(fd)) { + case void => void; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +fn fd_seek( + fd: file, + offs: off, + whence: whence, +) (off | error) = { + match (rt::lseek(fd, offs: i64, whence: int)) { + case let err: rt::errno => + return errors::errno(err); + case let n: i64 => + return n: off; + }; +}; + +fn fd_copy(to: file, from: file) (size | error) = errors::unsupported; + +fn fd_lock(fd: file, flags: int) (bool | error) = { + match (rt::flock(fd: int, flags)) { + case void => return true; + case let e: rt::errno => + if (e == rt::EWOULDBLOCK: rt::errno) { + return false; + } else { + return errors::errno(e); + }; + }; +}; + +fn fd_trunc(fd: file, ln: size) (void | error) = { + match (rt::ftruncate(fd: int, ln: rt::off_t)) { + case void => void; + case let e: rt::errno => return errors::errno(e); + }; +}; diff --git a/io/+netbsd/vector.ha b/io/+netbsd/vector.ha @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; +use types; + +export type vector = rt::iovec; + +// Creates a vector for use with [[writev]] and [[readv]]. +export fn mkvector(buf: []u8) vector = vector { + iov_base = buf: *[*]u8, + iov_len = len(buf), +}; + +// Performs a vectored read on the given file. A read is performed on each of +// the vectors, prepared with [[mkvector]], in order, and the total number of +// bytes read is returned. +export fn readv(fd: file, vectors: vector...) (size | EOF | error) = { + if (len(vectors) > types::INT_MAX: size) { + return errors::invalid; + }; + match (rt::readv(fd, vectors: *[*]rt::iovec, len(vectors): int)) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + switch (n) { + case 0 => + return EOF; + case => + return n; + }; + }; +}; + +// Performs a vectored write on the given file. Each of the vectors, prepared +// with [[mkvector]], are written to the file in order, and the total number of +// bytes written is returned. +export fn writev(fd: file, vectors: vector...) (size | error) = { + if (len(vectors) > types::INT_MAX: size) { + return errors::invalid; + }; + match (rt::writev(fd, vectors: *[*]rt::iovec, len(vectors): int)) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + return n; + }; +}; diff --git a/makefiles/netbsd.aarch64.mk b/makefiles/netbsd.aarch64.mk @@ -0,0 +1,256 @@ +# generated by cmd/genbootstrap +# DO NOT EDIT BY HAND. run 'make bootstrap' to update +TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td +RTSCRIPT = rt/+netbsd/hare.sc +OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o + +rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +$(HARECACHE)/rt.ssa: $(rt_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) + +rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s +$(HARECACHE)/rt.o: $(rt_s) + @printf 'AS\t%s\n' "$@" + @$(AS) $(ASFLAGS) -o $@ $(rt_s) + +encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha +$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) + +sort_cmp_ha = sort/cmp/cmp.ha +$(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) + +types_ha = types/arch+aarch64.ha types/classes.ha types/limits.ha +$(HARECACHE)/types.ssa: $(types_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) + +bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha +$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) + +strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha +$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) + +ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha +$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) + +errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha +$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) + +io_ha = io/+netbsd/dup.ha io/+netbsd/mmap.ha io/+netbsd/platform_file.ha io/+netbsd/vector.ha io/arch+aarch64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha +$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) + +bufio_ha = bufio/scanner.ha bufio/stream.ha +$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) + +crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha +$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) + +endian_ha = endian/big.ha endian/endian.ha endian/host+aarch64.ha endian/little.ha endian/network.ha +$(HARECACHE)/endian.ssa: $(endian_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) + +hash_ha = hash/hash.ha +$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) + +crypto_sha256_ha = crypto/sha256/sha256.ha +$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) + +math_ha = math/fenv+aarch64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha +$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) + +memio_ha = memio/ops.ha memio/stream.ha +$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) + +path_ha = path/+netbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha +$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) + +time_ha = time/+netbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha +$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) + +fs_ha = fs/fs.ha fs/types.ha fs/util.ha +$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) + +types_c_ha = types/c/arch+aarch64.ha types/c/strings.ha types/c/types.ha +$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) + +os_ha = os/+netbsd/dirfdfs.ha os/+netbsd/exit.ha os/+netbsd/fs.ha os/+netbsd/platform_environ.ha os/+netbsd/status.ha os/+netbsd/stdfd.ha os/environ.ha os/os.ha +$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) + +strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha +$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) + +fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha +$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) + +encoding_hex_ha = encoding/hex/hex.ha +$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) + +sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha +$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) + +hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha +$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) + +hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha +$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) + +hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha +$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) + +hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha +$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) + +time_chrono_ha = time/chrono/+netbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha +$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) + +time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha +$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) + +hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha +$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) + +unix_ha = unix/+netbsd/creds.ha unix/+netbsd/nice.ha unix/+netbsd/pipe.ha unix/+netbsd/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/+netbsd.ha unix/signal/types.ha +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/time.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) + +os_exec_ha = os/exec/+netbsd/exec.ha os/exec/+netbsd/platform_cmd.ha os/exec/+netbsd/process.ha os/exec/cmd.ha os/exec/types.ha +$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) + +shlex_ha = shlex/escape.ha shlex/split.ha +$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) + +unix_tty_ha = unix/tty/+netbsd/isatty.ha unix/tty/+netbsd/open.ha unix/tty/+netbsd/pgid.ha unix/tty/+netbsd/pty.ha unix/tty/+netbsd/termios.ha unix/tty/+netbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha +$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) + +cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha +$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) + +dirs_ha = dirs/xdg.ha +$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) + +getopt_ha = getopt/getopts.ha +$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) + +cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha +$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) diff --git a/makefiles/netbsd.riscv64.mk b/makefiles/netbsd.riscv64.mk @@ -0,0 +1,256 @@ +# generated by cmd/genbootstrap +# DO NOT EDIT BY HAND. run 'make bootstrap' to update +TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td +RTSCRIPT = rt/+netbsd/hare.sc +OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o + +rt_ha = rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +$(HARECACHE)/rt.ssa: $(rt_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) + +rt_s = $(HARECACHE)/rt.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s +$(HARECACHE)/rt.o: $(rt_s) + @printf 'AS\t%s\n' "$@" + @$(AS) $(ASFLAGS) -o $@ $(rt_s) + +encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha +$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) + +sort_cmp_ha = sort/cmp/cmp.ha +$(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) + +types_ha = types/arch+riscv64.ha types/classes.ha types/limits.ha +$(HARECACHE)/types.ssa: $(types_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) + +bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha +$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) + +strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha +$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) + +ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha +$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) + +errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha +$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) + +io_ha = io/+netbsd/dup.ha io/+netbsd/mmap.ha io/+netbsd/platform_file.ha io/+netbsd/vector.ha io/arch+riscv64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha +$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) + +bufio_ha = bufio/scanner.ha bufio/stream.ha +$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) + +crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha +$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) + +endian_ha = endian/big.ha endian/endian.ha endian/host+riscv64.ha endian/little.ha endian/network.ha +$(HARECACHE)/endian.ssa: $(endian_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) + +hash_ha = hash/hash.ha +$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) + +crypto_sha256_ha = crypto/sha256/sha256.ha +$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) + +math_ha = math/fenv+riscv64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha +$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) + +memio_ha = memio/ops.ha memio/stream.ha +$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) + +path_ha = path/+netbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha +$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) + +time_ha = time/+netbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha +$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) + +fs_ha = fs/fs.ha fs/types.ha fs/util.ha +$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) + +types_c_ha = types/c/arch+riscv64.ha types/c/strings.ha types/c/types.ha +$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) + +os_ha = os/+netbsd/dirfdfs.ha os/+netbsd/exit.ha os/+netbsd/fs.ha os/+netbsd/platform_environ.ha os/+netbsd/status.ha os/+netbsd/stdfd.ha os/environ.ha os/os.ha +$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) + +strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha +$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) + +fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha +$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) + +encoding_hex_ha = encoding/hex/hex.ha +$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) + +sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha +$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) + +hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha +$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) + +hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha +$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) + +hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha +$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) + +hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha +$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) + +time_chrono_ha = time/chrono/+netbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha +$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) + +time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha +$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) + +hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha +$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) + +unix_ha = unix/+netbsd/creds.ha unix/+netbsd/nice.ha unix/+netbsd/pipe.ha unix/+netbsd/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/+netbsd.ha unix/signal/types.ha +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/time.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) + +os_exec_ha = os/exec/+netbsd/exec.ha os/exec/+netbsd/platform_cmd.ha os/exec/+netbsd/process.ha os/exec/cmd.ha os/exec/types.ha +$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) + +shlex_ha = shlex/escape.ha shlex/split.ha +$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) + +unix_tty_ha = unix/tty/+netbsd/isatty.ha unix/tty/+netbsd/open.ha unix/tty/+netbsd/pgid.ha unix/tty/+netbsd/pty.ha unix/tty/+netbsd/termios.ha unix/tty/+netbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha +$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) + +cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha +$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) + +dirs_ha = dirs/xdg.ha +$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) + +getopt_ha = getopt/getopts.ha +$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) + +cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha +$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) diff --git a/makefiles/netbsd.x86_64.mk b/makefiles/netbsd.x86_64.mk @@ -0,0 +1,256 @@ +# generated by cmd/genbootstrap +# DO NOT EDIT BY HAND. run 'make bootstrap' to update +TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_sort::cmp=$(HARECACHE)/sort_cmp.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td +RTSCRIPT = rt/+netbsd/hare.sc +OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o + +rt_ha = rt/+netbsd/+x86_64.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +$(HARECACHE)/rt.ssa: $(rt_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha) + +rt_s = $(HARECACHE)/rt.s rt/+netbsd/start+x86_64-libc.s rt/+netbsd/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s +$(HARECACHE)/rt.o: $(rt_s) + @printf 'AS\t%s\n' "$@" + @$(AS) $(ASFLAGS) -o $@ $(rt_s) + +encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha encoding/utf8/types.ha +$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha) + +sort_cmp_ha = sort/cmp/cmp.ha +$(HARECACHE)/sort_cmp.ssa: $(sort_cmp_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort_cmp.td.tmp -N sort::cmp $(sort_cmp_ha) + +types_ha = types/arch+x86_64.ha types/classes.ha types/limits.ha +$(HARECACHE)/types.ssa: $(types_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types.td.tmp -N types $(types_ha) + +bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha +$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha) + +strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha +$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha) + +ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha +$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha) + +errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha +$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha) + +io_ha = io/+netbsd/dup.ha io/+netbsd/mmap.ha io/+netbsd/platform_file.ha io/+netbsd/vector.ha io/arch+x86_64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha +$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/io.td.tmp -N io $(io_ha) + +bufio_ha = bufio/scanner.ha bufio/stream.ha +$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha) + +crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha +$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha) $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha) + +endian_ha = endian/big.ha endian/endian.ha endian/host+x86_64.ha endian/little.ha endian/network.ha +$(HARECACHE)/endian.ssa: $(endian_ha) + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha) + +hash_ha = hash/hash.ha +$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/io.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha) + +crypto_sha256_ha = crypto/sha256/sha256.ha +$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha) + +math_ha = math/fenv+x86_64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha +$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/math.td.tmp -N math $(math_ha) + +memio_ha = memio/ops.ha memio/stream.ha +$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha) + +path_ha = path/+netbsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha +$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/path.td.tmp -N path $(path_ha) + +time_ha = time/+netbsd/functions.ha time/arithm.ha time/conv.ha time/types.ha +$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time.td.tmp -N time $(time_ha) + +fs_ha = fs/fs.ha fs/types.ha fs/util.ha +$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha) + +types_c_ha = types/c/arch+x86_64.ha types/c/strings.ha types/c/types.ha +$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha) + +os_ha = os/+netbsd/dirfdfs.ha os/+netbsd/exit.ha os/+netbsd/fs.ha os/+netbsd/platform_environ.ha os/+netbsd/status.ha os/+netbsd/stdfd.ha os/environ.ha os/os.ha +$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os.td.tmp -N os $(os_ha) + +strconv_ha = strconv/ftos.ha strconv/ftos_multiprecision.ha strconv/ftos_ryu.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha +$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha) + +fmt_ha = fmt/iter.ha fmt/print.ha fmt/wrappers.ha +$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha) + +encoding_hex_ha = encoding/hex/hex.ha +$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha) + +sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha +$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha) + +hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha +$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha) + +hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha +$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha) + +hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha +$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha) + +hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/syn.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha +$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha) + +time_chrono_ha = time/chrono/+netbsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha +$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha) + +time_date_ha = time/date/constants.ha time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha +$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha) + +hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha +$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha) + +unix_ha = unix/+netbsd/creds.ha unix/+netbsd/nice.ha unix/+netbsd/pipe.ha unix/+netbsd/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/+netbsd.ha unix/signal/types.ha +$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td $(HARECACHE)/time.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) + +os_exec_ha = os/exec/+netbsd/exec.ha os/exec/+netbsd/platform_cmd.ha os/exec/+netbsd/process.ha os/exec/cmd.ha os/exec/types.ha +$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha) + +shlex_ha = shlex/escape.ha shlex/split.ha +$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha) + +unix_tty_ha = unix/tty/+netbsd/isatty.ha unix/tty/+netbsd/open.ha unix/tty/+netbsd/pgid.ha unix/tty/+netbsd/pty.ha unix/tty/+netbsd/termios.ha unix/tty/+netbsd/winsize.ha unix/tty/pty_test.ha unix/tty/types.ha +$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha) + +cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/platform.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha +$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha) + +dirs_ha = dirs/xdg.ha +$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha) + +getopt_ha = getopt/getopts.ha +$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha) + +cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha +$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/sort_cmp.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td + @mkdir -p -- "$(HARECACHE)" + @printf 'HAREC\t%s\n' "$@" + @$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES) $(cmd_hare_ha) diff --git a/mime/+netbsd.ha b/mime/+netbsd.ha @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// Path to the system MIME database. +export def SYSTEM_DB: str = "/etc/mime.types"; diff --git a/net/+netbsd.ha b/net/+netbsd.ha @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use rt; + +// A network socket. +export type socket = io::file; + +// Optional flags to [[accept]] to be set on the returned [[socket]]. +// See the O_CLOEXEC and O_NONBLOCK sections of open(2) for details. +// Note that CLOEXEC is on by default, and NOCLOEXEC flag disables it. +export type sockflag = enum int { + NOCLOEXEC = rt::SOCK_CLOEXEC, + NONBLOCK = rt::SOCK_NONBLOCK +}; + +// Accepts the next connection from a socket. Blocks until a new connection is +// available. Optionally accepts NOCLOEXEC and NONBLOCK flags. If flags are +// supplied, the [[io::file]] returned will have the supplied flags set. +export fn accept(sock: socket, flags: sockflag = 0) (socket | error) = { + flags ^= rt::SOCK_CLOEXEC: sockflag; // invert CLOEXEC + const fd = match (rt::accept4(sock, null, null, flags)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + return io::fdopen(fd); +}; + +fn msg_to_native(msg: *msghdr) *rt::msghdr = { + let native = &msg.native; + if (len(msg.vectors) != 0) { + native.msg_iov = msg.vectors: *[*]rt::iovec; + native.msg_iovlen = len(msg.vectors): int; + }; + if (len(msg.control) != 0) { + native.msg_control = msg.control: *[*]u8; + native.msg_controllen = len(msg.control): rt::socklen_t; + }; + return native; +}; + +// Sends a message to a socket. See [[newmsg]] for details. +export fn sendmsg(sock: socket, msg: *msghdr) (size | error) = { + // TODO: Flags + match (rt::sendmsg(sock, msg_to_native(msg), 0)) { + case let n: int => + return n: size; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Receives a message from a socket. See [[newmsg]] for details. +export fn recvmsg(sock: socket, msg: *msghdr) (size | error) = { + // TODO: Flags + match (rt::recvmsg(sock, msg_to_native(msg), 0)) { + case let n: int => + return n: size; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Closes a [[socket]]. No further operations against this socket are permitted +// after calling this function. Closing a socket can fail only under certain +// conditions (for example, closing a socket twice, or an interrupted syscall). +// However, the user should not attempt to close the file again on failure - at +// best the user should print a diagnostic message and move on. See close(2) for +// details. +// +// On NetBSD, this function is an alias for [[io::close]]. +export fn close(sock: socket) (void | error) = match (io::close(sock)) { +case void => void; +case io::underread => abort(); +case let err: errors::error => + yield err; +}; + +// Shuts down part of a full-duplex connection. +export fn shutdown(sock: socket, how: shut) (void | error) = { + match (rt::shutdown(sock, how)) { + case void => void; + case let err: rt::errno => + return errors::errno(err); + }; +}; diff --git a/net/ip/+netbsd.ha b/net/ip/+netbsd.ha @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use endian; +use rt; + +export fn to_native(a: addr, port: u16) rt::sockaddr = { + match (a) { + case let v4: addr4 => + return rt::sockaddr { + in = rt::sockaddr_in { + sin_len = size(rt::in_addr): u8, + sin_family = rt::AF_INET, + sin_port = endian::htonu16(port), + sin_addr = rt::in_addr { s_addr = *(&v4[0]: *opaque: *u32) }, + ... + }, + ... + }; + case let v6: addr6 => + return rt::sockaddr { + in6 = rt::sockaddr_in6 { + sin6_len = size(rt::in6_addr): u8, + sin6_family = rt::AF_INET6, + sin6_port = endian::htonu16(port), + sin6_addr = rt::in6_addr { s6_addr = v6 }, + ... + }, + ... + }; + }; +}; + +export fn from_native(a: rt::sockaddr) (addr, u16) = { + let family = a.in.sin_family; + switch (family) { + case rt::AF_INET => + let addr = a.in.sin_addr.s_addr; + return ( + [addr: u8, (addr >> 8): u8, (addr >> 16): u8, + (addr >> 24): u8]: addr4, + endian::ntohu16(a.in.sin_port) + ); + case rt::AF_INET6 => + return ( + a.in6.sin6_addr.s6_addr: addr6, + endian::ntohu16(a.in6.sin6_port) + ); + case => + abort("Wrong address family!"); + }; +}; + +export fn native_addrlen(a: addr) u32 = { + match (a) { + case addr4 => + return size(rt::sockaddr_in): u32; + case addr6 => + return size(rt::sockaddr_in6): u32; + }; +}; diff --git a/net/tcp/+netbsd.ha b/net/tcp/+netbsd.ha @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use net; +use net::ip; +use os; +use rt; + +// Opens a TCP connection to the given host and port. Blocks until the +// connection is established. +export fn connect( + addr: ip::addr, + port: u16, + options: connect_option... +) (net::socket | net::error) = { + const sockaddr = ip::to_native(addr, port); + const family = match (addr) { + case ip::addr4 => + yield rt::AF_INET: int; + case ip::addr6 => + yield rt::AF_INET6: int; + }; + let f = 0i; + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case let fl: net::sockflag => + f |= fl; + case => void; + }; + }; + f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC + const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case keepalive => + setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; + case => void; + }; + }; + const sz = ip::native_addrlen(addr); + match (rt::connect(sockfd, &sockaddr, sz)) { + case let err: rt::errno => + if (err != rt::EINPROGRESS) { + return errors::errno(err); + }; + assert(f & rt::SOCK_NONBLOCK == rt::SOCK_NONBLOCK); + case int => void; + }; + return io::fdopen(sockfd); +}; + +// Binds a TCP socket to the given address. +export fn listen( + addr: ip::addr, + port: u16, + options: listen_option... +) (net::socket | net::error) = { + const sockaddr = ip::to_native(addr, port); + const family = match (addr) { + case ip::addr4 => + yield rt::AF_INET: int; + case ip::addr6 => + yield rt::AF_INET6: int; + }; + let f = 0i; + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case let fl: net::sockflag => + f |= fl; + case => void; + }; + }; + f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC + const sockfd = match (rt::socket(family, rt::SOCK_STREAM | f, 0)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + + let bk: u32 = 10; + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case reuseaddr => + setsockopt(sockfd, rt::SO_REUSEADDR, true)?; + case reuseport => + setsockopt(sockfd, rt::SO_REUSEPORT, true)?; + case keepalive => + setsockopt(sockfd, rt::SO_KEEPALIVE, true)?; + case let b: backlog => + bk = b; + case => void; + }; + }; + + const sz = ip::native_addrlen(addr); + match (rt::bind(sockfd, &sockaddr, sz)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; + match (rt::listen(sockfd, bk)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; + + for (let i = 0z; i < len(options); i += 1) { + let portout = match (options[i]) { + case let p: portassignment => + yield p; + case => + continue; + }; + let sn = rt::sockaddr {...}; + let al = size(rt::sockaddr): u32; + match (rt::getsockname(sockfd, &sn, &al)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; + const addr = ip::from_native(sn); + *portout = addr.1; + }; + + return sockfd; +}; + +// Returns the remote address for a given connection, or void if none is +// available. +export fn peeraddr(peer: net::socket) ((ip::addr, u16) | void) = { + let sn = rt::sockaddr {...}; + let sz = size(rt::sockaddr): u32; + if (rt::getpeername(peer, &sn, &sz) is rt::errno) { + return; + }; + return ip::from_native(sn); +}; + +fn setsockopt( + sockfd: int, + option: int, + value: bool, +) (void | net::error) = { + let val: int = if (value) 1 else 0; + match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, + &val: *opaque, size(int): u32)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; +}; diff --git a/net/udp/+netbsd.ha b/net/udp/+netbsd.ha @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use net; +use net::ip; +use os; +use rt; + +// Creates a UDP socket and sets the default destination to the given address. +export fn connect( + dest: ip::addr, + port: u16, + options: connect_option... +) (net::socket | net::error) = { + const family = match (dest) { + case ip::addr4 => + yield rt::AF_INET: int; + case ip::addr6 => + yield rt::AF_INET6: int; + }; + let f = 0i; + for (let i = 0z; i < len(options); i += 1) { + // Only sockflag for now + f |= options[i]; + }; + f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC + const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + + const sockaddr = ip::to_native(dest, port); + const sz = ip::native_addrlen(dest); + match (rt::connect(sockfd, &sockaddr, sz)) { + case int => + return io::fdopen(sockfd); + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Creates a UDP socket bound to an interface. +export fn listen( + addr: ip::addr, + port: u16, + options: listen_option... +) (net::socket | net::error) = { + const family = match (addr) { + case ip::addr4 => + yield rt::AF_INET: int; + case ip::addr6 => + yield rt::AF_INET6: int; + }; + let f = 0i; + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case let fl: net::sockflag => + f |= fl; + case => void; + }; + }; + f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC + const sockfd = match (rt::socket(family, rt::SOCK_DGRAM | f, 0)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case reuseaddr => + setsockopt(sockfd, rt::SO_REUSEADDR, true)?; + case reuseport => + setsockopt(sockfd, rt::SO_REUSEPORT, true)?; + case => void; + }; + }; + + const sockaddr = ip::to_native(addr, port); + const sz = ip::native_addrlen(addr); + match (rt::bind(sockfd, &sockaddr, sz)) { + case int => void; + case let err: rt::errno => + return errors::errno(err); + }; + + for (let i = 0z; i < len(options); i += 1) { + let portout = match (options[i]) { + case let p: portassignment => + yield p; + case => + continue; + }; + let sn = rt::sockaddr {...}; + let al = size(rt::sockaddr): u32; + match (rt::getsockname(sockfd, &sn, &al)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; + const addr = ip::from_native(sn); + *portout = addr.1; + }; + + return io::fdopen(sockfd); +}; + +// Sends a UDP packet to a [[connect]]ed UDP socket. +export fn send(sock: net::socket, buf: []u8) (size | net::error) = { + match (rt::send(sock, buf: *[*]u8, len(buf), 0)) { + case let sz: size => + return sz; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Sends a UDP packet using this socket. +export fn sendto( + sock: net::socket, + buf: []u8, + dest: ip::addr, + port: u16, +) (size | net::error) = { + const sockaddr = ip::to_native(dest, port); + const sz = ip::native_addrlen(dest); + match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) { + case let sz: size => + return sz; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Receives a UDP packet from a [[connect]]ed UDP socket. +export fn recv( + sock: net::socket, + buf: []u8, +) (size | net::error) = { + match (rt::recv(sock, buf: *[*]u8, len(buf), 0)) { + case let sz: size => + return sz; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Receives a UDP packet from a bound socket. +export fn recvfrom( + sock: net::socket, + buf: []u8, + src: nullable *ip::addr, + port: nullable *u16, +) (size | net::error) = { + let addrsz = size(rt::sockaddr): u32; + const sockaddr = rt::sockaddr { ... }; + const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0, + &sockaddr, &addrsz)) { + case let sz: size => + yield sz; + case let err: rt::errno => + return errors::errno(err); + }; + + assert(addrsz <= size(rt::sockaddr)); + const peer = ip::from_native(sockaddr); + match (src) { + case null => void; + case let src: *ip::addr => + *src = peer.0; + }; + match (port) { + case null => void; + case let port: *u16 => + *port = peer.1; + }; + + return sz; +}; + +fn setsockopt( + sockfd: int, + option: int, + value: bool, +) (void | net::error) = { + let val: int = if (value) 1 else 0; + match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option, + &val: *opaque, size(int): u32)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; +}; diff --git a/net/unix/+netbsd.ha b/net/unix/+netbsd.ha @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use fmt; +use io; +use net; +use os; +use rt; +use strings; +use types; + +// Opens a UNIX socket connection to the path. Blocks until the connection is +// established. +export fn connect( + addr: addr, + options: connect_option... +) (net::socket | net::error) = { + let sockaddr = match (to_native(addr)) { + case let a: rt::sockaddr => + yield a; + case invalid => + return errors::unsupported; // path too long + }; + let f = 0i; + for (let i = 0z; i < len(options); i += 1) { + // Only sockflag for now + f |= options[i]; + }; + f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC + const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + + const sz = size(rt::sockaddr_un): u32; + match (rt::connect(sockfd, &sockaddr, sz)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; + return io::fdopen(sockfd); +}; + +// Binds a UNIX socket to the given path. +export fn listen( + addr: addr, + options: listen_option... +) (net::socket | net::error) = { + let sockaddr = match (to_native(addr)) { + case let a: rt::sockaddr => + yield a; + case invalid => + return errors::unsupported; // path too long + }; + let f = 0i; + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case let fl: net::sockflag => + f |= fl; + case => void; + }; + }; + f ^= rt::SOCK_CLOEXEC; // invert CLOEXEC + const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM | f, 0)) { + case let err: rt::errno => + return errors::errno(err); + case let fd: int => + yield fd; + }; + + let bk: u32 = 10; + for (let i = 0z; i < len(options); i += 1) { + match (options[i]) { + case let b: backlog => + bk = b; + case => void; + }; + }; + + match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; + match (rt::listen(sockfd, bk)) { + case let err: rt::errno => + return errors::errno(err); + case int => void; + }; + + return sockfd; +}; + +// Converts a UNIX socket address to a native sockaddr. +fn to_native(addr: addr) (rt::sockaddr | invalid) = { + // sun_path should be NUL-terminated and fit into rt::UNIX_PATH_MAX + if (len(addr) > rt::UNIX_PATH_MAX - 1) { + return invalid; + }; + let ret = rt::sockaddr { + un = rt::sockaddr_un { + sun_len = size(rt::sockaddr_un): u8, + sun_family = rt::AF_UNIX, + ... + } + }; + match ((&addr: *types::string).data) { + case null => void; + case let data: *[*]u8 => + ret.un.sun_path[..len(addr)] = data[..len(addr)]; + }; + ret.un.sun_path[len(addr)] = 0; + return ret; +}; diff --git a/os/+netbsd/dirfdfs.ha b/os/+netbsd/dirfdfs.ha @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use encoding::utf8; +use errors; +use fs; +use io; +use path; +use rt; +use strings; +use time; +use types::c; + +type os_filesystem = struct { + fs: fs::fs, + dirfd: int, + getdents_bufsz: size, +}; + +// Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a +// directory file. The file will be closed when the fs is closed. +export fn dirfdopen(fd: io::file) *fs::fs = { + let ofs = alloc(os_filesystem { ... }); + let fs = static_dirfdopen(fd, ofs); + fs.close = &fs_close; + return fs; +}; + +fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = { + *filesystem = os_filesystem { + fs = fs::fs { + open = &fs_open, + openfile = &fs_open_file, + create = &fs_create, + createfile = &fs_create_file, + remove = &fs_remove, + rename = &fs_rename, + iter = &fs_iter, + stat = &fs_stat, + readlink = &fs_readlink, + mkdir = &fs_mkdir, + rmdir = &fs_rmdir, + chmod = &fs_chmod, + chown = &fs_chown, + chtimes = &fs_chtimes, + fchtimes = &fs_fchtimes, + resolve = &fs_resolve, + ... + }, + dirfd = fd, + getdents_bufsz = 32768, // 32 KiB + }; + return &filesystem.fs; +}; + +// Sets the buffer size to use with the getdents(2) system call, for use with +// [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can +// scan large directories faster. The default buffer size is 32 KiB. +// +// This function is not portable. +export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = { + assert(fs.open == &fs_open); + let fs = fs: *os_filesystem; + fs.getdents_bufsz = sz; +}; + +// Returns an [[io::file]] for this filesystem. This function is not portable. +export fn dirfile(fs: *fs::fs) io::file = { + assert(fs.open == &fs_open); + let fs = fs: *os_filesystem; + return fs.dirfd; +}; + +fn errno_to_fs(err: rt::errno) fs::error = { + switch (err) { + case rt::ENOENT => + return errors::noentry; + case rt::EEXIST => + return errors::exists; + case rt::EACCES => + return errors::noaccess; + case rt::EBUSY => + return errors::busy; + case rt::ENOTDIR => + return fs::wrongtype; + case rt::EOPNOTSUPP, rt::ENOSYS => + return errors::unsupported; + case rt::EXDEV => + return fs::cannotrename; + case => + return errors::errno(err); + }; +}; + +fn _fs_open( + fs: *fs::fs, + path: str, + flags: int, + mode: uint, +) (io::file | fs::error) = { + let fs = fs: *os_filesystem; + + let fd = match (rt::openat(fs.dirfd, path, flags, mode)) { + case let err: rt::errno => + return errno_to_fs(err); + case let fd: int => + yield fd; + }; + + return io::fdopen(fd); +}; + +fn fsflags_to_bsd(flags: fs::flag) (int | errors::unsupported) = { + let out = rt::O_NOCTTY | rt::O_CLOEXEC; + if (flags & fs::flag::WRONLY == fs::flag::WRONLY) { + out |= rt::O_WRONLY; + }; + if (flags & fs::flag::RDWR == fs::flag::RDWR) { + out |= rt::O_RDWR; + }; + if (flags & fs::flag::CREATE == fs::flag::CREATE) { + out |= rt::O_CREAT; + }; + if (flags & fs::flag::EXCL == fs::flag::EXCL) { + out |= rt::O_EXCL; + }; + if (flags & fs::flag::CTTY == fs::flag::CTTY) { + out &= ~rt::O_NOCTTY; + }; + if (flags & fs::flag::TRUNC == fs::flag::TRUNC) { + out |= rt::O_TRUNC; + }; + if (flags & fs::flag::APPEND == fs::flag::APPEND) { + out |= rt::O_APPEND; + }; + if (flags & fs::flag::NONBLOCK == fs::flag::NONBLOCK) { + out |= rt::O_NONBLOCK; + }; + if (flags & fs::flag::DSYNC == fs::flag::DSYNC) { + out |= rt::O_DSYNC; + }; + if (flags & fs::flag::SYNC == fs::flag::SYNC) { + out |= rt::O_SYNC; + }; + if (flags & fs::flag::RSYNC == fs::flag::RSYNC) { + out |= rt::O_SYNC; + }; + if (flags & fs::flag::DIRECTORY == fs::flag::DIRECTORY) { + out |= rt::O_DIRECTORY; + }; + if (flags & fs::flag::NOFOLLOW == fs::flag::NOFOLLOW) { + out |= rt::O_NOFOLLOW; + }; + if (flags & fs::flag::NOCLOEXEC == fs::flag::NOCLOEXEC) { + out &= ~rt::O_CLOEXEC; + }; + if (flags & fs::flag::PATH == fs::flag::PATH + || flags & fs::flag::NOATIME == fs::flag::NOATIME + || flags & fs::flag::TMPFILE == fs::flag::TMPFILE) { + return errors::unsupported; + }; + return out; +}; + +fn fs_open_file( + fs: *fs::fs, + path: str, + flags: fs::flag, +) (io::file | fs::error) = { + return _fs_open(fs, path, fsflags_to_bsd(flags)?, 0); +}; + +fn fs_open( + fs: *fs::fs, + path: str, + flags: fs::flag, +) (io::handle | fs::error) = fs_open_file(fs, path, flags)?; + +fn fs_create_file( + fs: *fs::fs, + path: str, + mode: fs::mode, + flags: fs::flag, +) (io::file | fs::error) = { + flags |= fs::flag::CREATE; + return _fs_open(fs, path, fsflags_to_bsd(flags)?, mode)?; +}; + +fn fs_create( + fs: *fs::fs, + path: str, + mode: fs::mode, + flags: fs::flag, +) (io::handle | fs::error) = { + return fs_create_file(fs, path, mode, flags)?; +}; + +fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = { + let fs = fs: *os_filesystem; + match (rt::unlinkat(fs.dirfd, path, 0)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn fs_rename(fs: *fs::fs, oldpath: str, newpath: str) (void | fs::error) = { + let fs = fs: *os_filesystem; + match (rt::renameat(fs.dirfd, oldpath, fs.dirfd, newpath)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = { + let fs = fs: *os_filesystem; + let st = rt::st { ... }; + match (rt::fstatat(fs.dirfd, path, &st, rt::AT_SYMLINK_NOFOLLOW)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; + return fs::filestat { + mask = fs::stat_mask::UID + | fs::stat_mask::GID + | fs::stat_mask::SIZE + | fs::stat_mask::INODE + | fs::stat_mask::ATIME + | fs::stat_mask::MTIME + | fs::stat_mask::CTIME, + mode = st.mode: fs::mode, + uid = st.uid, + gid = st.gid, + sz = st.sz: size, + inode = st.ino, + atime = time::instant { + sec = st.atime.tv_sec, + nsec = st.atime.tv_nsec, + }, + mtime = time::instant { + sec = st.mtime.tv_sec, + nsec = st.mtime.tv_nsec, + }, + ctime = time::instant { + sec = st.ctime.tv_sec, + nsec = st.ctime.tv_nsec, + }, + }; +}; + +fn fs_readlink(fs: *fs::fs, path: str) (str | fs::error) = { + let fs = fs: *os_filesystem; + static let buf: [rt::PATH_MAX]u8 = [0...]; + let z = match (rt::readlinkat(fs.dirfd, path, buf[..])) { + case let err: rt::errno => + switch (err) { + case rt::EINVAL => + return fs::wrongtype; + case => + return errno_to_fs(err); + }; + case let z: size => + yield z; + }; + return strings::fromutf8(buf[..z])!; +}; + +fn fs_rmdir(fs: *fs::fs, path: str) (void | fs::error) = { + let fs = fs: *os_filesystem; + match (rt::unlinkat(fs.dirfd, path, rt::AT_REMOVEDIR)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn fs_mkdir(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { + let fs = fs: *os_filesystem; + match (rt::mkdirat(fs.dirfd, path, mode: uint)) { + case let err: rt::errno => + switch (err) { + case rt::EISDIR => + return errors::exists; + case => + return errno_to_fs(err); + }; + case void => void; + }; +}; + +fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = { + let fs = fs: *os_filesystem; + match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn fs_fchmod(fd: io::file, mode: fs::mode) (void | fs::error) = { + match (rt::fchmod(fd, mode: uint)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = { + let fs = fs: *os_filesystem; + match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn fs_fchown(fd: io::file, uid: uint, gid: uint) (void | fs::error) = { + match (rt::fchown(fd, uid, gid)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn instant_to_timespec(time: (time::instant | void)) rt::timespec = { + match (time) { + case let t: time::instant => + return time::instant_to_timespec(t); + case void => + return rt::timespec{ + tv_sec = rt::UTIME_OMIT, + tv_nsec = rt::UTIME_OMIT + }; + }; +}; + +fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void), + mtime: (time::instant | void)) (void | fs::error) = { + let utimes: [2]rt::timespec = [ + instant_to_timespec(atime), + instant_to_timespec(mtime), + ]; + let fs = fs: *os_filesystem; + match (rt::utimensat(fs.dirfd, path, &utimes, 0)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +fn fs_fchtimes(fd: io::file, atime: (time::instant | void), + mtime: (time::instant | void)) (void | fs::error) = { + let utimes: [2]rt::timespec = [ + instant_to_timespec(atime), + instant_to_timespec(mtime), + ]; + match (rt::futimens(fd, &utimes)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +// TODO: cannot handle errors, i.e. path too long or cannot resolve. +fn fs_resolve(fs: *fs::fs, path: str) str = { + let fs = fs: *os_filesystem; + static let buf = path::buffer { ... }; + + if (path::abs(path)) { + return path; + }; + + if (fs.dirfd == rt::AT_FDCWD) { + path::set(&buf, getcwd(), path)!; + } else { + // XXX: this is the best we can for now. we should probably + // return an error + path::set(&buf, "<unknown>", path)!; + }; + + return path::string(&buf); +}; + +fn fs_close(fs: *fs::fs) void = { + let fs = fs: *os_filesystem; + rt::close(fs.dirfd)!; +}; + +// Based on musl's readdir +type os_iterator = struct { + iter: fs::iterator, + fd: int, + buf_pos: size, + buf_end: size, + buf: []u8, +}; + +fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { + let fs = fs: *os_filesystem; + let flags = rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY; + let fd: int = match (rt::openat(fs.dirfd, path, flags, 0)) { + case let err: rt::errno => + return errno_to_fs(err); + case let fd: int => + yield fd; + }; + + let buf = match (rt::malloc(fs.getdents_bufsz)) { + case let v: *opaque => + yield v: *[*]u8; + case null => + return errors::nomem; + }; + let iter = alloc(os_iterator { + iter = fs::iterator { + next = &iter_next, + finish = &iter_finish, + }, + fd = fd, + buf = buf[..fs.getdents_bufsz], + ... + }); + return &iter.iter; +}; + +fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = { + let iter = iter: *os_iterator; + if (iter.buf_pos >= iter.buf_end) { + let n = match (rt::getdents(iter.fd, + iter.buf: *[*]u8, len(iter.buf))) { + case let err: rt::errno => + return errno_to_fs(err); + case let n: size => + yield n; + }; + if (n == 0) { + return done; + }; + iter.buf_end = n; + iter.buf_pos = 0; + }; + let de = &iter.buf[iter.buf_pos]: *rt::dirent; + iter.buf_pos += de.d_reclen; + let name = c::tostr(&de.d_name: *const c::char)?; + if (name == "." || name == "..") { + return iter_next(iter); + }; + + let ftype: fs::mode = switch (de.d_type) { + case rt::DT_UNKNOWN => + yield fs::mode::UNKNOWN; + case rt::DT_FIFO => + yield fs::mode::FIFO; + case rt::DT_CHR => + yield fs::mode::CHR; + case rt::DT_DIR => + yield fs::mode::DIR; + case rt::DT_BLK => + yield fs::mode::BLK; + case rt::DT_REG => + yield fs::mode::REG; + case rt::DT_LNK => + yield fs::mode::LINK; + case rt::DT_SOCK => + yield fs::mode::SOCK; + case => + yield fs::mode::UNKNOWN; + }; + return fs::dirent { + name = name, + ftype = ftype, + }; +}; + +fn iter_finish(iter: *fs::iterator) void = { + let iter = iter: *os_iterator; + rt::close(iter.fd)!; + free(iter.buf); + free(iter); +}; diff --git a/os/+netbsd/exit+test.ha b/os/+netbsd/exit+test.ha @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// Exit the program with the provided status code. +export fn exit(status: int) never = { + abort("os::exit disabled in +test"); +}; diff --git a/os/+netbsd/exit.ha b/os/+netbsd/exit.ha @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use rt; + +// Exit the program with the provided status code. +export fn exit(status: int) never = { + rt::fini(); + rt::exit(status); +}; diff --git a/os/+netbsd/fs.ha b/os/+netbsd/fs.ha @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use fs; +use path; +use rt; +use types::c; + +@init fn init_cwd() void = { + static let cwd_fs = os_filesystem { ... }; + cwd = static_dirfdopen(rt::AT_FDCWD, &cwd_fs); +}; + +// Returns the current working directory. The return value is statically +// allocated and must be duplicated (see [[strings::dup]]) before calling getcwd +// again. +export fn getcwd() str = c::tostr(rt::getcwd() as *const u8: *const c::char)!; + +// Change the current working directory. +export fn chdir(target: (*fs::fs | str)) (void | fs::error) = { + const path: str = match (target) { + case let fs: *fs::fs => + assert(fs.open == &fs_open); + let fs = fs: *os_filesystem; + match (rt::fchdir(fs.dirfd)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => + return; + }; + case let s: str => + yield s; + }; + match (rt::chdir(path)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +// Changes the root directory of the process. Generally requires the caller to +// have root or otherwise elevated permissions. +// +// This function is not appropriate for sandboxing. +export fn chroot(target: str) (void | fs::error) = { + match (rt::chroot(target)) { + case let err: rt::errno => + return errno_to_fs(err); + case void => void; + }; +}; + +// Access modes for [[access]]. +export type amode = enum int { + F_OK = rt::F_OK, + R_OK = rt::R_OK, + W_OK = rt::W_OK, + X_OK = rt::X_OK, +}; + +// Returns true if the given mode of access is permissible. The use of this +// function is discouraged as it can allow for a race condition to occur betwen +// testing for the desired access mode and actually using the file should the +// permissions of the file change between these operations. It is recommended +// instead to attempt to use the file directly and to handle any errors that +// should occur at that time. +export fn access(path: str, mode: amode) (bool | fs::error) = { + match (rt::access(path, mode)) { + case let b: bool => + return b; + case let err: rt::errno => + return errno_to_fs(err); + }; +}; + +// TODO: NetBSD +// export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = { +// export fn mkblk( +// export fn mkchr( +// export fn mkfile( diff --git a/os/+netbsd/platform_environ.ha b/os/+netbsd/platform_environ.ha @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; +use strings; +use types::c; + +// The command line arguments provided to the program. By convention, the first +// member is usually the name of the program. +export let args: []str = []; + +// Statically allocate arg strings if there are few enough arguments, saves a +// syscall if we don't need it. +let args_static: [32]str = [""...]; + +@init fn args() void = { + if (rt::argc < len(args_static)) { + args = args_static[..rt::argc]; + for (let i = 0z; i < rt::argc; i += 1) { + args[i] = c::tostr(rt::argv[i]: *const c::char)!; + }; + } else { + args = alloc([], rt::argc); + for (let i = 0z; i < rt::argc; i += 1) { + append(args, c::tostr(rt::argv[i]: *const c::char)!); + }; + }; + +}; + +@fini fn args() void = { + if (rt::argc >= len(args_static)) { + free(args); + }; +}; + +// Returns a slice of the environment strings in the form KEY=VALUE. +export fn getenvs() []str = { + if (len(envp) != 0) { + return envp; + }; + for (let i = 0z; rt::envp[i] != null; i += 1) { + let s = c::tostr(rt::envp[i]: *const c::char)!; + append(envp, strings::dup(s)); + }; + return envp; +}; + +// Returns the host kernel name +export fn sysname() const str = { + static let buf: [512]u8 = [0...]; + let sz: size = len(buf); + rt::sysctl([rt::CTL_KERN, rt::KERN_OSTYPE], &buf, &sz, null, 0)!; + return strings::fromutf8(buf[..(sz - 1)])!; +}; + +// Returns the host system hostname +export fn hostname() const str = { + static let buf: [512]u8 = [0...]; + let sz: size = len(buf); + rt::sysctl([rt::CTL_KERN, rt::KERN_HOSTNAME], &buf, &sz, null, 0)!; + return strings::fromutf8(buf[..(sz - 1)])!; +}; + +// Returns the host kernel version +export fn release() const str = { + static let buf: [512]u8 = [0...]; + let sz: size = len(buf); + rt::sysctl([rt::CTL_KERN, rt::KERN_OSRELEASE], &buf, &sz, null, 0)!; + return strings::fromutf8(buf[..(sz - 1)])!; +}; + +// Returns the host operating system version +export fn version() const str = { + static let buf: [512]u8 = [0...]; + let sz: size = len(buf); + rt::sysctl([rt::CTL_KERN, rt::KERN_VERSION], &buf, &sz, null, 0)!; + return strings::fromutf8(buf[..(sz - 1)])!; +}; + +// Returns the host CPU architecture, in a platform-specific format. See +// [[architecture]] for a more portable wrapper. +export fn machine() const str = { + static let buf: [32]u8 = [0...]; + let sz: size = len(buf); + rt::sysctl([rt::CTL_HW, rt::HW_MACHINE], &buf, &sz, null, 0)!; + return strings::fromutf8(buf[..sz - 1])!; +}; + +// Returns the host CPU architecture. +export fn architecture() arch = { + switch (machine()) { + case "aarch64" => + return arch::AARCH64; + case "riscv64" => + return arch::RISCV64; + case "amd64" => + return arch::X86_64; + case => abort(); // unreachable + }; +}; + +// Returns the number of usable CPUs. +export fn cpucount() (size | errors::error) = { + let count = 0; + let length = size(int); + match (rt::sysctl([rt::CTL_HW, rt::HW_NCPU], &count, &length, null, 0)) { + case void => void; + case let err: rt::errno => + return errors::errno(err); + }; + return count: size; +}; diff --git a/os/+netbsd/status.ha b/os/+netbsd/status.ha @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// Values that may be passed to [[exit]] to indicate successful or unsuccessful +// termination, respectively. +export type status = enum { + SUCCESS = 0, + FAILURE = 1, +}; diff --git a/os/+netbsd/stdfd.ha b/os/+netbsd/stdfd.ha @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use bufio; +use io; +use rt; + +let stdin_bufio: bufio::stream = bufio::stream { + // Will be overwritten, but must be initialized + stream = null: io::stream, + source = 0, + ... +}; + +let stdout_bufio: bufio::stream = bufio::stream { + // Will be overwritten, but must be initialized + stream = null: io::stream, + source = 1, + ... +}; + +// The standard input. This handle is buffered. +export let stdin: io::handle = rt::STDIN_FILENO; // initialized by init_stdfd + +// The standard input, as an [[io::file]]. This handle is unbuffered. +export let stdin_file: io::file = rt::STDIN_FILENO; + +// The standard output. This handle is buffered. +export let stdout: io::handle = rt::STDOUT_FILENO; // initialized by init_stdfd + +// The standard output, as an [[io::file]]. This handle is unbuffered. +export let stdout_file: io::file = rt::STDOUT_FILENO; + +// The standard error. This handle is unbuffered. +export let stderr: io::handle = rt::STDERR_FILENO; + +// The standard error, as an [[io::file]]. This handle is unbuffered. +export let stderr_file: io::file = rt::STDERR_FILENO; + +// The recommended buffer size for reading from disk. +export def BUFSZ: size = 4096; // 4 KiB + +@init fn init_stdfd() void = { + static let stdinbuf: [BUFSZ]u8 = [0...]; + stdin_bufio = bufio::init(stdin_file, stdinbuf, []); + stdin = &stdin_bufio; + + static let stdoutbuf: [BUFSZ]u8 = [0...]; + stdout_bufio = bufio::init(stdout_file, [], stdoutbuf); + stdout = &stdout_bufio; +}; + +@fini fn fini_stdfd() void = { + // Flush any pending writes + io::close(stdout): void; +}; diff --git a/os/exec/+netbsd/exec.ha b/os/exec/+netbsd/exec.ha @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use os; +use rt; +use types::c; +use unix; + +// Forks the current process, returning the [[process]] of the child (to the +// parent) and void (to the child), or an error. +export fn fork() (process | void | error) = { + match (rt::fork()) { + case let err: rt::errno => + return errors::errno(err); + case let i: rt::pid_t => + return i: process; + case void => + return void; + }; +}; + +// Creates an anonymous pipe for use with [[addfile]]. Any data written to the +// second file may be read from the first file. The caller should close one or +// both of the file descriptors after they have transferred them to another +// process, and after they have finished using them themselves, if applicable. +// +// This function will abort the process if the system is unable to allocate the +// resources for a pipe. If you need to handle this error gracefully, you may +// call [[unix::pipe]] yourself, but this may reduce the portability of your +// software. +// +// To capture the standard output of a process: +// +// let pipe = exec::pipe(); +// exec::addfile(&cmd, pipe.1, os::stdout_file); +// let proc = exec::start(&cmd)!; +// io::close(pipe.1)!; +// +// let data = io::drain(pipe.0)!; +// io::close(pipe.0)!; +// exec::wait(&proc)!; +// +// To write to the standard input of a process: +// +// let pipe = exec::pipe(); +// exec::addfile(&cmd, os::stdin_file, pipe.0); +// let proc = exec::start(&cmd)!; +// +// io::writeall(data)!; +// io::close(pipe.1)!; +// io::close(pipe.0)!; +// exec::wait(&proc)!; +export fn pipe() (io::file, io::file) = { + return unix::pipe()!; +}; + +fn open(path: str) (platform_cmd | error) = { + let fd = match (rt::open(path, rt::O_RDONLY, 0u)) { + case let fd: int => + yield fd; + case let err: rt::errno => + return errors::errno(err); + }; + let success = false; + defer if (!success) rt::close(fd)!; + match (rt::access(path, rt::X_OK)) { + case let err: rt::errno => + return errors::errno(err); + case let b: bool => + if (!b) { + return errors::noaccess; + }; + }; + // Make sure we are not trying to execute anything weird. fstat() + // already dereferences symlinks, so if this is anything other than a + // regular file it cannot be executed. + let s = rt::st { ... }; + match (rt::fstat(fd, &s)) { + case let err: rt::errno => + return errors::errno(err); + case void => + if (s.mode & rt::S_IFREG == 0) { + return errors::noaccess; + }; + }; + success = true; + return fd; + +}; + +fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!; + +fn platform_exec(cmd: *command) error = { + // We don't worry about freeing the return values from c::fromstr + // because once we exec(2) our heap is fried anyway + let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); + for (let arg .. cmd.argv) { + append(argv, c::fromstr(arg)); + }; + append(argv, null); + + let envp: nullable *[*]nullable *const c::char = null; + if (len(cmd.env) != 0) { + let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); + for (let e .. cmd.env) { + append(env, c::fromstr(e)); + }; + append(env, null); + envp = env: *[*]nullable *const c::char; + }; + + let need_devnull = false; + for (let file &.. cmd.files) { + const from = match (file.0) { + case let file: io::file => + yield file; + case nullfd => + need_devnull = true; + continue; + case closefd => + continue; + }; + + file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) { + case let fd: int => + yield fd; + case let err: rt::errno => + return errors::errno(err); + }; + }; + + const devnull: io::file = if (need_devnull) { + yield os::open("/dev/null")!; + } else -1; + + for (let file .. cmd.files) { + const from = match (file.0) { + case let file: io::file => + yield file; + case nullfd => + yield devnull; + case closefd => + io::close(file.1)?; + continue; + }; + + if (file.1 == from) { + let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) { + case let flags: int => + yield flags; + case let e: rt::errno => + return errors::errno(e); + }; + rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!; + } else { + match (rt::dup2(from, file.1)) { + case int => void; + case let e: rt::errno => + return errors::errno(e); + }; + }; + }; + + if (cmd.dir != "") { + os::chdir(cmd.dir)?; + }; + + return errors::errno(rt::fexecve(cmd.platform, + argv: *[*]nullable *const u8, + envp: *[*]nullable *const u8)); +}; + +fn platform_start(cmd: *command) (process | errors::error) = { + // TODO: Let the user configure clone more to their taste (e.g. SIGCHLD) + let pipe: [2]int = [0...]; + match (rt::pipe2(&pipe, rt::O_CLOEXEC)) { + case let err: rt::errno => + return errors::errno(err); + case void => void; + }; + + match (rt::fork()) { + case let err: rt::errno => + return errors::errno(err); + case let pid: rt::pid_t => + rt::close(pipe[1])!; + defer rt::close(pipe[0])!; + let errno: int = 0; + match (rt::read(pipe[0], &errno, size(int))) { + case let err: rt::errno => + return errors::errno(err); + case let n: size => + switch (n) { + case size(int) => + return errors::errno(errno); + case 0 => + return pid; + case => + abort("Unexpected rt::read result"); + }; + }; + case void => + rt::close(pipe[0])!; + let err = platform_exec(cmd); + if (!(err is errors::opaque_)) { + rt::exit(1); + }; + let err = err as errors::opaque_; + let err = &err.data: *rt::errno; + rt::write(pipe[1], err, size(int))!; + rt::exit(1); + }; +}; diff --git a/os/exec/+netbsd/platform_cmd.ha b/os/exec/+netbsd/platform_cmd.ha @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use io; +use os; +use strings; + +export type platform_cmd = io::file; + +// Same as [[cmd]] except that executable file is determined by [[io::file]]. +// This function is not portable. +export fn cmdfile(file: io::file, name: str, args: str...) command = { + let cmd = command { + platform = file, + argv = alloc([], len(args) + 1), + env = strings::dupall(os::getenvs()), + files = [], + dir = "", + }; + append(cmd.argv, name); + append(cmd.argv, args...); + return cmd; +}; diff --git a/os/exec/+netbsd/process.ha b/os/exec/+netbsd/process.ha @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use fmt; +use rt; +use time; +use unix; +use unix::signal; + +// Stores information about a child process. +export type process = unix::pid; + +// Returns the currently running [[process]]. +export fn self() process = { + return unix::getpid(); +}; + +// Stores information about an exited process. +export type status = struct { + status: int, + // Not all of these members are supported on all operating systems. + // Only utime and stime are guaranteed to be available. + rusage: struct { + utime: time::instant, + stime: time::instant, + maxrss: i64, + ixrss: i64, + idrss: i64, + isrss: i64, + minflt: i64, + majflt: i64, + nswap: i64, + inblock: i64, + oublock: i64, + msgsnd: i64, + msgrcv: i64, + nsignals: i64, + nvcsw: i64, + nivcsw: i64, + }, +}; + +fn rusage(st: *status, ru: *rt::rusage) void = { + st.rusage.utime = time::instant { + sec = ru.ru_utime.tv_sec, + nsec = ru.ru_utime.tv_usec * time::MICROSECOND: i64, + }; + st.rusage.stime = time::instant { + sec = ru.ru_stime.tv_sec, + nsec = ru.ru_stime.tv_usec * time::MICROSECOND: i64, + }; + st.rusage.maxrss = ru.ru_maxrss; + st.rusage.ixrss = ru.ru_ixrss; + st.rusage.idrss = ru.ru_idrss; + st.rusage.isrss = ru.ru_isrss; + st.rusage.minflt = ru.ru_minflt; + st.rusage.majflt = ru.ru_majflt; + st.rusage.nswap = ru.ru_nswap; + st.rusage.inblock = ru.ru_inblock; + st.rusage.oublock = ru.ru_oublock; + st.rusage.msgsnd = ru.ru_msgsnd; + st.rusage.msgrcv = ru.ru_msgrcv; + st.rusage.nsignals = ru.ru_nsignals; + st.rusage.nvcsw = ru.ru_nvcsw; + st.rusage.nivcsw = ru.ru_nivcsw; +}; + +// Waits for a process to complete, then returns its status information. +export fn wait(proc: *process) (status | error) = { + let ru: rt::rusage = rt::rusage { ... }; + let st: status = status { ... }; + match (rt::wait4(*proc, &st.status, 0, &ru)) { + case let err: rt::errno => + return errors::errno(err); + case let pid: int => + assert(pid == *proc: int); + }; + rusage(&st, &ru); + return st; +}; + +// Waits for the first child process to complete, then returns its process info +// and status +export fn waitany() ((process, status) | error) = { + let ru: rt::rusage = rt::rusage { ... }; + let st: status = status { ... }; + match (rt::wait4(-1, &st.status, 0, &ru)) { + case let err: rt::errno => + return errors::errno(err); + case let pid: int => + rusage(&st, &ru); + return (pid: process, st); + }; +}; + +// Waits for all children to terminate succesfully. If a child process exits +// with a nonzero status, returns its process info and exit status immediately, +// not waiting for the remaining children. +export fn waitall() (uint | error | !(process, exit_status)) = { + let st: status = status { ... }; + let ru: rt::rusage = rt::rusage { ... }; + for (let i = 0u; true; i += 1) match (rt::wait4(-1, &st.status, 0, &ru)) { + case let err: rt::errno => + if (err == rt::ECHILD) { + return i; + } else { + return errors::errno(err); + }; + case let pid: int => + match (check(&st)) { + case void => void; + case let es: !exit_status => + return (pid: process, es); + }; + }; +}; + +// Checks for process completion, returning its status information on +// completion, or void if it is still running. +export fn peek(proc: *process) (status | void | error) = { + let ru: rt::rusage = rt::rusage { ... }; + let st: status = status { ... }; + match (rt::wait4(*proc, &st.status, rt::WNOHANG, &ru)) { + case let err: rt::errno => + return errors::errno(err); + case let pid: int => + switch (pid) { + case 0 => + return; + case => + assert(pid == *proc: int); + }; + }; + rusage(&st, &ru); + return st; +}; + +// Checks if any child process has completed, returning its process info and +// status if so. +export fn peekany() ((process, status) | void | error) = { + let ru: rt::rusage = rt::rusage { ... }; + let st: status = status { ... }; + match (rt::wait4(-1, &st.status, rt::WNOHANG, &ru)) { + case let err: rt::errno => + return errors::errno(err); + case let pid: int => + switch (pid) { + case 0 => + return; + case => + return (pid: process, st); + }; + }; +}; + +// The exit status code of a process. +export type exited = int; + +// The signal number which caused a process to terminate. +export type signaled = signal::sig; + +// The exit status of a process. +export type exit_status = (exited | signaled); + +// Returns a human friendly string describing the exit status. The string is +// statically allocated; use [[strings::dup]] to extend its lifetime. +export fn exitstr(status: exit_status) const str = { + static let buf: [1024]u8 = [0...]; + match (status) { + case let i: exited => + switch (i) { + case 0 => + return "exited normally"; + case => + return fmt::bsprintf(buf, "exited with status {}", + i: int); + }; + case let s: signaled => + return fmt::bsprintf(buf, "exited with signal {}", + signal::signame(s)); + }; +}; + +// Returns the exit status of a completed process. +export fn exit(stat: *status) exit_status = { + if (rt::wifexited(stat.status)) { + return rt::wexitstatus(stat.status): exited; + }; + if (rt::wifsignaled(stat.status)) { + return rt::wtermsig(stat.status): signaled; + }; + abort("Unexpected exit status"); +}; + +// Checks the exit status of a completed process, returning void if successful, +// or its status code as an error type if not. +export fn check(stat: *status) (void | !exit_status) = { + if (rt::wifexited(stat.status)) { + switch (rt::wexitstatus(stat.status)) { + case 0 => + return void; + case => + return exit(stat); + }; + }; + return exit(stat); +}; + +// Terminates a process. On NetBSD, this sends [[unix::signal::sig::TERM]] to +// the process. +export fn kill(proc: process) (void | errors::error) = { + return sig(proc, signal::sig::TERM); +}; + +// Sends a signal to a child process. This function is only supported on +// Unix-like systems. +export fn sig(proc: process, sig: signal::sig) (void | errors::error) = { + match (rt::kill(proc, sig)) { + case let errno: rt::errno => + return errors::errno(errno); + case void => + return; + }; +}; diff --git a/path/+netbsd.ha b/path/+netbsd.ha @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use rt; + +// Platform-specific path separator byte. +export def SEP: u8 = '/'; + +const sepstr: str = "/"; + +// Maximum length of a file path for this platform. +export def MAX = rt::PATH_MAX - 1; diff --git a/rt/+netbsd/+x86_64.ha b/rt/+netbsd/+x86_64.ha @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +export type siginfo = struct { + si_signo: int, + si_errno: int, + si_code: int, + si_pid: pid_t, + si_uid: uid_t, + si_status: int, + si_addr: *opaque, + si_value: sigval, + _reason: union { + _fault: struct { + _trapno: int, + }, + _timer: struct { + _timerid: int, + _overrun: int, + }, + _mesgq: struct { + _mqd: int, + }, + _poll: struct { + _band: i64, + }, + __spare__: struct { + __spare1__: i64, + __spare2__: [7]int, + }, + }, +}; + +export type ucontext = struct { + uc_sigmask: sigset, + uc_mcontext: mcontext, + uc_link: *ucontext, + uc_stack: stack_t, + uc_flags: int, + __spare__: [4]int, +}; + +export type mcontext = struct { + mc_onstack: u64, + mc_rdi: u64, + mc_rsi: u64, + mc_rdx: u64, + mc_rcx: u64, + mc_r8: u64, + mc_r9: u64, + mc_rax: u64, + mc_rbx: u64, + mc_rbp: u64, + mc_r10: u64, + mc_r11: u64, + mc_r12: u64, + mc_r13: u64, + mc_r14: u64, + mc_r15: u64, + mc_trapno: u32, + mc_fs: u16, + mc_gs: u16, + mc_addr: u64, + mc_flags: u32, + mc_es: u16, + mc_ds: u16, + mc_err: u64, + mc_rip: u64, + mc_cs: u64, + mc_rflags: u64, + mc_rsp: u64, + mc_ss: u64, +}; diff --git a/rt/+netbsd/env.ha b/rt/+netbsd/env.ha @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +export let argc: size = 0; +export let argv: *[*]*u8 = null: *[*]*u8; +export let envp: *[*]nullable *u8 = null: *[*]nullable *u8; diff --git a/rt/+netbsd/errno.ha b/rt/+netbsd/errno.ha @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// Represents an error returned from the NetBSD kernel. +export type errno = !int; + +// Checks the return value from a NetBSD syscall and, if found to be in error, +// returns the appropriate error. Otherwise, returns the original value. +fn wrap_return(r: u64) (errno | u64) = { + if (r > -4096: u64) { + return (-(r: i64)): errno; + }; + return r; +}; + +// Obtains a human-friendly reading of an [[errno]] (e.g. "Operation not +// permitted"). The return value may be statically allocated. +export fn strerror(err: errno) str = { + switch (err) { + case EPERM => + return "Operation not permitted"; + case ENOENT => + return "No such file or directory"; + case ESRCH => + return "No such process"; + case EINTR => + return "Interrupted system call"; + case EIO => + return "Input/output error"; + case ENXIO => + return "No such device or address"; + case E2BIG => + return "Argument list too long"; + case ENOEXEC => + return "Exec format error"; + case EBADF => + return "Bad file descriptor"; + case ECHILD => + return "No child processes"; + case EAGAIN => + return "Resource temporarily unavailable"; + case ENOMEM => + return "Cannot allocate memory"; + case EACCES => + return "Permission denied"; + case EFAULT => + return "Bad address"; + case ENOTBLK => + return "Block device required"; + case EBUSY => + return "Device or resource busy"; + case EEXIST => + return "File exists"; + case EXDEV => + return "Invalid cross-device link"; + case ENODEV => + return "No such device"; + case ENOTDIR => + return "Not a directory"; + case EISDIR => + return "Is a directory"; + case EINVAL => + return "Invalid argument"; + case ENFILE => + return "Too many open files in system"; + case EMFILE => + return "Too many open files"; + case ENOTTY => + return "Inappropriate ioctl for device"; + case ETXTBSY => + return "Text file busy"; + case EFBIG => + return "File too large"; + case ENOSPC => + return "No space left on device"; + case ESPIPE => + return "Illegal seek"; + case EROFS => + return "Read-only file system"; + case EMLINK => + return "Too many links"; + case EPIPE => + return "Broken pipe"; + case EDOM => + return "Numerical argument out of domain"; + case ERANGE => + return "Numerical result out of range"; + case EDEADLK => + return "Resource deadlock avoided"; + case ENAMETOOLONG => + return "File name too long"; + case ENOLCK => + return "No locks available"; + case ENOSYS => + return "Function not implemented"; + case ENOTEMPTY => + return "Directory not empty"; + case ELOOP => + return "Too many levels of symbolic links"; + case ENOMSG => + return "No message of desired type"; + case EIDRM => + return "Identifier removed"; + case EREMOTE => + return "Object is remote"; + case ENOLINK => + return "Link has been severed"; + case EPROTO => + return "Protocol error"; + case EMULTIHOP => + return "Multihop attempted"; + case EBADMSG => + return "Bad message"; + case EOVERFLOW => + return "Value too large for defined data type"; + case EILSEQ => + return "Invalid or incomplete multibyte or wide character"; + case EUSERS => + return "Too many users"; + case ENOTSOCK => + return "Socket operation on non-socket"; + case EDESTADDRREQ => + return "Destination address required"; + case EMSGSIZE => + return "Message too long"; + case EPROTOTYPE => + return "Protocol wrong type for socket"; + case ENOPROTOOPT => + return "Protocol not available"; + case EPROTONOSUPPORT => + return "Protocol not supported"; + case ESOCKTNOSUPPORT => + return "Socket type not supported"; + case EOPNOTSUPP => + return "Operation not supported"; + case EPFNOSUPPORT => + return "Protocol family not supported"; + case EAFNOSUPPORT => + return "Address family not supported by protocol"; + case EADDRINUSE => + return "Address already in use"; + case EADDRNOTAVAIL => + return "Cannot assign requested address"; + case ENETDOWN => + return "Network is down"; + case ENETUNREACH => + return "Network is unreachable"; + case ENETRESET => + return "Network dropped connection on reset"; + case ECONNABORTED => + return "Software caused connection abort"; + case ECONNRESET => + return "Connection reset by peer"; + case ENOBUFS => + return "No buffer space available"; + case EISCONN => + return "Transport endpoint is already connected"; + case ENOTCONN => + return "Transport endpoint is not connected"; + case ESHUTDOWN => + return "Cannot send after transport endpoint shutdown"; + case ETOOMANYREFS => + return "Too many references: cannot splice"; + case ETIMEDOUT => + return "Connection timed out"; + case ECONNREFUSED => + return "Connection refused"; + case EHOSTDOWN => + return "Host is down"; + case EHOSTUNREACH => + return "No route to host"; + case EALREADY => + return "Operation already in progress"; + case EINPROGRESS => + return "Operation now in progress"; + case ESTALE => + return "Stale file handle"; + case EDQUOT => + return "Disk quota exceeded"; + case ECANCELED => + return "Operation canceled"; + case EOWNERDEAD => + return "Owner died"; + case ENOTRECOVERABLE => + return "State not recoverable"; + case EAUTH => + return "Authentication error"; + case EBADRPC => + return "RPC struct is bad"; + case ECAPMODE => + return "Not permitted in capability mode"; + case EDOOFUS => + return "Programming error"; + case EINTEGRITY => + return "Integrity check failed"; + case ENEEDAUTH => + return "Need authenticator"; + case ENOATTR => + return "Attribute not found"; + case ENOTCAPABLE => + return "Capabilities insufficient"; + case EPROCLIM => + return "Too many processes"; + case EPROCUNAVAIL => + return "Bad procedure for program"; + case EPROGMISMATCH => + return "Program version wrong"; + case EPROGUNAVAIL => + return "RPC program not available"; + case ERPCMISMATCH => + return "RPC version wrong"; + case => + return unknown_errno(err); + }; +}; + +// Gets the programmer-friendly name for an [[errno]] (e.g. EPERM). The return +// value may be statically allocated. +export fn errname(err: errno) str = { + switch (err) { + case EPERM => + return "EPERM"; + case ENOENT => + return "ENOENT"; + case ESRCH => + return "ESRCH"; + case EINTR => + return "EINTR"; + case EIO => + return "EIO"; + case ENXIO => + return "ENXIO"; + case E2BIG => + return "E2BIG"; + case ENOEXEC => + return "ENOEXEC"; + case EBADF => + return "EBADF"; + case ECHILD => + return "ECHILD"; + case EAGAIN => + return "EAGAIN"; + case ENOMEM => + return "ENOMEM"; + case EACCES => + return "EACCES"; + case EFAULT => + return "EFAULT"; + case ENOTBLK => + return "ENOTBLK"; + case EBUSY => + return "EBUSY"; + case EEXIST => + return "EEXIST"; + case EXDEV => + return "EXDEV"; + case ENODEV => + return "ENODEV"; + case ENOTDIR => + return "ENOTDIR"; + case EISDIR => + return "EISDIR"; + case EINVAL => + return "EINVAL"; + case ENFILE => + return "ENFILE"; + case EMFILE => + return "EMFILE"; + case ENOTTY => + return "ENOTTY"; + case ETXTBSY => + return "ETXTBSY"; + case EFBIG => + return "EFBIG"; + case ENOSPC => + return "ENOSPC"; + case ESPIPE => + return "ESPIPE"; + case EROFS => + return "EROFS"; + case EMLINK => + return "EMLINK"; + case EPIPE => + return "EPIPE"; + case EDOM => + return "EDOM"; + case ERANGE => + return "ERANGE"; + case EDEADLK => + return "EDEADLK"; + case ENAMETOOLONG => + return "ENAMETOOLONG"; + case ENOLCK => + return "ENOLCK"; + case ENOSYS => + return "ENOSYS"; + case ENOTEMPTY => + return "ENOTEMPTY"; + case ELOOP => + return "ELOOP"; + case ENOMSG => + return "ENOMSG"; + case EIDRM => + return "EIDRM"; + case EREMOTE => + return "EREMOTE"; + case ENOLINK => + return "ENOLINK"; + case EPROTO => + return "EPROTO"; + case EMULTIHOP => + return "EMULTIHOP"; + case EBADMSG => + return "EBADMSG"; + case EOVERFLOW => + return "EOVERFLOW"; + case EILSEQ => + return "EILSEQ"; + case EUSERS => + return "EUSERS"; + case ENOTSOCK => + return "ENOTSOCK"; + case EDESTADDRREQ => + return "EDESTADDRREQ"; + case EMSGSIZE => + return "EMSGSIZE"; + case EPROTOTYPE => + return "EPROTOTYPE"; + case ENOPROTOOPT => + return "ENOPROTOOPT"; + case EPROTONOSUPPORT => + return "EPROTONOSUPPORT"; + case ESOCKTNOSUPPORT => + return "ESOCKTNOSUPPORT"; + case EOPNOTSUPP => + return "EOPNOTSUPP"; + case EPFNOSUPPORT => + return "EPFNOSUPPORT"; + case EAFNOSUPPORT => + return "EAFNOSUPPORT"; + case EADDRINUSE => + return "EADDRINUSE"; + case EADDRNOTAVAIL => + return "EADDRNOTAVAIL"; + case ENETDOWN => + return "ENETDOWN"; + case ENETUNREACH => + return "ENETUNREACH"; + case ENETRESET => + return "ENETRESET"; + case ECONNABORTED => + return "ECONNABORTED"; + case ECONNRESET => + return "ECONNRESET"; + case ENOBUFS => + return "ENOBUFS"; + case EISCONN => + return "EISCONN"; + case ENOTCONN => + return "ENOTCONN"; + case ESHUTDOWN => + return "ESHUTDOWN"; + case ETOOMANYREFS => + return "ETOOMANYREFS"; + case ETIMEDOUT => + return "ETIMEDOUT"; + case ECONNREFUSED => + return "ECONNREFUSED"; + case EHOSTDOWN => + return "EHOSTDOWN"; + case EHOSTUNREACH => + return "EHOSTUNREACH"; + case EALREADY => + return "EALREADY"; + case EINPROGRESS => + return "EINPROGRESS"; + case ESTALE => + return "ESTALE"; + case EDQUOT => + return "EDQUOT"; + case ECANCELED => + return "ECANCELED"; + case EOWNERDEAD => + return "EOWNERDEAD"; + case ENOTRECOVERABLE => + return "ENOTRECOVERABLE"; + case EAUTH => + return "EAUTH"; + case EBADRPC => + return "EBADRPC"; + case ECAPMODE => + return "ECAPMODE"; + case EDOOFUS => + return "EDOOFUS"; + case EINTEGRITY => + return "EINTEGRITY"; + case ENEEDAUTH => + return "ENEEDAUTH"; + case ENOATTR => + return "ENOATTR"; + case ENOTCAPABLE => + return "ENOTCAPABLE"; + case EPROCLIM => + return "EPROCLIM"; + case EPROCUNAVAIL => + return "EPROCUNAVAIL"; + case EPROGMISMATCH => + return "EPROGMISMATCH"; + case EPROGUNAVAIL => + return "EPROGUNAVAIL"; + case ERPCMISMATCH => + return "ERPCMISMATCH"; + case => + return unknown_errno(err); + }; +}; + +export def EPERM: errno = 1; +export def ENOENT: errno = 2; +export def ESRCH: errno = 3; +export def EINTR: errno = 4; +export def EIO: errno = 5; +export def ENXIO: errno = 6; +export def E2BIG: errno = 7; +export def ENOEXEC: errno = 8; +export def EBADF: errno = 9; +export def ECHILD: errno = 10; +export def EDEADLK: errno = 11; +export def ENOMEM: errno = 12; +export def EACCES: errno = 13; +export def EFAULT: errno = 14; +export def ENOTBLK: errno = 15; +export def EBUSY: errno = 16; +export def EEXIST: errno = 17; +export def EXDEV: errno = 18; +export def ENODEV: errno = 19; +export def ENOTDIR: errno = 20; +export def EISDIR: errno = 21; +export def EINVAL: errno = 22; +export def ENFILE: errno = 23; +export def EMFILE: errno = 24; +export def ENOTTY: errno = 25; +export def ETXTBSY: errno = 26; +export def EFBIG: errno = 27; +export def ENOSPC: errno = 28; +export def ESPIPE: errno = 29; +export def EROFS: errno = 30; +export def EMLINK: errno = 31; +export def EPIPE: errno = 32; +export def EDOM: errno = 33; +export def ERANGE: errno = 34; +export def EAGAIN: errno = 35; +export def EWOULDBLOCK: errno = EAGAIN; +export def EINPROGRESS: errno = 36; +export def EALREADY: errno = 37; +export def ENOTSOCK: errno = 38; +export def EDESTADDRREQ: errno = 39; +export def EMSGSIZE: errno = 40; +export def EPROTOTYPE: errno = 41; +export def ENOPROTOOPT: errno = 42; +export def EPROTONOSUPPORT: errno = 43; +export def ESOCKTNOSUPPORT: errno = 44; +export def EOPNOTSUPP: errno = 45; +export def ENOTSUP: errno = EOPNOTSUPP; +export def EPFNOSUPPORT: errno = 46; +export def EAFNOSUPPORT: errno = 47; +export def EADDRINUSE: errno = 48; +export def EADDRNOTAVAIL: errno = 49; +export def ENETDOWN: errno = 50; +export def ENETUNREACH: errno = 51; +export def ENETRESET: errno = 52; +export def ECONNABORTED: errno = 53; +export def ECONNRESET: errno = 54; +export def ENOBUFS: errno = 55; +export def EISCONN: errno = 56; +export def ENOTCONN: errno = 57; +export def ESHUTDOWN: errno = 58; +export def ETOOMANYREFS: errno = 59; +export def ETIMEDOUT: errno = 60; +export def ECONNREFUSED: errno = 61; +export def ELOOP: errno = 62; +export def ENAMETOOLONG: errno = 63; +export def EHOSTDOWN: errno = 64; +export def EHOSTUNREACH: errno = 65; +export def ENOTEMPTY: errno = 66; +export def EPROCLIM: errno = 67; +export def EUSERS: errno = 68; +export def EDQUOT: errno = 69; +export def ESTALE: errno = 70; +export def EREMOTE: errno = 71; +export def EBADRPC: errno = 72; +export def ERPCMISMATCH: errno = 73; +export def EPROGUNAVAIL: errno = 74; +export def EPROGMISMATCH: errno = 75; +export def EPROCUNAVAIL: errno = 76; +export def ENOLCK: errno = 77; +export def ENOSYS: errno = 78; +export def EFTYPE: errno = 79; +export def EAUTH: errno = 80; +export def ENEEDAUTH: errno = 81; +export def EIDRM: errno = 82; +export def ENOMSG: errno = 83; +export def EOVERFLOW: errno = 84; +export def ECANCELED: errno = 85; +export def EILSEQ: errno = 86; +export def ENOATTR: errno = 87; +export def EDOOFUS: errno = 88; +export def EBADMSG: errno = 89; +export def EMULTIHOP: errno = 90; +export def ENOLINK: errno = 91; +export def EPROTO: errno = 92; +export def ENOTCAPABLE: errno = 93; +export def ECAPMODE: errno = 94; +export def ENOTRECOVERABLE: errno = 95; +export def EOWNERDEAD: errno = 96; +export def EINTEGRITY: errno = 97; diff --git a/rt/+netbsd/hare.sc b/rt/+netbsd/hare.sc @@ -0,0 +1,47 @@ +PHDRS { + headers PT_PHDR PHDRS; + text PT_LOAD FILEHDR PHDRS; + data PT_LOAD; + note PT_NOTE; +} +ENTRY(_start); +SECTIONS { + . = 0x8000000; + .text : { + KEEP (*(.text)) + *(.text.*) + } :text + . = 0x80000000; + .data : { + KEEP (*(.data)) + *(.data.*) + } :data + + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } :data + + .fini_array : { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + } :data + + .test_array : { + PROVIDE_HIDDEN (__test_array_start = .); + KEEP (*(.test_array)) + PROVIDE_HIDDEN (__test_array_end = .); + } :data + + .note.netbsd.ident : { + KEEP (*(.note.netbsd.ident)) + *(.note.netbsd.*) + } :data :note + + .bss : { + KEEP (*(.bss)) + *(.bss.*) + } :data +} diff --git a/rt/+netbsd/initfini.ha b/rt/+netbsd/initfini.ha @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// Run all global initialization functions. +export fn init() void = { + const ninit = (&init_end: uintptr - &init_start: uintptr): size + / size(*fn() void); + for (let i = 0z; i < ninit; i += 1) { + init_start[i](); + }; +}; + +// Run all global finalization functions. +export fn fini() void = { + const nfini = (&fini_end: uintptr - &fini_start: uintptr): size + / size(*fn() void); + for (let i = nfini; i > 0; i -= 1) { + fini_start[i - 1](); + }; +}; diff --git a/rt/+netbsd/platform_abort.ha b/rt/+netbsd/platform_abort.ha @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +fn platform_abort(path: *str, line: u64, col: u64, msg: str) never = { + const prefix = "Abort: "; + const sep = ":"; + const sepspace = ": "; + const linefeed = "\n"; + write(STDERR_FILENO, *(&prefix: **opaque): *const u8, len(prefix)): void; + write(STDERR_FILENO, *(path: **opaque): *const u8, len(path)): void; + write(STDERR_FILENO, *(&sep: **opaque): *const u8, len(sep)): void; + let (line, z) = u64tos(line); + write(STDERR_FILENO, line, z): void; + write(STDERR_FILENO, *(&sep: **opaque): *const u8, len(sep)): void; + let (col, z) = u64tos(col); + write(STDERR_FILENO, col, z): void; + write(STDERR_FILENO, *(&sepspace: **opaque): *const u8, + len(sepspace)): void; + write(STDERR_FILENO, *(&msg: **opaque): *const u8, len(msg)): void; + write(STDERR_FILENO, *(&linefeed: **opaque): *const u8, 1): void; + kill(getpid(), SIGABRT): void; + for (true) void; +}; diff --git a/rt/+netbsd/platformstart-libc.ha b/rt/+netbsd/platformstart-libc.ha @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +export fn start_netbsd(iv: *[*]uintptr) never = { + // TODO: Find & parse auxv + argc = iv[0]: size; + argv = &iv[1]: *[*]*u8; + envp = &argv[argc + 1]: *[*]nullable *u8; + start_ha(); +}; diff --git a/rt/+netbsd/segmalloc.ha b/rt/+netbsd/segmalloc.ha @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// Allocates a segment. +fn segmalloc(n: size) nullable *opaque = { + return match (mmap(null, n, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0)) { + case let err: errno => + assert(err == ENOMEM: errno); + yield null; + case let p: *opaque => + yield p; + }; +}; + +// Frees a segment allocated with segmalloc. +fn segfree(p: *opaque, s: size) void = { + match (munmap(p, s)) { + case let err: errno => + abort("munmap failed"); + case void => void; + }; +}; diff --git a/rt/+netbsd/signal.ha b/rt/+netbsd/signal.ha @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// TODO: work when _NSIG != 32 + +export fn alarm(sec: uint) uint = { + let nval = itimerval { ... }; + let oval = itimerval { ... }; + nval.it_value.tv_sec = sec: time_t; + setitimer(ITIMER_REAL, &nval, &oval)!; + if (oval.it_value.tv_usec != 0) { + oval.it_value.tv_sec += 1; + }; + return oval.it_value.tv_sec: uint; +}; + +export def ITIMER_REAL: int = 0; +export def ITIMER_VIRTUAL: int = 1; +export def ITIMER_PROF: int = 2; + +export type itimerval = struct { + it_interval: timeval, + it_value: timeval, +}; + +export fn getitimer( + which: int, + cur: *itimerval, +) (void | errno) = { + wrap_return(syscall2(SYS_compat_50_getitimer, which: u64, cur: uintptr: u64))?; +}; + +export fn setitimer( + which: int, + newval: *itimerval, + oldval: nullable *itimerval, +) (void | errno) = { + wrap_return(syscall3(SYS_compat_50_setitimer, + which: u64, + newval: uintptr: u64, + oldval: uintptr: u64))?; +}; + +export fn sigtimedwait( + set: *sigset, + info: nullable *siginfo, + timeout: nullable *timespec, +) (int | errno) = { + return wrap_return(syscall3(SYS_compat_50___sigtimedwait, + set: uintptr: u64, + info: uintptr: u64, + timeout: uintptr: u64, + ))?: int; +}; + +export fn sigwait(set: *sigset, sig: *int) (void | errno) = { + *sig = sigtimedwait(set, null, null)?; +}; + +export fn sigwaitinfo(set: *sigset, info: nullable *siginfo) (void | errno) = { + sigtimedwait(set, info, null)?; +}; + +export fn sigemptyset(set: *sigset) void = { + for (let i = 0z; i < len(set.__bits); i += 1) { + set.__bits[i] = 0; + }; +}; + +export fn sigaddset(set: *sigset, signum: int) (void | errno) = { + if (signum < 1 || signum > NSIG) { + return EINVAL; + }; + signum -= 1; + set.__bits[signum >> 5] |= (1 << signum): u32; +}; + +export fn sigdelset(set: *sigset, signum: int) (void | errno) = { + if (signum < 1 || signum > NSIG) { + return EINVAL; + }; + signum -= 1; + set.__bits[signum >> 5] &= ~(1 << signum: u32); +}; + +export fn sigismember(set: *sigset, signum: int) (bool | errno) = { + if (signum < 1 || signum > NSIG) { + return EINVAL; + }; + signum -= 1; + return (set.__bits[signum >> 5] & (1 << signum: u32)) != 0; +}; + +export fn sigfillset(set: *sigset) (void | errno) = { + for (let i = 0z; i < len(set.__bits); i += 1) { + set.__bits[i] = ~0u32; + }; +}; + +// Test sigset operations do not fail for valid signal numbers. +@test fn sigset_valid_signum() void = { + let set: sigset = sigset { ... }; + sigemptyset(&set); + + assert(!(sigismember(&set, 1) is errno), "Unexpected error"); + assert(!(sigismember(&set, 15) is errno), "Unexpected error"); + assert(!(sigismember(&set, NSIG) is errno), "Unexpected error"); + + assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); + assert(!(sigaddset(&set, 15) is errno), "Unexpected error"); + assert(!(sigaddset(&set, NSIG) is errno), "Unexpected error"); + + // It's ok to add a signal that is already present in the set. + assert(!(sigaddset(&set, 1) is errno), "Unexpected error"); + + assert(!(sigdelset(&set, 1) is errno), "Unexpected error"); + assert(!(sigdelset(&set, 15) is errno), "Unexpected error"); + assert(!(sigdelset(&set, NSIG) is errno), "Unexpected error"); + + // It's ok to delete a signal that is not present in the set. + assert(!(sigdelset(&set, 10) is errno), "Unexpected error"); +}; + +// Test sigset operations fail for invalid signal numbers. +@test fn sigset_invalid_signum() void = { + let set: sigset = sigset { ... }; + sigemptyset(&set); + + assert(sigismember(&set, -1) is errno, "Expected error"); + assert(sigismember(&set, 0) is errno, "Expected error"); + assert(sigismember(&set, NSIG + 1) is errno, "Expected error"); + + assert(sigaddset(&set, -1) is errno, "Expected error"); + assert(sigaddset(&set, 0) is errno, "Expected error"); + assert(sigaddset(&set, NSIG + 1) is errno, "Expected error"); + + assert(sigdelset(&set, -1) is errno, "Expected error"); + assert(sigdelset(&set, 0) is errno, "Expected error"); + assert(sigdelset(&set, NSIG + 1) is errno, "Expected error"); +}; diff --git a/rt/+netbsd/socket.ha b/rt/+netbsd/socket.ha @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +export type sa_family_t = u8; +export type socklen_t = u32; + +export type in_addr = struct { + s_addr: u32 +}; + +export type sockaddr_in = struct { + sin_len: u8, + sin_family: sa_family_t, + sin_port: u16, + sin_addr: in_addr, + __pad: [8]u8, +}; + +export type in6_addr = struct { + union { + s6_addr: [16]u8, + s6_addr16: [8]u16, + s6_addr32: [4]u32, + } +}; + +export type sockaddr_in6 = struct { + sin6_len: u8, + sin6_family: sa_family_t, + sin6_port: u16, + sin6_flowinfo: u32, + sin6_addr: in6_addr, + sin6_scope_id: u32, +}; + +export def UNIX_PATH_MAX: size = 104; + +export type sockaddr_un = struct { + sun_len: u8, + sun_family: sa_family_t, + sun_path: [UNIX_PATH_MAX]u8, +}; + +export type sockaddr = struct { + union { + in: sockaddr_in, + in6: sockaddr_in6, + un: sockaddr_un, + }, +}; + +export def SCM_RIGHTS: int = 0x01; +export def SCM_CREDENTIALS: int = 0x02; + +export type msghdr = struct { + msg_name: nullable *opaque, + msg_namelen: socklen_t, + + msg_iov: nullable *[*]iovec, + msg_iovlen: int, + + msg_control: nullable *opaque, + msg_controllen: socklen_t, + + msg_flags: int +}; + +export type cmsghdr = struct { + cmsg_len: socklen_t, + cmsg_level: int, + cmsg_type: int, +}; + +export type cmsg = struct { + hdr: cmsghdr, + cmsg_data: [*]u8, +}; + +export def AF_UNSPEC: sa_family_t = 0; +export def AF_UNIX: sa_family_t = 1; +export def AF_LOCAL: sa_family_t = AF_UNIX; +export def AF_INET: sa_family_t = 2; +export def AF_IMPLINK: sa_family_t = 3; +export def AF_PUP: sa_family_t = 4; +export def AF_CHAOS: sa_family_t = 5; +export def AF_NETBIOS: sa_family_t = 6; +export def AF_ISO: sa_family_t = 7; +export def AF_OSI: sa_family_t = AF_ISO; +export def AF_ECMA: sa_family_t = 8; +export def AF_DATAKIT: sa_family_t = 9; +export def AF_CCITT: sa_family_t = 10; +export def AF_SNA: sa_family_t = 11; +export def AF_DECnet: sa_family_t = 12; +export def AF_DLI: sa_family_t = 13; +export def AF_LAT: sa_family_t = 14; +export def AF_HYLINK: sa_family_t = 15; +export def AF_APPLETALK: sa_family_t = 16; +export def AF_ROUTE: sa_family_t = 17; +export def AF_LINK: sa_family_t = 18; +export def pseudo_AF_XTP: sa_family_t = 19; +export def AF_COIP: sa_family_t = 20; +export def AF_CNT: sa_family_t = 21; +export def pseudo_AF_RTIP: sa_family_t = 22; +export def AF_IPX: sa_family_t = 23; +export def AF_SIP: sa_family_t = 24; +export def pseudo_AF_PIP: sa_family_t = 25; +export def AF_ISDN: sa_family_t = 26; +export def AF_E164: sa_family_t = AF_ISDN; +export def AF_INET6: sa_family_t = 28; +export def AF_NATM: sa_family_t = 29; +export def AF_ATM: sa_family_t = 30; +export def AF_NETGRAPH: sa_family_t = 32; +export def AF_SLOW: sa_family_t = 33; +export def AF_SCLUSTER: sa_family_t = 34; +export def AF_ARP: sa_family_t = 35; +export def AF_BLUETOOTH: sa_family_t = 36; +export def AF_IEEE80211: sa_family_t = 37; +export def AF_INET_SDP: sa_family_t = 40; +export def AF_INET6_SDP: sa_family_t = 42; +export def AF_HYPERV: sa_family_t = 43; +export def AF_MAX: sa_family_t = 43; +export def AF_VENDOR00: sa_family_t = 39; +export def AF_VENDOR01: sa_family_t = 41; +export def AF_VENDOR03: sa_family_t = 45; +export def AF_VENDOR04: sa_family_t = 47; +export def AF_VENDOR05: sa_family_t = 49; +export def AF_VENDOR06: sa_family_t = 51; +export def AF_VENDOR07: sa_family_t = 53; +export def AF_VENDOR08: sa_family_t = 55; +export def AF_VENDOR09: sa_family_t = 57; +export def AF_VENDOR10: sa_family_t = 59; +export def AF_VENDOR11: sa_family_t = 61; +export def AF_VENDOR12: sa_family_t = 63; +export def AF_VENDOR13: sa_family_t = 65; +export def AF_VENDOR14: sa_family_t = 67; +export def AF_VENDOR15: sa_family_t = 69; +export def AF_VENDOR16: sa_family_t = 71; +export def AF_VENDOR17: sa_family_t = 73; +export def AF_VENDOR18: sa_family_t = 75; +export def AF_VENDOR19: sa_family_t = 77; +export def AF_VENDOR20: sa_family_t = 79; +export def AF_VENDOR21: sa_family_t = 81; +export def AF_VENDOR22: sa_family_t = 83; +export def AF_VENDOR23: sa_family_t = 85; +export def AF_VENDOR24: sa_family_t = 87; +export def AF_VENDOR25: sa_family_t = 89; +export def AF_VENDOR26: sa_family_t = 91; +export def AF_VENDOR27: sa_family_t = 93; +export def AF_VENDOR28: sa_family_t = 95; +export def AF_VENDOR29: sa_family_t = 97; +export def AF_VENDOR30: sa_family_t = 99; +export def AF_VENDOR31: sa_family_t = 101; +export def AF_VENDOR32: sa_family_t = 103; +export def AF_VENDOR33: sa_family_t = 105; +export def AF_VENDOR34: sa_family_t = 107; +export def AF_VENDOR35: sa_family_t = 109; +export def AF_VENDOR36: sa_family_t = 111; +export def AF_VENDOR37: sa_family_t = 113; +export def AF_VENDOR38: sa_family_t = 115; +export def AF_VENDOR39: sa_family_t = 117; +export def AF_VENDOR40: sa_family_t = 119; +export def AF_VENDOR41: sa_family_t = 121; +export def AF_VENDOR42: sa_family_t = 123; +export def AF_VENDOR43: sa_family_t = 125; +export def AF_VENDOR44: sa_family_t = 127; +export def AF_VENDOR45: sa_family_t = 129; +export def AF_VENDOR46: sa_family_t = 131; +export def AF_VENDOR47: sa_family_t = 133; + +export def SOCK_STREAM: int = 1; +export def SOCK_DGRAM: int = 2; +export def SOCK_RAW: int = 3; +export def SOCK_RDM: int = 4; +export def SOCK_SEQPACKET: int = 5; +export def SOCK_CLOEXEC: int = 0x10000000; +export def SOCK_NONBLOCK: int = 0x20000000; + +export def IPPROTO_IP: int = 0; +export def IPPROTO_ICMP: int = 1; +export def IPPROTO_TCP: int = 6; +export def IPPROTO_UDP: int = 17; +export def IPPROTO_IPV6: int = 41; +export def IPPROTO_RAW: int = 255; +export def IPPROTO_HOPOPTS: int = 0; +export def IPPROTO_IGMP: int = 2; +export def IPPROTO_GGP: int = 3; +export def IPPROTO_IPV4: int = 4; +export def IPPROTO_IPIP: int = IPPROTO_IPV4; +export def IPPROTO_ST: int = 7; +export def IPPROTO_EGP: int = 8; +export def IPPROTO_PIGP: int = 9; +export def IPPROTO_RCCMON: int = 10; +export def IPPROTO_NVPII: int = 11; +export def IPPROTO_PUP: int = 12; +export def IPPROTO_ARGUS: int = 13; +export def IPPROTO_EMCON: int = 14; +export def IPPROTO_XNET: int = 15; +export def IPPROTO_CHAOS: int = 16; +export def IPPROTO_MUX: int = 18; +export def IPPROTO_MEAS: int = 19; +export def IPPROTO_HMP: int = 20; +export def IPPROTO_PRM: int = 21; +export def IPPROTO_IDP: int = 22; +export def IPPROTO_TRUNK1: int = 23; +export def IPPROTO_TRUNK2: int = 24; +export def IPPROTO_LEAF1: int = 25; +export def IPPROTO_LEAF2: int = 26; +export def IPPROTO_RDP: int = 27; +export def IPPROTO_IRTP: int = 28; +export def IPPROTO_TP: int = 29; +export def IPPROTO_BLT: int = 30; +export def IPPROTO_NSP: int = 31; +export def IPPROTO_INP: int = 32; +export def IPPROTO_DCCP: int = 33; +export def IPPROTO_3PC: int = 34; +export def IPPROTO_IDPR: int = 35; +export def IPPROTO_XTP: int = 36; +export def IPPROTO_DDP: int = 37; +export def IPPROTO_CMTP: int = 38; +export def IPPROTO_TPXX: int = 39; +export def IPPROTO_IL: int = 40; +export def IPPROTO_SDRP: int = 42; +export def IPPROTO_ROUTING: int = 43; +export def IPPROTO_FRAGMENT: int = 44; +export def IPPROTO_IDRP: int = 45; +export def IPPROTO_RSVP: int = 46; +export def IPPROTO_GRE: int = 47; +export def IPPROTO_MHRP: int = 48; +export def IPPROTO_BHA: int = 49; +export def IPPROTO_ESP: int = 50; +export def IPPROTO_AH: int = 51; +export def IPPROTO_INLSP: int = 52; +export def IPPROTO_SWIPE: int = 53; +export def IPPROTO_NHRP: int = 54; +export def IPPROTO_MOBILE: int = 55; +export def IPPROTO_TLSP: int = 56; +export def IPPROTO_SKIP: int = 57; +export def IPPROTO_ICMPV6: int = 58; +export def IPPROTO_NONE: int = 59; +export def IPPROTO_DSTOPTS: int = 60; +export def IPPROTO_AHIP: int = 61; +export def IPPROTO_CFTP: int = 62; +export def IPPROTO_HELLO: int = 63; +export def IPPROTO_SATEXPAK: int = 64; +export def IPPROTO_KRYPTOLAN: int = 65; +export def IPPROTO_RVD: int = 66; +export def IPPROTO_IPPC: int = 67; +export def IPPROTO_ADFS: int = 68; +export def IPPROTO_SATMON: int = 69; +export def IPPROTO_VISA: int = 70; +export def IPPROTO_IPCV: int = 71; +export def IPPROTO_CPNX: int = 72; +export def IPPROTO_CPHB: int = 73; +export def IPPROTO_WSN: int = 74; +export def IPPROTO_PVP: int = 75; +export def IPPROTO_BRSATMON: int = 76; +export def IPPROTO_ND: int = 77; +export def IPPROTO_WBMON: int = 78; +export def IPPROTO_WBEXPAK: int = 79; +export def IPPROTO_EON: int = 80; +export def IPPROTO_VMTP: int = 81; +export def IPPROTO_SVMTP: int = 82; +export def IPPROTO_VINES: int = 83; +export def IPPROTO_TTP: int = 84; +export def IPPROTO_IGP: int = 85; +export def IPPROTO_DGP: int = 86; +export def IPPROTO_TCF: int = 87; +export def IPPROTO_IGRP: int = 88; +export def IPPROTO_OSPFIGP: int = 89; +export def IPPROTO_SRPC: int = 90; +export def IPPROTO_LARP: int = 91; +export def IPPROTO_MTP: int = 92; +export def IPPROTO_AX25: int = 93; +export def IPPROTO_IPEIP: int = 94; +export def IPPROTO_MICP: int = 95; +export def IPPROTO_SCCSP: int = 96; +export def IPPROTO_ETHERIP: int = 97; +export def IPPROTO_ENCAP: int = 98; +export def IPPROTO_APES: int = 99; +export def IPPROTO_GMTP: int = 100; +export def IPPROTO_IPCOMP: int = 108; +export def IPPROTO_SCTP: int = 132; +export def IPPROTO_MH: int = 135; +export def IPPROTO_UDPLITE: int = 136; +export def IPPROTO_HIP: int = 139; +export def IPPROTO_SHIM6: int = 140; +export def IPPROTO_PIM: int = 103; +export def IPPROTO_CARP: int = 112; +export def IPPROTO_PGM: int = 113; +export def IPPROTO_MPLS: int = 137; +export def IPPROTO_PFSYNC: int = 240; +export def IPPROTO_RESERVED_253: int = 253; +export def IPPROTO_RESERVED_254: int = 254; + +export def MSG_OOB: int = 0x00000001; +export def MSG_PEEK: int = 0x00000002; +export def MSG_DONTROUTE: int = 0x00000004; +export def MSG_EOR: int = 0x00000008; +export def MSG_TRUNC: int = 0x00000010; +export def MSG_CTRUNC: int = 0x00000020; +export def MSG_WAITALL: int = 0x00000040; +export def MSG_DONTWAIT: int = 0x00000080; +export def MSG_EOF: int = 0x00000100; +export def MSG_NOTIFICATION: int = 0x00002000; +export def MSG_NBIO: int = 0x00004000; +export def MSG_COMPAT: int = 0x00008000; +export def MSG_NOSIGNAL: int = 0x00020000; +export def MSG_CMSG_CLOEXEC: int = 0x00040000; +export def MSG_WAITFORONE: int = 0x00080000; + +export def SO_DEBUG: int = 0x00000001; +export def SO_ACCEPTCONN: int = 0x00000002; +export def SO_REUSEADDR: int = 0x00000004; +export def SO_KEEPALIVE: int = 0x00000008; +export def SO_DONTROUTE: int = 0x00000010; +export def SO_BROADCAST: int = 0x00000020; +export def SO_USELOOPBACK: int = 0x00000040; +export def SO_LINGER: int = 0x00000080; +export def SO_OOBINLINE: int = 0x00000100; +export def SO_REUSEPORT: int = 0x00000200; +export def SO_TIMESTAMP: int = 0x00000400; +export def SO_NOSIGPIPE: int = 0x00000800; +export def SO_ACCEPTFILTER: int = 0x00001000; +export def SO_BINTIME: int = 0x00002000; +export def SO_NO_OFFLOAD: int = 0x00004000; +export def SO_NO_DDP: int = 0x00008000; +export def SO_REUSEPORT_LB: int = 0x00010000; +export def SO_SNDBUF: int = 0x1001; +export def SO_RCVBUF: int = 0x1002; +export def SO_SNDLOWAT: int = 0x1003; +export def SO_RCVLOWAT: int = 0x1004; +export def SO_SNDTIMEO: int = 0x1005; +export def SO_RCVTIMEO: int = 0x1006; +export def SO_ERROR: int = 0x1007; +export def SO_TYPE: int = 0x1008; +export def SO_LABEL: int = 0x1009; +export def SO_PEERLABEL: int = 0x1010; +export def SO_LISTENQLIMIT: int = 0x1011; +export def SO_LISTENQLEN: int = 0x1012; +export def SO_LISTENINCQLEN: int = 0x1013; +export def SO_SETFIB: int = 0x1014; +export def SO_USER_COOKIE: int = 0x1015; +export def SO_PROTOCOL: int = 0x1016; +export def SO_PROTOTYPE: int = SO_PROTOCOL; +export def SO_TS_CLOCK: int = 0x1017; +export def SO_MAX_PACING_RATE: int = 0x1018; +export def SO_DOMAIN: int = 0x1019; +export def SO_TS_REALTIME_MICRO: int = 0; +export def SO_TS_BINTIME: int = 1; +export def SO_TS_REALTIME: int = 2; +export def SO_TS_MONOTONIC: int = 3; +export def SO_TS_DEFAULT: int = SO_TS_REALTIME_MICRO; +export def SO_TS_CLOCK_MAX: int = SO_TS_MONOTONIC; + +export def SOL_SOCKET: int = 0xffff; diff --git a/rt/+netbsd/start+test.ha b/rt/+netbsd/start+test.ha @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +@symbol("__test_main") fn test_main() size; + +const @symbol("__init_array_start") init_start: [*]*fn() void; +const @symbol("__init_array_end") init_end: [*]*fn() void; +const @symbol("__fini_array_start") fini_start: [*]*fn() void; +const @symbol("__fini_array_end") fini_end: [*]*fn() void; + +export fn start_ha() never = { + init(); + const nfail = test_main(); + fini(); + exit(if (nfail > 0) 1 else 0); +}; diff --git a/rt/+netbsd/start+x86_64-libc.s b/rt/+netbsd/start+x86_64-libc.s @@ -0,0 +1,16 @@ +.section ".note.netbsd.ident", "a" + .long 2f-1f + .long 4f-3f + .long 1 +1: .asciz "NetBSD" +2: .p2align 2 +3: .long 199905 +4: .p2align 2 + +.text +.global _start +_start: + xor %rbp, %rbp + movq %rsp, %rdi + and $-16, %rsp + call rt.start_netbsd diff --git a/rt/+netbsd/start.ha b/rt/+netbsd/start.ha @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +@symbol("main") fn main() void; + +const @symbol("__init_array_start") init_start: [*]*fn() void; +const @symbol("__init_array_end") init_end: [*]*fn() void; +const @symbol("__fini_array_start") fini_start: [*]*fn() void; +const @symbol("__fini_array_end") fini_end: [*]*fn() void; + +export fn start_ha() never = { + init(); + main(); + fini(); + exit(0); +}; diff --git a/rt/+netbsd/syscall+x86_64.s b/rt/+netbsd/syscall+x86_64.s @@ -0,0 +1,81 @@ +.section .text +error: + neg %rax + ret + +.section .text.rt.syscall0 +.global rt.syscall0 +rt.syscall0: + movq %rdi, %rax + syscall + jc error + ret + +.section .text.rt.syscall1 +.global rt.syscall1 +rt.syscall1: + movq %rdi, %rax + movq %rsi, %rdi + syscall + jc error + ret + +.section .text.rt.syscall2 +.global rt.syscall2 +rt.syscall2: + movq %rdi, %rax + movq %rsi, %rdi + movq %rdx, %rsi + syscall + jc error + ret + +.section .text.rt.syscall3 +.global rt.syscall3 +rt.syscall3: + movq %rdi, %rax + movq %rsi, %rdi + movq %rdx, %rsi + movq %rcx, %rdx + syscall + jc error + ret + +.section .text.rt.syscall4 +.global rt.syscall4 +rt.syscall4: + movq %rdi, %rax + movq %r8, %r10 + movq %rsi, %rdi + movq %rdx, %rsi + movq %rcx, %rdx + syscall + jc error + ret + +.section .text.rt.syscall5 +.global rt.syscall5 +rt.syscall5: + movq %rdi, %rax + movq %r8, %r10 + movq %rsi, %rdi + movq %r9, %r8 + movq %rdx, %rsi + movq %rcx, %rdx + syscall + jc error + ret + +.section .text.rt.syscall6 +.global rt.syscall6 +rt.syscall6: + movq %rdi, %rax + movq %r8, %r10 + movq %rsi, %rdi + movq %r9, %r8 + movq %rdx, %rsi + movq 8(%rsp), %r9 + movq %rcx, %rdx + syscall + jc error + ret diff --git a/rt/+netbsd/syscallno.ha b/rt/+netbsd/syscallno.ha @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +export def SYS_syscall: u64 = 0; +export def SYS_exit: u64 = 1; +export def SYS_fork: u64 = 2; +export def SYS_read: u64 = 3; +export def SYS_write: u64 = 4; +export def SYS_open: u64 = 5; +export def SYS_close: u64 = 6; +export def SYS_compat_50_wait4: u64 = 7; +export def SYS_compat_43_ocreat: u64 = 8; +export def SYS_link: u64 = 9; +export def SYS_unlink: u64 = 10; +export def SYS_chdir: u64 = 12; +export def SYS_fchdir: u64 = 13; +export def SYS_compat_50_mknod: u64 = 14; +export def SYS_chmod: u64 = 15; +export def SYS_chown: u64 = 16; +export def SYS_break: u64 = 17; +export def SYS_compat_20_getfsstat: u64 = 18; +export def SYS_compat_43_olseek: u64 = 19; +export def SYS_getpid: u64 = 20; +export def SYS_compat_40_mount: u64 = 21; +export def SYS_unmount: u64 = 22; +export def SYS_setuid: u64 = 23; +export def SYS_getuid: u64 = 24; +export def SYS_geteuid: u64 = 25; +export def SYS_ptrace: u64 = 26; +export def SYS_recvmsg: u64 = 27; +export def SYS_sendmsg: u64 = 28; +export def SYS_recvfrom: u64 = 29; +export def SYS_accept: u64 = 30; +export def SYS_getpeername: u64 = 31; +export def SYS_getsockname: u64 = 32; +export def SYS_access: u64 = 33; +export def SYS_chflags: u64 = 34; +export def SYS_fchflags: u64 = 35; +export def SYS_sync: u64 = 36; +export def SYS_kill: u64 = 37; +export def SYS_compat_43_stat43: u64 = 38; +export def SYS_getppid: u64 = 39; +export def SYS_compat_43_lstat43: u64 = 40; +export def SYS_dup: u64 = 41; +export def SYS_pipe: u64 = 42; +export def SYS_getegid: u64 = 43; +export def SYS_profil: u64 = 44; +export def SYS_ktrace: u64 = 45; +export def SYS_compat_13_sigaction13: u64 = 46; +export def SYS_getgid: u64 = 47; +export def SYS_compat_13_sigprocmask13: u64 = 48; +export def SYS___getlogin: u64 = 49; +export def SYS___setlogin: u64 = 50; +export def SYS_acct: u64 = 51; +export def SYS_compat_13_sigpending13: u64 = 52; +export def SYS_compat_13_sigaltstack13: u64 = 53; +export def SYS_ioctl: u64 = 54; +export def SYS_compat_12_oreboot: u64 = 55; +export def SYS_revoke: u64 = 56; +export def SYS_symlink: u64 = 57; +export def SYS_readlink: u64 = 58; +export def SYS_execve: u64 = 59; +export def SYS_umask: u64 = 60; +export def SYS_chroot: u64 = 61; +export def SYS_compat_43_fstat43: u64 = 62; +export def SYS_compat_43_ogetkerninfo: u64 = 63; +export def SYS_compat_43_ogetpagesize: u64 = 64; +export def SYS_compat_12_msync: u64 = 65; +export def SYS_vfork: u64 = 66; +export def SYS_compat_43_ommap: u64 = 71; +export def SYS_vadvise: u64 = 72; +export def SYS_munmap: u64 = 73; +export def SYS_mprotect: u64 = 74; +export def SYS_madvise: u64 = 75; +export def SYS_mincore: u64 = 78; +export def SYS_getgroups: u64 = 79; +export def SYS_setgroups: u64 = 80; +export def SYS_getpgrp: u64 = 81; +export def SYS_setpgid: u64 = 82; +export def SYS_compat_50_setitimer: u64 = 83; +export def SYS_compat_43_owait: u64 = 84; +export def SYS_compat_12_oswapon: u64 = 85; +export def SYS_compat_50_getitimer: u64 = 86; +export def SYS_compat_43_ogethostname: u64 = 87; +export def SYS_compat_43_osethostname: u64 = 88; +export def SYS_compat_43_ogetdtablesize: u64 = 89; +export def SYS_dup2: u64 = 90; +export def SYS_getrandom: u64 = 91; +export def SYS_fcntl: u64 = 92; +export def SYS_compat_50_select: u64 = 93; +export def SYS_fsync: u64 = 95; +export def SYS_setpriority: u64 = 96; +export def SYS_compat_30_socket: u64 = 97; +export def SYS_connect: u64 = 98; +export def SYS_compat_43_oaccept: u64 = 99; +export def SYS_getpriority: u64 = 100; +export def SYS_compat_43_osend: u64 = 101; +export def SYS_compat_43_orecv: u64 = 102; +export def SYS_compat_13_sigreturn13: u64 = 103; +export def SYS_bind: u64 = 104; +export def SYS_setsockopt: u64 = 105; +export def SYS_listen: u64 = 106; +export def SYS_compat_43_osigvec: u64 = 108; +export def SYS_compat_43_osigblock: u64 = 109; +export def SYS_compat_43_osigsetmask: u64 = 110; +export def SYS_compat_13_sigsuspend13: u64 = 111; +export def SYS_compat_43_osigstack: u64 = 112; +export def SYS_compat_43_orecvmsg: u64 = 113; +export def SYS_compat_43_osendmsg: u64 = 114; +export def SYS_compat_50_gettimeofday: u64 = 116; +export def SYS_compat_50_getrusage: u64 = 117; +export def SYS_getsockopt: u64 = 118; +export def SYS_readv: u64 = 120; +export def SYS_writev: u64 = 121; +export def SYS_compat_50_settimeofday: u64 = 122; +export def SYS_fchown: u64 = 123; +export def SYS_fchmod: u64 = 124; +export def SYS_compat_43_orecvfrom: u64 = 125; +export def SYS_rename: u64 = 128; +export def SYS_compat_43_otruncate: u64 = 129; +export def SYS_compat_43_oftruncate: u64 = 130; +export def SYS_flock: u64 = 131; +export def SYS_mkfifo: u64 = 132; +export def SYS_sendto: u64 = 133; +export def SYS_shutdown: u64 = 134; +export def SYS_socketpair: u64 = 135; +export def SYS_mkdir: u64 = 136; +export def SYS_rmdir: u64 = 137; +export def SYS_compat_50_utimes: u64 = 138; +export def SYS_compat_50_adjtime: u64 = 140; +export def SYS_compat_43_ogetpeername: u64 = 141; +export def SYS_compat_43_ogethostid: u64 = 142; +export def SYS_compat_43_osethostid: u64 = 143; +export def SYS_compat_43_ogetrlimit: u64 = 144; +export def SYS_compat_43_osetrlimit: u64 = 145; +export def SYS_compat_43_okillpg: u64 = 146; +export def SYS_setsid: u64 = 147; +export def SYS_compat_50_quotactl: u64 = 148; +export def SYS_compat_43_oquota: u64 = 149; +export def SYS_compat_43_ogetsockname: u64 = 150; +export def SYS_nfssvc: u64 = 155; +export def SYS_compat_43_ogetdirentries: u64 = 156; +export def SYS_compat_20_statfs: u64 = 157; +export def SYS_compat_20_fstatfs: u64 = 158; +export def SYS_compat_30_getfh: u64 = 161; +export def SYS_compat_09_ogetdomainname: u64 = 162; +export def SYS_compat_09_osetdomainname: u64 = 163; +export def SYS_compat_09_ouname: u64 = 164; +export def SYS_sysarch: u64 = 165; +export def SYS_compat_10_osemsys: u64 = 169; +export def SYS_compat_10_omsgsys: u64 = 170; +export def SYS_compat_10_oshmsys: u64 = 171; +export def SYS_pread: u64 = 173; +export def SYS_pwrite: u64 = 174; +export def SYS_compat_30_ntp_gettime: u64 = 175; +export def SYS_ntp_adjtime: u64 = 176; +export def SYS_setgid: u64 = 181; +export def SYS_setegid: u64 = 182; +export def SYS_seteuid: u64 = 183; +export def SYS_lfs_bmapv: u64 = 184; +export def SYS_lfs_markv: u64 = 185; +export def SYS_lfs_segclean: u64 = 186; +export def SYS_compat_50_lfs_segwait: u64 = 187; +export def SYS_compat_12_stat12: u64 = 188; +export def SYS_compat_12_fstat12: u64 = 189; +export def SYS_compat_12_lstat12: u64 = 190; +export def SYS_pathconf: u64 = 191; +export def SYS_fpathconf: u64 = 192; +export def SYS_getsockopt2: u64 = 193; +export def SYS_getrlimit: u64 = 194; +export def SYS_setrlimit: u64 = 195; +export def SYS_compat_12_getdirentries: u64 = 196; +export def SYS_mmap: u64 = 197; +export def SYS___syscall: u64 = 198; +export def SYS_lseek: u64 = 199; +export def SYS_truncate: u64 = 200; +export def SYS_ftruncate: u64 = 201; +export def SYS___sysctl: u64 = 202; +export def SYS_mlock: u64 = 203; +export def SYS_munlock: u64 = 204; +export def SYS_undelete: u64 = 205; +export def SYS_compat_50_futimes: u64 = 206; +export def SYS_getpgid: u64 = 207; +export def SYS_reboot: u64 = 208; +export def SYS_poll: u64 = 209; +export def SYS_afssys: u64 = 210; +export def SYS_compat_14___semctl: u64 = 220; +export def SYS_semget: u64 = 221; +export def SYS_semop: u64 = 222; +export def SYS_semconfig: u64 = 223; +export def SYS_compat_14_msgctl: u64 = 224; +export def SYS_msgget: u64 = 225; +export def SYS_msgsnd: u64 = 226; +export def SYS_msgrcv: u64 = 227; +export def SYS_shmat: u64 = 228; +export def SYS_compat_14_shmctl: u64 = 229; +export def SYS_shmdt: u64 = 230; +export def SYS_shmget: u64 = 231; +export def SYS_compat_50_clock_gettime: u64 = 232; +export def SYS_compat_50_clock_settime: u64 = 233; +export def SYS_compat_50_clock_getres: u64 = 234; +export def SYS_timer_create: u64 = 235; +export def SYS_timer_delete: u64 = 236; +export def SYS_compat_50_timer_settime: u64 = 237; +export def SYS_compat_50_timer_gettime: u64 = 238; +export def SYS_timer_getoverrun: u64 = 239; +export def SYS_compat_50_nanosleep: u64 = 240; +export def SYS_fdatasync: u64 = 241; +export def SYS_mlockall: u64 = 242; +export def SYS_munlockall: u64 = 243; +export def SYS_compat_50___sigtimedwait: u64 = 244; +export def SYS_sigqueueinfo: u64 = 245; +export def SYS_modctl: u64 = 246; +export def SYS__ksem_init: u64 = 247; +export def SYS__ksem_open: u64 = 248; +export def SYS__ksem_unlink: u64 = 249; +export def SYS__ksem_close: u64 = 250; +export def SYS__ksem_post: u64 = 251; +export def SYS__ksem_wait: u64 = 252; +export def SYS__ksem_trywait: u64 = 253; +export def SYS__ksem_getvalue: u64 = 254; +export def SYS__ksem_destroy: u64 = 255; +export def SYS__ksem_timedwait: u64 = 256; +export def SYS_mq_open: u64 = 257; +export def SYS_mq_close: u64 = 258; +export def SYS_mq_unlink: u64 = 259; +export def SYS_mq_getattr: u64 = 260; +export def SYS_mq_setattr: u64 = 261; +export def SYS_mq_notify: u64 = 262; +export def SYS_mq_send: u64 = 263; +export def SYS_mq_receive: u64 = 264; +export def SYS_compat_50_mq_timedsend: u64 = 265; +export def SYS_compat_50_mq_timedreceive: u64 = 266; +export def SYS___posix_rename: u64 = 270; +export def SYS_swapctl: u64 = 271; +export def SYS_compat_30_getdents: u64 = 272; +export def SYS_minherit: u64 = 273; +export def SYS_lchmod: u64 = 274; +export def SYS_lchown: u64 = 275; +export def SYS_compat_50_lutimes: u64 = 276; +export def SYS___msync13: u64 = 277; +export def SYS_compat_30___stat13: u64 = 278; +export def SYS_compat_30___fstat13: u64 = 279; +export def SYS_compat_30___lstat13: u64 = 280; +export def SYS___sigaltstack14: u64 = 281; +export def SYS___vfork14: u64 = 282; +export def SYS___posix_chown: u64 = 283; +export def SYS___posix_fchown: u64 = 284; +export def SYS___posix_lchown: u64 = 285; +export def SYS_getsid: u64 = 286; +export def SYS___clone: u64 = 287; +export def SYS_fktrace: u64 = 288; +export def SYS_preadv: u64 = 289; +export def SYS_pwritev: u64 = 290; +export def SYS_compat_16___sigaction14: u64 = 291; +export def SYS___sigpending14: u64 = 292; +export def SYS___sigprocmask14: u64 = 293; +export def SYS___sigsuspend14: u64 = 294; +export def SYS_compat_16___sigreturn14: u64 = 295; +export def SYS___getcwd: u64 = 296; +export def SYS_fchroot: u64 = 297; +export def SYS_compat_30_fhopen: u64 = 298; +export def SYS_compat_30_fhstat: u64 = 299; +export def SYS_compat_20_fhstatfs: u64 = 300; +export def SYS_compat_50_____semctl13: u64 = 301; +export def SYS_compat_50___msgctl13: u64 = 302; +export def SYS_compat_50___shmctl13: u64 = 303; +export def SYS_lchflags: u64 = 304; +export def SYS_issetugid: u64 = 305; +export def SYS_utrace: u64 = 306; +export def SYS_getcontext: u64 = 307; +export def SYS_setcontext: u64 = 308; +export def SYS__lwp_create: u64 = 309; +export def SYS__lwp_exit: u64 = 310; +export def SYS__lwp_self: u64 = 311; +export def SYS__lwp_wait: u64 = 312; +export def SYS__lwp_suspend: u64 = 313; +export def SYS__lwp_continue: u64 = 314; +export def SYS__lwp_wakeup: u64 = 315; +export def SYS__lwp_getprivate: u64 = 316; +export def SYS__lwp_setprivate: u64 = 317; +export def SYS__lwp_kill: u64 = 318; +export def SYS__lwp_detach: u64 = 319; +export def SYS_compat_50__lwp_park: u64 = 320; +export def SYS__lwp_unpark: u64 = 321; +export def SYS__lwp_unpark_all: u64 = 322; +export def SYS__lwp_setname: u64 = 323; +export def SYS__lwp_getname: u64 = 324; +export def SYS__lwp_ctl: u64 = 325; +export def SYS_compat_60_sa_register: u64 = 330; +export def SYS_compat_60_sa_stacks: u64 = 331; +export def SYS_compat_60_sa_enable: u64 = 332; +export def SYS_compat_60_sa_setconcurrency: u64 = 333; +export def SYS_compat_60_sa_yield: u64 = 334; +export def SYS_compat_60_sa_preempt: u64 = 335; +export def SYS___sigaction_sigtramp: u64 = 340; +export def SYS_rasctl: u64 = 343; +export def SYS_kqueue: u64 = 344; +export def SYS_compat_50_kevent: u64 = 345; +export def SYS__sched_setparam: u64 = 346; +export def SYS__sched_getparam: u64 = 347; +export def SYS__sched_setaffinity: u64 = 348; +export def SYS__sched_getaffinity: u64 = 349; +export def SYS_sched_yield: u64 = 350; +export def SYS__sched_protect: u64 = 351; +export def SYS_fsync_range: u64 = 354; +export def SYS_uuidgen: u64 = 355; +export def SYS_getvfsstat: u64 = 356; +export def SYS_statvfs1: u64 = 357; +export def SYS_fstatvfs1: u64 = 358; +export def SYS_compat_30_fhstatvfs1: u64 = 359; +export def SYS_extattrctl: u64 = 360; +export def SYS_extattr_set_file: u64 = 361; +export def SYS_extattr_get_file: u64 = 362; +export def SYS_extattr_delete_file: u64 = 363; +export def SYS_extattr_set_fd: u64 = 364; +export def SYS_extattr_get_fd: u64 = 365; +export def SYS_extattr_delete_fd: u64 = 366; +export def SYS_extattr_set_link: u64 = 367; +export def SYS_extattr_get_link: u64 = 368; +export def SYS_extattr_delete_link: u64 = 369; +export def SYS_extattr_list_fd: u64 = 370; +export def SYS_extattr_list_file: u64 = 371; +export def SYS_extattr_list_link: u64 = 372; +export def SYS_compat_50_pselect: u64 = 373; +export def SYS_compat_50_pollts: u64 = 374; +export def SYS_setxattr: u64 = 375; +export def SYS_lsetxattr: u64 = 376; +export def SYS_fsetxattr: u64 = 377; +export def SYS_getxattr: u64 = 378; +export def SYS_lgetxattr: u64 = 379; +export def SYS_fgetxattr: u64 = 380; +export def SYS_listxattr: u64 = 381; +export def SYS_llistxattr: u64 = 382; +export def SYS_flistxattr: u64 = 383; +export def SYS_removexattr: u64 = 384; +export def SYS_lremovexattr: u64 = 385; +export def SYS_fremovexattr: u64 = 386; +export def SYS_compat_50___stat30: u64 = 387; +export def SYS_compat_50___fstat30: u64 = 388; +export def SYS_compat_50___lstat30: u64 = 389; +export def SYS___getdents30: u64 = 390; +export def SYS_compat_30___fhstat30: u64 = 392; +export def SYS_compat_50___ntp_gettime30: u64 = 393; +export def SYS___socket30: u64 = 394; +export def SYS___getfh30: u64 = 395; +export def SYS___fhopen40: u64 = 396; +export def SYS___fhstatvfs140: u64 = 397; +export def SYS_compat_50___fhstat40: u64 = 398; +export def SYS_aio_cancel: u64 = 399; +export def SYS_aio_error: u64 = 400; +export def SYS_aio_fsync: u64 = 401; +export def SYS_aio_read: u64 = 402; +export def SYS_aio_return: u64 = 403; +export def SYS_compat_50_aio_suspend: u64 = 404; +export def SYS_aio_write: u64 = 405; +export def SYS_lio_listio: u64 = 406; +export def SYS___mount50: u64 = 410; +export def SYS_mremap: u64 = 411; +export def SYS_pset_create: u64 = 412; +export def SYS_pset_destroy: u64 = 413; +export def SYS_pset_assign: u64 = 414; +export def SYS__pset_bind: u64 = 415; +export def SYS___posix_fadvise50: u64 = 416; +export def SYS___select50: u64 = 417; +export def SYS___gettimeofday50: u64 = 418; +export def SYS___settimeofday50: u64 = 419; +export def SYS___utimes50: u64 = 420; +export def SYS___adjtime50: u64 = 421; +export def SYS___lfs_segwait50: u64 = 422; +export def SYS___futimes50: u64 = 423; +export def SYS___lutimes50: u64 = 424; +export def SYS___setitimer50: u64 = 425; +export def SYS___getitimer50: u64 = 426; +export def SYS___clock_gettime50: u64 = 427; +export def SYS___clock_settime50: u64 = 428; +export def SYS___clock_getres50: u64 = 429; +export def SYS___nanosleep50: u64 = 430; +export def SYS_____sigtimedwait50: u64 = 431; +export def SYS___mq_timedsend50: u64 = 432; +export def SYS___mq_timedreceive50: u64 = 433; +export def SYS_compat_60__lwp_park: u64 = 434; +export def SYS___kevent50: u64 = 435; +export def SYS___pselect50: u64 = 436; +export def SYS___pollts50: u64 = 437; +export def SYS___aio_suspend50: u64 = 438; +export def SYS___stat50: u64 = 439; +export def SYS___fstat50: u64 = 440; +export def SYS___lstat50: u64 = 441; +export def SYS_____semctl50: u64 = 442; +export def SYS___shmctl50: u64 = 443; +export def SYS___msgctl50: u64 = 444; +export def SYS___getrusage50: u64 = 445; +export def SYS___timer_settime50: u64 = 446; +export def SYS___timer_gettime50: u64 = 447; +export def SYS___ntp_gettime50: u64 = 448; +export def SYS___wait450: u64 = 449; +export def SYS___mknod50: u64 = 450; +export def SYS___fhstat50: u64 = 451; +export def SYS_pipe2: u64 = 453; +export def SYS_dup3: u64 = 454; +export def SYS_kqueue1: u64 = 455; +export def SYS_paccept: u64 = 456; +export def SYS_linkat: u64 = 457; +export def SYS_renameat: u64 = 458; +export def SYS_mkfifoat: u64 = 459; +export def SYS_mknodat: u64 = 460; +export def SYS_mkdirat: u64 = 461; +export def SYS_faccessat: u64 = 462; +export def SYS_fchmodat: u64 = 463; +export def SYS_fchownat: u64 = 464; +export def SYS_fexecve: u64 = 465; +export def SYS_fstatat: u64 = 466; +export def SYS_utimensat: u64 = 467; +export def SYS_openat: u64 = 468; +export def SYS_readlinkat: u64 = 469; +export def SYS_symlinkat: u64 = 470; +export def SYS_unlinkat: u64 = 471; +export def SYS_futimens: u64 = 472; +export def SYS___quotactl: u64 = 473; +export def SYS_posix_spawn: u64 = 474; +export def SYS_recvmmsg: u64 = 475; +export def SYS_sendmmsg: u64 = 476; +export def SYS_clock_nanosleep: u64 = 477; +export def SYS____lwp_park60: u64 = 478; +export def SYS_posix_fallocate: u64 = 479; +export def SYS_fdiscard: u64 = 480; +export def SYS_wait6: u64 = 481; +export def SYS_clock_getcpuclockid2: u64 = 482; +export def SYS_MAXSYSCALL: u64 = 483; +export def SYS_NSYSENT: u64 = 512; diff --git a/rt/+netbsd/syscalls.ha b/rt/+netbsd/syscalls.ha @@ -0,0 +1,614 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +fn syscall0(u64) u64; +fn syscall1(u64, u64) u64; +fn syscall2(u64, u64, u64) u64; +fn syscall3(u64, u64, u64, u64) u64; +fn syscall4(u64, u64, u64, u64, u64) u64; +fn syscall5(u64, u64, u64, u64, u64, u64) u64; +fn syscall6(u64, u64, u64, u64, u64, u64, u64) u64; + +let pathbuf: [PATH_MAX]u8 = [0...]; + +// The use of this function is discouraged, as it can create race conditions. +// TOCTOU is preferred: attempt to simply use the resource you need and handle +// any access errors which occur. +export fn access(path: path, mode: int) (bool | errno) = + faccessat(AT_FDCWD, path, mode, 0); + +export fn fchdir(fd: int) (void | errno) = { + wrap_return(syscall1(SYS_fchdir, fd: u64))?; +}; + +export fn chdir(path: path) (void | errno) = { + let path = kpath(path)?; + wrap_return(syscall1(SYS_chdir, path: uintptr: u64))?; +}; + +export fn chroot(path: path) (void | errno) = { + let path = kpath(path)?; + wrap_return(syscall1(SYS_chroot, path: uintptr: u64))?; +}; + +export fn fchmod(fd: int, mode: uint) (void | errno) = { + wrap_return(syscall2(SYS_fchmod, + fd: u64, mode: u64))?; +}; + +export fn fchmodat(dirfd: int, path: path, mode: uint, flags: int) (void | errno) = { + let path = kpath(path)?; + wrap_return(syscall4(SYS_fchmodat, + dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))?; +}; + +export fn fchown(fd: int, uid: uint, gid: uint) (void | errno) = { + wrap_return(syscall3(SYS_fchown, + fd: u64, uid: u32, gid: u32))?; +}; + +export fn fchownat(dirfd: int, path: path, uid: uint, gid: uint, flags: int) (void | errno) = { + let path = kpath(path)?; + wrap_return(syscall5(SYS_fchownat, + dirfd: u64, path: uintptr: u64, uid: u32, gid: u32, flags: u64))?; +}; + +export fn fstatat(fd: int, path: path, _stat: *st, flag: int) (void | errno) = { + let path = kpath(path)?; + let fbstat = stat { ... }; + wrap_return(syscall4(SYS_fstatat, fd: u64, + path: uintptr: u64, &fbstat: uintptr: u64, flag: u64))?; + _stat.dev = fbstat.st_dev; + _stat.ino = fbstat.st_ino; + _stat.mode = fbstat.st_mode; + _stat.nlink = fbstat.st_nlink; + _stat.uid = fbstat.st_uid; + _stat.gid = fbstat.st_gid; + _stat.rdev = fbstat.st_rdev; + _stat.atime.tv_sec = fbstat.st_atim.tv_sec; + _stat.atime.tv_nsec = fbstat.st_atim.tv_nsec: i64; + _stat.mtime.tv_sec = fbstat.st_mtim.tv_sec; + _stat.mtime.tv_nsec = fbstat.st_mtim.tv_nsec: i64; + _stat.ctime.tv_sec = fbstat.st_ctim.tv_sec; + _stat.ctime.tv_nsec = fbstat.st_ctim.tv_nsec: i64; + _stat.btime.tv_sec = fbstat.st_birthtim.tv_sec; + _stat.btime.tv_nsec = fbstat.st_birthtim.tv_nsec: i64; + _stat.sz = fbstat.st_size; + _stat.blocks = fbstat.st_blocks; + _stat.blksz = fbstat.st_blksize; + _stat.flags = fbstat.st_flags; +}; + +export fn futimens(fd: int, ts: *[2]timespec) (void | errno) = { + wrap_return(syscall2(SYS_futimens, + fd: u64, ts: uintptr: u64))?; +}; + +export fn getdents(dirfd: int, buf: *opaque, nbytes: size) (size | errno) = { + return wrap_return(syscall3(SYS_compat_30_getdents, dirfd: u64, + buf: uintptr: u64, nbytes: u64))?: size; +}; + +// The return value is statically allocated and must be duplicated before +// calling getcwd again. +export fn getcwd() (*const u8 | errno) = { + static let pathbuf: [PATH_MAX]u8 = [0...]; + wrap_return(syscall2(SYS___getcwd, + &pathbuf: *[*]u8: uintptr: u64, + PATH_MAX))?; + return &pathbuf: *const u8; +}; + +export fn mkdirat(dirfd: int, path: path, mode: uint) (void | errno) = { + let path = kpath(path)?; + wrap_return(syscall3(SYS_mkdirat, + dirfd: u64, path: uintptr: u64, mode: u64))?; +}; + +export fn openat( + dirfd: int, + path: path, + flags: int, + mode: uint, +) (int | errno) = { + let path = kpath(path)?; + return wrap_return(syscall4(SYS_openat, dirfd: u64, + path: uintptr: u64, flags: u64, mode: u64))?: int; +}; + +export fn readlinkat( + dirfd: int, + path: path, + buf: []u8, +) (size | errno) = { + let path = kpath(path)?; + return wrap_return(syscall4(SYS_readlinkat, + dirfd: u64, path: uintptr: u64, + buf: *[*]u8: uintptr: u64, + len(buf): u64))?: size; +}; + +export fn renameat( + olddirfd: int, + oldpath: str, + newdirfd: int, + newpath: str, +) (void | errno) = { + let oldpath = kpath(oldpath)?; + static let newpathbuf: [PATH_MAX]u8 = [0...]; + let newpath = copy_kpath(newpath, newpathbuf)?; + wrap_return(syscall4(SYS_renameat, + olddirfd: u64, oldpath: uintptr: u64, + newdirfd: u64, newpath: uintptr: u64))?; +}; + +export fn sysctl(name: []const u32, oldp: nullable *opaque, oldlenp: nullable *size, + newp: nullable *const opaque, newlen: size) (void | errno) = { + wrap_return(syscall6(SYS___sysctl, + &name[0]: uintptr: u64, len(name): u64, + oldp: uintptr: u64, oldlenp: uintptr: u64, + newp: uintptr: u64, newlen: u64))?; +}; + +export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = { + let path = kpath(path)?; + wrap_return(syscall3(SYS_unlinkat, + dirfd: u64, path: uintptr: u64, flags: u64))?; +}; + +export fn utimensat(dirfd: int, path: str, ts: *[2]timespec, flags: int) (void | errno) = { + let path = kpath(path)?; + wrap_return(syscall4(SYS_utimensat, + dirfd: u64, path: uintptr: u64, ts: uintptr: u64, flags: u64))?; +}; + +export fn close(fd: int) (void | errno) = { + wrap_return(syscall1(SYS_close, fd: u64))?; +}; + +export fn lseek(fd: int, off: i64, whence: int) (i64 | errno) = { + return wrap_return(syscall3(SYS_lseek, + fd: u64, off: u64, whence: u64))?: i64; +}; + +export fn dup2(old: int, new: int) (int | errno) = + wrap_return(syscall2(SYS_dup2, old: u64, new: u64))?: int; + +export fn getpid() pid_t = syscall0(SYS_getpid): pid_t; + +export def EXIT_SUCCESS: int = 0; + +export fn exit(status: int) never = { + syscall1(SYS_exit, status: u64); + abort(); +}; + +export fn fork() (pid_t | void | errno) = { + let n = wrap_return(syscall0(SYS_fork))?: pid_t; + switch (n) { + case 0 => + return; + case => + return n; + }; +}; + +export fn execve( + path: *const u8, + argv: *[*]nullable *const u8, + envp: *[*]nullable *const u8, +) int = syscall3(SYS_execve, + path: uintptr: u64, + argv: uintptr: u64, + envp: uintptr: u64): int; + +export fn wait4( + pid: pid_t, + wstatus: nullable *int, + options: int, + rusage: nullable *rusage, +) (int | errno) = { + return wrap_return(syscall4(SYS_compat_50_wait4, + pid: u64, wstatus: uintptr: u64, + options: u64, rusage: uintptr: u64))?: int; +}; + +export fn wifexited(status: int) bool = wtermsig(status) == 0; +export fn wexitstatus(status: int) int = (status & 0xff00) >> 8; + +export fn wtermsig(status: int) int = status & 0x7f; +export fn wifsignaled(status: int) bool = + wtermsig(status) != 0o177 && wtermsig(status) != 0 && status != 0x13; + +export fn kill(pid: pid_t, signal: int) (void | errno) = { + wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?; +}; + +export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = { + wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?; +}; + +export fn mmap( + addr: nullable *opaque, + length: size, + prot: uint, + flags: uint, + fd: int, + offs: size +) (errno | *opaque) = { + return wrap_return(syscall6(SYS_mmap, addr: uintptr: u64, length: u64, + prot: u64, flags: u64, fd: u64, offs: u64)): uintptr: *opaque; +}; + +export fn munmap(addr: *opaque, length: size) (void | errno) = { + wrap_return(syscall2(SYS_munmap, addr: uintptr: u64, length: u64))?; +}; + +export type fcntl_arg = (void | int | *st_flock | *u64); + +export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = { + let _fd = fd: u64, _cmd = cmd: u64; + return wrap_return(match (arg) { + case void => + yield syscall2(SYS_fcntl, _fd, _cmd); + case let i: int => + yield syscall3(SYS_fcntl, _fd, _cmd, i: u64); + case let l: *st_flock => + yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64); + case let u: *u64 => + yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64); + })?: int; +}; + +export fn read(fd: int, buf: *opaque, count: size) (size | errno) = { + return wrap_return(syscall3(SYS_read, + fd: u64, buf: uintptr: u64, count: u64))?: size; +}; + +export fn write(fd: int, buf: *const opaque, count: size) (size | errno) = { + return wrap_return(syscall3(SYS_write, + fd: u64, buf: uintptr: u64, count: u64))?: size; +}; + +export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { + return wrap_return(syscall3(SYS_readv, + fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; +}; + +export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = { + return wrap_return(syscall3(SYS_writev, + fd: u64, iov: uintptr: u64, iovcnt: u64))?: size; +}; + +export fn flock(fd: int, op: int) (void | errno) = { + wrap_return(syscall2(SYS_flock, + fd: u64, op: u64))?; +}; + +export fn ftruncate(fd: int, ln: off_t) (void | errno) = { + wrap_return(syscall2(SYS_ftruncate, fd: u64, ln: u32))?; +}; + +export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = { + wrap_return(syscall2(SYS_compat_50_nanosleep, + req: uintptr: u64, rem: uintptr: u64))?; +}; + +export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = { + wrap_return(syscall2(SYS___clock_gettime50, + clock_id: u64, tp: uintptr: u64))?; +}; + +export fn faccessat( + dirfd: int, + path: path, + mode: int, + flags: int, +) (bool | errno) = { + let path = kpath(path)?; + match (wrap_return(syscall4(SYS_faccessat, dirfd: u64, + path: uintptr: u64, mode: u64, flags: u64))) { + case let err: errno => + switch (err) { + case EACCES => + return false; + case => + return err; + }; + case let n: u64 => + assert(n == 0); + return true; + }; +}; + +// NUL terminates a string and stores it in a static buffer of PATH_MAX bytes in +// length. +fn kpath(path: path) (*const u8 | errno) = { + return copy_kpath(path, pathbuf); +}; + +fn copy_kpath(path: path, buf: []u8) (*const u8 | errno) = { + let path = match (path) { + case let c: *const u8 => + return c; + case let s: str => + let ptr = &s: *struct { + buf: *[*]u8, + length: size, + capacity: size, + }; + yield ptr.buf[..ptr.length]; + case let b: []u8 => + yield b; + }; + if (len(path) + 1 >= len(pathbuf)) { + return ENAMETOOLONG; + }; + memcpy(buf: *[*]u8, path: *[*]u8, len(path)); + buf[len(path)] = 0; + return buf: *[*]u8: *const u8; +}; + +export fn getgroups(gids: []gid_t) (uint | errno) = { + return wrap_return(syscall2(SYS_getgroups, + len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint; +}; + +export fn setgroups(gids: []gid_t) (void | errno) = { + wrap_return(syscall2(SYS_setgroups, + len(gids): u64, gids: *[*]gid_t: uintptr: u64))?; +}; + +export fn getppid() pid_t = syscall0(SYS_getppid): pid_t; + +export fn getpgrp() pid_t = syscall0(SYS_getpgrp): 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, + which: u64, who: u64))?: int; +}; + +export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = { + wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?; +}; + +export fn umask(mode: mode_t) (mode_t | errno) = { + return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t; +}; + +export fn getuid() (uid_t | errno) = { + return wrap_return(syscall0(SYS_getuid))?: uid_t; +}; + +export fn geteuid() (uid_t | errno) = { + return wrap_return(syscall0(SYS_geteuid))?: uid_t; +}; + +export fn getgid() (gid_t | errno) = { + return wrap_return(syscall0(SYS_getgid))?: gid_t; +}; + +export fn getegid() (gid_t | errno) = { + return wrap_return(syscall0(SYS_getegid))?: gid_t; +}; + +export fn setuid(uid: *uid_t) (void | errno) = { + wrap_return(syscall1(SYS_setuid, + uid: uintptr: u64))?; +}; + +export fn seteuid(euid: *uid_t) (void | errno) = { + wrap_return(syscall1(SYS_seteuid, + euid: uintptr: u64))?; +}; + +export fn setgid(gid: *gid_t) (void | errno) = { + wrap_return(syscall1(SYS_setgid, + gid: uintptr: u64))?; +}; + +export fn setegid(egid: *gid_t) (void | errno) = { + wrap_return(syscall1(SYS_setegid, + egid: uintptr: u64))?; +}; + +export fn sigaction( + signum: int, + act: *const sigact, + old: nullable *sigact, +) (int | errno) = { + return wrap_return(syscall3(SYS_compat_13_sigaction13, + signum: u64, act: uintptr: u64, old: uintptr: u64))?: int; +}; + +export fn sigprocmask( + how: int, + set: nullable *const sigset, + old: nullable *sigset, +) (int | errno) = { + return wrap_return(syscall3(SYS_compat_13_sigprocmask13, + how: u64, set: uintptr: u64, old: uintptr: u64))?: int; +}; + +export fn open( + path: path, + flags: int, + mode: uint, +) (int | errno) = { + let path = kpath(path)?; + return wrap_return(syscall3(SYS_open, + path: uintptr: u64, flags: u64, mode: u64))?: int; +}; + +export fn fstat(fd: int, _stat: *st) (void | errno) = { + let fbstat = stat43 { ... }; + wrap_return(syscall2(SYS_compat_43_fstat43, fd: u64, + &fbstat: uintptr: u64))?; + _stat.dev = fbstat.st_dev; + _stat.ino = fbstat.st_ino; + _stat.mode = fbstat.st_mode; + _stat.nlink = fbstat.st_nlink; + _stat.uid = fbstat.st_uid; + _stat.gid = fbstat.st_gid; + _stat.rdev = fbstat.st_rdev; + _stat.atime.tv_sec = fbstat.st_atim.tv_sec; + _stat.atime.tv_nsec = fbstat.st_atim.tv_nsec: i64; + _stat.mtime.tv_sec = fbstat.st_mtim.tv_sec; + _stat.mtime.tv_nsec = fbstat.st_mtim.tv_nsec: i64; + _stat.ctime.tv_sec = fbstat.st_ctim.tv_sec; + _stat.ctime.tv_nsec = fbstat.st_ctim.tv_nsec: i64; + _stat.btime.tv_sec = fbstat.st_birthtim.tv_sec; + _stat.btime.tv_nsec = fbstat.st_birthtim.tv_nsec: i64; + _stat.sz = fbstat.st_size; + _stat.blocks = fbstat.st_blocks; + _stat.blksz = fbstat.st_blksize; + _stat.flags = fbstat.st_flags; +}; + +export fn fexecve(fd: int, argv: *[*]nullable *const u8, + envp: *[*]nullable *const u8) errno = { + return match (wrap_return(syscall3(SYS_fexecve, fd: u64, + argv: uintptr: u64, envp: uintptr: u64))) { + case let err: errno => + yield err; + case u64 => + abort("unreachable"); + }; +}; + +export type ioctl_arg = (nullable *opaque | u64); + +export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = { + let fd = fd: u64, req = req: u64; + return wrap_return(match (arg) { + case let u: u64 => + yield syscall3(SYS_ioctl, fd, req, u); + case let v: nullable *opaque => + yield syscall3(SYS_ioctl, fd, req, v: uintptr: u64); + })?: int; +}; + +export fn posix_openpt(flags: int) (int | errno) = { + return open("/dev/ptmx", flags, 0); +}; + +export fn sigaltstack( + ss: nullable *stack_t, + old_ss: nullable *stack_t, +) (void | errno) = { + wrap_return(syscall2(SYS___sigaltstack14, + ss: uintptr: u64, old_ss: uintptr: u64))?; +}; + +export fn ppoll( + fds: *[*]pollfd, + nfds: nfds_t, + timeout: const nullable *timespec, + sigmask: const nullable *sigset, +) (int | errno) = { + return wrap_return(syscall4(SYS___pollts50, fds: uintptr: u64, + nfds: u64, timeout: uintptr: u64, + sigmask: uintptr: u64))?: int; +}; + +export fn getrandom(buf: *opaque, bufln: size, flags: uint) (size | errno) = { + return wrap_return(syscall3(SYS_getrandom, + buf: uintptr: u64, bufln: u64, flags: u64))?: size; +}; + +export fn paccept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, mask: nullable *int, flags: int) (int | errno) = { + return wrap_return(syscall5(SYS_paccept, sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, mask: uintptr: u64, flags: u64))?: int; +}; + +export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = { + return paccept(sockfd, addr, addrlen, null, flags); +}; + +export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { + return wrap_return(syscall3(SYS_sendmsg, + fd: u64, msg: uintptr: u64, flags: u64))?: int; +}; + +export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = { + return wrap_return(syscall3(SYS_recvmsg, + fd: u64, msg: uintptr: u64, flags: u64))?: int; +}; + +export fn shutdown(sockfd: int, how: int) (void | errno) = { + wrap_return(syscall2(SYS_shutdown, + sockfd: u64, how: u64))?; +}; + +export fn socket(domain: int, type_: int, protocol: int) (int | errno) = { + return wrap_return(syscall3(SYS___socket30, + domain: u64, type_: u64, protocol: u64))?: int; +}; + +export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { + return wrap_return(syscall3(SYS_connect, + sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; +}; + +export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = { + return wrap_return(syscall3(SYS_bind, + sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int; +}; + +export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { + return wrap_return(syscall3(SYS_getsockname, + sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; +}; + +export fn send(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { + return sendto(sockfd, buf, len_, flags, null, 0); +}; + +export fn sendto(sockfd: int, buf: *opaque, len_: size, flags: int, + dest_addr: nullable *sockaddr, addrlen: u32 +) (size | errno) = { + return wrap_return(syscall6(SYS_sendto, + sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, + dest_addr: uintptr: u64, addrlen: u64))?: size; +}; + +export fn recv(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = { + return recvfrom(sockfd, buf, len_, flags, null, null); +}; + +export fn setsockopt(sockfd: int, level: int, optname: int, optval: *opaque, optlen: u32) (int | errno) = { + return wrap_return(syscall5(SYS_setsockopt, + sockfd: u64, level: u64, optname: u64, + optval: uintptr: u64, optlen: u64))?: int; +}; + +export fn recvfrom(sockfd: int, buf: *opaque, len_: size, flags: int, + src_addr: nullable *sockaddr, addrlen: nullable *u32 +) (size | errno) = { + return wrap_return(syscall6(SYS_recvfrom, + sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64, + src_addr: uintptr: u64, addrlen: uintptr: u64))?: size; +}; + +export fn listen(sockfd: int, backlog: u32) (int | errno) = { + return wrap_return(syscall2(SYS_listen, + sockfd: u64, backlog: u64))?: int; +}; + +export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = { + return wrap_return(syscall3(SYS_getpeername, + sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int; +}; + +export fn socketpair( + domain: int, + type_: int, + protocol: int, + sv: *[*]int, +) (int | errno) = { + return wrap_return(syscall4(SYS_socketpair, domain: u64, + type_: u64, protocol: u64, sv: uintptr : u64))?: int; +}; diff --git a/rt/+netbsd/sysctl.ha b/rt/+netbsd/sysctl.ha @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// Taken from NetBSD's sys/sysctl.h + +export def CTL_KERN: u32 = 1; // "high kernel": proc, limits +export def CTL_VM: u32 = 2; // virtual memory +export def CTL_VFS: u32 = 3; // file system, mount type is next +export def CTL_NET: u32 = 4; // network, see socket.h +export def CTL_DEBUG: u32 = 5; // debugging parameters +export def CTL_HW: u32 = 6; // generic CPU/io +export def CTL_MACHDEP: u32 = 7; // machine dependent +export def CTL_USER: u32 = 8; // user-level +export def CTL_DDB: u32 = 9; // in-kernel debugger +export def CTL_PROC: u32 = 10; // per-proc attr +export def CTL_VENDOR: u32 = 11; // vendor-specific data +export def CTL_EMUL: u32 = 12; // emulation-specific data +export def CTL_SECURITY: u32 = 13; // security + +export def KERN_OSTYPE: u32 = 1; // string: system version +export def KERN_OSRELEASE: u32 = 2; // string: system release +export def KERN_OSREV: u32 = 3; // int: system revision +export def KERN_VERSION: u32 = 4; // string: compile time info +export def KERN_MAXVNODES: u32 = 5; // int: max vnodes +export def KERN_MAXPROC: u32 = 6; // int: max processes +export def KERN_MAXFILES: u32 = 7; // int: max open files +export def KERN_ARGMAX: u32 = 8; // int: max arguments to exec +export def KERN_SECURELVL: u32 = 9; // int: system security level +export def KERN_HOSTNAME: u32 = 10; // string: hostname +export def KERN_HOSTID: u32 = 11; // int: host identifier +export def KERN_CLOCKRATE: u32 = 12; // struct: struct clockinfo +export def KERN_VNODE: u32 = 13; // struct: vnode structures +export def KERN_PROC: u32 = 14; // struct: process entries +export def KERN_FILE: u32 = 15; // struct: file entries +export def KERN_PROF: u32 = 16; // node: kernel profiling info +export def KERN_POSIX1: u32 = 17; // int: POSIX.1 version +export def KERN_NGROUPS: u32 = 18; // int: # of supplemental group ids +export def KERN_JOB_CONTROL: u32 = 19; // int: is job control available +export def KERN_SAVED_IDS: u32 = 20; // int: saved set-user/group-ID +export def KERN_OBOOTTIME: u32 = 21; // struct: time kernel was booted +export def KERN_DOMAINNAME: u32 = 22; // string: (YP) domainname +export def KERN_MAXPARTITIONS: u32 = 23; // int: number of partitions/disk +export def KERN_RAWPARTITION: u32 = 24; // int: raw partition number +export def KERN_NTPTIME: u32 = 25; // struct: extended-precision time +export def KERN_TIMEX: u32 = 26; // struct: ntp timekeeping state +export def KERN_AUTONICETIME: u32 = 27; // int: proc time before autonice +export def KERN_AUTONICEVAL: u32 = 28; // int: auto nice value +export def KERN_RTC_OFFSET: u32 = 29; // int: offset of rtc from gmt +export def KERN_ROOT_DEVICE: u32 = 30; // string: root device +export def KERN_MSGBUFSIZE: u32 = 31; // int: max # of chars in msg buffer +export def KERN_FSYNC: u32 = 32; // int: file synchronization support +export def KERN_OLDSYSVMSG: u32 = 33; // old: SysV message queue support +export def KERN_OLDSYSVSEM: u32 = 34; // old: SysV semaphore support +export def KERN_OLDSYSVSHM: u32 = 35; // old: SysV shared memory support +export def KERN_OLDSHORTCORENAME: u32 = 36; // old, unimplemented +export def KERN_SYNCHRONIZED_IO: u32 = 37; // int: POSIX synchronized I/O +export def KERN_IOV_MAX: u32 = 38; // int: max iovec's for readv(2) etc. +export def KERN_MBUF: u32 = 39; // node: mbuf parameters +export def KERN_MAPPED_FILES: u32 = 40; // int: POSIX memory mapped files +export def KERN_MEMLOCK: u32 = 41; // int: POSIX memory locking +export def KERN_MEMLOCK_RANGE: u32 = 42; // int: POSIX memory range locking +export def KERN_MEMORY_PROTECTION: u32 = 43; // int: POSIX memory protections +export def KERN_LOGIN_NAME_MAX: u32 = 44; // int: max length login name + NUL +export def KERN_DEFCORENAME: u32 = 45; // old: sort core name format +export def KERN_LOGSIGEXIT: u32 = 46; // int: log signaled processes +export def KERN_PROC2: u32 = 47; // struct: process entries +export def KERN_PROC_ARGS: u32 = 48; // struct: process argv/env +export def KERN_FSCALE: u32 = 49; // int: fixpt FSCALE +export def KERN_CCPU: u32 = 50; // old: fixpt ccpu +export def KERN_CP_TIME: u32 = 51; // struct: CPU time counters +export def KERN_OLDSYSVIPC_INFO: u32 = 52; // old: number of valid kern ids +export def KERN_MSGBUF: u32 = 53; // kernel message buffer +export def KERN_CONSDEV: u32 = 54; // dev_t: console terminal device +export def KERN_MAXPTYS: u32 = 55; // int: maximum number of ptys +export def KERN_PIPE: u32 = 56; // node: pipe limits +export def KERN_MAXPHYS: u32 = 57; // int: kernel value of MAXPHYS +export def KERN_SBMAX: u32 = 58; // int: max socket buffer size +export def KERN_TKSTAT: u32 = 59; // tty in/out counters +export def KERN_MONOTONIC_CLOCK: u32 = 60; // int: POSIX monotonic clock +export def KERN_URND: u32 = 61; // int: random integer from urandom +export def KERN_LABELSECTOR: u32 = 62; // int: disklabel sector +export def KERN_LABELOFFSET: u32 = 63; // int: offset of label within sector +export def KERN_LWP: u32 = 64; // struct: lwp entries +export def KERN_FORKFSLEEP: u32 = 65; // int: sleep length on failed fork +export def KERN_POSIX_THREADS: u32 = 66; // int: POSIX Threads option +export def KERN_POSIX_SEMAPHORES: u32 = 67; // int: POSIX Semaphores option +export def KERN_POSIX_BARRIERS: u32 = 68; // int: POSIX Barriers option +export def KERN_POSIX_TIMERS: u32 = 69; // int: POSIX Timers option +export def KERN_POSIX_SPIN_LOCKS: u32 = 70; // int: POSIX Spin Locks option +export def KERN_POSIX_READER_WRITER_LOCKS: u32 = 71; // int: POSIX R/W Locks option +export def KERN_DUMP_ON_PANIC: u32 = 72; // int: dump on panic +export def KERN_SOMAXKVA: u32 = 73; // int: max socket kernel virtual mem +export def KERN_ROOT_PARTITION: u32 = 74; // int: root partition +export def KERN_DRIVERS: u32 = 75; // struct: driver names and majors #s +export def KERN_BUF: u32 = 76; // struct: buffers +export def KERN_FILE2: u32 = 77; // struct: file entries +export def KERN_VERIEXEC: u32 = 78; // node: verified exec +export def KERN_CP_ID: u32 = 79; // struct: cpu id numbers +export def KERN_HARDCLOCK_TICKS: u32 = 80; // int: number of hardclock ticks +export def KERN_ARND: u32 = 81; // void *buf, size_t siz random +export def KERN_SYSVIPC: u32 = 82; // node: SysV IPC parameters +export def KERN_BOOTTIME: u32 = 83; // struct: time kernel was booted +export def KERN_EVCNT: u32 = 84; // struct: evcnts +export def KERN_SOFIXEDBUF: u32 = 85; // bool: fixed socket buffer sizes +export def KERN_PROC_ALL: u32 = 0; // everything +export def KERN_PROC_PID: u32 = 1; // by process id +export def KERN_PROC_PGRP: u32 = 2; // by process group id +export def KERN_PROC_SESSION: u32 = 3; // by session of pid +export def KERN_PROC_TTY: u32 = 4; // by controlling tty +export def KERN_PROC_UID: u32 = 5; // by effective uid +export def KERN_PROC_RUID: u32 = 6; // by real uid +export def KERN_PROC_GID: u32 = 7; // by effective gid +export def KERN_PROC_RGID: u32 = 8; // by real gid +export def KERN_PROC_TTY_NODEV: u32 = NODEV: u32; // no controlling tty +export def KERN_PROC_TTY_REVOKE: u32 = -2; // revoked tty +export def KERN_PROC_ARGV: u32 = 1; // argv +export def KERN_PROC_NARGV: u32 = 2; // number of strings in above +export def KERN_PROC_ENV: u32 = 3; // environ +export def KERN_PROC_NENV: u32 = 4; // number of strings in above +export def KERN_PROC_PATHNAME: u32 = 5; // path to executable +export def KERN_PROC_CWD: u32 = 6; // current working dir +export def KERN_SYSVIPC_INFO: u32 = 1; // struct: number of valid kern ids +export def KERN_SYSVIPC_MSG: u32 = 2; // int: SysV message queue support +export def KERN_SYSVIPC_SEM: u32 = 3; // int: SysV semaphore support +export def KERN_SYSVIPC_SHM: u32 = 4; // int: SysV shared memory support +export def KERN_SYSVIPC_SHMMAX: u32 = 5; // int: max shared memory segment size (bytes) +export def KERN_SYSVIPC_SHMMNI: u32 = 6; // int: max number of shared memory identifiers +export def KERN_SYSVIPC_SHMSEG: u32 = 7; // int: max shared memory segments per process +export def KERN_SYSVIPC_SHMMAXPGS: u32 = 8; // int: max amount of shared memory (pages) +export def KERN_SYSVIPC_SHMUSEPHYS: u32 = 9; // int: physical memory usage +export def KERN_SYSVIPC_MSG_INFO: u32 = 4; // msginfo and msgid_ds +export def KERN_SYSVIPC_SEM_INFO: u32 = 5; // seminfo and semid_ds +export def KERN_SYSVIPC_SHM_INFO: u32 = 6; // shminfo and shmid_ds +export def KERN_TKSTAT_NIN: u32 = 1; // total input character +export def KERN_TKSTAT_NOUT: u32 = 2; // total output character +export def KERN_TKSTAT_CANCC: u32 = 3; // canonical input character +export def KERN_TKSTAT_RAWCC: u32 = 4; // raw input character +export def KERN_BUF_ALL: u32 = 0; // all buffers +export def KERN_BUFSLOP: u32 = 20; +export def KERN_FILE_BYFILE: u32 = 1; +export def KERN_FILE_BYPID: u32 = 2; +export def KERN_FILESLOP: u32 = 10; +export def KERN_EVCNT_COUNT_ANY: u32 = 0; +export def KERN_EVCNT_COUNT_NONZERO: u32 = 1; + +export def HW_MACHINE: u32 = 1; // string: machine class +export def HW_MODEL: u32 = 2; // string: specific machine model +export def HW_NCPU: u32 = 3; // int: number of cpus +export def HW_BYTEORDER: u32 = 4; // int: machine byte order +export def HW_PHYSMEM: u32 = 5; // int: total memory (bytes) +export def HW_USERMEM: u32 = 6; // int: non-kernel memory (bytes) +export def HW_PAGESIZE: u32 = 7; // int: software page size +export def HW_DISKNAMES: u32 = 8; // string: disk drive names +export def HW_IOSTATS: u32 = 9; // struct: iostats[] +export def HW_MACHINE_ARCH: u32 = 10; // string: machine architecture +export def HW_ALIGNBYTES: u32 = 11; // int: ALIGNBYTES for the kernel +export def HW_CNMAGIC: u32 = 12; // string: console magic sequence(s) +export def HW_PHYSMEM64: u32 = 13; // quad: total memory (bytes) +export def HW_USERMEM64: u32 = 14; // quad: non-kernel memory (bytes) +export def HW_IOSTATNAMES: u32 = 15; // string: iostat names +export def HW_NCPUONLINE: u32 = 16; // number CPUs online + +export def USER_CS_PATH: u32 = 1; // string: _CS_PATH +export def USER_BC_BASE_MAX: u32 = 2; // int: BC_BASE_MAX +export def USER_BC_DIM_MAX: u32 = 3; // int: BC_DIM_MAX +export def USER_BC_SCALE_MAX: u32 = 4; // int: BC_SCALE_MAX +export def USER_BC_STRING_MAX: u32 = 5; // int: BC_STRING_MAX +export def USER_COLL_WEIGHTS_MAX: u32 = 6; // int: COLL_WEIGHTS_MAX +export def USER_EXPR_NEST_MAX: u32 = 7; // int: EXPR_NEST_MAX +export def USER_LINE_MAX: u32 = 8; // int: LINE_MAX +export def USER_RE_DUP_MAX: u32 = 9; // int: RE_DUP_MAX +export def USER_POSIX2_VERSION: u32 = 10; // int: POSIX2_VERSION +export def USER_POSIX2_C_BIND: u32 = 11; // int: POSIX2_C_BIND +export def USER_POSIX2_C_DEV: u32 = 12; // int: POSIX2_C_DEV +export def USER_POSIX2_CHAR_TERM: u32 = 13; // int: POSIX2_CHAR_TERM +export def USER_POSIX2_FORT_DEV: u32 = 14; // int: POSIX2_FORT_DEV +export def USER_POSIX2_FORT_RUN: u32 = 15; // int: POSIX2_FORT_RUN +export def USER_POSIX2_LOCALEDEF: u32 = 16; // int: POSIX2_LOCALEDEF +export def USER_POSIX2_SW_DEV: u32 = 17; // int: POSIX2_SW_DEV +export def USER_POSIX2_UPE: u32 = 18; // int: POSIX2_UPE +export def USER_STREAM_MAX: u32 = 19; // int: POSIX2_STREAM_MAX +export def USER_TZNAME_MAX: u32 = 20; // int: _POSIX_TZNAME_MAX +export def USER_ATEXIT_MAX: u32 = 21; // int: {ATEXIT_MAX} + +export def PROC_CURPROC: u32 = ~(1 << 31); +export def PROC_PID_CORENAME: u32 = 1; +export def PROC_PID_LIMIT: u32 = 2; +export def PROC_PID_STOPFORK: u32 = 3; +export def PROC_PID_STOPEXEC: u32 = 4; +export def PROC_PID_STOPEXIT: u32 = 5; +export def PROC_PID_PAXFLAGS: u32 = 6; +export def PROC_PID_LIMIT_CPU: u32 = (RLIMIT_CPU+1): u32; +export def PROC_PID_LIMIT_FSIZE: u32 = (RLIMIT_FSIZE+1): u32; +export def PROC_PID_LIMIT_DATA: u32 = (RLIMIT_DATA+1): u32; +export def PROC_PID_LIMIT_STACK: u32 = (RLIMIT_STACK+1): u32; +export def PROC_PID_LIMIT_CORE: u32 = (RLIMIT_CORE+1): u32; +export def PROC_PID_LIMIT_RSS: u32 = (RLIMIT_RSS+1): u32; +export def PROC_PID_LIMIT_MEMLOCK: u32 = (RLIMIT_MEMLOCK+1): u32; +export def PROC_PID_LIMIT_NPROC: u32 = (RLIMIT_NPROC+1): u32; +export def PROC_PID_LIMIT_NOFILE: u32 = (RLIMIT_NOFILE+1): u32; +export def PROC_PID_LIMIT_SBSIZE: u32 = (RLIMIT_SBSIZE+1): u32; +export def PROC_PID_LIMIT_AS: u32 = (RLIMIT_AS+1): u32; +export def PROC_PID_LIMIT_NTHR: u32 = (RLIMIT_NTHR+1): u32; +export def PROC_PID_LIMIT_TYPE_SOFT: u32 = 1; +export def PROC_PID_LIMIT_TYPE_HARD: u32 = 2; + +export def EMUL_LINUX: u32 = 1; +export def EMUL_LINUX32: u32 = 5; diff --git a/rt/+netbsd/types.ha b/rt/+netbsd/types.ha @@ -0,0 +1,518 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +export type time_t = i64; +export type suseconds_t = i64; +export type dev_t = u64; +export type ino_t = u64; +export type nlink_t = u64; +export type id_t = uint; +export type pid_t = u64; +export type uid_t = u32; +export type gid_t = u32; +export type off_t = i64; +export type blkcnt_t = i64; +export type blksize_t = i32; +export type fflags_t = u32; +export type mode_t = u32; +export type nfds_t = uint; +export type rlim_t = u64; + +export type path = (str | []u8 | *const u8); + +// Maximum length of a file path including the NUL terminator. +export def PATH_MAX = 1024z; + +export def NGROUPS_MAX: size = 1023; +export def NSIG: int = 32; + +export type sigset = struct { + __bits: [4]u32, +}; + +export def SA_ONSTACK: u64 = 0x0001; +export def SA_RESTART: u64 = 0x0002; +export def SA_RESETHAND: u64 = 0x0004; +export def SA_NOCLDSTOP: u64 = 0x0008; +export def SA_NODEFER: u64 = 0x0010; +export def SA_NOCLDWAIT: u64 = 0x0020; +export def SA_SIGINFO: u64 = 0x0040; + +export def SIG_ERR: uintptr = -1; +export def SIG_DFL: uintptr = 0; +export def SIG_IGN: uintptr = 1; +export def SIG_CATCH: uintptr = 2; +export def SIG_HOLD: uintptr = 3; + +export type sigact = struct { + union { + sa_handler: *fn (int) void, + sa_sigaction: *fn (int, *siginfo, *opaque) void, + }, + sa_flags: int, + sa_mask: sigset, +}; + +export def SIG_BLOCK: int = 1; +export def SIG_UNBLOCK: int = 2; +export def SIG_SETMASK: int = 3; + +export type sigval = union { + sival_t: int, + sival_ptr: *opaque, +}; + +export type stack_t = struct { + ss_sp: *opaque, + ss_size: size, + ss_flags: int, +}; + +export type pollfd = struct { + fd: int, + events: i16, + revents: i16, +}; + +export type timespec = struct { + tv_sec: time_t, + tv_nsec: i64, +}; + +export def UTIME_OMIT = -0x2; + +export type timeval = struct { + tv_sec: time_t, + tv_usec: suseconds_t, +}; + +export type st_flock = struct { + l_start: off_t, + l_len: off_t, + l_pid: pid_t, + l_type: i16, + l_whence: i16, + l_sysid: int, +}; + +export type st = struct { + dev: dev_t, + ino: ino_t, + nlink: nlink_t, + mode: mode_t, + uid: uid_t, + gid: gid_t, + rdev: dev_t, + atime: timespec, + mtime: timespec, + ctime: timespec, + btime: timespec, + sz: off_t, + blocks: blkcnt_t, + blksz: blksize_t, + flags: fflags_t, +}; + +export type stat = struct { + st_dev: u64, + st_mode: mode_t, + __pad0: u32, + st_ino: u64, + st_nlink: u32, + st_uid: uid_t, + st_gid: gid_t, + __pad1: u32, + st_rdev: u64, + st_atim: timespec, + st_mtim: timespec, + st_ctim: timespec, + st_birthtim: timespec, + st_size: off_t, + st_blocks: blkcnt_t, + st_blksize: blksize_t, + st_flags: fflags_t, + st_gen: u32, + st_spare: [2]u32, +}; + +export type stat43 = struct { + st_dev: u32, + st_ino: u32, + st_mode: mode_t, + st_nlink: u16, + st_uid: uid_t, + st_gid: gid_t, + st_rdev: u32, + st_atim: timespec, + st_mtim: timespec, + st_ctim: timespec, + st_size: off_t, + st_blocks: blkcnt_t, + st_blksize: blksize_t, + st_flags: fflags_t, + st_gen: u32, + st_lspare: u32, + st_birthtim: timespec, +}; + +export type dirent = struct { + d_fileno: u32, + d_reclen: u16, + d_type: u8, + d_namlen: u8, + d_name: [*]u8, +}; + +export type iovec = struct { + iov_base: *opaque, + iov_len: size +}; + +export type winsize = struct { + ws_row: u16, + ws_col: u16, + ws_xpixel: u16, + ws_ypixel: u16, +}; + +export type termios = struct { + c_iflag: tcflag, + c_oflag: tcflag, + c_cflag: tcflag, + c_lflag: tcflag, + c_cc: [NCCS]cc, +}; + +export def NCCS: size = 20; + +export type tcflag = enum uint { + // c_iflag bits + IGNBRK = 0x00000001, + BRKINT = 0x00000002, + IGNPAR = 0x00000004, + PARMRK = 0x00000008, + INPCK = 0x00000010, + ISTRIP = 0x00000020, + INLCR = 0x00000040, + IGNCR = 0x00000080, + ICRNL = 0x00000100, + IXON = 0x00000200, + IXOFF = 0x00000400, + IXANY = 0x00000800, + IMAXBEL = 0x00002000, + + // c_oflag bits + OPOST = 0x00000001, + ONLCR = 0x00000002, + TABDLY = 0x00000004, + TAB0 = 0x00000000, + TAB3 = 0x00000004, + ONOEOT = 0x00000008, + OCRNL = 0x00000010, + ONOCR = 0x00000020, + ONLRET = 0x00000040, + + // c_cflag bits + CIGNORE = 0x00000001, + CSIZE = 0x00000300, + CS5 = 0x00000000, + CS6 = 0x00000100, + CS7 = 0x00000200, + CS8 = 0x00000300, + CSTOPB = 0x00000400, + CREAD = 0x00000800, + PARENB = 0x00001000, + PARODD = 0x00002000, + HUPCL = 0x00004000, + CLOCAL = 0x00008000, + CCTS_OFLOW = 0x00010000, + CRTS_IFLOW = 0x00020000, + CRTSCTS = (CCTS_OFLOW | CRTS_IFLOW), + CDTR_IFLOW = 0x00040000, + CDSR_OFLOW = 0x00080000, + CCAR_OFLOW = 0x00100000, + CNO_RTSDTR = 0x00200000, + + // c_lflag bits + ECHOKE = 0x00000001, + ECHOE = 0x00000002, + ECHOK = 0x00000004, + ECHO = 0x00000008, + ECHONL = 0x00000010, + ECHOPRT = 0x00000020, + ECHOCTL = 0x00000040, + ISIG = 0x00000080, + ICANON = 0x00000100, + ALTWERASE = 0x00000200, + IEXTEN = 0x00000400, + EXTPROC = 0x00000800, + TOSTOP = 0x00400000, + FLUSHO = 0x00800000, + NOKERNINFO = 0x02000000, + PENDIN = 0x20000000, + NOFLSH = 0x80000000, +}; + +export type cc = enum u8 { + VEOF = 0, + VEOL = 1, + VEOL2 = 2, + VERASE = 3, + VWERASE = 4, + VKILL = 5, + VREPRINT = 6, + VERASE2 = 7, + VINTR = 8, + VQUIT = 9, + VSUSP = 10, + VDSUSP = 11, + VSTART = 12, + VSTOP = 13, + VLNEXT = 14, + VDISCARD = 15, + VMIN = 16, + VTIME = 17, + VSTATUS = 18, +}; + +export def TIOCGWINSZ: u64 = 0x40087468; +export def TIOCSWINSZ: u64 = 0x80087467; +export def TIOCGETA: u64 = 0x402c7413; +export def TIOCSETA: u64 = 0x802c7414; +export def TIOCPTSNAME: u64 = 0x48087448; +export def TIOCSPGRP: u64 = 0x80047476; +export def FIODGNAME: u64 = 0x80106678; + +export type ptmget = struct { + cfd: int, + sfd: int, + cn: [PATH_MAX]u8, + sn: [PATH_MAX]u8, +}; + +export type rusage = struct { + ru_utime: timeval, + ru_stime: timeval, + ru_maxrss: i64, + ru_ixrss: i64, + ru_idrss: i64, + ru_isrss: i64, + ru_minflt: i64, + ru_majflt: i64, + ru_nswap: i64, + ru_inblock: i64, + ru_oublock: i64, + ru_msgsnd: i64, + ru_msgrcv: i64, + ru_nsignals: i64, + ru_nvcsw: i64, + ru_nivcsw: i64, +}; + +export def DT_UNKNOWN: u8 = 0; +export def DT_FIFO: u8 = 1; +export def DT_CHR: u8 = 2; +export def DT_DIR: u8 = 4; +export def DT_BLK: u8 = 6; +export def DT_REG: u8 = 8; +export def DT_LNK: u8 = 10; +export def DT_SOCK: u8 = 12; +export def DT_WHT: u8 = 14; + +export def O_RDONLY: int = 0x0000; +export def O_WRONLY: int = 0x0001; +export def O_RDWR: int = 0x0002; +export def O_ACCMODE: int = 0x0003; +export def O_NONBLOCK: int = 0x0004; +export def O_APPEND: int = 0x0008; +export def O_SHLOCK: int = 0x0010; +export def O_EXLOCK: int = 0x0020; +export def O_ASYNC: int = 0x0040; +export def O_FSYNC: int = 0x0080; +export def O_SYNC: int = 0x0080; +export def O_NOFOLLOW: int = 0x0100; +export def O_CREAT: int = 0x0200; +export def O_TRUNC: int = 0x0400; +export def O_EXCL: int = 0x0800; +export def O_NOCTTY: int = 0x8000; +export def O_DIRECT: int = 0x00010000; +export def O_DIRECTORY: int = 0x00020000; +export def O_EXEC: int = 0x00040000; +export def O_TTY_INIT: int = 0x00080000; +export def O_CLOEXEC: int = 0x00400000; +export def O_DSYNC: int = 0x01000000; + +export def AT_FDCWD: int = -100; +export def AT_EACCESS: int = 0x0100; +export def AT_SYMLINK_NOFOLLOW: int = 0x0200; +export def AT_SYMLINK_FOLLOW: int = 0x0400; +export def AT_REMOVEDIR: int = 0x0800; +export def AT_RESOLVE_BENEATH: int = 0x2000; + +export def S_IFIFO: mode_t = 0o010000; +export def S_IFCHR: mode_t = 0o020000; +export def S_IFDIR: mode_t = 0o040000; +export def S_IFBLK: mode_t = 0o060000; +export def S_IFREG: mode_t = 0o100000; +export def S_IFLNK: mode_t = 0o120000; +export def S_IFSOCK: mode_t = 0o140000; + +export def MAP_SHARED: uint = 0x0001; +export def MAP_PRIVATE: uint = 0x0002; +export def MAP_FIXED: uint = 0x0010; +export def MAP_HASSEMAPHORE: uint = 0x0200; +export def MAP_STACK: uint = 0x0400; +export def MAP_NOSYNC: uint = 0x0800; +export def MAP_FILE: uint = 0x0000; +export def MAP_ANON: uint = 0x1000; +export def MAP_GUARD: uint = 0x00002000; +export def MAP_EXCL: uint = 0x00004000; +export def MAP_NOCORE: uint = 0x00020000; +export def MAP_PREFAULT_READ: uint = 0x00040000; +export def MAP_32BIT: uint = 0x00080000; + +export def PROT_NONE: uint = 0x00; +export def PROT_READ: uint = 0x01; +export def PROT_WRITE: uint = 0x02; +export def PROT_EXEC: uint = 0x04; + +export def SIGHUP: int = 1; +export def SIGINT: int = 2; +export def SIGQUIT: int = 3; +export def SIGILL: int = 4; +export def SIGTRAP: int = 5; +export def SIGABRT: int = 6; +export def SIGIOT: int = SIGABRT; +export def SIGEMT: int = 7; +export def SIGFPE: int = 8; +export def SIGKILL: int = 9; +export def SIGBUS: int = 10; +export def SIGSEGV: int = 11; +export def SIGSYS: int = 12; +export def SIGPIPE: int = 13; +export def SIGALRM: int = 14; +export def SIGTERM: int = 15; +export def SIGURG: int = 16; +export def SIGSTOP: int = 17; +export def SIGTSTP: int = 18; +export def SIGCONT: int = 19; +export def SIGCHLD: int = 20; +export def SIGTTIN: int = 21; +export def SIGTTOU: int = 22; +export def SIGIO: int = 23; +export def SIGXCPU: int = 24; +export def SIGXFSZ: int = 25; +export def SIGVTALRM: int = 26; +export def SIGPROF: int = 27; +export def SIGWINCH: int = 28; +export def SIGINFO: int = 29; +export def SIGUSR1: int = 30; +export def SIGUSR2: int = 31; +export def SIGTHR: int = 32; +export def SIGLWP: int = SIGTHR; +export def SIGLIBRT: int = 33; + +export def F_DUPFD: int = 0; +export def F_GETFD: int = 1; +export def F_SETFD: int = 2; +export def F_GETFL: int = 3; +export def F_SETFL: int = 4; +export def F_GETOWN: int = 5; +export def F_SETOWN: int = 6; +export def F_OGETLK: int = 7; +export def F_OSETLK: int = 8; +export def F_OSETLKW: int = 9; +export def F_DUP2FD: int = 10; +export def F_GETLK: int = 11; +export def F_SETLK: int = 12; +export def F_SETLKW: int = 13; +export def F_SETLK_REMOTE: int = 14; +export def F_READAHEAD: int = 15; +export def F_RDAHEAD: int = 16; +export def F_DUPFD_CLOEXEC: int = 12; +export def F_DUP2FD_CLOEXEC: int = 18; +export def F_ADD_SEALS: int = 16; +export def F_GET_SEALS: int = 17; +export def F_ISUNIONSTACK: int = 21; + +export def F_SEAL_SEAL: int = 0x0001; +export def F_SEAL_SHRINK: int = 0x0002; +export def F_SEAL_GROW: int = 0x0004; +export def F_SEAL_WRITE: int = 0x0008; + +export def FD_CLOEXEC: int = 1; +export def F_UNLCKSYS: int = 4; +export def F_CANCEL: int = 5; + +export def F_RDLCK: i16 = 1; +export def F_UNLCK: i16 = 2; +export def F_WRLCK: i16 = 3; + +export def PRIO_PROCESS: int = 0; +export def PRIO_PGRP: int = 1; +export def PRIO_USER: int = 2; + +export def F_OK: int = 0; +export def X_OK: int = 0x01; +export def W_OK: int = 0x02; +export def R_OK: int = 0x04; + +export def CLOCK_REALTIME: int = 0; +export def CLOCK_VIRTUAL: int = 1; +export def CLOCK_PROF: int = 2; +export def CLOCK_MONOTONIC: int = 3; +export def CLOCK_THREAD_CPUTIME_ID: int = 0x20000000; +export def CLOCK_PROCESS_CPUTIME_ID: int = 0x40000000; + +export def WNOHANG: int = 1; +export def WUNTRACED: int = 2; +export def WSTOPPED: int = WUNTRACED; +export def WCONTINUED: int = 4; +export def WNOWAIT: int = 8; +export def WEXITED: int = 16; +export def WTRAPPED: int = 32; + +export def STDIN_FILENO: int = 0; +export def STDOUT_FILENO: int = 1; +export def STDERR_FILENO: int = 2; + +export def SEEK_SET: int = 0; +export def SEEK_CUR: int = 1; +export def SEEK_END: int = 2; + +// Flock operations +export def LOCK_SH: int = 1; +export def LOCK_EX: int = 2; +export def LOCK_NB: int = 4; +export def LOCK_UN: int = 8; + +export type rlimit = struct { + rlim_cur: rlim_t, + rlim_max: rlim_t, +}; + +export def RLIM_INFINITY: rlim_t = -1; + +export def RLIMIT_CPU: int = 0; +export def RLIMIT_FSIZE: int = 1; +export def RLIMIT_DATA: int = 2; +export def RLIMIT_STACK: int = 3; +export def RLIMIT_CORE: int = 4; +export def RLIMIT_RSS: int = 5; +export def RLIMIT_MEMLOCK: int = 6; +export def RLIMIT_NPROC: int = 7; +export def RLIMIT_NOFILE: int = 8; +export def RLIMIT_SBSIZE: int = 9; +export def RLIMIT_VMEM: int = 10; +export def RLIMIT_AS: int = RLIMIT_VMEM; +export def RLIMIT_NPTS: int = 11; +export def RLIMIT_SWAP: int = 12; +export def RLIMIT_KQUEUES: int = 13; +export def RLIMIT_UMTXP: int = 14; +export def RLIMIT_NTHR: int = 11; // number of threads + +export def SHUT_RD: int = 0; +export def SHUT_WR: int = 1; +export def SHUT_RDWR: int = 2; + +export def NODEV: int = -1; // non-existent device diff --git a/scripts/genbootstrap b/scripts/genbootstrap @@ -3,7 +3,7 @@ cd "$(dirname "$0")/.." mkdir -p "${BINOUT:-.bin}" makefiles/ hare build -o "${BINOUT:-.bin}"/genbootstrap cmd/genbootstrap -for platform in linux freebsd openbsd; do +for platform in linux freebsd openbsd netbsd; do platformtags= if [ $platform = "openbsd" ]; then platformtags=libc diff --git a/temp/+netbsd.ha b/temp/+netbsd.ha @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use crypto::random; +use encoding::hex; +use errors; +use fmt; +use fs; +use io; +use memio; +use os; +use path; + +fn get_tmpdir() str = os::tryenv("TMPDIR", "/tmp"); + +// Creates an unnamed temporary file. The file may or may not have a name; not +// all systems support the creation of temporary inodes which are not linked to +// any directory. If it is necessary to create a real file, it will be removed +// when the stream is closed. +// +// The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. +export fn file(iomode: io::mode, mode: fs::mode) (io::file | fs::error) = { + // TODO: Add a custom "close" function which removes the named file + let file = named(os::cwd, get_tmpdir(), iomode, mode)?; + free(file.1); + return file.0; +}; + +// Creates a named temporary file in the given directory of the given +// filesystem. The caller is responsible for closing and removing the file when +// they're done with it. The name is statically allocated, and will be +// overwritten on subsequent calls. +// +// The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]]. +export fn named( + fs: *fs::fs, + path: str, + iomode: io::mode, + mode: fs::mode, +) ((io::file, str) | fs::error) = { + assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR); + + let oflags = fs::flag::EXCL; + if (iomode == io::mode::RDWR) { + oflags |= fs::flag::RDWR; + } else { + oflags |= fs::flag::WRONLY; + }; + + static let pathbuf = path::buffer { ... }; + static let namebuf: [32]u8 = [0...]; + for (true) { + let rand: [size(u64)]u8 = [0...]; + random::buffer(rand); + + const id = *(&rand[0]: *u64); + const name = fmt::bsprintf(namebuf, "temp.{}", id); + const path = path::set(&pathbuf, path, name)!; + + match (fs::create_file(fs, path, mode, oflags)) { + case errors::exists => + continue; + case let err: fs::error => + return err; + case let f: io::file => + return (f, path); + }; + }; +}; + +// Creates a temporary directory. This function only guarantees that the +// directory will have a unique name and be placed in the system temp directory, +// but not that it will be removed automatically; the caller must remove it when +// they're done using it via [[os::rmdir]] or [[os::rmdirall]]. +// +// The return value is statically allocated and will be overwritten on +// subsequent calls. +export fn dir() str = { + let buf: [8]u8 = [0...], name: [16]u8 = [0...]; + random::buffer(buf[..]); + + let sink = memio::fixed(name); + const enc = hex::newencoder(&sink); + io::write(&enc, buf)!; + let name = memio::string(&sink)!; + + static let buf = path::buffer { ... }; + path::set(&buf, get_tmpdir(), name)!; + const path = path::string(&buf); + match (os::mkdir(path,0o755)) { + case let err: fs::error => abort("Could not create temp directory"); + case void => void; + }; + return path; +}; diff --git a/time/+netbsd/functions.ha b/time/+netbsd/functions.ha @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use rt; + +// Converts a [[duration]] to an [[rt::timespec]]. This function is +// non-portable. +export fn duration_to_timespec(n: duration) rt::timespec = rt::timespec { + tv_sec = n / SECOND, + tv_nsec = n % SECOND, +}; + +// Converts a [[duration]] to an [[rt::timeval]]. This function is +// non-portable. +export fn duration_to_timeval(d: duration) rt::timeval = rt::timeval { + tv_sec = d / SECOND, + tv_usec = d % SECOND / 1000, +}; + +// Converts an [[instant]] to an [[rt::timespec]]. This function is +// non-portable. +export fn instant_to_timespec(t: instant) rt::timespec = rt::timespec { + tv_sec = t.sec, + tv_nsec = t.nsec, +}; + +// Converts a [[rt::timespec]] to an [[instant]]. This function is +// non-portable. +export fn timespec_to_instant(ts: rt::timespec) instant = instant { + sec = ts.tv_sec, + nsec = ts.tv_nsec, +}; + +// Yields the process to the kernel and returns after the requested duration. +export fn sleep(d: duration) void = { + let req = duration_to_timespec(d); + + for (true) { + let res = rt::timespec { ... }; + match (rt::nanosleep(&req, &res)) { + case void => + return; + case let err: rt::errno => + switch (err) { + case rt::EINTR => + req = res; + case => + abort("Unexpected error from nanosleep"); + }; + }; + }; +}; + +// An enumeration of clocks available on this system. Different clocks represent +// times from different epochs, and have different characteristics with regards +// to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME +// and MONOTONIC clocks at least; use of other clocks is not guaranteed to be +// portable. +export type clock = enum { + // The current wall-clock time. This may jump forwards or backwards in + // time to account for leap seconds, NTP adjustments, etc. + REALTIME = rt::CLOCK_REALTIME, + + // The current monotonic time. This clock measures from some undefined + // epoch and is not affected by leap seconds, NTP adjustments, and + // changes to the system time: it always increases by one second per + // second. + MONOTONIC = rt::CLOCK_MONOTONIC, + + // Increments only when the CPU is running in user mode on behalf of the + // calling process. + VIRTUAL = rt::CLOCK_VIRTUAL, + + // Increments when the CPU is running in user or kernel mode. + PROF = rt::CLOCK_PROF, + + // The thread CPU clock. It begins at zero and is advanced while the + // calling thread is running in user or kernel mode. + THREAD_CPUTIME_ID = rt::CLOCK_THREAD_CPUTIME_ID, + + // The process CPU clock. It begins at zero and is advanced while the + // calling process is running in user or kernel mode. + PROCESS_CPUTIME_ID = rt::CLOCK_PROCESS_CPUTIME_ID, +}; + +// Returns the current time for a given clock. +export fn now(clock: clock) instant = { + let tp = rt::timespec { ... }; + match (rt::clock_gettime(clock, &tp)) { + case void => + return timespec_to_instant(tp); + case let err: rt::errno => + abort("Unexpected error from clock_gettime"); + }; +}; diff --git a/time/chrono/+netbsd.ha b/time/chrono/+netbsd.ha @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +def LOCALTIME_PATH: str = "/etc/localtime"; +def TZDB_PATH: str = "/usr/share/zoneinfo/"; + +// The filepath of the system's "leap-seconds.list" file, which contains UTC/TAI +// leap second data. +export def UTC_LEAPSECS_PATH: str = "/usr/share/zoneinfo/leap-seconds.list"; diff --git a/unix/+netbsd/creds.ha b/unix/+netbsd/creds.ha @@ -0,0 +1,108 @@ +// 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() as rt::uid_t: uid; + +// Returns the current process effective user ID. +export fn geteuid() uid = rt::geteuid() as rt::uid_t: uid; + +// Returns the current process group ID. +export fn getgid() gid = rt::getgid() as rt::gid_t: gid; + +// Returns the current process effective group ID. +export fn getegid() gid = rt::getegid() as rt::gid_t: gid; + +// 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(euid: uid) void = rt::seteuid(&euid)!; + +// 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(egid: gid) void = rt::setegid(&egid)!; + +// 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/+netbsd/nice.ha b/unix/+netbsd/nice.ha @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use rt; + +// Adds the argument to the niceness of the current process. The input should be +// between -20 and 19 (inclusive); lower numbers represent a higher priority. +// Generally, you must have elevated permissions to reduce your niceness, but +// not to increase it. +export fn nice(inc: int) (void | errors::error) = { + let prio = inc; + if (inc > -40 && inc <= 40) { + prio += rt::getpriority(rt::PRIO_PROCESS, 0) as int; + }; + if (prio > 19) { + prio = 19; + }; + if (prio < -20) { + prio = -20; + }; + match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) { + case void => void; + case let err: rt::errno => + return errors::errno(err); + }; +}; diff --git a/unix/+netbsd/pipe.ha b/unix/+netbsd/pipe.ha @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use rt; + +// Flags to use for the [[io::file]]s returned by [[pipe]]. +// Only NOCLOEXEC and NONBLOCK are guaranteed to be available. +export type pipe_flag = enum { + NOCLOEXEC = rt::O_CLOEXEC, + NONBLOCK = rt::O_NONBLOCK, +}; + +// Create a pair of two linked [[io::file]]s, such that any data written to the +// second [[io::file]] may be read from the first. +export fn pipe(flags: pipe_flag = 0) ((io::file, io::file) | errors::error) = { + let fds: [2]int = [0...]; + flags ^= pipe_flag::NOCLOEXEC; // invert CLOEXEC + match (rt::pipe2(&fds, flags)) { + case void => void; + case let e: rt::errno => + return errors::errno(e); + }; + return (fds[0], fds[1]); +}; diff --git a/unix/+netbsd/umask.ha b/unix/+netbsd/umask.ha @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use fs; +use rt; + +// Sets the file mode creation mask for the current process and return the +// previous value of the mask. +export fn umask(mode: fs::mode) fs::mode = rt::umask(mode: rt::mode_t)!: fs::mode; diff --git a/unix/hosts/+netbsd.ha b/unix/hosts/+netbsd.ha @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +def PATH: str = "/etc/hosts"; diff --git a/unix/poll/+netbsd.ha b/unix/poll/+netbsd.ha @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use rt; +use time; + +// Events bitfield for the events and revents field of [[pollfd]]. +export type event = enum i16 { + POLLIN = 1, + POLLPRI = 2, + POLLOUT = 4, + POLLERR = 8, + POLLHUP = 16, +}; + +// A single file descriptor to be polled. +export type pollfd = struct { + fd: io::file, + events: i16, + revents: i16, +}; + +// Pass this [[time::duration]] to [[poll]] to cause it wait indefinitely for +// the next event. +export def INDEF: time::duration = -1; + +// Pass this [[time::duration]] to [[poll]] to cause it to return immediately if +// no events are available. +export def NONBLOCK: time::duration = 0; + +// Polls for the desired events on a slice of [[pollfd]]s, blocking until an +// event is available, or the timeout expires. Set the timeout to [[INDEF]] to +// block forever, or [[NONBLOCK]] to return immediately if no events are +// available. Returns the number of [[pollfd]] items which have events, i.e. +// those which have revents set to a nonzero value. +export fn poll( + fds: []pollfd, + timeout: time::duration, +) (uint | error) = { + let ts = time::duration_to_timespec(timeout); + let ts = if (timeout == INDEF) null else &ts; + match (rt::ppoll(fds: *[*]pollfd: *[*]rt::pollfd, len(fds): rt::nfds_t, ts, null)) { + case let err: rt::errno => + return errors::errno(err); + case let n: int => + return n: uint; + }; +}; diff --git a/unix/resolvconf/+netbsd.ha b/unix/resolvconf/+netbsd.ha @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +def PATH: str = "/etc/resolv.conf"; diff --git a/unix/signal/+netbsd.ha b/unix/signal/+netbsd.ha @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use rt; +use time; +use unix; + +// Requests that [[sig::ALRM]] is delivered to the calling process in (about) +// "sec" seconds. Returns the number of seconds until the previously scheduled +// alarm, or zero if none was scheduled. +export fn alarm(sec: uint) uint = { + return rt::alarm(sec); +}; + +// Configures a new signal handler, returning the old details (which can be +// passed to [[restore]] to restore its behavior). +// +// The variadic parameters specify either [[flag]]s to enable or a signal mask +// to use via [[sigset]]; if the latter is provided no more than one may be +// used. +export fn handle( + signum: sig, + handler: *handler, + opt: (flag | sigset)... +) sigaction = { + let sa_mask = newsigset(); + + let sa_flags = rt::SA_SIGINFO: int, nmask = 0; + for (let i = 0z; i < len(opt); i += 1) { + match (opt[i]) { + case let flag: flag => + sa_flags |= flag: int; + case let mask: sigset => + assert(nmask == 0, "Multiple signal masks provided to signal::handle"); + nmask += 1; + sa_mask = mask; + }; + }; + + let new = rt::sigact { + sa_sigaction = handler: *fn(int, *rt::siginfo, *opaque) void, + sa_mask = sa_mask, + sa_flags = sa_flags, + }; + let old = rt::sigact { + sa_sigaction = null: *fn(int, *rt::siginfo, *opaque) void, + ... + }; + match (rt::sigaction(signum, &new, &old)) { + case rt::errno => + abort("sigaction failed (invalid signal?)"); + case int => void; + }; + return old; +}; + +// Restores previous signal behavior following [[handle]]. +export fn restore(signum: sig, action: *sigaction) void = { + match (rt::sigaction(signum, action: *rt::sigact, null)) { + case rt::errno => + abort("sigaction failed (invalid signal?)"); + case int => void; + }; +}; + +// Unregisters signal handlers for the specified signal. +export fn reset(signum: sig) void = { + handle(signum, rt::SIG_DFL: *handler); +}; + +// Unregisters all signal handlers. +export fn resetall() void = { + // sig::KILL and sig::STOP deliberately omitted; see sigaction(2) + reset(sig::HUP); + reset(sig::INT); + reset(sig::QUIT); + reset(sig::ILL); + reset(sig::TRAP); + reset(sig::ABRT); + reset(sig::EMT); + reset(sig::FPE); + reset(sig::BUS); + reset(sig::SEGV); + reset(sig::SYS); + reset(sig::PIPE); + reset(sig::ALRM); + reset(sig::TERM); + reset(sig::URG); + reset(sig::TSTP); + reset(sig::CONT); + reset(sig::CHLD); + reset(sig::TTIN); + reset(sig::TTOU); + reset(sig::IO); + reset(sig::XCPU); + reset(sig::XFSZ); + reset(sig::VTALRM); + reset(sig::PROF); + reset(sig::WINCH); + reset(sig::INFO); + reset(sig::USR1); + reset(sig::USR2); + reset(sig::THR); + reset(sig::LIBRT); +}; + +// Prevents given signal from arriving to the current process. +// One common use case is to ignore SIGCHLD to avoid zombie child processes. +export fn ignore(signum: sig) void = { + handle(signum, rt::SIG_IGN: *handler); +}; + +// Adds the given list of signals to the process's current signal mask, +// returning the old signal mask. This is a convenience function around +// [[setprocmask]]. +export fn block(signals: sig...) sigset = { + let new = newsigset(signals...); + return setprocmask(how::BLOCK, &new); +}; + +// Removes the given list of signals from the process's current signal mask, +// returning the old signal mask. This is a convenience function around +// [[setprocmask]]. +export fn unblock(signals: sig...) sigset = { + let new = newsigset(signals...); + return setprocmask(how::UNBLOCK, &new); +}; + +// Sets the process's signal mask, returning the previous mask. +export fn setprocmask(how: how, mask: *sigset) sigset = { + let old = sigset { ... }; + rt::sigprocmask(how, mask: *rt::sigset, &old)!; + return old; +}; + +// Gets the current process's signal mask. +export fn getprocmask() sigset = { + let old = sigset { ... }; + rt::sigprocmask(how::SETMASK, null, &old)!; + return old; +}; + +// Defines the modes of operation for [[setprocmask]]. +export type how = enum int { + // Adds the given set of signals to the current mask. + BLOCK = rt::SIG_BLOCK, + // Removes the given set of signals from the current mask. + UNBLOCK = rt::SIG_UNBLOCK, + // Sets the process mask to the given set. + SETMASK = rt::SIG_SETMASK, +}; + +export type sigaction = rt::sigact; + +export type sigset = rt::sigset; + +// Creates a new signal set filled in with the provided signals (or empty if +// none are provided). +export fn newsigset(items: sig...) sigset = { + let set = sigset { ... }; + rt::sigemptyset(&set); + sigset_add(&set, items...); + return set; +}; + +// Sets a [[sigset]] to empty. +export fn sigset_empty(set: *sigset) void = { + rt::sigemptyset(set: *rt::sigset); +}; + +// Adds signals to a [[sigset]]. +export fn sigset_add(set: *sigset, items: sig...) void = { + for (let i = 0z; i < len(items); i += 1) { + rt::sigaddset(set: *rt::sigset, items[i])!; + }; +}; + +// Removes signals from a [[sigset]]. +export fn sigset_del(set: *sigset, items: sig...) void = { + for (let i = 0z; i < len(items); i += 1) { + rt::sigdelset(set: *rt::sigset, items[i])!; + }; +}; + +// Adds all platform-defined signals to a [[sigset]]. +export fn sigset_fill(set: *sigset) void = { + rt::sigfillset(set: *rt::sigset)!; +}; + +// Returns true if the given signal is a member of this [[sigset]]. +export fn sigset_member(set: *sigset, item: sig) bool = { + return rt::sigismember(set: *rt::sigset, item)!; +}; + +// Waits for a signal among the given [[sigset]] to be delivered, then returns +// the signal number. +// +// If a signal is received while waiting, [[errors::interrupted]] is returned. +// Most consumers of this function will likely wish to block all signals and +// handle them exclusively through [[wait]] et al, in which case this error +// cannot occur. +// +// See also [[waitinfo]] and [[timedwait]]. +export fn wait(set: *sigset) (sig | errors::interrupted) = { + let signal = 0i; + match (rt::sigwait(set: *rt::sigset, &signal)) { + case let err: rt::errno => + assert(err == rt::EINTR); + return errors::interrupted; + case void => + return signal: sig; + }; +}; + +// Waits for a signal among the given [[sigset]] to be delivered, then returns +// the corresponding [[siginfo]] data. +// +// See notes on [[wait]] regarding the [[errors::interrupted]] case. +// +// This function is designed to provide the portable subset of the semantics of +// sigwaitinfo(3) as defined by POSIX.1-2008. To access the complete siginfo_t +// structure provided by the underlying platform, use [[rt::sigwaitinfo]] and +// [[rt::siginfo_t]] directly. +// +// Note that this function is not supported on NetBSD. +export fn waitinfo(set: *sigset) (siginfo | errors::interrupted) = { + let info = rt::siginfo { + si_addr = null: *opaque, + si_value = rt::sigval { ... }, + ... + }; + match (rt::sigwaitinfo(set: *rt::sigset, &info)) { + case let err: rt::errno => + assert(err == rt::EINTR); + return errors::interrupted; + case int => + return *(&info: *siginfo); + }; +}; + +// Waits for a signal among the given [[sigset]] to be delivered, then returns +// the corresponding [[siginfo]] data. +// +// Returns a [[siginfo]] if a signal is successfully processed through this +// function, or [[errors::again]] if the timeout expired. See notes on [[wait]] +// regarding the [[errors::interrupted]] case. +// +// This function is designed to provide the portable subset of the semantics of +// sigtimedwait(3) as defined by POSIX.1-2008. To access the complete siginfo_t +// structure provided by the underlying platform, use [[rt::sigtimedwait]] and +// [[rt::siginfo_t]] directly. +// +// Note that this function is not supported on OpenBSD. +export fn timedwait( + set: *sigset, + timeout: time::duration, +) (siginfo | errors::interrupted | errors::again) = { + let info = rt::siginfo { + si_addr = null: *opaque, + si_value = rt::sigval { ... }, + ... + }; + let to = time::duration_to_timeval(timeout); + match (rt::sigwaitinfo(set: *rt::sigset, &info)) { + case let err: rt::errno => + switch (err) { + case rt::EINTR => + return errors::interrupted; + case rt::EAGAIN => + return errors::again; + case => abort(); + }; + case int => + return *(&info: *siginfo); + }; +}; + +// Provides additional information about signal deliveries. Only the members +// defined by POSIX are available here; cast to [[rt::siginfo]] to access +// non-portable members. +export type siginfo = union { + struct { + // The signal number being delivered. + signo: sig, + // The errno, if any, associated with this signal. See + // [[errors::errno]] to convert to a Hare-native error. + errno: rt::errno, + // The signal code, if any. + code: code, + // Process ID of the sender. + pid: unix::pid, + // Real user ID of the sending process. + uid: unix::uid, + // Exit value or signal. + status: int, + // Address of the faulting instruction. + addr: *opaque, + }, + // Pads the structure out to the length used by the kernel; do not use. + _si_pad: [128 - 3 * size(int)]u8, +}; + +// A code indicating why a signal was sent. +export type code = enum int { + USER = 0, // sent by userspace program (kill) + KERNEL = 128, // sent by kernel + QUEUE = -1, // sent by sigqueue + TIMER = -2, // generated by expiration of a timer + MESQ = -3, // generated by arrival of a message on an empty queue + ASYNCIO = -4, // generated by completion of an asynchronous I/O request + SIGIO = -5, + TKILL = -6, // sent by userspace program (tkill, tgkill) + ASYNCNL = -60, + + ILLOPC = 1, // sig::ILL: illegal opcode + ILLOPN = 2, // sig::ILL: illegal operand + ILLADR = 3, // sig::ILL: illegal addressing mode + ILLTRP = 4, // sig::ILL: illegal trap + PRVOPC = 5, // sig::ILL: privileged opcode + PRVREG = 6, // sig::ILL: privileged register + COPROC = 7, // sig::ILL: coprocessor error + BADSTK = 8, // sig::ILL: internal stack error + + INTOVF = 1, // sig::FPE: integer overflow + INTDIV = 2, // sig::FPE: integer divide by zero + FLTDIV = 3, // sig::FPE: floating-point divide by zero + FLTOVF = 4, // sig::FPE: floating-point overflow + FLTUND = 5, // sig::FPE: floating-point underflow + FLTRES = 6, // sig::FPE: floating-point inexact result + FLTINV = 7, // sig::FPE: invalid floating-point operation + FLTSUB = 8, // sig::FPE: subscript out of range + + MAPERR = 1, // sig::SEGV: address not mapped to object + ACCERR = 2, // sig::SEGV: invalid permissions for mapped object + PKUERR = 100, // sig::SEGV: access was denied by memory protection keys (x86_64) + + ADRALN = 1, // sig::BUS: invalid address alignment + ADRERR = 2, // sig::BUS: nonexistent physical address + OBJERR = 3, // sig::BUS: object-specific hardware error + OOMERR = 100, // sig::BUS: out of memory + + BRKPT = 1, // sig::TRAP: process breakpoint + TRACE = 2, // sig::TRAP: process trace trap + DTRACE = 3, // sig::TRAP: DTrace induced trap + CAP = 4, // sig::TRAP: capabilities protection trap + + EXITED = 1, // sig::CHLD: child exited + KILLED = 2, // sig::CHLD: child terminated abnormally without a core file + DUMPED = 3, // sig::CHLD: child terminated abnormally with a core file + TRAPPED = 4, // sig::CHLD: traced child has trapped + STOPPED = 5, // sig::CHLD: child has stopped + CONTINUED = 6, // sig::CHLD: stopped child has continued + + IN = 1, // sig::IO: data input available + OUT = 2, // sig::IO: output buffers available + MSG = 3, // sig::IO: input message available + ERR = 4, // sig::IO: I/O error + PRI = 5, // sig::IO: high priority input available + HUP = 6, // sig::IO: device disconnected +}; + +// Flags used to configure the behavior of a signal handler. +export type flag = enum int { + // For use with sig::CHLD. Prevents notifications when child processes + // stop (e.g. via sig::STOP) or resume (i.e. sig::CONT). + NOCLDSTOP = rt::SA_NOCLDSTOP: int, + // For use with sig::CHLD. Do not transform children into zombies when + // they terminate. Note that POSIX leaves the delivery of sig::CHLD + // unspecified when this flag is present; some systems will still + // deliver a signal and others may not. + NOCLDWAIT = rt::SA_NOCLDWAIT: int, + // Uses an alternate stack when handling this signal. See + // [[setaltstack]] and [[getaltstack]] for details. + ONSTACK = rt::SA_ONSTACK: int, + // Do not add the signal to the signal mask while executing the signal + // handler. This can cause the same signal to be delivered again during + // the execution of the signal handler. + NODEFER = rt::SA_NODEFER: int, + // Restore the signal handler to the default behavior upon entering the + // signal handler. + RESETHAND = rt::SA_RESETHAND: int, + // Makes certain system calls restartable across signals. See signal(7) + // or similar documentation for your local system for details. + RESTART = rt::SA_RESTART: int, +}; + +// All possible signals. +export type sig = enum int { + HUP = rt::SIGHUP, // Hangup. + INT = rt::SIGINT, // Terminal interrupt. + QUIT = rt::SIGQUIT, // Terminal quit. + ILL = rt::SIGILL, // Illegal instruction. + TRAP = rt::SIGTRAP, // Trace/breakpoint trap. + ABRT = rt::SIGABRT, // Process abort. + IOT = rt::SIGIOT, // Synonym for ABRT, provided for compatibility. + EMT = rt::SIGEMT, // Emulate instruction executed. + FPE = rt::SIGFPE, // Erroneous arithmetic operation. + KILL = rt::SIGKILL, // Kill (cannot be caught or ignored). + BUS = rt::SIGBUS, // Access to an undefined portion of a memory object. + SEGV = rt::SIGSEGV, // Invalid memory reference. + SYS = rt::SIGSYS, // Bad system call. + PIPE = rt::SIGPIPE, // Write on a pipe with no one to read it. + ALRM = rt::SIGALRM, // Alarm clock. + TERM = rt::SIGTERM, // Termination. + URG = rt::SIGURG, // High bandwidth data is available at a socket. + STOP = rt::SIGSTOP, // Stop executing (cannot be caught or ignored). + TSTP = rt::SIGTSTP, // Terminal stop. + CONT = rt::SIGCONT, // Continue executing, if stopped. + CHLD = rt::SIGCHLD, // Child process terminated, stopped, or continued. + TTIN = rt::SIGTTIN, // Background process attempting read. + TTOU = rt::SIGTTOU, // Background process attempting write. + IO = rt::SIGIO, // I/O now possible. + XCPU = rt::SIGXCPU, // CPU time limit exceeded. + XFSZ = rt::SIGXFSZ, // File size limit exceeded. + VTALRM = rt::SIGVTALRM, // Virtual timer expired. + PROF = rt::SIGPROF, // Profiling timer expired. + WINCH = rt::SIGWINCH, // Window resize. + INFO = rt::SIGINFO, // Status request from keyboard. + USR1 = rt::SIGUSR1, // User-defined signal 1. + USR2 = rt::SIGUSR2, // User-defined signal 2. + THR = rt::SIGTHR, // Thread interrupt. + LIBRT = rt::SIGLIBRT, // Real-time library interrupt. +}; + +// Returns the human friendly name of a given signal. +export fn signame(sig: sig) const str = { + switch (sig) { + case sig::HUP => + return "SIGHUP"; + case sig::INT => + return "SIGINT"; + case sig::QUIT => + return "SIGQUIT"; + case sig::ILL => + return "SIGILL"; + case sig::TRAP => + return "SIGTRAP"; + case sig::ABRT => + return "SIGABRT"; + case sig::EMT => + return "SIGEMT"; + case sig::FPE => + return "SIGFPE"; + case sig::KILL => + return "SIGKILL"; + case sig::BUS => + return "SIGBUS"; + case sig::SEGV => + return "SIGSEGV"; + case sig::SYS => + return "SIGSYS"; + case sig::PIPE => + return "SIGPIPE"; + case sig::ALRM => + return "SIGALRM"; + case sig::TERM => + return "SIGTERM"; + case sig::URG => + return "SIGURG"; + case sig::STOP => + return "SIGSTOP"; + case sig::TSTP => + return "SIGTSTP"; + case sig::CONT => + return "SIGCONT"; + case sig::CHLD => + return "SIGCHLD"; + case sig::TTIN => + return "SIGTTIN"; + case sig::TTOU => + return "SIGTTOU"; + case sig::IO => + return "SIGIO"; + case sig::XCPU => + return "SIGXCPU"; + case sig::XFSZ => + return "SIGXFSZ"; + case sig::VTALRM => + return "SIGVTALRM"; + case sig::PROF => + return "SIGPROF"; + case sig::WINCH => + return "SIGWINCH"; + case sig::INFO => + return "SIGINFO"; + case sig::USR1 => + return "SIGUSR1"; + case sig::USR2 => + return "SIGUSR2"; + case sig::THR => + return "SIGTHR"; + case sig::LIBRT => + return "SIGLIBRT"; + }; +}; diff --git a/unix/tty/+netbsd/isatty.ha b/unix/tty/+netbsd/isatty.ha @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use io; +use os; +use rt; + +// Returns whether the given stream is connected to a terminal. +export fn isatty(fd: io::file) bool = { + let wsz = rt::winsize { ... }; + match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { + case let e: rt::errno => + return false; + case let r: int => + return r == 0; + }; +}; diff --git a/unix/tty/+netbsd/open.ha b/unix/tty/+netbsd/open.ha @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use fs; +use io; +use os; + +// Returns a stream connected to the TTY of the current process. The caller must +// close it using [[io::close]]. +export fn open() (io::file | error) = { + match (os::open("/dev/tty", fs::flag::RDWR)) { + case let f: io::file => + return f; + case fs::error => + return errors::noentry; + }; +}; diff --git a/unix/tty/+netbsd/pgid.ha b/unix/tty/+netbsd/pgid.ha @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use os::exec; +use rt; + +// Sets the process group on the foreground of this terminal. +export fn tcsetpgrp(fd: io::file, pg: exec::process) (void | errors::error) = { + match (rt::ioctl(fd, rt::TIOCSPGRP, pg: u64)) { + case int => void; + case let err: rt::errno => + return errors::errno(err); + }; +}; diff --git a/unix/tty/+netbsd/pty.ha b/unix/tty/+netbsd/pty.ha @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use fmt; +use fs; +use io; +use os; +use rt; +use types::c; +use strings; + +// Opens an available pseudoterminal and returns the file descriptors of the +// master and slave. +export fn openpty() ((io::file, io::file) | fs::error) = { + let master = open_master()?; + let slave = match (get_slave(master)) { + case let e: fs::error => + io::close(master)!; + return e; + case let s: io::file => + yield s; + }; + return (master, slave); +}; + +// Opens an available pseudoterminal master. +fn open_master() (io::file | fs::error) = { + match (rt::posix_openpt(rt::O_RDWR | rt::O_NOCTTY)) { + case let e: rt::errno => + return errors::errno(e); + case let i: int => + return io::fdopen(i); + }; +}; + +// Returns a file descriptor referring to the pseudoterminal slave for a +// pseudoterminal master. +fn get_slave(master: io::file) (io::file | fs::error) = + os::open(ptsname(master)?, fs::flag::RDWR); + +// Returns the filename of the pseudoterminal slave. +export fn ptsname(master: io::file) (str | error) = { + let pm = rt::ptmget { ... }; + match (rt::ioctl(master, rt::TIOCPTSNAME, &pm)) { + case let e: rt::errno => + switch (e) { + case rt::EBADF => + return errors::invalid; + case rt::EINVAL, rt::ENOTTY => + return errors::unsupported; + case => + abort("Unexpected error from ioctl"); + }; + case => void; + }; + return strings::dup(c::tostr(&pm.sn: *const c::char)!); +}; + +// Sets the dimensions of the underlying pseudoterminal for an [[io::file]]. +export fn set_winsize(pty: io::file, sz: ttysize) (void | error) = { + let wsz = rt::winsize { ws_row = sz.rows, ws_col = sz.columns, ... }; + match (rt::ioctl(pty, rt::TIOCSWINSZ, &wsz)) { + case let e: rt::errno => + switch (e) { + case rt::EBADF, rt::EINVAL => + return errors::invalid; + case rt::ENOTTY => + return errors::unsupported; + case => + abort("Unexpected error from ioctl"); + }; + case => void; + }; +}; diff --git a/unix/tty/+netbsd/termios.ha b/unix/tty/+netbsd/termios.ha @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use rt; + +export type termios = struct { + file: io::file, + saved: rt::termios, + current: rt::termios, +}; + +// Retrieves serial port settings of the given terminal. +export fn termios_query(file: io::file) (termios | errors::error) = { + let settings = rt::termios { ... }; + + match (rt::ioctl(file, rt::TIOCGETA, &settings)) { + case int => void; + case let err: rt::errno => + return errors::errno(err); + }; + + return termios { + file = file, + saved = settings, + current = settings, + }; +}; + +// Restores original serial port settings. +export fn termios_restore(termios: *const termios) void = { + rt::ioctl(termios.file, rt::TIOCSETA, &termios.saved): void; +}; + +// Sets serial port settings. +export fn termios_set(termios: *const termios) (void | errors::error) = { + match (rt::ioctl(termios.file, rt::TIOCSETA, &termios.current)) { + case int => void; + case let err: rt::errno => + return errors::errno(err); + }; +}; + +// Enables "raw" mode for this terminal, disabling echoing, line +// editing, and signal handling. Users should call [[termios_query]] +// prior to this to save the previous terminal settings, and +// [[termios_restore]] to restore them before exiting. +export fn makeraw(termios: *termios) (void | errors::error) = { + // Disable break signal and CR<->LF processing + termios.current.c_iflag &= ~(rt::tcflag::IGNBRK | rt::tcflag::BRKINT + | rt::tcflag::INLCR | rt::tcflag::IGNCR + | rt::tcflag::ICRNL); + // Disable output post-processing + termios.current.c_oflag &= ~rt::tcflag::OPOST; + // Disable character echo, canonical mode, implementation defined + // extensions and INTR/QUIT/SUSP characters + termios.current.c_lflag &= ~(rt::tcflag::ECHO | rt::tcflag::ECHONL + | rt::tcflag::ICANON | rt::tcflag::IEXTEN + | rt::tcflag::ISIG); + + termios_set(termios)?; +}; + +// Disables "echo" on this terminal. Users should call [[termios_restore]] to +// restore settings. +export fn noecho(termios: *termios) (void | errors::error) = { + termios.current.c_lflag &= ~rt::tcflag::ECHO; + termios_set(termios)?; +}; + +// Enables "noncanonical" mode for this terminal, disabling line buffering and +// line editing. Users should call [[termios_restore]] to restore settings. +export fn noncanonical(termios: *termios) (void | errors::error) = { + termios.current.c_lflag &= ~rt::tcflag::ICANON; + termios_set(termios)?; +}; diff --git a/unix/tty/+netbsd/winsize.ha b/unix/tty/+netbsd/winsize.ha @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; +use os; +use rt; + +// Returns the dimensions of underlying terminal for an [[io::file]]. +export fn winsize(fd: io::file) (ttysize | error) = { + let wsz = rt::winsize { ... }; + match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *opaque)) { + case let e: rt::errno => + switch (e) { + case rt::EBADF => + return errors::invalid; + case rt::ENOTTY => + return errors::unsupported; + case => + abort("Unexpected error from ioctl"); + }; + case int => + return ttysize { + rows = wsz.ws_row, + columns = wsz.ws_col, + }; + }; +};