Welcome to little lamb

Code » limb » commit 658092a

djbunix.h: Adjust doc/interfaces & complete documentation

author Olivier Brunel
2023-07-04 11:45:23 UTC
committer Olivier Brunel
2023-07-24 10:16:42 UTC
parent b7653a232ce46ced14486dd6411518fb4f44f1b5

djbunix.h: Adjust doc/interfaces & complete documentation

src/doc/djbunix.h.0.md +268 -44
src/doc/djbunix.h/coe.3.md +43 -0
src/doc/djbunix.h/fd_chdir.3.md +30 -0
src/doc/djbunix.h/fd_mkdirpat.3.md +1 -1
src/doc/djbunix.h/ndelay_off.3.md +1 -0
src/doc/djbunix.h/ndelay_on.3.md +1 -0
src/doc/djbunix.h/open2.3.md +52 -0
src/doc/djbunix.h/open2_at.3.md +1 -0
src/doc/djbunix.h/open3.3.md +1 -0
src/doc/djbunix.h/open3_at.3.md +1 -0
src/doc/djbunix.h/open_append.3.md +1 -0
src/doc/djbunix.h/open_appendat.3.md +1 -0
src/doc/djbunix.h/open_atb.3.md +1 -0
src/doc/djbunix.h/open_b.3.md +44 -0
src/doc/djbunix.h/open_create.3.md +1 -0
src/doc/djbunix.h/open_createat.3.md +1 -0
src/doc/djbunix.h/open_excl.3.md +1 -0
src/doc/djbunix.h/open_exclat.3.md +1 -0
src/doc/djbunix.h/open_parsed_name.3.md +2 -2
src/doc/djbunix.h/open_read.3.md +255 -0
src/doc/djbunix.h/open_read_close.3.md +1 -29
src/doc/djbunix.h/open_read_closeat.3.md +64 -0
src/doc/djbunix.h/open_readat.3.md +1 -0
src/doc/djbunix.h/open_readatb.3.md +1 -0
src/doc/djbunix.h/open_readb.3.md +1 -0
src/doc/{unix-transactional.h/open_slurp_closeat.3.md => djbunix.h/open_saread_close.3.md} +0 -0
src/doc/djbunix.h/open_saread_closeat.3.md +1 -0
src/doc/djbunix.h/open_slurp_close.3.md +0 -1
src/doc/djbunix.h/open_tmp.3.md +1 -1
src/doc/{unix-transactional.h => djbunix.h}/open_tmpat.3.md +1 -1
src/doc/djbunix.h/open_trunc.3.md +1 -0
src/doc/djbunix.h/open_truncat.3.md +1 -0
src/doc/djbunix.h/open_write.3.md +1 -0
src/doc/djbunix.h/open_write_close.3.md +1 -1
src/doc/{unix-transactional.h => djbunix.h}/open_write_closeat.3.md +18 -7
src/doc/djbunix.h/open_writeat.3.md +1 -0
src/doc/djbunix.h/open_writeatb.3.md +1 -0
src/doc/djbunix.h/open_writeb.3.md +1 -0
src/doc/djbunix.h/open_writev_close.3.md +1 -1
src/doc/{unix-transactional.h => djbunix.h}/open_writev_closeat.3.md +0 -0
src/doc/djbunix.h/openb_read.3.md +1 -0
src/doc/djbunix.h/openb_readat.3.md +1 -0
src/doc/djbunix.h/openb_write.3.md +1 -0
src/doc/djbunix.h/openb_writeat.3.md +1 -0
src/doc/djbunix.h/openbc_read.3.md +1 -0
src/doc/djbunix.h/openbc_readat.3.md +1 -0
src/doc/djbunix.h/openbc_write.3.md +1 -0
src/doc/djbunix.h/openbc_writeat.3.md +1 -0
src/doc/djbunix.h/openc_append.3.md +1 -0
src/doc/djbunix.h/openc_appendat.3.md +1 -0
src/doc/djbunix.h/openc_create.3.md +1 -0
src/doc/djbunix.h/openc_createat.3.md +1 -0
src/doc/djbunix.h/openc_excl.3.md +1 -0
src/doc/djbunix.h/openc_exclat.3.md +1 -0
src/doc/djbunix.h/openc_read.3.md +1 -0
src/doc/djbunix.h/openc_readat.3.md +1 -0
src/doc/djbunix.h/openc_readatb.3.md +1 -0
src/doc/djbunix.h/openc_readb.3.md +1 -0
src/doc/djbunix.h/openc_trunc.3.md +1 -0
src/doc/djbunix.h/openc_truncat.3.md +1 -0
src/doc/djbunix.h/openc_write.3.md +1 -0
src/doc/djbunix.h/openc_writeat.3.md +1 -0
src/doc/djbunix.h/openc_writeatb.3.md +1 -0
src/doc/djbunix.h/openc_writeb.3.md +1 -0
src/doc/djbunix.h/read_close.3.md +31 -0
src/doc/djbunix.h/rm_rf.3.md +92 -0
src/doc/djbunix.h/rm_rf_in_tmp.3.md +1 -0
src/doc/djbunix.h/rm_rf_in_tmpat.3.md +1 -1
src/doc/djbunix.h/rm_rf_tmp.3.md +1 -0
src/doc/djbunix.h/rm_rf_tmpat.3.md +1 -1
src/doc/djbunix.h/rm_rfat.3.md +1 -82
src/doc/djbunix.h/rmstar.3.md +1 -0
src/doc/djbunix.h/rmstar_in_tmpat.3.md +1 -1
src/doc/djbunix.h/rmstar_tmp.3.md +1 -0
src/doc/djbunix.h/rmstar_tmpat.3.md +1 -1
src/doc/djbunix.h/rmstarat.3.md +1 -1
src/doc/djbunix.h/sa_ls.3.md +1 -0
src/doc/djbunix.h/sa_lsat.3.md +46 -0
src/doc/djbunix.h/sa_read.3.md +38 -0
src/doc/djbunix.h/sa_readlink.3.md +1 -0
src/doc/djbunix.h/sa_readlink0.3.md +1 -0
src/doc/djbunix.h/sa_readlinkat.3.md +55 -0
src/doc/djbunix.h/sa_readlinkat0.3.md +1 -0
src/doc/djbunix.h/sa_readmax.3.md +1 -0
src/doc/djbunix.h/sa_realpath.3.md +1 -0
src/doc/djbunix.h/sa_realpathat.3.md +51 -0
src/doc/djbunix.h/salsat.3.md +0 -55
src/doc/djbunix.h/salst.3.md +0 -1
src/doc/djbunix.h/salstat.3.md +0 -1
src/doc/djbunix.h/sareadlinkat.3.md +0 -59
src/doc/djbunix.h/sarealpath.3.md +0 -59
src/doc/djbunix.h/uncoe.3.md +1 -0
src/doc/unix-transactional.h.0.md +0 -57
src/doc/unix-transactional.h/open_createat.3.md +0 -37
src/doc/unix-transactional.h/open_exclat.3.md +0 -37
src/doc/unix-transactional.h/open_read_closeat.3.md +0 -54
src/doc/unix-transactional.h/openb_readat.3.md +0 -35
src/doc/unix-transactional.h/openbc_readat.3.md +0 -1
src/doc/unix-transactional.h/openc_createat.3.md +0 -1
src/doc/unix-transactional.h/openc_exclat.3.md +0 -1
src/liblimb/direntry.h/open_writeb.c +10 -0
src/liblimb/direntry.h/openc_writeb.c +10 -0
src/liblimb/direntry.h/opendirat.c +1 -2
src/liblimb/djbunix.h/fd_mkdirpat.c +0 -1
src/liblimb/djbunix.h/open_atb.c +16 -0
src/liblimb/djbunix.h/open_b.c +16 -0
src/liblimb/{unix-transactional.h => djbunix.h}/open_createat.c +1 -2
src/liblimb/{unix-transactional.h => djbunix.h}/open_exclat.c +1 -2
src/liblimb/{unix-transactional.h => djbunix.h}/open_read_closeat.c +0 -1
src/liblimb/{unix-transactional.h/open_slurp_closeat.c => djbunix.h/open_saread_closeat.c} +2 -3
src/liblimb/{unix-transactional.h => djbunix.h}/open_write_closeat.c +0 -1
src/liblimb/{unix-transactional.h => djbunix.h}/open_writev_closeat.c +0 -1
src/liblimb/{unix-transactional.h => djbunix.h}/openb_readat.c +1 -1
src/liblimb/djbunix.h/openb_write.c +11 -0
src/liblimb/djbunix.h/openb_writeat.c +11 -0
src/liblimb/{unix-transactional.h => djbunix.h}/openbc_readat.c +1 -1
src/liblimb/djbunix.h/openbc_write.c +11 -0
src/liblimb/djbunix.h/openbc_writeat.c +11 -0
src/liblimb/{unix-transactional.h => djbunix.h}/openc_createat.c +1 -2
src/liblimb/{unix-transactional.h => djbunix.h}/openc_exclat.c +1 -2
src/liblimb/djbunix.h/rmstar_in_tmpat.c +1 -1
src/liblimb/djbunix.h/{salsat.c => sa_lsat.c} +1 -1
src/liblimb/djbunix.h/{sareadlinkat.c => sa_readlinkat.c} +1 -1
src/liblimb/djbunix.h/{sareadlinkat0.c => sa_readlinkat0.c} +2 -2
src/liblimb/djbunix.h/{sarealpathat.c => sa_realpathat.c} +2 -2
src/liblimb/djbunix.h/sareadlink0.c +0 -18
src/liblimb/hmac.h/hmac.c +1 -1
src/liblimb/include/limb/djbunix.h +43 -10
src/liblimb/include/limb/unix-transactional.h +0 -26
src/liblimb/readopt.h/readopt.c +1 -1
src/liblimb/shldata-rw.h/shldata_read.c +0 -1
src/liblimb/shldata-rw.h/shldata_write.c +0 -1

diff --git a/src/doc/djbunix.h.0.md b/src/doc/djbunix.h.0.md
index 78b3e1a..8526836 100644
--- a/src/doc/djbunix.h.0.md
+++ b/src/doc/djbunix.h.0.md
@@ -14,105 +14,329 @@ djbunix.h - standard I/O and other Unix system calls interfaces
 `djbunix` offers alternative API to basic Unix concepts, dealing with I/O
 operations, file descriptors, environment, child processes, and so on.
 
-! INFO: skalibs
-! This header is a complement to skalibs' own [skalibs/djbunix.h](0) and thusly
-! includes said header.
+<inc skalibs.md>
 
 ## Functions
 
 The following functions/macros are defined :
 
-: [fd_mkdirpat](3)
-:: Create a path of directories and returns the file descriptor.
+: [open_read](3)
+:: Open a file for reading with *O_NONBLOCK* set.
 
-: [fd_mkdirp](3)
-:: Same as [fd_mkdirpat](3) but relative path are based on current working
-:: directory.
+: [open_readat](3)
+:: Similar to [open_read](3) but relative path are based on given file
+:: descriptor.
 
-: [fd_same](3)
-:: Return whether or not two file descriptors reference the same file.
+: [open_readb](3)
+:: Similar to [open_read](3) but clears *O_NONBLOCK* after opening.
 
-: [mkdirpat](3)
-:: Create a path of directories.
+: [open_readatb](3)
+:: Similar to [open_readb](3) but relative path are based on given file
+:: descriptor.
 
-: [mkdirp](3)
-:: Same as [mkdirpat](3) but relative path are based on current working
-:: directory.
+: [openb_read](3)
+:: Similar to [open_read](3) but without *O_NONBLOCK*.
+
+: [openb_readat](3)
+:: Similar to [openb_read](3) but relative path are based on given file
+:: descriptor.
+
+: [openbc_read](3)
+:: Similar to [openb_read](3) but with *O_CLOEXEC* set.
+
+: [openbc_readat](3)
+:: Similar to [openbc_read](3) but relative path are based on given file
+:: descriptor.
+
+: [openc_read](3)
+:: Similar to [open_read](3) but with *O_CLOEXEC* set.
+
+: [openc_readat](3)
+:: Similar to [openc_read](3) but relative path on based on given file
+:: descriptor.
+
+: [openc_readb](3)
+:: Similar to [openc_read](3) but clears *O_NONBLOCK* after opening.
+
+: [openc_readatb](3)
+:: Similar to [openc_readb](3) but relative path on based on given file
+:: descriptor.
+
+
+: [open_write](3)
+:: Open a file for writing with *O_NONBLOCK* set.
+
+: [open_writeat](3)
+:: Similar to [open_write](3) but relative path are based on given file
+:: descriptor.
+
+: [open_writeb](3)
+:: Similar to [open_write](3) but clears *O_NONBLOCK* after opening.
+
+: [open_writeatb](3)
+:: Similar to [open_writeb](3) but relative path are based on given file
+:: descriptor.
+
+: [openb_write](3)
+:: Similar to [open_write](3) but without *O_NONBLOCK*.
+
+: [openb_writeat](3)
+:: Similar to [openb_write](3) but relative path are based on given file
+:: descriptor.
+
+: [openbc_write](3)
+:: Similar to [openb_write](3) but with *O_CLOEXEC* set.
+
+: [openbc_writeat](3)
+:: Similar to [openbc_write](3) but relative path are based on given file
+:: descriptor.
+
+: [openc_write](3)
+:: Similar to [open_write](3) but with *O_CLOEXEC* set.
+
+: [openc_writeat](3)
+:: Similar to [openc_write](3) but relative path on based on given file
+:: descriptor.
+
+: [openc_writeb](3)
+:: Similar to [openc_write](3) but clears *O_NONBLOCK* after opening.
+
+: [openc_writeatb](3)
+:: Similar to [openc_writeb](3) but relative path on based on given file
+:: descriptor.
+
+
+: [open_create](3)
+:: Similar to [open_write](3) but create the file if it doesn't exist.
+
+: [open_createat](3)
+:: Similar to [open_create](3) but relative path are based of given file
+:: descriptor.
+
+: [openc_create](3)
+:: Similar to [open_create](3) but with *O_CLOEXEC* set.
+
+: [openc_createat](3)
+:: Similar to [openc_create](3) but relative path are based of given file
+:: descriptor.
+
+
+: [open_excl](3)
+:: Similar to [open_create](3) but fails if the file exists.
+
+: [open_exclat](3)
+:: Similar to [open_excl](3) but relative path are based of given file
+:: descriptor.
+
+: [openc_excl](3)
+:: Similar to [open_excl](3) but with *O_CLOEXEC* set.
+
+: [openc_exclat](3)
+:: Similar to [openc_excl](3) but relative path are based of given file
+:: descriptor.
+
+
+: [open_append](3)
+:: Similar to [open_create](3) but the file is opened in append-mode.
+
+: [open_appendat](3)
+:: Similar to [open_append](3) but relative path are based of given file
+:: descriptor.
+
+: [openc_append](3)
+:: Similar to [open_append](3) but with *O_CLOEXEC* set.
+
+: [openc_appendat](3)
+:: Similar to [openc_append](3) but relative path are based of given file
+:: descriptor.
+
+
+: [open_trunc](3)
+:: Similar to [open_create](3) but truncate the file if it exists.
+
+: [open_truncat](3)
+:: Similar to [open_trunc](3) but relative path are based of given file
+:: descriptor.
+
+: [openc_trunc](3)
+:: Similar to [open_trunc](3) but with *O_CLOEXEC* set.
+
+: [openc_truncat](3)
+:: Similar to [openc_trunc](3) but relative path are based of given file
+:: descriptor.
 
-: [open_parsed_name](3)
-:: Return the specified file descriptor, or that of the given file name.
 
 : [open_tmp](3)
 :: Open a new temporary file for writing.
 
+: [open_tmpat](3)
+:: Similar to [open_tmp](3) but relative path are based of given file
+:: descriptor.
+
+
+: [open2](3)
+:: Wrapper for [open](3) that takes 2 arguments, and can't be interrupted by
+:: signals.
+
+: [open2_at](3)
+:: Wrapper for [openat](3) that takes 2 arguments, and can't be interrupted by
+:: signals.
+
+: [open3](3)
+:: Wrapper for [open](3) that takes 3 arguments, and can't be interrupted by
+:: signals.
+
+: [open3_at](3)
+:: Wrapper for [openat](3) that takes 3 arguments, and can't be interrupted by
+:: signals.
+
+
+: [open_b](3)
+:: Open a file using given *open_fn* then clears *O_NONBLOCK*.
+
+: [open_atb](3)
+:: Similar to [open_b](3) but relative path are based on given file descriptor.
+
+
+: [open_parsed_name](3)
+:: Return the specified file descriptor, or that of the given file name.
+
+
+: [coe](3)
+:: Ensure a file descriptor has *O_CLOEXEC* set.
+
+: [uncoe](3)
+:: Ensure a file descriptor has *O_CLOEXEC* unset.
+
+: [ndelay_on](3)
+:: Ensure a file descriptor has *O_NONBLOCK* set.
+
+: [ndelay_off](3)
+:: Ensure a file descriptor has *O_NONBLOCK* unset.
+
+
+: [open_read_closeat](3)
+:: Open, read & close a file into memory.
+
 : [open_read_close](3)
 :: Same as [open_read_closeat](3) but relative path are based on current working
 :: directory.
 
-: [open_slurp_close](3)
-:: Same as [open_slurp_closeat](3) but relative path are based on current
+: [open_saread_closeat](3)
+:: Open, read & close a file into a *stralloc*.
+
+: [open_saread_close](3)
+:: Same as [open_saread_closeat](3) but relative path are based on current
 :: working directory.
 
+: [open_write_closeat](3)
+:: Open, write & close a file with data from pointed memory.
+
 : [open_write_close](3)
 :: Same as [open_write_closeat](3) but relative path are based on current
 :: working directory.
 
+: [open_writev_closeat](3)
+:: Open, write & close a file with data from array of vectors.
+
 : [open_writev_close](3)
 :: Same as [open_writev_closeat](3) but relative path are based on current
 :: working directory.
 
+
+: [read_close](3)
+:: Read & close a file into memory.
+
+
+: [sa_read](3)
+:: Read a file appending its content to a *stralloc*.
+
+: [sa_readmax](3)
+:: Similar to [sa_read](3) but with a limit.
+
+
+: [fd_close](3)
+:: Close a file descriptor without affecting `errno`.
+
+: [fd_same](3)
+:: Return whether or not two file descriptors reference the same file.
+
+
+: [fd_chdir](3)
+:: Similar to [fchdir](3) but without signal interruption.
+
+: [fd_mkdirpat](3)
+:: Create a path of directories and returns the file descriptor.
+
+: [fd_mkdirp](3)
+:: Same as [fd_mkdirpat](3) but relative path are based on current working
+:: directory.
+
+: [mkdirpat](3)
+:: Create a path of directories.
+
+: [mkdirp](3)
+:: Same as [mkdirpat](3) but relative path are based on current working
+:: directory.
+
+
 : [rm_rfat](3)
 :: Remove an entire directory entry, with relative path based on given file
 :: descriptor
 
 : [rm_rf_tmpat](3)
-: Different interface, using the given stralloc as head-allocated temporary
-:: space
+:: Different interface, using the given *stralloc* as head-allocated temporary
+:: space.
 
 : [rm_rf_in_tmpat](3)
 :: Different interface, expecting the name to be found as NUL-terminated string
-:: inside the given stralloc
+:: inside the given *stralloc*
 
 
 : [rmstarat](3)
 :: Remove the full content of a directory, with relative path based on given
-:: file descriptor
+:: file descriptor.
 
 : [rmstar_tmpat](3)
-: Different interface, using the given stralloc as head-allocated temporary
-:: space
+:: Different interface, using the given *stralloc* as head-allocated temporary
+:: space.
 
 : [rmstar_in_tmpat](3)
 :: Different interface, expecting the name to be found as NUL-terminated string
-:: inside the given stralloc
-
+:: inside the given *stralloc*.
 
-: [salsat](3)
-:: Appends the names of all files in a directory into the given stralloc
 
+: [sa_basename](3)
+:: Append the basename of a given path to a *stralloc*.
 
-: [salst](3)
-:: Slightly different interface than [sals](3), having the stralloc as first
-:: argument
+: [sa_dirname](3)
+:: Append the dirname of a given path to a *stralloc*.
 
-: [salstat](3)
-:: Slightly different interface than [salsat](3), having the stralloc as first
-:: argument
 
+: [sa_readlink](3)
+:: Places the content of a symbolic link into a *stralloc*.
 
-: [sareadlink0](3)
-:: Similar to [sareadlink](3) but ensures the content is NUL-terminated
+: [sa_readlink0](3)
+:: Similar to [sa_readlink](3) but ensures the content is NUL-terminated.
 
-: [sareadlinkat](3)
-:: Place the content of a symbolic link into the given stralloc
+: [sa_readlinkat](3)
+:: Similar to [sa_readlink](3) but relative path are based on given file
+:: descriptor.
 
-: [sareadlinkat0](3)
-:: Similar to [sareadlinkat](3) but ensures the content is NUL-terminated
+: [sa_readlinkat0](3)
+:: Similar to [sa_readlinkat](3) but ensures the content is NUL-terminated.
 
 
-: [sarealpath](3)
+: [sa_realpath](3)
 :: Place the canonicalized absolute pathname into the given *stralloc*.
 
-: [sarealpathat](3)
-:: Similar to [sarealpath](3) except for relative path, relative to given file
+: [sa_realpathat](3)
+:: Similar to [sa_realpath](3) but relative path are base on given file
 :: descriptor.
+
+
+: [sa_ls](3)
+:: Appends the names of all files in a directory into the given *stralloc*.
+
+: [sa_lsat](3)
+:: Similar to [sa_ls](3) but relative path are based on given file descriptor.
diff --git a/src/doc/djbunix.h/coe.3.md b/src/doc/djbunix.h/coe.3.md
new file mode 100644
index 0000000..c0a51bc
--- /dev/null
+++ b/src/doc/djbunix.h/coe.3.md
@@ -0,0 +1,43 @@
+% limb manual
+% coe(3)
+
+# NAME
+
+coe, uncoe - ensure a file descriptor is/isn't close-on-exec
+ndelay_on, ndelay_off - ensure a file descriptor is/isn't in blocking mode
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+int coe(int <em>fd</em>)
+int uncoe(int <em>fd</em>)
+
+int ndelay_on(int <em>fd</em>)
+int ndelay_off(int <em>fd</em>)
+```
+
+# DESCRIPTION
+
+The `coe`() function ensures the file descriptor `fd` has the *O_CLOEXEC* flag
+set, setting it if needed.
+
+The `uncoe`() function ensures the file descriptor `fd` has the *O_CLOEXEC* flag
+clear, clearing it if needed.
+
+The `ndelay_on`() function ensures the file descriptor `fd` has the *O_NONBLOCK*
+flag set, setting it if needed.
+
+The `ndelay_off`() function ensures the file descriptor `fd` has the
+*O_NONBLOCK* flag clear, clearing it if needed.
+
+# RETURN VALUE
+
+On success, these functions return a value other than -1. Otherwise, they
+return -1 and set `errno` to indicate the error.
+
+# ERRORS
+
+These functions may fail and set `errno` for any of the errors specified for
+[fcntl](3) (with either *F_GETFL* or *F_SETFL*).
diff --git a/src/doc/djbunix.h/fd_chdir.3.md b/src/doc/djbunix.h/fd_chdir.3.md
new file mode 100644
index 0000000..c06ae45
--- /dev/null
+++ b/src/doc/djbunix.h/fd_chdir.3.md
@@ -0,0 +1,30 @@
+% limb manual
+% fd_chdir(3)
+
+# NAME
+
+fd_chdir - change working directory
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+int fd_chdir(int <em>fd</em>)
+```
+
+# DESCRIPTION
+
+The `fd_chdir`() function is a safe wrapper around [fchdir](3), i.e. it cannot
+be interrupted by signals. More precisely, if [fchdir](3) fails with *EINTR* it
+is automatically called again until it succeeds or fails with another error.
+
+# RETURN VALUE
+
+On success, the `fd_chdir`() function return 0. Otherwise, it returns -1 and
+sets `errno` to indicate the error.
+
+# ERRORS
+
+The `fd_chdir`() function may fail and set `errno` for any of the errors
+specified for [fchdir](3) except *EINTR*.
diff --git a/src/doc/djbunix.h/fd_mkdirpat.3.md b/src/doc/djbunix.h/fd_mkdirpat.3.md
index b476523..df990dc 100644
--- a/src/doc/djbunix.h/fd_mkdirpat.3.md
+++ b/src/doc/djbunix.h/fd_mkdirpat.3.md
@@ -3,7 +3,7 @@
 
 # NAME
 
-fd\_mkdirpat, fd\_mkdirp, mkdirpat, mkdirp - create a path of directories
+fd_mkdirpat, fd_mkdirp, mkdirpat, mkdirp - create a path of directories
 
 # SYNOPSIS
 
diff --git a/src/doc/djbunix.h/ndelay_off.3.md b/src/doc/djbunix.h/ndelay_off.3.md
new file mode 120000
index 0000000..b577275
--- /dev/null
+++ b/src/doc/djbunix.h/ndelay_off.3.md
@@ -0,0 +1 @@
+coe.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/ndelay_on.3.md b/src/doc/djbunix.h/ndelay_on.3.md
new file mode 120000
index 0000000..b577275
--- /dev/null
+++ b/src/doc/djbunix.h/ndelay_on.3.md
@@ -0,0 +1 @@
+coe.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open2.3.md b/src/doc/djbunix.h/open2.3.md
new file mode 100644
index 0000000..7639e94
--- /dev/null
+++ b/src/doc/djbunix.h/open2.3.md
@@ -0,0 +1,52 @@
+% limb manual
+% open2(3)
+
+# NAME
+
+open2, open2_at, open3, open3_at - wrappers around open that can't be
+interrupted by signals
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+int open2(const char *<em>file</em>, unsigned <em>flags</em>)
+int open3(const char *<em>file</em>, unsigned <em>flags</em>, unsigned <em>mode</em>)
+
+int open2_at(int <em>fd</em>, const char *<em>file</em>, int <em>flags</em>)
+int open3_at(int <em>fd</em>, const char *<em>file</em>, int <em>flags</em>, unsigned <em>mode</em>)
+```
+
+# DESCRIPTION
+
+The `open2`() function is a wrapper around [open](2) that takes 2 arguments, and
+cannot be interrupted by signals, i.e. if [open](3) fails with *EINTR* a new
+call is automatically being made until it either succeeds or fails with a
+different error.
+
+The `open3`() function is similar to `open2`() only it takes a third argument.
+
+The `open2_at`() function is similar to `open2`() except when `file` is a
+relative path, in which case it is relative to the directory associated with the
+file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `open3_at`() function is similar to `open3`() except when `file` is a
+relative path, in which case it is relative to the directory associated with the
+file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+# RETURN VALUE
+
+Upon successful completion, these functions return the file descriptor
+associated with the opened file. Otherwise they return -1 and set `errno` to
+indicate the error.
+
+# ERRORS
+
+The `open2`() and `open3`() functions may fail and set `errno` for any of the
+errors specified for [open](3).
+
+The `open2_at`() and `open3_at`() functions may fail and set `errno` for any of
+the errors specified for [openat](3).
diff --git a/src/doc/djbunix.h/open2_at.3.md b/src/doc/djbunix.h/open2_at.3.md
new file mode 120000
index 0000000..85888dc
--- /dev/null
+++ b/src/doc/djbunix.h/open2_at.3.md
@@ -0,0 +1 @@
+open2.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open3.3.md b/src/doc/djbunix.h/open3.3.md
new file mode 120000
index 0000000..85888dc
--- /dev/null
+++ b/src/doc/djbunix.h/open3.3.md
@@ -0,0 +1 @@
+open2.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open3_at.3.md b/src/doc/djbunix.h/open3_at.3.md
new file mode 120000
index 0000000..85888dc
--- /dev/null
+++ b/src/doc/djbunix.h/open3_at.3.md
@@ -0,0 +1 @@
+open2.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_append.3.md b/src/doc/djbunix.h/open_append.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_append.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_appendat.3.md b/src/doc/djbunix.h/open_appendat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_appendat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_atb.3.md b/src/doc/djbunix.h/open_atb.3.md
new file mode 120000
index 0000000..c42742e
--- /dev/null
+++ b/src/doc/djbunix.h/open_atb.3.md
@@ -0,0 +1 @@
+open_b.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_b.3.md b/src/doc/djbunix.h/open_b.3.md
new file mode 100644
index 0000000..c97be9a
--- /dev/null
+++ b/src/doc/djbunix.h/open_b.3.md
@@ -0,0 +1,44 @@
+% limb manual
+% open_b(3)
+
+# NAME
+
+open_b, open_atb - open a file using given function then clears *O_NONBLOCK*
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+int open_b(open_fn <em>fn</em>, const char *<em>file</em>)
+int open_atb(openat_fn <em>fnat</em>, int <em>fd</em>, const char *<em>file</em>)
+```
+
+# DESCRIPTION
+
+The `open_b`() function calls the function `fn` with `file` as its only
+argument. This function should open the file whose name is pointed by `file` and
+return the corresponding file descriptor on success, otherwise it should return
+-1 and set `errno` to indicate the error.
+
+After the file has been successfully opened, the `open_b`() function will ensure
+that it is in blocking mode, i.e. that it has *O_NONBLOCK* clear.
+
+The `open_atb`() function is similar except that it takes an additional argument
+`fd` being used along side `file` as arguments to the function `fnat`, which
+must be similar to `fn` except when `file` is a relative path, in which case it
+must be treated as relative to the directory associated with the file
+descriptor `fd`, which may be *AT_FDCWD* to user the current working directory.
+
+# RETURN VALUE
+
+On success, these functions return the opened file descriptor, which always has
+the *O_NONBLOCK* flag clear. Otherwise they return -1 and set `errno` to
+indicate the error.
+
+# ERRORS
+
+The `open_b`() and `open_atb`() functions may fail and set `errno` for any of
+the errors specified for the given `fn` or `fnat` function, respectively.
+
+They may also fail and set `errno` for the errors described for [ndelay_off](3).
diff --git a/src/doc/djbunix.h/open_create.3.md b/src/doc/djbunix.h/open_create.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_create.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_createat.3.md b/src/doc/djbunix.h/open_createat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_createat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_excl.3.md b/src/doc/djbunix.h/open_excl.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_excl.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_exclat.3.md b/src/doc/djbunix.h/open_exclat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_exclat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_parsed_name.3.md b/src/doc/djbunix.h/open_parsed_name.3.md
index 56fa5b3..a92751a 100644
--- a/src/doc/djbunix.h/open_parsed_name.3.md
+++ b/src/doc/djbunix.h/open_parsed_name.3.md
@@ -3,7 +3,7 @@
 
 # NAME
 
-open\_parsed\_name - return given file descriptor, or opened file
+open_parsed_name - return given file descriptor, or opened file
 
 # SYNOPSIS
 
@@ -38,5 +38,5 @@ or the file descriptor of the opened file. Otherwise, it returns -1 and sets
 
 # ERRORS
 
-This function may fail for the errors described for [u160_scan](3) (when parsing
+This function may fail for the errors described for [u16_scan0](3) (when parsing
 the file descriptor), or those for `open`.
diff --git a/src/doc/djbunix.h/open_read.3.md b/src/doc/djbunix.h/open_read.3.md
new file mode 100644
index 0000000..48d036d
--- /dev/null
+++ b/src/doc/djbunix.h/open_read.3.md
@@ -0,0 +1,255 @@
+% limb manual
+% open_read(3)
+
+# NAME
+
+open_read, open_readat, open_readb, open_readatb, openb_read, openb_readat,
+openbc_read, openbc_readat, openc_read, openc_readat, openc_readb,
+openc_readatb - open a file for reading
+
+open_write, open_writeat, open_writeb, open_writeatb, openb_write,
+openb_writeat, openbc_write, openbc_writeat, openc_write, openc_writeat,
+openc_writeb, openc_writeatb, open_create, open_createat, openc_create,
+openc_createat, open_excl, open_exclat, openc_excl, openc_exclat, open_append,
+open_appendat, openc_append, openc_appendat, open_trunc, open_truncat,
+openc_trunc, openc_truncat - open a file for writing
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+int open_read(const char *<em>file</em>)
+int open_readat(int <em>fd</em>, const char *<em>file</em>)
+int open_readb(const char *<em>file</em>)
+int open_readatb(int <em>fd</em>, const char *<em>file</em>)
+int openb_read(const char *<em>file</em>)
+int openb_readat(int <em>fd</em>, const char *<em>file</em>)
+int openbc_read(const char *<em>file</em>)
+int openbc_readat(int <em>fd</em>, const char *<em>file</em>)
+int openc_read(const char *<em>file</em>)
+int openc_readat(int <em>fd</em>, const char *<em>file</em>)
+int openc_readb(const char *<em>file</em>)
+int openc_readatb(int <em>fd</em>, const char *<em>file</em>)
+
+int open_write(const char *<em>file</em>)
+int open_writeat(int <em>fd</em>, const char *<em>file</em>)
+int open_writeb(const char *<em>file</em>)
+int open_writeatb(int <em>fd</em>, const char *<em>file</em>)
+int openb_write(const char *<em>file</em>)
+int openb_writeat(int <em>fd</em>, const char *<em>file</em>)
+int openbc_write(const char *<em>file</em>)
+int openbc_writeat(int <em>fd</em>, const char *<em>file</em>)
+int openc_write(const char *<em>file</em>)
+int openc_writeat(int <em>fd</em>, const char *<em>file</em>)
+int openc_writeb(const char *<em>file</em>)
+int openc_writeatb(int <em>fd</em>, const char *<em>file</em>)
+
+int open_create(const char *<em>file</em>)
+int open_createat(int <em>fd</em>, const char *<em>file</em>)
+int openc_create(const char *<em>file</em>)
+int openc_createat(int <em>fd</em>, const char *<em>file</em>)
+
+int open_excl(const char *<em>file</em>)
+int open_exclat(int <em>fd</em>, const char *<em>file</em>)
+int openc_excl(const char *<em>file</em>)
+int openc_exclat(int <em>fd</em>, const char *<em>file</em>)
+
+int open_append(const char *<em>file</em>)
+int open_appendat(int <em>fd</em>, const char *<em>file</em>)
+int openc_append(const char *<em>file</em>)
+int openc_appendat(int <em>fd</em>, const char *<em>file</em>)
+
+int open_trunc(const char *<em>file</em>)
+int open_truncat(int <em>fd</em>, const char *<em>file</em>)
+int openc_trunc(const char *<em>file</em>)
+int openc_truncat(int <em>fd</em>, const char *<em>file</em>)
+```
+
+# DESCRIPTION
+
+## Open for reading
+
+The `open_read`() function opens the file whose name is pointed by `file` for
+reading in non-blocking mode, i.e. with *O_NONBLOCK* set.
+
+The `open_readat`() function is similar to `open_read`() except when `file` is a
+relative path, in which case it is relative to the directory associated with the
+file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `open_readb`() function is similar to `open_read`() but clears *O_NONBLOCK*
+/after/ opening.
+
+The `open_readatb`() function is similar to `open_readb`() except when `file` is
+a relative path, in which case it is relative to the directory associated with
+the file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `openb_read`() function is similar to `open_read`() but it opens the file in
+blocking mode, i.e. with *O_NONBLOCK* clear.
+
+The `openb_readat`() function is similar to `openb_read`() except when `file` is
+a relative path, in which case it is relative to the directory associated with
+the file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `openbc_read`() function is similar to `openb_read`(3) but it opens the file
+with *O_CLOEXEC* set.
+
+The `openbc_readat`() function is similar to `openbc_read`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+The `openc_read`() function is similar to `open_read`() but with it opens the
+file with *O_CLOEXEC* set.
+
+The `openc_readat`() function is similar to `openc_read`() except when `file` is
+a relative path, in which case it is relative to the directory associated with
+the file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `openc_readb`() function is similar to `openc_read`() but clears
+*O_NONBLOCK* after opening.
+
+The `openc_readatb`() function is similar to `openc_readb`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+## Open for writing
+
+The `open_write`() function opens the file whose name is pointed by `file` for
+writing in non-blocking mode, i.e. with *O_NONBLOCK* set.
+
+The `open_writeat`() function is similar to `open_write`() except when `file` is
+a relative path, in which case it is relative to the directory associated with
+the file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `open_writeb`() function is similar to `open_write`() but clears
+*O_NONBLOCK* after opening.
+
+The `open_writeatb`() function is similar to `open_writeb`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+The `openb_write`() function is similar to `open_write`() but it opens the file
+in blocking mode, i.e. with *O_NONBLOCK* clear.
+
+The `openb_writeat`() function is similar to `openb_write`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+The `openbc_write`() function is similar to `openb_write`() but with *O_CLOEXEC*
+set.
+
+The `openbc_writeat`() function is similar to `openbc_write`() except when
+`file` is a relative path, in which case it is relative to the directory
+associated with the file descriptor `fd`, which may be *AT_FDCWD* to use the
+current working directory.
+
+The `openc_write`() function is similar to `open_write`() but with *O_CLOEXEC*
+set.
+
+The `openc_writeat`() function is similar to `openc_write`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+The `openc_writeb`() function is similar to `openc_write`() but clears
+*O_NONBLOCK* after opening.
+
+The `openc_writeatb`() function is similar to `openc_writeb`() except when
+`file` is a relative path, in which case it is relative to the directory
+associated with the file descriptor `fd`, which may be *AT_FDCWD* to use the
+current working directory.
+
+### Creating file if needed
+
+The `open_create`() function is similar to `open_write`() but it creates the
+file if it doesn't exist.
+
+The `open_createat`() function is similar to `open_create`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+The `openc_create`() function is similar to `open_create`() but with *O_CLOEXEC*
+set.
+
+The `openc_createat`() function is similar to `openc_create`() except when
+`file` is a relative path, in which case it is relative to the directory
+associated with the file descriptor `fd`, which may be *AT_FDCWD* to use the
+current working directory.
+
+### Creating file or failing
+
+The `open_excl`() function is similar to `open_create`() but it fails if the
+file exists.
+
+The `open_exclat`() function is similar to `open_excl`() except when `file` is a
+relative path, in which case it is relative to the directory associated with the
+file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `openc_excl`() function is similar to `open_excl`() but with *O_CLOEXEC*
+set.
+
+The `openc_exclat`() function is similar to `openc_excl`() except when `file` is
+a relative path, in which case it is relative to the directory associated with
+the file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+### Creating file and/or in append mode
+
+The `open_append`() function is similar to `open_create`(3 but the file is
+opened in append-mode (i.e. it has *O_APPEND* set).
+
+The `open_appendat`() function is similar to `open_append`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+The `openc_append`() function is similar to `open_append`() but with *O_CLOEXEC*
+set.
+
+The `openc_appendat`() function is similar to `openc_append`() except when
+`file` is a relative path, in which case it is relative to the directory
+associated with the file descriptor `fd`, which may be *AT_FDCWD* to use the
+current working directory.
+
+### Creating file or truncating
+
+The `open_trunc`() function is similar to `open_create`() but it truncates the
+file if it exists.
+
+The `open_truncat`() function is similar to `open_trunc`() except when `file` is
+a relative path, in which case it is relative to the directory associated with
+the file descriptor `fd`, which may be *AT_FDCWD* to use the current working
+directory.
+
+The `openc_trunc`() function is similar to `open_trunc`() but with *O_CLOEXEC*
+set.
+
+The `openc_truncat`() function is similar to `openc_trunc`() except when `file`
+is a relative path, in which case it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+# RETURN VALUE
+
+These functions return the opened file descriptor on success. Otherwise they
+return -1 and set `errno` to indicate the error.
+
+# ERRORS
+
+The `open_*at{,b}`() family of functions may fail and set `errno` for any of the
+errors described for [openat](3); the other functions may fail and set `errno`
+for any of the errors described for [open](3).
+
+The `open_*b`() family of functions may also fail and set `errno` for any of the
+errors described for [ndelay_off](3).
diff --git a/src/doc/djbunix.h/open_read_close.3.md b/src/doc/djbunix.h/open_read_close.3.md
deleted file mode 100644
index 2fd2513..0000000
--- a/src/doc/djbunix.h/open_read_close.3.md
+++ /dev/null
@@ -1,29 +0,0 @@
-% limb manual
-% open_read_close(3)
-
-# NAME
-
-open\_read\_close, open\_slurp\_close,
-open\_write\_close, open\_writev\_close - open, read or write & close a file
-
-# SYNOPSIS
-
-    #include <limb/djbunix.h>
-
-```pre hl
-ssize_t open_read_close(char *<em>dst</em>, size_t <em>dlen</em>, const char *<em>file</em>)
-int open_slurp_close(stralloc *<em>sa</em>, const char *<em>file</em>)
-int open_write_close(const char *<em>file</em>, const char *<em>data</em>, size_t <em>dlen</em>)
-int open_writev_close(const char *<em>file</em>, const struct iovec *<em>v</em>, unsigned <em>n</em>)
-```
-
-# DESCRIPTION
-
-These functions are similar to their \*at counterparts, only when `file`
-describes a relative path it is always to the current working directory.
-
-! NOTE:
-! These are implemented as macros to their \*at counterparts.
-
-For more information, refer to [open_read_closeat](3), [open_slurp_closeat](3),
-[open_write_closeat](3) and [open_writev_closeat](3).
diff --git a/src/doc/djbunix.h/open_read_close.3.md b/src/doc/djbunix.h/open_read_close.3.md
new file mode 120000
index 0000000..e347874
--- /dev/null
+++ b/src/doc/djbunix.h/open_read_close.3.md
@@ -0,0 +1 @@
+open_read_closeat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_read_closeat.3.md b/src/doc/djbunix.h/open_read_closeat.3.md
new file mode 100644
index 0000000..9413a0f
--- /dev/null
+++ b/src/doc/djbunix.h/open_read_closeat.3.md
@@ -0,0 +1,64 @@
+% limb manual
+% open_read_closeat(3)
+
+# NAME
+
+open_read_closeat, open_read_close, open_saread_closeat, open_saread_close -
+open, read & close a file
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+ssize_t open_read_closeat(char *<em>dst</em>, size_t <em>dlen</em>, int <em>fd</em>, const char *<em>file</em>)
+ssize_t open_read_close(char *<em>dst</em>, size_t <em>dlen</em>, const char *<em>file</em>)
+
+int open_saread_closeat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>file</em>)
+int open_saread_close(stralloc *<em>sa</em>, const char *<em>file</em>)
+```
+
+# DESCRIPTION
+
+The `open_read_closeat`() function will open the file named `file` for reading
+in blocking mode. If `file` describes a relative path, it is relative to the
+directory associated with the file descriptor `fd`, which may be *AT_FDCWD* to
+use the current working directory.
+
+The content of the file will be read and copied into the memory pointed by `dst`
+up to a maximum of `dlen` bytes, and the file be closed.
+
+The `open_read_close`() macro is similar to `open_read_closeat`() only relative
+paths are relative to the current working directory.
+
+The `open_saread_closeat`() function is to `open_read_closeat`(), except the
+entirety of the file will be placed into the *stralloc* pointed by `sa`,
+allocating as much memory as needed.
+
+The `open_saread_close`() macro is similar to `open_saread_closeat`() only
+relative paths are relative to the current working directory.
+
+# RETURN VALUE
+
+The `open_read_close`() and `open_read_closeat`() functions return the amount of
+data read from the file, and written into `dst`, on success. Otherwise they
+return -1 and set `errno` to indicate the error.
+
+The `open_saread_close`() and `open_saread_closeat`() functions return 1 on
+success. Otherwise they return 0 and set `errno` to indicate the error.
+
+# ERRORS
+
+These functions may fail and set `errno` for the errors described for
+[openb_readat](3).
+
+The `open_read_close`() and `open_read_closeat`() functions may also fail if :
+
+: *ENOBUFS*
+:: Not enough space available in `dst` to store the entire file.
+
+The `open_read_close`() and `open_read_closeat`() functions may also fail and
+set `errno` for the errors described for [allread](3).
+
+The `open_saread_close`() and `open_saread_closeat`() fucntions may also fail
+and set `errno` for the errors described for [sa_read](3).
diff --git a/src/doc/djbunix.h/open_readat.3.md b/src/doc/djbunix.h/open_readat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_readat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_readatb.3.md b/src/doc/djbunix.h/open_readatb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_readatb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_readb.3.md b/src/doc/djbunix.h/open_readb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_readb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/unix-transactional.h/open_slurp_closeat.3.md b/src/doc/djbunix.h/open_saread_close.3.md
similarity index 100%
rename from src/doc/unix-transactional.h/open_slurp_closeat.3.md
rename to src/doc/djbunix.h/open_saread_close.3.md
diff --git a/src/doc/djbunix.h/open_saread_closeat.3.md b/src/doc/djbunix.h/open_saread_closeat.3.md
new file mode 120000
index 0000000..e347874
--- /dev/null
+++ b/src/doc/djbunix.h/open_saread_closeat.3.md
@@ -0,0 +1 @@
+open_read_closeat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_slurp_close.3.md b/src/doc/djbunix.h/open_slurp_close.3.md
deleted file mode 120000
index 1f4c5d2..0000000
--- a/src/doc/djbunix.h/open_slurp_close.3.md
+++ /dev/null
@@ -1 +0,0 @@
-open_read_close.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_tmp.3.md b/src/doc/djbunix.h/open_tmp.3.md
index b7e54ac..fece101 100644
--- a/src/doc/djbunix.h/open_tmp.3.md
+++ b/src/doc/djbunix.h/open_tmp.3.md
@@ -3,7 +3,7 @@
 
 # NAME
 
-open\_tmp - open a new temporary file
+open_tmp - open a new temporary file
 
 # SYNOPSIS
 
diff --git a/src/doc/unix-transactional.h/open_tmpat.3.md b/src/doc/djbunix.h/open_tmpat.3.md
similarity index 96%
rename from src/doc/unix-transactional.h/open_tmpat.3.md
rename to src/doc/djbunix.h/open_tmpat.3.md
index ce76948..4e398fc 100644
--- a/src/doc/unix-transactional.h/open_tmpat.3.md
+++ b/src/doc/djbunix.h/open_tmpat.3.md
@@ -3,7 +3,7 @@
 
 # NAME
 
-open\_tmpat - open a new temporary file
+open_tmpat - open a new temporary file
 
 # SYNOPSIS
 
diff --git a/src/doc/djbunix.h/open_trunc.3.md b/src/doc/djbunix.h/open_trunc.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_trunc.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_truncat.3.md b/src/doc/djbunix.h/open_truncat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_truncat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_write.3.md b/src/doc/djbunix.h/open_write.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_write.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_write_close.3.md b/src/doc/djbunix.h/open_write_close.3.md
index 1f4c5d2..454cca6 120000
--- a/src/doc/djbunix.h/open_write_close.3.md
+++ b/src/doc/djbunix.h/open_write_close.3.md
@@ -1 +1 @@
-open_read_close.3.md
\ No newline at end of file
+open_write_closeat.3.md
\ No newline at end of file
diff --git a/src/doc/unix-transactional.h/open_write_closeat.3.md b/src/doc/djbunix.h/open_write_closeat.3.md
similarity index 52%
rename from src/doc/unix-transactional.h/open_write_closeat.3.md
rename to src/doc/djbunix.h/open_write_closeat.3.md
index 35b2059..9db2061 100644
--- a/src/doc/unix-transactional.h/open_write_closeat.3.md
+++ b/src/doc/djbunix.h/open_write_closeat.3.md
@@ -3,7 +3,8 @@
 
 # NAME
 
-open\_write_closeat, open\_writev\_closetat - open, write & close a file
+open_write_closeat, open_write_close, open_writev_closeat, open_writev_close -
+open, write & close a file
 
 # SYNOPSIS
 
@@ -11,7 +12,10 @@ open\_write_closeat, open\_writev\_closetat - open, write & close a file
 
 ```pre hl
 int open_write_closeat(int <em>fd</em>, const char *<em>file</em>, const char *<em>data</em>, size_t <em>dlen</em>)
+int open_write_close(const char *<em>file</em>, const char *<em>data</em>, size_t <em>dlen</em>)
+
 int open_writev_closeat(int <em>fd</em>, const char *<em>file</em>, const struct iovec *<em>v</em>, unsigned <em>n</em>)
+int open_writev_close(const char *<em>file</em>, const struct iovec *<em>v</em>, unsigned <em>n</em>)
 ```
 
 # DESCRIPTION
@@ -26,8 +30,15 @@ and then renames it to `file`. As such, any error will leave any previously
 existing file of the same name unchanged (and the temporary file will have been
 removed).
 
-The `open_writev_closeat`() function is similar, only the data to be written
-will be gathered from the array of vectors pointed by `v` of `n` elements.
+The `open_write_close`() macro is similar to `open_write_closeat`() except
+relative paths are relative to the current working directory.
+
+The `open_writev_closeat`() function is similar to `open_write_closeat`(),
+except the data to be written will be gathered from the array pointed by `v` of
+`n` vectors.
+
+The `open_writev_close`() macro is similar to `open_writev_closeat`() except
+relative paths are relative to the current working directory.
 
 # RETURN VALUE
 
@@ -39,8 +50,8 @@ indicate the error.
 These functions may fail and set `errno` for the errors described for
 [open_tmpat](3) and [renameat](3).
 
-The `open_write_closeat`() function may also fail and set `errno` for the errors
-described for [write](3).
+The `open_write_close`() and `open_write_closeat`() functions may also fail and
+set `errno` for the errors described for [allwrite](3).
 
-The `open_writev_closeat`() function may also fail and set `errno` for the
-errors described for [writev](3).
+The `open_writev_close`() and `open_writev_closeat`() functions may also fail
+and set `errno` for the errors described for [allwritev](3).
diff --git a/src/doc/djbunix.h/open_writeat.3.md b/src/doc/djbunix.h/open_writeat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_writeat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_writeatb.3.md b/src/doc/djbunix.h/open_writeatb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_writeatb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_writeb.3.md b/src/doc/djbunix.h/open_writeb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/open_writeb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/open_writev_close.3.md b/src/doc/djbunix.h/open_writev_close.3.md
index 1f4c5d2..454cca6 120000
--- a/src/doc/djbunix.h/open_writev_close.3.md
+++ b/src/doc/djbunix.h/open_writev_close.3.md
@@ -1 +1 @@
-open_read_close.3.md
\ No newline at end of file
+open_write_closeat.3.md
\ No newline at end of file
diff --git a/src/doc/unix-transactional.h/open_writev_closeat.3.md b/src/doc/djbunix.h/open_writev_closeat.3.md
similarity index 100%
rename from src/doc/unix-transactional.h/open_writev_closeat.3.md
rename to src/doc/djbunix.h/open_writev_closeat.3.md
diff --git a/src/doc/djbunix.h/openb_read.3.md b/src/doc/djbunix.h/openb_read.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openb_read.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openb_readat.3.md b/src/doc/djbunix.h/openb_readat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openb_readat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openb_write.3.md b/src/doc/djbunix.h/openb_write.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openb_write.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openb_writeat.3.md b/src/doc/djbunix.h/openb_writeat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openb_writeat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openbc_read.3.md b/src/doc/djbunix.h/openbc_read.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openbc_read.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openbc_readat.3.md b/src/doc/djbunix.h/openbc_readat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openbc_readat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openbc_write.3.md b/src/doc/djbunix.h/openbc_write.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openbc_write.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openbc_writeat.3.md b/src/doc/djbunix.h/openbc_writeat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openbc_writeat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_append.3.md b/src/doc/djbunix.h/openc_append.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_append.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_appendat.3.md b/src/doc/djbunix.h/openc_appendat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_appendat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_create.3.md b/src/doc/djbunix.h/openc_create.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_create.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_createat.3.md b/src/doc/djbunix.h/openc_createat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_createat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_excl.3.md b/src/doc/djbunix.h/openc_excl.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_excl.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_exclat.3.md b/src/doc/djbunix.h/openc_exclat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_exclat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_read.3.md b/src/doc/djbunix.h/openc_read.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_read.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_readat.3.md b/src/doc/djbunix.h/openc_readat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_readat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_readatb.3.md b/src/doc/djbunix.h/openc_readatb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_readatb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_readb.3.md b/src/doc/djbunix.h/openc_readb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_readb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_trunc.3.md b/src/doc/djbunix.h/openc_trunc.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_trunc.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_truncat.3.md b/src/doc/djbunix.h/openc_truncat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_truncat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_write.3.md b/src/doc/djbunix.h/openc_write.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_write.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_writeat.3.md b/src/doc/djbunix.h/openc_writeat.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_writeat.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_writeatb.3.md b/src/doc/djbunix.h/openc_writeatb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_writeatb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/openc_writeb.3.md b/src/doc/djbunix.h/openc_writeb.3.md
new file mode 120000
index 0000000..cb65a34
--- /dev/null
+++ b/src/doc/djbunix.h/openc_writeb.3.md
@@ -0,0 +1 @@
+open_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/read_close.3.md b/src/doc/djbunix.h/read_close.3.md
new file mode 100644
index 0000000..dc210ec
--- /dev/null
+++ b/src/doc/djbunix.h/read_close.3.md
@@ -0,0 +1,31 @@
+% limb manual
+% read_close(3)
+
+# NAME
+
+read_close - read a file into memory and close it
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+ssize_t read_close(char *<em>dst</em>, size_t <em>dlen</em>, int <em>fd</em>)
+```
+
+# DESCRIPTION
+
+The `read_close`() function reads the entire content of the file associated with
+file descriptor `fd` and places it into the memory pointed by `dst`, up to a
+maximum of `dlen` bytes.
+
+# RETURN VALUE
+
+On success, the `read_close`() function returns the number of bytes read and
+copied into memory. Otherwise, it returns -1 and sets `errno` to indicate the
+error.
+
+# ERRORS
+
+The `read_close`() function may fail and set `errno` for any of the errors
+described for [allread](3).
diff --git a/src/doc/djbunix.h/rm_rf.3.md b/src/doc/djbunix.h/rm_rf.3.md
new file mode 100644
index 0000000..bd5cbe7
--- /dev/null
+++ b/src/doc/djbunix.h/rm_rf.3.md
@@ -0,0 +1,92 @@
+% limb manual
+% rm_rf(3)
+
+# NAME
+
+rm_rf, rm_rfat, rm_rf_tmp, rm_rf_tmpat, rm_rf_in_tmp, rm_rf_in_tmpat - remove
+an entire directory entry
+
+rmstar, rmstarat, rmstar_tmp, rmstar_tmpat, rmstar_in_tmp, rmstar_in_tmpat -
+remove the full content of a directory
+
+# SYNOPSIS
+
+    #include <fcntl.h> /* AT_FDCWD */
+    #include <limb/djbunix.h>
+
+```pre hl
+int rm_rf(const char *<em>name</em>)
+int rm_rfat(int <em>fd</em>, const char *<em>name</em>)
+
+int rm_rf_tmp(const char *<em>name</em>, stralloc *<em>sa</em>)
+int rm_rf_tmpat(int <em>fd</em>, const char *<em>name</em>, stralloc *<em>sa</em>)
+
+int rm_rf_in_tmp(stralloc *<em>sa</em>, size_t <em>offset</em>)
+int rm_rf_in_tmpat(int <em>fd</em>, stralloc *<em>sa</em>, size_t <em>offset</em>)
+
+int rmstar(const char *<em>name</em>)
+int rmstarat(int <em>fd</em>, const char *<em>name</em>)
+
+int rmstar_tmp(const char *<em>name</em>, stralloc *<em>sa</em>)
+int rmstar_tmpat(int <em>fd</em>, const char *<em>name</em>, stralloc *<em>sa</em>)
+
+int rmstar_in_tmpat(int <em>fd</em>, stralloc *<em>sa</em>, size_t <em>offset</em>)
+```
+
+# DESCRIPTION
+
+The `rm_rf`() function removes the entire directory entry named `name` from
+the filesystem, whether a file, a directory (empty or not), etc.
+
+The `rm_rfat`() function is similar to `rm_rf`() except when `name` specifies a
+relative path, relative to the directory associated with the file descriptor
+`fd` instead of the current working directory.
+If passed the special value *AT_FDCWD* in the `fd` parameter, the current
+working directory is used.
+
+The `rm_rf_tmp`() and `rm_rf_tmpat`() functions are similar to `rm_rf`() and
+`rm_rfat`() respectively, except that they will use the given stralloc `sa` as
+heap-allocated temporary space.
+
+The `rm_rf_in_tp`() and `rm_rf_in_tmpat`() functions are similar to
+`rm_rm_tmp`() and `rm_rm_tmpat`() respectively, except that they expect `sa` to
+contain a NUL-terminated string of the name at offset `offset`.
+
+
+The `rmstar`() function removes the full content of directory `name` recursively
+(leaving only the (empty) directory itself).
+
+The `rmstarat`() function is similar to `rmstar`() except when `name` specifies
+a relative path, relative to the directory associated with the file descriptor
+`fd` instead of the current working directory.
+If passed the special value *AT_FDCWD* in the `fd` parameter, the current
+working directory is used.
+
+The `rmstar_tmp`() and `rmstar_tmpat`() function are similar to `rmstar`() and
+`rm_starat`() respectively, except that they will use the given stralloc `sa` as
+heap-allocated temporary space.
+
+The `rmstar_in_tmpat`() function is similar to `rmstar_tmpat`() except that it
+expects `sa` to contain a NUL-terminated string of the name at offset `offset`.
+
+
+# RETURN VALUE
+
+Upon successful completion, these functions return 0. Otherwise, they return -1
+and set `errno` to indicate the error.
+
+Note that these functions are *not* atomic and, in case of failure, might leave
+the relevant directory partially removed.
+
+# ERRORS
+
+These functions may fail if :
+
+: *ENOMEM*
+:: Out of memory
+
+The `rm*at`() family of functions may also fail and set `errno` for any of the
+errors specified for the functions [unlinkat](3) and [sa_lsat](3).
+
+The other family of functions may also fail and set `errno` for any of the
+errors specified for the functions [unlink](3), [rmdir](3) and [sa_ls](3).
diff --git a/src/doc/djbunix.h/rm_rf_in_tmp.3.md b/src/doc/djbunix.h/rm_rf_in_tmp.3.md
new file mode 120000
index 0000000..185133a
--- /dev/null
+++ b/src/doc/djbunix.h/rm_rf_in_tmp.3.md
@@ -0,0 +1 @@
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rm_rf_in_tmpat.3.md b/src/doc/djbunix.h/rm_rf_in_tmpat.3.md
index 5efdb0c..185133a 120000
--- a/src/doc/djbunix.h/rm_rf_in_tmpat.3.md
+++ b/src/doc/djbunix.h/rm_rf_in_tmpat.3.md
@@ -1 +1 @@
-rm_rfat.3.md
\ No newline at end of file
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rm_rf_tmp.3.md b/src/doc/djbunix.h/rm_rf_tmp.3.md
new file mode 120000
index 0000000..185133a
--- /dev/null
+++ b/src/doc/djbunix.h/rm_rf_tmp.3.md
@@ -0,0 +1 @@
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rm_rf_tmpat.3.md b/src/doc/djbunix.h/rm_rf_tmpat.3.md
index 5efdb0c..185133a 120000
--- a/src/doc/djbunix.h/rm_rf_tmpat.3.md
+++ b/src/doc/djbunix.h/rm_rf_tmpat.3.md
@@ -1 +1 @@
-rm_rfat.3.md
\ No newline at end of file
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rm_rfat.3.md b/src/doc/djbunix.h/rm_rfat.3.md
deleted file mode 100644
index 68ae11c..0000000
--- a/src/doc/djbunix.h/rm_rfat.3.md
+++ /dev/null
@@ -1,82 +0,0 @@
-% limb manual
-% rm_rfat(3)
-
-# NAME
-
-rm\_rfat, rm\_rf\_tmpat, rm\_rf\_in\_tmpat - remove an entire directory entry
-
-rmstarat, rmstar\_tmpat, rmstar\_in\_tmpat - remove the full content of a directory
-
-# SYNOPSIS
-
-    #include <fcntl.h> /* AT_FDCWD */
-    #include <limb/djbunix.h>
-
-```pre hl
-int rm_rfat(int <em>fd</em>, const char *<em>name</em>)
-int rm_rf_tmpat(int <em>fd</em>, const char *<em>name</em>, stralloc *<em>sa</em>)
-int rm_rf_in_tmpat(int <em>fd</em>, stralloc *<em>sa</em>, size_t <em>offset</em>)
-
-int rmstarat(int <em>fd</em>, const char *<em>name</em>)
-int rmstar_tmpat(int <em>fd</em>, const char *<em>name</em>, stralloc *<em>sa</em>)
-int rmstar_in_tmpat(int <em>fd</em>, stralloc *<em>sa</em>, size_t <em>offset</em>)
-```
-
-# DESCRIPTION
-
-The `rm_rfat`() function removes the entire directory entry named `name` from
-the filesystem, whether a file, a directory (empty or not), etc.
-
-It is the equivalent to [rm_rf](3) function except when `name` specifies a
-relative path, the directory to be opened is then determined relative to the
-directory associated with the file descriptor `fd` instead of the current
-working directory.
-If passed the special value *AT_FDCWD* in the `fd` parameter, the current
-working directory is used.
-
-The `rm_rf_tmpat`() function is similar except that it will use the given
-stralloc `sa` as heap-allocated temporary space.
-
-It is the equivalent of the [rm_rf_tmp](3) function except when `name` specifies
-a relative path, as with [rm_rfat](3).
-
-The `rm_rf_in_tmpat`() function is similar except that it expects `sa` to
-contain a NUL-terminated string of the name at offset `offset`.
-
-It is the equivalent of the [rm_rf_in_tmp](3) function except when `name`
-specifies a relative path, as with [rm_rfat](3).
-
-
-The `rmstarat`() function removes the full content of directory `name`
-recursively (leaving only the (empty) directory itself).
-
-It is the equivalent of the [rmstar](3) function except when `name` specifies a
-relative path, as with [rm_rfat](3).
-
-The `rmstar_tmpat`() function is similar except that it will use the given
-stralloc `sa` as heap-allocated temporary space.
-
-It is the equivalent of the [rmstar_tmp](3) function except when `name`
-specifies a relative path, as with [rm_rfat](3).
-
-The `rmstar_in_tmpat`() function is similar except that it expects `sa` to
-contain a NUL-terminated string of the name at offset `offset`.
-
-
-# RETURN VALUE
-
-Upon successful completion, these functions return 0. Otherwise, they return -1
-and set `errno` to indicate the error.
-
-Note that these functions are *not* atomic and, in case of failure, might leave
-the relevant directory partially removed.
-
-# ERRORS
-
-These functions may fail if :
-
-: *ENOMEM*
-:: Out of memory
-
-They may also fail and set `errno` for any of the errors specified for the
-functions [unlinkat](3) and [salsat](3).
diff --git a/src/doc/djbunix.h/rm_rfat.3.md b/src/doc/djbunix.h/rm_rfat.3.md
new file mode 120000
index 0000000..185133a
--- /dev/null
+++ b/src/doc/djbunix.h/rm_rfat.3.md
@@ -0,0 +1 @@
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rmstar.3.md b/src/doc/djbunix.h/rmstar.3.md
new file mode 120000
index 0000000..185133a
--- /dev/null
+++ b/src/doc/djbunix.h/rmstar.3.md
@@ -0,0 +1 @@
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rmstar_in_tmpat.3.md b/src/doc/djbunix.h/rmstar_in_tmpat.3.md
index 5efdb0c..185133a 120000
--- a/src/doc/djbunix.h/rmstar_in_tmpat.3.md
+++ b/src/doc/djbunix.h/rmstar_in_tmpat.3.md
@@ -1 +1 @@
-rm_rfat.3.md
\ No newline at end of file
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rmstar_tmp.3.md b/src/doc/djbunix.h/rmstar_tmp.3.md
new file mode 120000
index 0000000..185133a
--- /dev/null
+++ b/src/doc/djbunix.h/rmstar_tmp.3.md
@@ -0,0 +1 @@
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rmstar_tmpat.3.md b/src/doc/djbunix.h/rmstar_tmpat.3.md
index 5efdb0c..185133a 120000
--- a/src/doc/djbunix.h/rmstar_tmpat.3.md
+++ b/src/doc/djbunix.h/rmstar_tmpat.3.md
@@ -1 +1 @@
-rm_rfat.3.md
\ No newline at end of file
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/rmstarat.3.md b/src/doc/djbunix.h/rmstarat.3.md
index 5efdb0c..185133a 120000
--- a/src/doc/djbunix.h/rmstarat.3.md
+++ b/src/doc/djbunix.h/rmstarat.3.md
@@ -1 +1 @@
-rm_rfat.3.md
\ No newline at end of file
+rm_rf.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sa_ls.3.md b/src/doc/djbunix.h/sa_ls.3.md
new file mode 120000
index 0000000..191b8eb
--- /dev/null
+++ b/src/doc/djbunix.h/sa_ls.3.md
@@ -0,0 +1 @@
+sa_lsat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sa_lsat.3.md b/src/doc/djbunix.h/sa_lsat.3.md
new file mode 100644
index 0000000..fc972c7
--- /dev/null
+++ b/src/doc/djbunix.h/sa_lsat.3.md
@@ -0,0 +1,46 @@
+% limb manual
+% sa_lsat(3)
+
+# NAME
+
+sa_lsat, sa_ls - append directory listing into an stralloc
+
+# SYNOPSIS
+
+    #include <fcntl.h> /* AT_FDCWD */
+    #include <limb/djbunix.h>
+
+```pre hl
+int sa_lsat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>name</em>, size_t *<em>maxlen</em>)
+int sa_ls(stralloc *<em>sa</em>, const char *<em>name</em>, size_t *<em>maxlen</em>)
+```
+
+# DESCRIPTION
+
+The `sa_lsat`() function appends the names of all files (except for `.` and `..`)
+in directory `name` into the stralloc pointed by `sa` as NUL-terminated strings.
+
+If `name` is a realtive path it is relative to the directory associated with the
+file descriptor `fd`, which may by *AT_FDCWD* to use the current working
+directory.
+
+If not NULL, `maxlen` will be set to the length of the longest file name added.
+(It will be 0 in case of empty directory.)
+
+The `sa_ls`() macro is similar except when `name` is a relative path, in
+which case it is relative to the current working directory.
+
+# RETURN VALUE
+
+On success, these functions return the number of names added into `sa`.
+Otherwise, they return -1 and set `errno` to indicate the error.
+
+# ERRORS
+
+These functions may fail if :
+
+: *ENOMEM*
+:: Out of memory to add names into `sa`
+
+They may also fail and set errno for any of the errors specified for the
+functions [opendirat](3) and [readdir](3).
diff --git a/src/doc/djbunix.h/sa_read.3.md b/src/doc/djbunix.h/sa_read.3.md
new file mode 100644
index 0000000..31e37ae
--- /dev/null
+++ b/src/doc/djbunix.h/sa_read.3.md
@@ -0,0 +1,38 @@
+% limb manual
+% sa_read(3)
+
+# NAME
+
+sa_read, sa_readmax - read a file and append its content to a stralloc
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+int sa_read(stralloc *<em>sa</em>, int <em>fd</em>)
+int sa_readmax(stralloc *<em>sa</em>, int <em>fd</em>, size_t <em>max</em>)
+```
+
+# DESCRIPTION
+
+The `sa_read`() function reads the entire content of the file associated with
+file descriptor `fd` and appends it into the *stralloc* pointed by `sa`.
+
+The `sa_readmax`() function is similar to `sa_read`() but it will only read up
+to `max` bytes.
+
+# RETURN VALUE
+
+On success, the `sa_read`() and `sa_readmax`() functions return 1. Otherwise
+they return 0 and set `errno` to indicate the error.
+
+# ERRORS
+
+The `sa_read`() and `sa_readmax`() functions may fail and set `errno` for
+any of the errors described for [fd_read](3) and [stralloc_readyplus](3).
+
+The `sa_readmax`() functions may also fail if :
+
+: *ENOBUFS*
+:: The file is larger than `max` bytes.
diff --git a/src/doc/djbunix.h/sa_readlink.3.md b/src/doc/djbunix.h/sa_readlink.3.md
new file mode 120000
index 0000000..8e6ceeb
--- /dev/null
+++ b/src/doc/djbunix.h/sa_readlink.3.md
@@ -0,0 +1 @@
+sa_readlinkat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sa_readlink0.3.md b/src/doc/djbunix.h/sa_readlink0.3.md
new file mode 120000
index 0000000..8e6ceeb
--- /dev/null
+++ b/src/doc/djbunix.h/sa_readlink0.3.md
@@ -0,0 +1 @@
+sa_readlinkat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sa_readlinkat.3.md b/src/doc/djbunix.h/sa_readlinkat.3.md
new file mode 100644
index 0000000..3b732b3
--- /dev/null
+++ b/src/doc/djbunix.h/sa_readlinkat.3.md
@@ -0,0 +1,55 @@
+% limb manual
+% sa_readlinkat(3)
+
+# NAME
+
+sa_readlink, sa_readlinkat, sa_readlink0, sa_readlinkat0 - read the content of
+a symbolic link into a stralloc
+
+# SYNOPSIS
+
+    #include <fcntl.h> /* AT_FDCWD */
+    #include <limb/djbunix.h>
+
+```pre hl
+int sa_readlinkat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>file</em>)
+int sa_readlinkat0(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>file</em>)
+
+int sa_readlink(stralloc *<em>sa</em>, const char *<em>file</em>)
+int sa_readlink0(stralloc *<em>sa</em>, const char *<em>file</em>)
+```
+
+# DESCRIPTION
+
+The `sa_readlinkat`() function places the content of the symbolic link referred
+to by `file` in the stralloc `sa`. If `file` specifies a relative path, it is
+relative to the directory associated with the file descriptor `fd`, which may be
+*AT_FDCWD* to use the current working directory.
+
+For more details, refer to [readlinkat](3).
+
+The `sa_readlinkat0`() function is similar to `sa_readlinkat`() except that it
+ensures the content placed in `sa` is NUL-terminated.
+
+The `sa_readlink`() macro is similar to `sa_readlinkat`() except when `file`
+specifies a relative path, in which case it is relative to the current working
+directory.
+
+The `sa_readlink0`() macro is similar to `sa_readlinkat0`() except when `file`
+specifies a relative path, in which case it is relative to the current working
+directory.
+
+# RETURN VALUE
+
+On success these functions return 0. Otherwise they return -1 and set `errno` to
+indicate the error.
+
+# ERRORS
+
+These functions may fail if:
+
+: *ENOMEM*
+:: Insufficient memory available to grow `sa`
+
+They may also fail and set `errno` for any of the errors specified for the
+function [readlinkat](3).
diff --git a/src/doc/djbunix.h/sa_readlinkat0.3.md b/src/doc/djbunix.h/sa_readlinkat0.3.md
new file mode 120000
index 0000000..8e6ceeb
--- /dev/null
+++ b/src/doc/djbunix.h/sa_readlinkat0.3.md
@@ -0,0 +1 @@
+sa_readlinkat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sa_readmax.3.md b/src/doc/djbunix.h/sa_readmax.3.md
new file mode 120000
index 0000000..7682daa
--- /dev/null
+++ b/src/doc/djbunix.h/sa_readmax.3.md
@@ -0,0 +1 @@
+sa_read.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sa_realpath.3.md b/src/doc/djbunix.h/sa_realpath.3.md
new file mode 120000
index 0000000..37d8c1b
--- /dev/null
+++ b/src/doc/djbunix.h/sa_realpath.3.md
@@ -0,0 +1 @@
+sa_realpathat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sa_realpathat.3.md b/src/doc/djbunix.h/sa_realpathat.3.md
new file mode 100644
index 0000000..a45aea9
--- /dev/null
+++ b/src/doc/djbunix.h/sa_realpathat.3.md
@@ -0,0 +1,51 @@
+% limb manual
+% sa_realpathat(3)
+
+# NAME
+
+sa_realpathat, sa_realpath - place canonicalized absolute pathname into a
+stralloc
+
+# SYNOPSIS
+
+    #include <fcntl.h> /* AT_FDCWD */
+    #include <limb/djbunix.h>
+
+```pre hl
+int sa_realpathat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>path</em>)
+int sa_realpath(stralloc *<em>sa</em>, const char *<em>path</em>)
+```
+
+# DESCRIPTION
+
+The `sa_realpathat`() function expands all symbolic links and resolves
+references to `.` and `..` in the NUL-terminated string pointed by `path` to
+produce the corresponding canonicalized absolute pathname, added into the
+stralloc pointed by `sa`.
+
+If `path` specify a relative path, it is relative to the directory associated
+with the file descriptor `fd`, which may be *AT_FDCWD* to use the current
+working directory.
+
+For more details, refer to [realpath](3).
+
+The `sa_realpath`() macro is similar except when `path` specifies a relative
+path, in which case it is relative to the current working directory.
+
+# RETURN VALUE
+
+On success these functions return 0. Otherwise they return -1 and set `errno` to
+indicate the error.
+
+# ERRORS
+
+These functions may fail and set `errno` if :
+
+: *ENOMEM*
+:: Insufficient memory available to grow `sa`
+
+They may may fail and set `errno` for any of the errors described for
+[realpath](3).
+
+The `sa_realpathat`() function may also fail and set `errno` for any of the
+errors described for [open_read](3) or [fd_chdir](3).
diff --git a/src/doc/djbunix.h/salsat.3.md b/src/doc/djbunix.h/salsat.3.md
deleted file mode 100644
index a5aa1ca..0000000
--- a/src/doc/djbunix.h/salsat.3.md
+++ /dev/null
@@ -1,55 +0,0 @@
-% limb manual
-% salsat(3)
-
-# NAME
-
-salsat, salst, salstat - append directory listing into an stralloc
-
-# SYNOPSIS
-
-    #include <fcntl.h> /* AT_FDCWD */
-    #include <limb/djbunix.h>
-
-```pre hl
-int salsat(int <em>fd</em>, const char *<em>name</em>, stralloc *<em>sa</em>, size_t *<em>maxlen</em>)
-
-int salst(stralloc *<em>sa</em>, const char *<em>name</em>, size_t *<em>maxlen</em>)
-int salstat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>name</em>, size_t *<em>maxlen</em>)
-```
-
-# DESCRIPTION
-
-The `salsat`() function appends the names of all files (except for `.` and `..`)
-in directory `name` into the specified stralloc `sa` as NUL-terminated strings.
-
-It is the equivalent to [sals](3) function except when `name` specifies a
-relative path, the directory to be opened is then determined relative to the
-directory associated with the file descriptor `fd` instead of the current
-working directory.
-If passed the special value *AT_FDCWD* in the `fd` parameter, the current
-working directory is used.
-
-If not NULL, `maxlen` will be set to the length of the longest file name added.
-(It will be 0 in case of empty directory.)
-
-`salst`() is a macro to [sals](3) with a slightly different interface, namely
-the stralloc `sa` as first argument.
-
-Similarly, `salstat`() is a macro to `salsat`() with a slightly different
-interface as well.
-
-# RETURN VALUE
-
-Upon successful completion, the `salsat` functions returns the number of names
-added into `sa`. Otherwise, it returns -1 and sets `errno` to indicate the
-error.
-
-# ERRORS
-
-The `salsat`() function may fail if :
-
-: *ENOMEM*
-:: Out of memory to add names into `sa`
-
-It may also fail and set errno for any of the errors specified for the
-functions [opendirat](3) and [readdir](3).
diff --git a/src/doc/djbunix.h/salst.3.md b/src/doc/djbunix.h/salst.3.md
deleted file mode 120000
index 8a7c62d..0000000
--- a/src/doc/djbunix.h/salst.3.md
+++ /dev/null
@@ -1 +0,0 @@
-salsat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/salstat.3.md b/src/doc/djbunix.h/salstat.3.md
deleted file mode 120000
index 8a7c62d..0000000
--- a/src/doc/djbunix.h/salstat.3.md
+++ /dev/null
@@ -1 +0,0 @@
-salsat.3.md
\ No newline at end of file
diff --git a/src/doc/djbunix.h/sareadlinkat.3.md b/src/doc/djbunix.h/sareadlinkat.3.md
deleted file mode 100644
index 107b053..0000000
--- a/src/doc/djbunix.h/sareadlinkat.3.md
+++ /dev/null
@@ -1,59 +0,0 @@
-% limb manual
-% sareadlinkat(3)
-
-# NAME
-
-sareadlinkat - read the content of a symbolic link
-
-# SYNOPSIS
-
-    #include <fcntl.h> /* AT_FDCWD */
-    #include <limb/djbunix.h>
-
-```pre hl
-int sareadlink0(stralloc *<em>sa</em>, const char * restrict <em>file</em>)
-
-int sareadlinkat(stralloc *<em>sa</em>, int <em>fd</em>, const char * restrict <em>file</em>)
-int sareadlinkat0(stralloc *<em>sa</em>, int <em>fd</em>, const char * restrict <em>file</em>)
-```
-
-# DESCRIPTION
-
-The `sareadlinkat`() function places the content of the symbolic link referred
-to by `file` in the stralloc `sa`.
-
-For more details, refer to [readlinkat](3).
-
-It is equivalent to [sareadlink](3) except when `file` specifies a relative
-path, the symbolic link whose content is read is then determined relative to
-the directory associated with the file descriptor `fd`.
-If passed the special value *AT_FDCWD* in the `fd` parameter, the current
-working directory is used.
-
-The `sareadlinkat0`() function is similar to `sareadlinkat`() except that it
-ensures the content placed in `sa` is NUL-terminated.
-
-The `sareadlink0`() function is similar to [sareadlink](3) except that it
-ensures the content placed in `sa` is NUL-terminated.
-
-# RETURN VALUE
-
-Upon successful completion these functions return 0. Otherwise they return -1
-and set `errno` to indicate the error.
-
-# ERRORS
-
-These functions may fail if:
-
-: *ENOMEM*
-:: Insufficient memory available to grow `sa`
-
-The `sareadlinkat`() and `sareadlinkat0`() functions may also fail and set
-`errno` for any of the errors specified for the function [readlinkat](3).
-
-The `sareadlink0`() function may also fail and set `errno` for any of the errors
-specified for the function [readlink](3).
-
-# SEE ALSO
-
-[readlinkat](3), [sareadlink](3)
diff --git a/src/doc/djbunix.h/sarealpath.3.md b/src/doc/djbunix.h/sarealpath.3.md
deleted file mode 100644
index 9d7b8dd..0000000
--- a/src/doc/djbunix.h/sarealpath.3.md
+++ /dev/null
@@ -1,59 +0,0 @@
-% limb manual
-% sarealpath(3)
-
-# NAME
-
-sarealpath, sarealpathat - place canonicalized absolute pathname into a stralloc
-
-# SYNOPSIS
-
-    #include <fcntl.h> /* AT_FDCWD */
-    #include <limb/djbunix.h>
-
-```pre hl
-int sarealpath(stralloc *<em>sa</em>, const char *<em>path</em>)
-int sarealpathat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>path</em>)
-```
-
-# DESCRIPTION
-
-The `sarealpath`() function expands all symbolic links and resolves references
-to `.` and `..` in the NUL-terminated string pointed by `path` to produce the
-corresponding canonicalized absolute pathname, added into the stralloc pointed
-by `sa`.
-
-For more details, refer to [realpath](3).
-
-The `sarealpathat`() function is similar except when `path` specifies a relative
-path, in which case it is then determined relative to the directory associated
-with the file descriptor `fd`.
-If passed the special value *AT_FDCWD* in the `fd` parameter, the current
-working directory is used.
-
-# RETURN VALUE
-
-Upon successful completion these functions return 0. Otherwise they return -1
-and set `errno` to indicate the error.
-
-# ERRORS
-
-The `sarealpath`() and `sarealpathat`() functions may fail and set `errno` for
-any of the errors specified for the function [realpath](3).
-
-They may also fail and set `errno` if:
-
-: *ENOMEM*
-:: Insufficient memory available to grow `sa`
-
-The `sarealpathat`() function may also fail and set `errno` if :
-
-: *EACCESS*
-:: Search permission is denied for the current working directory or the
-:: directory referenced by `fd`.
-
-: *EMFILE*
-:: All dile descriptors available to the process are currently open, or the
-:: maximum allowable number of files is currently open in the system.
-
-: *EIO*
-:: An I/O error occured while reading from the file system.
diff --git a/src/doc/djbunix.h/uncoe.3.md b/src/doc/djbunix.h/uncoe.3.md
new file mode 120000
index 0000000..b577275
--- /dev/null
+++ b/src/doc/djbunix.h/uncoe.3.md
@@ -0,0 +1 @@
+coe.3.md
\ No newline at end of file
diff --git a/src/doc/unix-transactional.h.0.md b/src/doc/unix-transactional.h.0.md
deleted file mode 100644
index 49b5504..0000000
--- a/src/doc/unix-transactional.h.0.md
+++ /dev/null
@@ -1,57 +0,0 @@
-% limb manual
-% unix-transactional.h(0)
-
-# NAME
-
-unix-transactional.h - transactional filesystem operations
-
-# SYNOPSIS
-
-    #include <limb/unix-transactional.h>
-
-# DESCRIPTION
-
-This header defines functions allowing to perform transactional filesystem
-operations.
-
-! INFO: skalibs
-! This header is a complement to skalibs' own [skalibs/unix-transactional.h](0)
-! and thusly includes said header.
-
-## Functions
-
-The following functions are defined :
-
-: [openb_readat](3)
-:: Same as [openb_read](3) but relative path are based on given file descriptor.
-
-: [openbc_readat](3)
-:: Same as [openc_read](3) but relative path are based on given file descriptor.
-
-: [open_createat](3)
-:: Same as [open_create](3) but relative path are based of given file descriptor
-
-: [openc_createat](3)
-:: Same as [openc_create](3) but relative path are based of given file
-:: descriptor
-
-: [open_exclat](3)
-:: Same as [open_excl](3) but relative path are based of given file descriptor
-
-: [openc_exclat](3)
-:: Same as [openc_excl](3) but relative path are based of given file descriptor
-
-: [open_tmpat](3)
-:: Same as [open_tmp](3) but relative path are based of given file descriptor.
-
-: [open_read_closeat](3)
-:: Open, read & close a file into memory.
-
-: [open_slurp_closeat](3)
-:: Open, read & close a file into a *stralloc*.
-
-: [open_write_closeat](3)
-:: Open, write & close a file with data from pointed memory.
-
-: [open_writev_closeat](3)
-:: Open, write & close a file with data from array of vectors.
diff --git a/src/doc/unix-transactional.h/open_createat.3.md b/src/doc/unix-transactional.h/open_createat.3.md
deleted file mode 100644
index edc0f45..0000000
--- a/src/doc/unix-transactional.h/open_createat.3.md
+++ /dev/null
@@ -1,37 +0,0 @@
-% limb manual
-% open_createat(3)
-% limb 0.0.1
-% 2023.01.16
-
-# NAME
-
-open_createat, openc_createat - open file relative to directory file descriptor
-
-# SYNOPSIS
-
-    #include <limb/unix-transactional.h>
-
-```pre hl
-int open_createat(int <em>fd</em>, const char *<em>file</em>);
-int openc_createat(int <em>fd</em>, const char *<em>file</em>);
-```
-
-# DESCRIPTION
-
-The `open_createat`() function opens a file for writing, creating it if it
-doesn't exist, in non-blocking mode.
-
-The `openc_createat`() function is similar, only with the *FD_CLOEXEC* flag set
-for the file descriptor.
-
-# RETURN VALUE
-
-Upon successful completion, these functions shall open the file and return a
-non-negative integer representing the lowest numbered unused file descriptor.
-Otherwise, these functions shall return -1 and set errno to indicate the error.
-If -1 is returned, no files shall be created or modified.
-
-# ERRORS
-
-These functions may fail and set errno for any of the errors specified for the
-routine [openat](2).
diff --git a/src/doc/unix-transactional.h/open_exclat.3.md b/src/doc/unix-transactional.h/open_exclat.3.md
deleted file mode 100644
index f92f94a..0000000
--- a/src/doc/unix-transactional.h/open_exclat.3.md
+++ /dev/null
@@ -1,37 +0,0 @@
-% limb manual
-% open_exclat(3)
-% limb 0.0.1
-% 2023.01.16
-
-# NAME
-
-open_exclat, openc_exclat - create file relative to directory file descriptor
-
-# SYNOPSIS
-
-    #include <limb/unix-transactional.h>
-
-```pre hl
-int open_exclat(int <em>fd</em>, const char *<em>file</em>);
-int openc_exclat(int <em>fd</em>, const char *<em>file</em>);
-```
-
-# DESCRIPTION
-
-The `open_exclat`() function attempts to create a new file and open it for
-writing, in non-blocking mode, failing with *EEXIST* if it already exists.
-
-The `openc_exclat`() function is similar, only with the *FD_CLOEXEC* flag set
-for the file descriptor.
-
-# RETURN VALUE
-
-Upon successful completion, these functions shall open the file and return a
-non-negative integer representing the lowest numbered unused file descriptor.
-Otherwise, these functions shall return -1 and set errno to indicate the error.
-If -1 is returned, no files shall be created or modified.
-
-# ERRORS
-
-These functions may fail and set errno for any of the errors specified for the
-routine [openat](2).
diff --git a/src/doc/unix-transactional.h/open_read_closeat.3.md b/src/doc/unix-transactional.h/open_read_closeat.3.md
deleted file mode 100644
index 5870ee2..0000000
--- a/src/doc/unix-transactional.h/open_read_closeat.3.md
+++ /dev/null
@@ -1,54 +0,0 @@
-% limb manual
-% open_read_closeat(3)
-
-# NAME
-
-open\_read\_closeat, open\_slurp\_closeat - open, read & close a file
-
-# SYNOPSIS
-
-    #include <limb/unix-transactional.h>
-
-```pre hl
-ssize_t open_read_closeat(char *<em>dst</em>, size_t <em>dlen</em>, int <em>fd</em>, const char *<em>file</em>)
-int open_slurp_closeat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>file</em>)
-```
-
-# DESCRIPTION
-
-The `open_read_closeat`() function will open the file named `file` for reading
-in blocking mode. If `file` describes a relative path, it is relative to the
-directory associated with the file descriptor `fd`, which may be *AT_FDCWD* to
-use the current working directory.
-
-The content of the file will be read and copied into the memory pointed by `dst`
-up to a maximum of `dlen` bytes, and the file be closed.
-
-The `open_slurp_closeat`() function is similar, only the entirety of the file
-will be placed into the *stralloc* pointed by `sa`, allocating as much memory as
-needed.
-
-# RETURN VALUE
-
-The `open_read_closeat`() function returns the amount of data read from the
-file, and written into `dst`, on success. Otherwise it returns -1 and sets
-`errno` to indicate the error.
-
-The `open_slurp_closeat`() function returns 1 on success. Otherwise it returns 0
-and sets `errno` to indicate the error.
-
-# ERRORS
-
-The `open_read_closeat`() and `open_slurp_closeat`() function may fail and set
-`errno` for the errors described for [openb_readat](3).
-
-The `open_read_closeat`() function may also fail if :
-
-: *ENOBUFS*
-:: Not enough space available in `dst` to store the entire file.
-
-The `open_read_closeat`() may also fail and set `errno` for the errors described
-for [read](3).
-
-The `open_slurp_closeat`() may also fail and set `errno` for the errors
-described for [slurp](3).
diff --git a/src/doc/unix-transactional.h/openb_readat.3.md b/src/doc/unix-transactional.h/openb_readat.3.md
deleted file mode 100644
index 3cd837d..0000000
--- a/src/doc/unix-transactional.h/openb_readat.3.md
+++ /dev/null
@@ -1,35 +0,0 @@
-% limb manual
-% openb_readat(3)
-
-# NAME
-
-openb\_readat, openbc\_readat - open file relative to directory file descriptor
-
-# SYNOPSIS
-
-    #include <limb/unix-transactional.h>
-
-```pre hl
-int openb_readat(int <em>fd</em>, const char *<em>file</em>);
-int openbc_readat(int <em>fd</em>, const char *<em>file</em>);
-```
-
-# DESCRIPTION
-
-The `openb_readat`() function opens `file` for reading in blocking mode. If
-`file` specifies a relative path, it is relative to the directory associated
-with the file descripor `fd`, which may be *AT_FDCWD* to use the current working
-directory.
-
-The `openbc_readat`() function is similar, only with the *FD_CLOEXEC* flag set
-for the opened file descriptor.
-
-# RETURN VALUE
-
-These functions return the opened file descriptor on success. Otherwise they
-return -1 and set `errno` to indicate the error.
-
-# ERRORS
-
-These functions may fail and set `errno` for any of the errors described for
-[open2_at](3).
diff --git a/src/doc/unix-transactional.h/openbc_readat.3.md b/src/doc/unix-transactional.h/openbc_readat.3.md
deleted file mode 120000
index 3501b8a..0000000
--- a/src/doc/unix-transactional.h/openbc_readat.3.md
+++ /dev/null
@@ -1 +0,0 @@
-openb_readat.3.md
\ No newline at end of file
diff --git a/src/doc/unix-transactional.h/openc_createat.3.md b/src/doc/unix-transactional.h/openc_createat.3.md
deleted file mode 120000
index 2e9455d..0000000
--- a/src/doc/unix-transactional.h/openc_createat.3.md
+++ /dev/null
@@ -1 +0,0 @@
-open_createat.3.md
\ No newline at end of file
diff --git a/src/doc/unix-transactional.h/openc_exclat.3.md b/src/doc/unix-transactional.h/openc_exclat.3.md
deleted file mode 120000
index 1530217..0000000
--- a/src/doc/unix-transactional.h/openc_exclat.3.md
+++ /dev/null
@@ -1 +0,0 @@
-open_exclat.3.md
\ No newline at end of file
diff --git a/src/liblimb/direntry.h/open_writeb.c b/src/liblimb/direntry.h/open_writeb.c
new file mode 100644
index 0000000..62b0fb2
--- /dev/null
+++ b/src/liblimb/direntry.h/open_writeb.c
@@ -0,0 +1,10 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <limb/djbunix.h>
+
+int
+open_writeb(const char *file)
+{
+    return open_b(open_write, file);
+}
diff --git a/src/liblimb/direntry.h/openc_writeb.c b/src/liblimb/direntry.h/openc_writeb.c
new file mode 100644
index 0000000..5b23b17
--- /dev/null
+++ b/src/liblimb/direntry.h/openc_writeb.c
@@ -0,0 +1,10 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <limb/djbunix.h>
+
+int
+openc_writeb(const char *file)
+{
+    return open_b(openc_write, file);
+}
diff --git a/src/liblimb/direntry.h/opendirat.c b/src/liblimb/direntry.h/opendirat.c
index 3c4291d..cf67d00 100644
--- a/src/liblimb/direntry.h/opendirat.c
+++ b/src/liblimb/direntry.h/opendirat.c
@@ -1,8 +1,7 @@
 /* This file is part of limb                           https://lila.oss/limb
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
-#include <skalibs/djbunix.h>
-#include <skalibs/unix-transactional.h>
+#include <limb/djbunix.h>
 #include <limb/direntry.h>
 
 DIR *
diff --git a/src/liblimb/djbunix.h/fd_mkdirpat.c b/src/liblimb/djbunix.h/fd_mkdirpat.c
index c14701a..d468360 100644
--- a/src/liblimb/djbunix.h/fd_mkdirpat.c
+++ b/src/liblimb/djbunix.h/fd_mkdirpat.c
@@ -6,7 +6,6 @@
 #include <sys/stat.h>
 #include <limb/bytestr.h>
 #include <limb/djbunix.h>
-#include <limb/unix-transactional.h>
 
 int
 fd_mkdirpat(int bfd, const char *name, mode_t mode)
diff --git a/src/liblimb/djbunix.h/open_atb.c b/src/liblimb/djbunix.h/open_atb.c
new file mode 100644
index 0000000..0dc00f6
--- /dev/null
+++ b/src/liblimb/djbunix.h/open_atb.c
@@ -0,0 +1,16 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <limb/djbunix.h>
+
+int
+open_atb(openat_fn fn, int bfd, const char *file)
+{
+    int fd = fn(bfd, file);
+    if (fd < 0) return -1;
+    if (ndelay_off(fd) < 0) {
+        fd_close(fd);
+        return -1;
+    }
+    return fd;
+}
diff --git a/src/liblimb/djbunix.h/open_b.c b/src/liblimb/djbunix.h/open_b.c
new file mode 100644
index 0000000..4ff47bb
--- /dev/null
+++ b/src/liblimb/djbunix.h/open_b.c
@@ -0,0 +1,16 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <limb/djbunix.h>
+
+int
+open_b(open_fn fn, const char *file)
+{
+    int fd = fn(file);
+    if (fd < 0) return -1;
+    if (ndelay_off(fd) < 0) {
+        fd_close(fd);
+        return -1;
+    }
+    return fd;
+}
diff --git a/src/liblimb/unix-transactional.h/open_createat.c b/src/liblimb/djbunix.h/open_createat.c
similarity index 81%
rename from src/liblimb/unix-transactional.h/open_createat.c
rename to src/liblimb/djbunix.h/open_createat.c
index dbcc4ab..baebeb5 100644
--- a/src/liblimb/unix-transactional.h/open_createat.c
+++ b/src/liblimb/djbunix.h/open_createat.c
@@ -2,8 +2,7 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <fcntl.h>
-#include <skalibs/unix-transactional.h>
-#include <limb/unix-transactional.h>
+#include <limb/djbunix.h>
 
 int
 open_createat(int fd, const char *file)
diff --git a/src/liblimb/unix-transactional.h/open_exclat.c b/src/liblimb/djbunix.h/open_exclat.c
similarity index 81%
rename from src/liblimb/unix-transactional.h/open_exclat.c
rename to src/liblimb/djbunix.h/open_exclat.c
index adf45d4..417b8f8 100644
--- a/src/liblimb/unix-transactional.h/open_exclat.c
+++ b/src/liblimb/djbunix.h/open_exclat.c
@@ -2,8 +2,7 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <fcntl.h>
-#include <skalibs/unix-transactional.h>
-#include <limb/unix-transactional.h>
+#include <limb/djbunix.h>
 
 int
 open_exclat(int fd, const char *file)
diff --git a/src/liblimb/unix-transactional.h/open_read_closeat.c b/src/liblimb/djbunix.h/open_read_closeat.c
similarity index 95%
rename from src/liblimb/unix-transactional.h/open_read_closeat.c
rename to src/liblimb/djbunix.h/open_read_closeat.c
index 010809d..1839b51 100644
--- a/src/liblimb/unix-transactional.h/open_read_closeat.c
+++ b/src/liblimb/djbunix.h/open_read_closeat.c
@@ -4,7 +4,6 @@
 #include <errno.h>
 #include <skalibs/allreadwrite.h>
 #include <limb/djbunix.h>
-#include <limb/unix-transactional.h>
 
 ssize_t
 open_read_closeat(char *dst, size_t dlen, int bfd, const char *file)
diff --git a/src/liblimb/unix-transactional.h/open_slurp_closeat.c b/src/liblimb/djbunix.h/open_saread_closeat.c
similarity index 72%
rename from src/liblimb/unix-transactional.h/open_slurp_closeat.c
rename to src/liblimb/djbunix.h/open_saread_closeat.c
index 16ff4ff..d7b09cb 100644
--- a/src/liblimb/unix-transactional.h/open_slurp_closeat.c
+++ b/src/liblimb/djbunix.h/open_saread_closeat.c
@@ -2,15 +2,14 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <limb/djbunix.h>
-#include <limb/unix-transactional.h>
 
 int
-open_slurp_closeat(stralloc *sa, int bfd, const char *file)
+open_saread_closeat(stralloc *sa, int bfd, const char *file)
 {
     int fd = openb_readat(bfd, file);
     if (fd < 0) return -1;
 
-    int r = slurp(sa, fd);
+    int r = sa_read(sa, fd);
     fd_close(fd);
     return r;
 }
diff --git a/src/liblimb/unix-transactional.h/open_write_closeat.c b/src/liblimb/djbunix.h/open_write_closeat.c
similarity index 94%
rename from src/liblimb/unix-transactional.h/open_write_closeat.c
rename to src/liblimb/djbunix.h/open_write_closeat.c
index 0ee3cdc..7aeddb2 100644
--- a/src/liblimb/unix-transactional.h/open_write_closeat.c
+++ b/src/liblimb/djbunix.h/open_write_closeat.c
@@ -4,7 +4,6 @@
 #include <stdio.h>
 #include <skalibs/allreadwrite.h>
 #include <limb/djbunix.h>
-#include <limb/unix-transactional.h>
 
 int
 open_write_closeat(int bfd, const char *file, const char *data, size_t dlen)
diff --git a/src/liblimb/unix-transactional.h/open_writev_closeat.c b/src/liblimb/djbunix.h/open_writev_closeat.c
similarity index 94%
rename from src/liblimb/unix-transactional.h/open_writev_closeat.c
rename to src/liblimb/djbunix.h/open_writev_closeat.c
index c48744a..5c65a43 100644
--- a/src/liblimb/unix-transactional.h/open_writev_closeat.c
+++ b/src/liblimb/djbunix.h/open_writev_closeat.c
@@ -5,7 +5,6 @@
 #include <skalibs/allreadwrite.h>
 #include <limb/djbunix.h>
 #include <limb/siovec.h>
-#include <limb/unix-transactional.h>
 
 int
 open_writev_closeat(int bfd, const char *file, const struct iovec *v, unsigned n)
diff --git a/src/liblimb/unix-transactional.h/openb_readat.c b/src/liblimb/djbunix.h/openb_readat.c
similarity index 89%
rename from src/liblimb/unix-transactional.h/openb_readat.c
rename to src/liblimb/djbunix.h/openb_readat.c
index a1fca88..a73b8be 100644
--- a/src/liblimb/unix-transactional.h/openb_readat.c
+++ b/src/liblimb/djbunix.h/openb_readat.c
@@ -2,7 +2,7 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <fcntl.h>
-#include <limb/unix-transactional.h>
+#include <limb/djbunix.h>
 
 int
 openb_readat(int fd, const char *file)
diff --git a/src/liblimb/djbunix.h/openb_write.c b/src/liblimb/djbunix.h/openb_write.c
new file mode 100644
index 0000000..671a073
--- /dev/null
+++ b/src/liblimb/djbunix.h/openb_write.c
@@ -0,0 +1,11 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <fcntl.h>
+#include <limb/djbunix.h>
+
+int
+openb_write(const char *file)
+{
+    return open2(file, O_WRONLY);
+}
diff --git a/src/liblimb/djbunix.h/openb_writeat.c b/src/liblimb/djbunix.h/openb_writeat.c
new file mode 100644
index 0000000..e422105
--- /dev/null
+++ b/src/liblimb/djbunix.h/openb_writeat.c
@@ -0,0 +1,11 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <fcntl.h>
+#include <limb/djbunix.h>
+
+int
+openb_writeat(int fd, const char *file)
+{
+    return open2_at(fd, file, O_WRONLY);
+}
diff --git a/src/liblimb/unix-transactional.h/openbc_readat.c b/src/liblimb/djbunix.h/openbc_readat.c
similarity index 89%
rename from src/liblimb/unix-transactional.h/openbc_readat.c
rename to src/liblimb/djbunix.h/openbc_readat.c
index 4305316..8896f05 100644
--- a/src/liblimb/unix-transactional.h/openbc_readat.c
+++ b/src/liblimb/djbunix.h/openbc_readat.c
@@ -2,7 +2,7 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <fcntl.h>
-#include <limb/unix-transactional.h>
+#include <limb/djbunix.h>
 
 int
 openbc_readat(int fd, const char *file)
diff --git a/src/liblimb/djbunix.h/openbc_write.c b/src/liblimb/djbunix.h/openbc_write.c
new file mode 100644
index 0000000..37ce56f
--- /dev/null
+++ b/src/liblimb/djbunix.h/openbc_write.c
@@ -0,0 +1,11 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <fcntl.h>
+#include <limb/djbunix.h>
+
+int
+openbc_write(const char *file)
+{
+    return open2(file, O_WRONLY | O_CLOEXEC);
+}
diff --git a/src/liblimb/djbunix.h/openbc_writeat.c b/src/liblimb/djbunix.h/openbc_writeat.c
new file mode 100644
index 0000000..6b4a4c3
--- /dev/null
+++ b/src/liblimb/djbunix.h/openbc_writeat.c
@@ -0,0 +1,11 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <fcntl.h>
+#include <limb/djbunix.h>
+
+int
+openbc_writeat(int fd, const char *file)
+{
+    return open2_at(fd, file, O_WRONLY | O_CLOEXEC);
+}
diff --git a/src/liblimb/unix-transactional.h/openc_createat.c b/src/liblimb/djbunix.h/openc_createat.c
similarity index 82%
rename from src/liblimb/unix-transactional.h/openc_createat.c
rename to src/liblimb/djbunix.h/openc_createat.c
index de198cd..df50cd2 100644
--- a/src/liblimb/unix-transactional.h/openc_createat.c
+++ b/src/liblimb/djbunix.h/openc_createat.c
@@ -2,8 +2,7 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <fcntl.h>
-#include <skalibs/unix-transactional.h>
-#include <limb/unix-transactional.h>
+#include <limb/djbunix.h>
 
 int
 openc_createat(int fd, const char *file)
diff --git a/src/liblimb/unix-transactional.h/openc_exclat.c b/src/liblimb/djbunix.h/openc_exclat.c
similarity index 82%
rename from src/liblimb/unix-transactional.h/openc_exclat.c
rename to src/liblimb/djbunix.h/openc_exclat.c
index 925dca3..6a7830a 100644
--- a/src/liblimb/unix-transactional.h/openc_exclat.c
+++ b/src/liblimb/djbunix.h/openc_exclat.c
@@ -2,8 +2,7 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <fcntl.h>
-#include <skalibs/unix-transactional.h>
-#include <limb/unix-transactional.h>
+#include <limb/djbunix.h>
 
 int
 openc_exclat(int fd, const char *file)
diff --git a/src/liblimb/djbunix.h/rmstar_in_tmpat.c b/src/liblimb/djbunix.h/rmstar_in_tmpat.c
index 2e47cc9..c3a6e74 100644
--- a/src/liblimb/djbunix.h/rmstar_in_tmpat.c
+++ b/src/liblimb/djbunix.h/rmstar_in_tmpat.c
@@ -11,7 +11,7 @@ rmstar_in_tmpat(int fd, stralloc *sa, size_t offset)
     int ret = 0;
 
     /* get all names from within */
-    if (salstat(sa, fd, sa->s + offset, &maxlen) < 0)
+    if (sa_lsat(sa, fd, sa->s + offset, &maxlen) < 0)
         return -1;
 
     size_t l = strlen(sa->s + offset);
diff --git a/src/liblimb/djbunix.h/salsat.c b/src/liblimb/djbunix.h/sa_lsat.c
similarity index 91%
rename from src/liblimb/djbunix.h/salsat.c
rename to src/liblimb/djbunix.h/sa_lsat.c
index a96bd96..47e7dab 100644
--- a/src/liblimb/djbunix.h/salsat.c
+++ b/src/liblimb/djbunix.h/sa_lsat.c
@@ -19,7 +19,7 @@ sa_scandir_name(stralloc *sa, direntry *de, int bfd gccattr_unused, void *mlen_)
 }
 
 int
-salsat(int fd, const char *name, stralloc *sa, size_t *mlen)
+sa_lsat(stralloc *sa, int fd, const char *name, size_t *mlen)
 {
     if (mlen) *mlen = 0;
     return sa_scandirat(sa, fd, name, sa_scandir_name, mlen);
diff --git a/src/liblimb/djbunix.h/sareadlinkat.c b/src/liblimb/djbunix.h/sa_readlinkat.c
similarity index 89%
rename from src/liblimb/djbunix.h/sareadlinkat.c
rename to src/liblimb/djbunix.h/sa_readlinkat.c
index 0e9887a..12110be 100644
--- a/src/liblimb/djbunix.h/sareadlinkat.c
+++ b/src/liblimb/djbunix.h/sa_readlinkat.c
@@ -5,7 +5,7 @@
 #include <limb/djbunix.h>
 
 int
-sareadlinkat(stralloc *sa, int fd, const char * restrict file)
+sa_readlinkat(stralloc *sa, int fd, const char * restrict file)
 {
     size_t len = 256;
     ssize_t r;
diff --git a/src/liblimb/djbunix.h/sareadlinkat0.c b/src/liblimb/djbunix.h/sa_readlinkat0.c
similarity index 79%
rename from src/liblimb/djbunix.h/sareadlinkat0.c
rename to src/liblimb/djbunix.h/sa_readlinkat0.c
index 9930076..ae88b95 100644
--- a/src/liblimb/djbunix.h/sareadlinkat0.c
+++ b/src/liblimb/djbunix.h/sa_readlinkat0.c
@@ -4,9 +4,9 @@
 #include <limb/djbunix.h>
 
 int
-sareadlinkat0(stralloc *sa, int fd, const char * restrict file)
+sa_readlinkat0(stralloc *sa, int fd, const char * restrict file)
 {
-    int r = sareadlinkat(sa, fd, file);
+    int r = sa_readlinkat(sa, fd, file);
     if (r < 0)
         return r;
 
diff --git a/src/liblimb/djbunix.h/sarealpathat.c b/src/liblimb/djbunix.h/sa_realpathat.c
similarity index 86%
rename from src/liblimb/djbunix.h/sarealpathat.c
rename to src/liblimb/djbunix.h/sa_realpathat.c
index c72ff59..6dd1d18 100644
--- a/src/liblimb/djbunix.h/sarealpathat.c
+++ b/src/liblimb/djbunix.h/sa_realpathat.c
@@ -4,7 +4,7 @@
 #include <limb/djbunix.h>
 
 int
-sarealpathat(stralloc *sa, int bfd, const char *file)
+sa_realpathat(stralloc *sa, int bfd, const char *file)
 {
     int ret = -1;
     int cwd = -1;
@@ -19,7 +19,7 @@ sarealpathat(stralloc *sa, int bfd, const char *file)
         }
     }
 
-    if (!sarealpath(sa, file))
+    if (!sa_realpath(sa, file))
         ret = 0;
 
     if (cwd >= 0) {
diff --git a/src/liblimb/djbunix.h/sareadlink0.c b/src/liblimb/djbunix.h/sareadlink0.c
deleted file mode 100644
index 03ba44a..0000000
--- a/src/liblimb/djbunix.h/sareadlink0.c
+++ /dev/null
@@ -1,18 +0,0 @@
-/* This file is part of limb                           https://lila.oss/limb
- * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
-/* SPDX-License-Identifier: GPL-2.0-only */
-#include <skalibs/djbunix.h>
-
-int
-sareadlink0(stralloc *sa, const char * restrict file)
-{
-    int r = sareadlink(sa, file);
-    if (r < 0)
-        return r;
-
-    /* make sure it ends with a NUL - which isn't guaranteed */
-    if (sa->s[sa->len - 1] != 0 && !stralloc_0(sa))
-        return -1;
-
-    return 0;
-}
diff --git a/src/liblimb/hmac.h/hmac.c b/src/liblimb/hmac.h/hmac.c
index 15121b5..2458487 100644
--- a/src/liblimb/hmac.h/hmac.c
+++ b/src/liblimb/hmac.h/hmac.c
@@ -2,7 +2,7 @@
  * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <string.h>
-#include <skalibs/bytestr.h>
+#include <limb/bytestr.h>
 #include <limb/hmac.h>
 #include <limb/memxor.h>
 
diff --git a/src/liblimb/include/limb/djbunix.h b/src/liblimb/include/limb/djbunix.h
index b204d41..7fcf1a4 100644
--- a/src/liblimb/include/limb/djbunix.h
+++ b/src/liblimb/include/limb/djbunix.h
@@ -5,17 +5,49 @@
 #define LIMB_DJBUNIX_H
 
 #include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+#include <limb/posixplz.h>
+#include <limb/siovec.h>
 #include <limb/stralloc.h>
-#include <limb/unix-transactional.h>
 
 typedef int (*open_fn) (const char *file);
+typedef int (*openat_fn) (int bfd, const char *file);
+
+extern int open_b(open_fn fn, const char *file);
+extern int open_atb(openat_fn fn, int bfd, const char *file);
+
+extern int openb_readat(int fd, const char *file);
+extern int openbc_readat(int fd, const char *file);
+
+extern int open_writeb(const char *file);
+extern int openb_write(const char *file);
+extern int openb_writeat(int fd, const char *file);
+extern int openc_writeb(const char *file);
+extern int openbc_write(const char *file);
+extern int openbc_writeat(int fd, const char *file);
+
+extern int open_createat(int fd, const char *file);
+extern int openc_createat(int fd, const char *file);
+
+extern int open_exclat(int fd, const char *file);
+extern int openc_exclat(int fd, const char *file);
+
+#define open_tmp(tmp)           mkfiletemp(tmp, (create_func) (void (*)(void)) open_excl, 0, NULL)
+#define open_tmpat(fd,tmp)      mkfiletempat(fd, tmp, (createat_fn) (void (*)(void)) open_exclat, 0, NULL)
 
 extern int open_parsed_name(const char *name, open_fn open);
 
-#define open_tmp(tmp)       mkfiletemp(tmp, (create_func) (void (*)(void)) open_excl, 0, NULL)
+#define read_close(dst,dlen,fd) readnclose(fd, dst, dlen)
+#define sa_read(sa,fd)          slurpn(fd, sa, 0)
+#define sa_readmax(sa,fd,max)   slurpn(fd, sa, max)
+
+extern ssize_t open_read_closeat(char *dst, size_t dlen, int bfd, const char *file);
+extern int open_saread_closeat(stralloc *sa, int bfd, const char *file);
+extern int open_write_closeat(int fd, const char *file, const char *data, size_t dlen);
+extern int open_writev_closeat(int fd, const char *file, const struct iovec *v, unsigned n);
 
 #define open_read_close(dst,dlen,file)      open_read_closeat(dst, dlen, AT_FDCWD, file)
-#define open_slurp_close(sa,file)           open_slurp_closeat(sa, AT_FDCWD, file)
+#define open_saread_close(sa,file)          open_saread_closeat(sa, AT_FDCWD, file)
 #define open_write_close(file,data,dlen)    open_write_closeat(AT_FDCWD, file, data, dlen)
 #define open_writev_close(file,v,n)         open_writev_closeat(AT_FDCWD, file, v, n)
 
@@ -33,13 +65,14 @@ extern int rmstarat(int fd, const char *name);
 extern int rmstar_tmpat(int fd, const char *name, stralloc *sa);
 extern int rmstar_in_tmpat(int fd, stralloc *sa, size_t offset);
 
-extern int salsat(int fd, const char *name, stralloc *sa, size_t *maxlen);
-extern int sareadlink0(stralloc *sa, const char * restrict file);
-extern int sareadlinkat(stralloc *sa, int fd, const char * restrict file);
-extern int sareadlinkat0(stralloc *sa, int fd, const char * restrict file);
-extern int sarealpathat(stralloc *sa, int fd, const char * restrict file);
+extern int sa_readlinkat(stralloc *sa, int fd, const char *file);
+extern int sa_readlinkat0(stralloc *sa, int fd, const char *file);
+extern int sa_realpathat(stralloc *sa, int fd, const char *file);
+extern int sa_lsat(stralloc *sa, int fd, const char *name, size_t *maxlen);
 
-#define salst(sa,name,maxlen)       sals(name, sa,maxlen)
-#define salstat(sa,fd,name,maxlen)  salsat(fd, name, sa, maxlen)
+#define sa_readlink(sa,name)            sa_readlinkat(sa, AT_FDCWD, name)
+#define sa_readlink0(sa,name)           sa_readlinkat0(sa, AT_FDCWD, name)
+#define sa_realpath(sa,name)            sarealpath(sa, name)
+#define sa_ls(sa,name,maxlen)           sa_lsat(sa, AT_FDCWD, name, maxlen)
 
 #endif /* LIMB_DJBUNIX_H */
diff --git a/src/liblimb/include/limb/unix-transactional.h b/src/liblimb/include/limb/unix-transactional.h
deleted file mode 100644
index d965036..0000000
--- a/src/liblimb/include/limb/unix-transactional.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This file is part of limb                           https://lila.oss/limb
- * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
-/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef LIMB_UNIXTRANSACTIONAL_H
-#define LIMB_UNIXTRANSACTIONAL_H
-
-#include <skalibs/unix-transactional.h>
-#include <limb/posixplz.h>
-#include <limb/siovec.h>
-
-extern int openb_readat(int fd, const char *file);
-extern int openbc_readat(int fd, const char *file);
-
-extern int openc_createat(int fd, const char *file);
-extern int open_createat(int fd, const char *file);
-extern int openc_exclat(int fd, const char *file);
-extern int open_exclat(int fd, const char *file);
-
-#define open_tmpat(fd,tmp)     mkfiletempat(fd, tmp, (createat_fn) (void (*)(void)) open_exclat, 0, NULL)
-
-extern ssize_t open_read_closeat(char *dst, size_t dlen, int bfd, const char *file);
-extern int open_slurp_closeat(stralloc *sa, int bfd, const char *file);
-extern int open_write_closeat(int fd, const char *file, const char *data, size_t dlen);
-extern int open_writev_closeat(int fd, const char *file, const struct iovec *v, unsigned n);
-
-#endif /* LIMB_UNIXTRANSACTIONAL_H */
diff --git a/src/liblimb/readopt.h/readopt.c b/src/liblimb/readopt.h/readopt.c
index 719a1d0..2e81849 100644
--- a/src/liblimb/readopt.h/readopt.c
+++ b/src/liblimb/readopt.h/readopt.c
@@ -3,8 +3,8 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 #include <errno.h>
 #include <limb/bytestr.h>
+#include <limb/djbunix.h>
 #include <limb/readopt.h>
-#include <limb/unix-transactional.h>
 
 ssize_t
 readopt(char *dst, size_t dlen, int bfd, const char *name)
diff --git a/src/liblimb/shldata-rw.h/shldata_read.c b/src/liblimb/shldata-rw.h/shldata_read.c
index ab86ed6..615206e 100644
--- a/src/liblimb/shldata-rw.h/shldata_read.c
+++ b/src/liblimb/shldata-rw.h/shldata_read.c
@@ -6,7 +6,6 @@
 #include <limb/buffer-shldata.h>
 #include <limb/djbunix.h>
 #include <limb/shldata-rw.h>
-#include <limb/unix-transactional.h>
 
 static int
 chkmagic(u32 magic, u32 wmagic)
diff --git a/src/liblimb/shldata-rw.h/shldata_write.c b/src/liblimb/shldata-rw.h/shldata_write.c
index 244b22a..807326d 100644
--- a/src/liblimb/shldata-rw.h/shldata_write.c
+++ b/src/liblimb/shldata-rw.h/shldata_write.c
@@ -7,7 +7,6 @@
 #include <limb/buffer.h>
 #include <limb/buffer-shldata.h>
 #include <limb/djbunix.h>
-#include <limb/unix-transactional.h>
 #include <limb/shldata-rw.h>
 #include <limb/siovec.h>