std/os/errno: add missing module (was untracked in prior aproc commit)

ober

8c39c3f3c9ea75fb14bb0a3c378ef33c0558199e

diff --git a/lib/std/os/errno.sls b/lib/std/os/errno.sls
new file mode 100644
index 0000000..9c5b3e4
--- /dev/null
+++ b/lib/std/os/errno.sls
@@ -0,0 +1,162 @@
+#!chezscheme
+;;; (std os errno) -- Cross-platform errno access and POSIX error constants
+;;;
+;;; Thin module so callers (aproc, debug-repl, future syscall wrappers)
+;;; can read errno and check well-known values without pulling in the
+;;; rest of (std os posix). Tries the three known C-side symbols:
+;;;
+;;;   macOS / *BSD:   __error      (thread-local errno pointer)
+;;;   Linux glibc:    __errno_location
+;;;   Bionic / musl:  __errno
+;;;
+;;; Use:
+;;;   (errno)            => current errno (int)
+;;;   (errno-strerror n) => string for errno N
+;;;   (errno-name n)     => 'EINTR / 'ECHILD / ... or 'UNKNOWN
+;;;   E* constants exported by name (EINTR EAGAIN EWOULDBLOCK ECHILD EINVAL EPIPE
+;;;                                   ESRCH EPERM EBADF ENOENT EACCES EEXIST EIO
+;;;                                   ETIMEDOUT EBUSY ENOMEM EFAULT ENOTDIR)
+;;;
+;;; Numeric values differ between Linux and the BSDs; the constants are
+;;; resolved at load time based on (machine-type).
+
+(library (std os errno)
+  (export
+    errno
+    errno-strerror
+    errno-name
+    errno-supported?
+
+    EINTR EAGAIN EWOULDBLOCK ECHILD EINVAL EPIPE
+    ESRCH EPERM EBADF ENOENT EACCES EEXIST EIO
+    ETIMEDOUT EBUSY ENOMEM EFAULT ENOTDIR ENOSYS
+    EMFILE ENFILE ENOEXEC E2BIG)
+
+  (import (chezscheme))
+
+  ;; Try to make libc symbols visible. (load-shared-object #f) maps the
+  ;; running image, which works for static binaries; the platform fallbacks
+  ;; handle dynamic builds where libc isn't already in the image.
+  (define _libc-loaded
+    (or (guard (e [#t #f]) (load-shared-object #f))
+        (guard (e [#t #f]) (load-shared-object "libc.so.7"))
+        (guard (e [#t #f]) (load-shared-object "libc.so.6"))
+        (guard (e [#t #f]) (load-shared-object "libc.so"))
+        (guard (e [#t #f]) (load-shared-object "/usr/lib/libSystem.B.dylib"))
+        (guard (e [#t #f]) (load-shared-object "libSystem.dylib"))
+        (guard (e [#t #f]) (load-shared-object "libc.dylib"))))
+
+  ;; ========== Platform detection ==========
+  (define machine-type-str (symbol->string (machine-type)))
+
+  (define (ends-with? s suf)
+    (let ((sl (string-length s)) (fl (string-length suf)))
+      (and (>= sl fl)
+           (string=? (substring s (- sl fl) sl) suf))))
+
+  (define *freebsd?* (memq (machine-type) '(a6fb ta6fb i3fb ti3fb arm64fb)))
+  (define *openbsd?* (memq (machine-type) '(a6ob ta6ob arm64ob)))
+  (define *netbsd?*  (memq (machine-type) '(a6nb ta6nb arm64nb)))
+  (define *macos?*   (ends-with? machine-type-str "osx"))
+  (define *bsd-family?* (or *freebsd?* *openbsd?* *netbsd?* *macos?*))
+
+  ;; ========== errno location ==========
+  ;; Returns a thunk that yields a void* pointer to the current thread's
+  ;; errno cell — or #f if no known symbol resolved.
+  (define c-errno-location
+    (let try ((names (if *bsd-family?*
+                       '("__error" "__errno_location" "__errno")
+                       '("__errno_location" "__errno" "__error"))))
+      (cond
+        ((null? names) #f)
+        (else
+         (or (guard (e [#t #f])
+               (foreign-procedure (car names) () void*))
+             (try (cdr names)))))))
+
+  (define (errno-supported?)
+    (and c-errno-location #t))
+
+  (define (errno)
+    (if c-errno-location
+      (foreign-ref 'int (c-errno-location) 0)
+      0))
+
+  ;; ========== strerror ==========
+  (define c-strerror
+    (foreign-procedure "strerror" (int) string))
+
+  (define (errno-strerror n)
+    (or (guard (e [#t #f]) (c-strerror n))
+        (string-append "errno=" (number->string n))))
+
+  ;; ========== Errno constants ==========
+  ;; Most are stable across platforms; the divergent ones (EAGAIN/EWOULDBLOCK
+  ;; on BSDs vs Linux, EDEADLK numbering, etc.) get a platform branch.
+  (define EPERM    1)
+  (define ENOENT   2)
+  (define ESRCH    3)
+  (define EINTR    4)
+  (define EIO      5)
+  (define E2BIG    7)
+  (define ENOEXEC  8)
+  (define EBADF    9)
+  (define ECHILD  10)
+  (define EACCES  13)
+  (define EFAULT  14)
+  (define EBUSY   16)
+  (define EEXIST  17)
+  (define ENOTDIR 20)
+  (define EINVAL  22)
+  (define ENFILE  23)
+  (define EMFILE  24)
+  (define ENOMEM (if *bsd-family?* 12 12))
+  ;; EPIPE = 32 on Linux/glibc and the BSDs alike.
+  (define EPIPE   32)
+
+  ;; EAGAIN/EWOULDBLOCK
+  ;;   Linux:   EAGAIN = EWOULDBLOCK = 11
+  ;;   *BSD:    EAGAIN = EWOULDBLOCK = 35
+  (define EAGAIN     (if *bsd-family?* 35 11))
+  (define EWOULDBLOCK EAGAIN)
+
+  ;; ETIMEDOUT
+  ;;   Linux:  110
+  ;;   FreeBSD: 60   macOS: 60   OpenBSD: 60
+  (define ETIMEDOUT (if *bsd-family?* 60 110))
+
+  ;; ENOSYS
+  ;;   Linux:  38
+  ;;   FreeBSD: 78  macOS: 78
+  (define ENOSYS    (if *bsd-family?* 78 38))
+
+  ;; ========== Name lookup ==========
+  ;; Reverse map: errno value -> symbol. Returns 'UNKNOWN for codes we
+  ;; haven't enumerated. Used by error messages, not by hot paths.
+  (define (errno-name n)
+    (cond
+      ((= n EPERM)        'EPERM)
+      ((= n ENOENT)       'ENOENT)
+      ((= n ESRCH)        'ESRCH)
+      ((= n EINTR)        'EINTR)
+      ((= n EIO)          'EIO)
+      ((= n E2BIG)        'E2BIG)
+      ((= n ENOEXEC)      'ENOEXEC)
+      ((= n EBADF)        'EBADF)
+      ((= n ECHILD)       'ECHILD)
+      ((= n EAGAIN)       'EAGAIN)
+      ((= n EACCES)       'EACCES)
+      ((= n EFAULT)       'EFAULT)
+      ((= n EBUSY)        'EBUSY)
+      ((= n EEXIST)       'EEXIST)
+      ((= n ENOTDIR)      'ENOTDIR)
+      ((= n EINVAL)       'EINVAL)
+      ((= n ENFILE)       'ENFILE)
+      ((= n EMFILE)       'EMFILE)
+      ((= n ENOMEM)       'ENOMEM)
+      ((= n EPIPE)        'EPIPE)
+      ((= n ETIMEDOUT)    'ETIMEDOUT)
+      ((= n ENOSYS)       'ENOSYS)
+      (else               'UNKNOWN)))
+
+) ;; end library