feat(errno): public errno.h with strerror/strerror_r
This commit is contained in:
+229
@@ -0,0 +1,229 @@
|
|||||||
|
#ifndef VLIBC_ERRNO_H
|
||||||
|
#define VLIBC_ERRNO_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — <errno.h>.
|
||||||
|
*
|
||||||
|
* errno is per-thread state. It lives in a slot of the thread control block
|
||||||
|
* (TCB), addressed relative to the x86_64 FS thread pointer; there is no
|
||||||
|
* process-global errno object and no compiler-managed TLS (`__thread`) here.
|
||||||
|
* The errno macro below expands to a dereference of __errno_location(), the
|
||||||
|
* implementation-reserved accessor that returns the address of the calling
|
||||||
|
* thread's errno slot. The offset of that slot inside the TCB is the ABI
|
||||||
|
* constant VLIBC_TCB_ERRNO_OFF, owned by the internal TCB/ABI headers (see
|
||||||
|
* src/internal/errno.h) — this public header is the single canonical home
|
||||||
|
* for the errno macro, the __errno_location() declaration, and the E*
|
||||||
|
* constant table, so internal code includes it instead of keeping a copy.
|
||||||
|
*
|
||||||
|
* Levels are cumulative (see include/vlibc/features.h):
|
||||||
|
* Level 1 (onlyposix): POSIX base — strerror.
|
||||||
|
* Level 2 (muslmimic): XSI — strerror_r (the int-returning flavor; the
|
||||||
|
* GNU char*-returning variant is level 3+ and is
|
||||||
|
* deliberately not provided).
|
||||||
|
*
|
||||||
|
* This header includes <vlibc/features.h> itself, so the gates below always
|
||||||
|
* see the configured VLIBC_LEVEL even when the caller included no vlibc
|
||||||
|
* header first, and <stddef.h> for size_t.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <vlibc/features.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the address of the calling thread's errno slot.
|
||||||
|
*
|
||||||
|
* Requires the thread pointer (FS) to be initialized to a TCB whose first
|
||||||
|
* word is the TCB's own address — the startup todo owns that bootstrap and
|
||||||
|
* sets it before any code that can touch errno runs. This function itself
|
||||||
|
* performs no setup and no other TCB access.
|
||||||
|
*
|
||||||
|
* The name sits in the implementation-reserved namespace deliberately: it is
|
||||||
|
* this libc's private errno accessor, not public API.
|
||||||
|
*/
|
||||||
|
int *
|
||||||
|
__errno_location(void); // NOLINT(bugprone-reserved-identifier)
|
||||||
|
|
||||||
|
/* The conventional errno lvalue; resolves to the caller's TCB slot. */
|
||||||
|
#define errno (*__errno_location())
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error numbers: the Linux errno ABI (asm-generic/errno-base.h plus
|
||||||
|
* asm-generic/errno.h, which is the table x86_64 uses), transcribed as
|
||||||
|
* kernel-ABI facts. These values are fixed and shared with the kernel.
|
||||||
|
* Values 41 and 58 do not exist in the ABI (EWOULDBLOCK and EDEADLOCK are
|
||||||
|
* aliases of EAGAIN and EDEADLK); EHWPOISON is the last defined value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EPERM 1 /* Operation not permitted */
|
||||||
|
#define ENOENT 2 /* No such file or directory */
|
||||||
|
#define ESRCH 3 /* No such process */
|
||||||
|
#define EINTR 4 /* Interrupted system call */
|
||||||
|
#define EIO 5 /* I/O error */
|
||||||
|
#define ENXIO 6 /* No such device or address */
|
||||||
|
#define E2BIG 7 /* Argument list too long */
|
||||||
|
#define ENOEXEC 8 /* Exec format error */
|
||||||
|
#define EBADF 9 /* Bad file descriptor */
|
||||||
|
#define ECHILD 10 /* No child processes */
|
||||||
|
#define EAGAIN 11 /* Try again */
|
||||||
|
#define ENOMEM 12 /* Out of memory */
|
||||||
|
#define EACCES 13 /* Permission denied */
|
||||||
|
#define EFAULT 14 /* Bad address */
|
||||||
|
#define ENOTBLK 15 /* Block device required */
|
||||||
|
#define EBUSY 16 /* Device or resource busy */
|
||||||
|
#define EEXIST 17 /* File exists */
|
||||||
|
#define EXDEV 18 /* Cross-device link */
|
||||||
|
#define ENODEV 19 /* No such device */
|
||||||
|
#define ENOTDIR 20 /* Not a directory */
|
||||||
|
#define EISDIR 21 /* Is a directory */
|
||||||
|
#define EINVAL 22 /* Invalid argument */
|
||||||
|
#define ENFILE 23 /* File table overflow */
|
||||||
|
#define EMFILE 24 /* Too many open files */
|
||||||
|
#define ENOTTY 25 /* Not a typewriter */
|
||||||
|
#define ETXTBSY 26 /* Text file busy */
|
||||||
|
#define EFBIG 27 /* File too large */
|
||||||
|
#define ENOSPC 28 /* No space left on device */
|
||||||
|
#define ESPIPE 29 /* Illegal seek */
|
||||||
|
#define EROFS 30 /* Read-only file system */
|
||||||
|
#define EMLINK 31 /* Too many links */
|
||||||
|
#define EPIPE 32 /* Broken pipe */
|
||||||
|
#define EDOM 33 /* Math argument out of domain of func */
|
||||||
|
#define ERANGE 34 /* Math result not representable */
|
||||||
|
#define EDEADLK 35 /* Resource deadlock would occur */
|
||||||
|
#define ENAMETOOLONG 36 /* File name too long */
|
||||||
|
#define ENOLCK 37 /* No record locks available */
|
||||||
|
#define ENOSYS 38 /* Invalid system call number */
|
||||||
|
#define ENOTEMPTY 39 /* Directory not empty */
|
||||||
|
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||||
|
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||||
|
#define ENOMSG 42 /* No message of desired type */
|
||||||
|
#define EIDRM 43 /* Identifier removed */
|
||||||
|
#define ECHRNG 44 /* Channel number out of range */
|
||||||
|
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||||
|
#define EL3HLT 46 /* Level 3 halted */
|
||||||
|
#define EL3RST 47 /* Level 3 reset */
|
||||||
|
#define ELNRNG 48 /* Link number out of range */
|
||||||
|
#define EUNATCH 49 /* Protocol driver not attached */
|
||||||
|
#define ENOCSI 50 /* No CSI structure available */
|
||||||
|
#define EL2HLT 51 /* Level 2 halted */
|
||||||
|
#define EBADE 52 /* Invalid exchange */
|
||||||
|
#define EBADR 53 /* Invalid request descriptor */
|
||||||
|
#define EXFULL 54 /* Exchange full */
|
||||||
|
#define ENOANO 55 /* No anode */
|
||||||
|
#define EBADRQC 56 /* Invalid request code */
|
||||||
|
#define EBADSLT 57 /* Invalid slot */
|
||||||
|
#define EDEADLOCK EDEADLK /* File locking deadlock error */
|
||||||
|
#define EBFONT 59 /* Bad font file format */
|
||||||
|
#define ENOSTR 60 /* Device not a stream */
|
||||||
|
#define ENODATA 61 /* No data available */
|
||||||
|
#define ETIME 62 /* Timer expired */
|
||||||
|
#define ENOSR 63 /* Out of streams resources */
|
||||||
|
#define ENONET 64 /* Machine is not on the network */
|
||||||
|
#define ENOPKG 65 /* Package not installed */
|
||||||
|
#define EREMOTE 66 /* Object is remote */
|
||||||
|
#define ENOLINK 67 /* Link has been severed */
|
||||||
|
#define EADV 68 /* Advertise error */
|
||||||
|
#define ESRMNT 69 /* Srmount error */
|
||||||
|
#define ECOMM 70 /* Communication error on send */
|
||||||
|
#define EPROTO 71 /* Protocol error */
|
||||||
|
#define EMULTIHOP 72 /* Multihop attempted */
|
||||||
|
#define EDOTDOT 73 /* RFS specific error */
|
||||||
|
#define EBADMSG 74 /* Not a data message */
|
||||||
|
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||||
|
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||||
|
#define EBADFD 77 /* File descriptor in bad state */
|
||||||
|
#define EREMCHG 78 /* Remote address changed */
|
||||||
|
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||||
|
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||||
|
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||||
|
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||||
|
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||||
|
#define EILSEQ 84 /* Illegal byte sequence */
|
||||||
|
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||||
|
#define ESTRPIPE 86 /* Streams pipe error */
|
||||||
|
#define EUSERS 87 /* Too many users */
|
||||||
|
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||||
|
#define EDESTADDRREQ 89 /* Destination address required */
|
||||||
|
#define EMSGSIZE 90 /* Message too long */
|
||||||
|
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||||
|
#define ENOPROTOOPT 92 /* Protocol not available */
|
||||||
|
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||||
|
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||||
|
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||||
|
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||||
|
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||||
|
#define EADDRINUSE 98 /* Address already in use */
|
||||||
|
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||||
|
#define ENETDOWN 100 /* Network is down */
|
||||||
|
#define ENETUNREACH 101 /* Network is unreachable */
|
||||||
|
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||||
|
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||||
|
#define ECONNRESET 104 /* Connection reset by peer */
|
||||||
|
#define ENOBUFS 105 /* No buffer space available */
|
||||||
|
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||||
|
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||||
|
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||||
|
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||||
|
#define ETIMEDOUT 110 /* Connection timed out */
|
||||||
|
#define ECONNREFUSED 111 /* Connection refused */
|
||||||
|
#define EHOSTDOWN 112 /* Host is down */
|
||||||
|
#define EHOSTUNREACH 113 /* No route to host */
|
||||||
|
#define EALREADY 114 /* Operation already in progress */
|
||||||
|
#define EINPROGRESS 115 /* Operation now in progress */
|
||||||
|
#define ESTALE 116 /* Stale file handle */
|
||||||
|
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||||
|
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||||
|
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||||
|
#define EISNAM 120 /* Is a named type file */
|
||||||
|
#define EREMOTEIO 121 /* Remote I/O error */
|
||||||
|
#define EDQUOT 122 /* Quota exceeded */
|
||||||
|
#define ENOMEDIUM 123 /* No medium found */
|
||||||
|
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||||
|
#define ECANCELED 125 /* Operation canceled */
|
||||||
|
#define ENOKEY 126 /* Required key not available */
|
||||||
|
#define EKEYEXPIRED 127 /* Key has expired */
|
||||||
|
#define EKEYREVOKED 128 /* Key has been revoked */
|
||||||
|
#define EKEYREJECTED 129 /* Key was rejected by service */
|
||||||
|
#define EOWNERDEAD 130 /* Owner died */
|
||||||
|
#define ENOTRECOVERABLE 131 /* State not recoverable */
|
||||||
|
#define ERFKILL 132 /* Operation not possible due to RF-kill */
|
||||||
|
#define EHWPOISON 133 /* Memory page has hardware error */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a pointer to the message string for errnum. The string for a known
|
||||||
|
* value points to immutable static storage and is safe to keep across calls;
|
||||||
|
* an unknown value yields "Unknown error <errnum>", formatted into shared
|
||||||
|
* static storage whose contents a later call may overwrite (unknown errno
|
||||||
|
* values are a rare diagnostic path; see strerror.c). Never returns NULL.
|
||||||
|
*
|
||||||
|
* No intent attribute: the unknown-value path writes shared storage.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
strerror(int errnum);
|
||||||
|
|
||||||
|
#if VLIBC_LEVEL_GE(2)
|
||||||
|
/* Level 2 (muslmimic): XSI. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XSI strerror_r: copy the message for errnum into buf, truncated to buflen
|
||||||
|
* and always NUL-terminated when buflen > 0, and return 0 — including for
|
||||||
|
* unknown errnum values, whose text is "Unknown error <errnum>". When buflen
|
||||||
|
* is 0 nothing is written and 0 is returned; when buf is NULL and buflen > 0,
|
||||||
|
* EINVAL is returned. The GNU char*-returning variant is deliberately not
|
||||||
|
* provided.
|
||||||
|
*
|
||||||
|
* No intent attribute: it writes memory.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
strerror_r(int errnum, char *buf, size_t buflen);
|
||||||
|
#endif /* VLIBC_LEVEL_GE(2) */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* VLIBC_ERRNO_H */
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — strerror / strerror_r (todo 2).
|
||||||
|
*
|
||||||
|
* strerror maps an errno value to an informative, descriptive message. The
|
||||||
|
* messages are this libc's own standard English texts (they need not match
|
||||||
|
* glibc verbatim). Known values resolve to immutable static string constants;
|
||||||
|
* unknown values resolve to "Unknown error <N>" with <N> formatted in place.
|
||||||
|
*
|
||||||
|
* Thread-safety of the unknown-value path: the formatted string lives in a
|
||||||
|
* single static buffer, so two threads formatting *unknown* errno values
|
||||||
|
* concurrently can observe each other's text. This tradeoff is deliberate at
|
||||||
|
* this stage: unknown errno values are a rare diagnostic path, the library
|
||||||
|
* has no per-thread storage beyond the errno TCB slot yet, and strerror must
|
||||||
|
* not depend on malloc (or any other subsystem). The pointer returned for
|
||||||
|
* known values is unaffected. Once the real TCB layout lands (startup todo),
|
||||||
|
* this can migrate to a per-thread buffer without changing the interface.
|
||||||
|
*
|
||||||
|
* The unknown-value formatter is hand-rolled: strerror is libc base and must
|
||||||
|
* not pull in stdio/string before those exist.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Message table: one entry per defined E* value, indexed directly by the
|
||||||
|
* errno number. Designated initializers keep name/value pairs provably in
|
||||||
|
* sync with <errno.h>; entries for the ABI gaps (41, 58 — values the kernel
|
||||||
|
* never produces) stay NULL and are treated as unknown. EWOULDBLOCK and
|
||||||
|
* EDEADLOCK are aliases of EAGAIN and EDEADLK, so they share those entries.
|
||||||
|
* The array auto-sizes to EHWPOISON + 1 (134) entries.
|
||||||
|
*/
|
||||||
|
static const char *const errmsg[] = {
|
||||||
|
[0] = "Success",
|
||||||
|
[EPERM] = "Operation not permitted",
|
||||||
|
[ENOENT] = "No such file or directory",
|
||||||
|
[ESRCH] = "No such process",
|
||||||
|
[EINTR] = "Interrupted system call",
|
||||||
|
[EIO] = "Input/output error",
|
||||||
|
[ENXIO] = "No such device or address",
|
||||||
|
[E2BIG] = "Argument list too long",
|
||||||
|
[ENOEXEC] = "Exec format error",
|
||||||
|
[EBADF] = "Bad file descriptor",
|
||||||
|
[ECHILD] = "No child processes",
|
||||||
|
[EAGAIN] = "Resource temporarily unavailable",
|
||||||
|
[ENOMEM] = "Cannot allocate memory",
|
||||||
|
[EACCES] = "Permission denied",
|
||||||
|
[EFAULT] = "Bad address",
|
||||||
|
[ENOTBLK] = "Block device required",
|
||||||
|
[EBUSY] = "Device or resource busy",
|
||||||
|
[EEXIST] = "File exists",
|
||||||
|
[EXDEV] = "Invalid cross-device link",
|
||||||
|
[ENODEV] = "No such device",
|
||||||
|
[ENOTDIR] = "Not a directory",
|
||||||
|
[EISDIR] = "Is a directory",
|
||||||
|
[EINVAL] = "Invalid argument",
|
||||||
|
[ENFILE] = "Too many open files in system",
|
||||||
|
[EMFILE] = "Too many open files",
|
||||||
|
[ENOTTY] = "Inappropriate ioctl for device",
|
||||||
|
[ETXTBSY] = "Text file busy",
|
||||||
|
[EFBIG] = "File too large",
|
||||||
|
[ENOSPC] = "No space left on device",
|
||||||
|
[ESPIPE] = "Illegal seek",
|
||||||
|
[EROFS] = "Read-only file system",
|
||||||
|
[EMLINK] = "Too many links",
|
||||||
|
[EPIPE] = "Broken pipe",
|
||||||
|
[EDOM] = "Numerical argument out of domain",
|
||||||
|
[ERANGE] = "Numerical result out of range",
|
||||||
|
[EDEADLK] = "Resource deadlock would occur",
|
||||||
|
[ENAMETOOLONG] = "File name too long",
|
||||||
|
[ENOLCK] = "No locks available",
|
||||||
|
[ENOSYS] = "Function not implemented",
|
||||||
|
[ENOTEMPTY] = "Directory not empty",
|
||||||
|
[ELOOP] = "Too many levels of symbolic links",
|
||||||
|
[ENOMSG] = "No message of desired type",
|
||||||
|
[EIDRM] = "Identifier removed",
|
||||||
|
[ECHRNG] = "Channel number out of range",
|
||||||
|
[EL2NSYNC] = "Level 2 not synchronized",
|
||||||
|
[EL3HLT] = "Level 3 halted",
|
||||||
|
[EL3RST] = "Level 3 reset",
|
||||||
|
[ELNRNG] = "Link number out of range",
|
||||||
|
[EUNATCH] = "Protocol driver not attached",
|
||||||
|
[ENOCSI] = "No CSI structure available",
|
||||||
|
[EL2HLT] = "Level 2 halted",
|
||||||
|
[EBADE] = "Invalid exchange",
|
||||||
|
[EBADR] = "Invalid request descriptor",
|
||||||
|
[EXFULL] = "Exchange full",
|
||||||
|
[ENOANO] = "No anode",
|
||||||
|
[EBADRQC] = "Invalid request code",
|
||||||
|
[EBADSLT] = "Invalid slot",
|
||||||
|
[EBFONT] = "Bad font file format",
|
||||||
|
[ENOSTR] = "Device not a stream",
|
||||||
|
[ENODATA] = "No data available",
|
||||||
|
[ETIME] = "Timer expired",
|
||||||
|
[ENOSR] = "Out of streams resources",
|
||||||
|
[ENONET] = "Machine is not on the network",
|
||||||
|
[ENOPKG] = "Package not installed",
|
||||||
|
[EREMOTE] = "Object is remote",
|
||||||
|
[ENOLINK] = "Link has been severed",
|
||||||
|
[EADV] = "Advertise error",
|
||||||
|
[ESRMNT] = "Srmount error",
|
||||||
|
[ECOMM] = "Communication error on send",
|
||||||
|
[EPROTO] = "Protocol error",
|
||||||
|
[EMULTIHOP] = "Multihop attempted",
|
||||||
|
[EDOTDOT] = "RFS specific error",
|
||||||
|
[EBADMSG] = "Bad message",
|
||||||
|
[EOVERFLOW] = "Value too large for defined data type",
|
||||||
|
[ENOTUNIQ] = "Name not unique on network",
|
||||||
|
[EBADFD] = "File descriptor in bad state",
|
||||||
|
[EREMCHG] = "Remote address changed",
|
||||||
|
[ELIBACC] = "Can not access a needed shared library",
|
||||||
|
[ELIBBAD] = "Accessing a corrupted shared library",
|
||||||
|
[ELIBSCN] = ".lib section in a.out corrupted",
|
||||||
|
[ELIBMAX] = "Attempting to link in too many shared libraries",
|
||||||
|
[ELIBEXEC] = "Cannot exec a shared library directly",
|
||||||
|
[EILSEQ] = "Invalid or incomplete multibyte or wide character",
|
||||||
|
[ERESTART] = "Interrupted system call should be restarted",
|
||||||
|
[ESTRPIPE] = "Streams pipe error",
|
||||||
|
[EUSERS] = "Too many users",
|
||||||
|
[ENOTSOCK] = "Socket operation on non-socket",
|
||||||
|
[EDESTADDRREQ] = "Destination address required",
|
||||||
|
[EMSGSIZE] = "Message too long",
|
||||||
|
[EPROTOTYPE] = "Protocol wrong type for socket",
|
||||||
|
[ENOPROTOOPT] = "Protocol not available",
|
||||||
|
[EPROTONOSUPPORT] = "Protocol not supported",
|
||||||
|
[ESOCKTNOSUPPORT] = "Socket type not supported",
|
||||||
|
[EOPNOTSUPP] = "Operation not supported",
|
||||||
|
[EPFNOSUPPORT] = "Protocol family not supported",
|
||||||
|
[EAFNOSUPPORT] = "Address family not supported by protocol",
|
||||||
|
[EADDRINUSE] = "Address already in use",
|
||||||
|
[EADDRNOTAVAIL] = "Cannot assign requested address",
|
||||||
|
[ENETDOWN] = "Network is down",
|
||||||
|
[ENETUNREACH] = "Network is unreachable",
|
||||||
|
[ENETRESET] = "Network dropped connection on reset",
|
||||||
|
[ECONNABORTED] = "Software caused connection abort",
|
||||||
|
[ECONNRESET] = "Connection reset by peer",
|
||||||
|
[ENOBUFS] = "No buffer space available",
|
||||||
|
[EISCONN] = "Transport endpoint is already connected",
|
||||||
|
[ENOTCONN] = "Transport endpoint is not connected",
|
||||||
|
[ESHUTDOWN] = "Cannot send after transport endpoint shutdown",
|
||||||
|
[ETOOMANYREFS] = "Too many references: cannot splice",
|
||||||
|
[ETIMEDOUT] = "Connection timed out",
|
||||||
|
[ECONNREFUSED] = "Connection refused",
|
||||||
|
[EHOSTDOWN] = "Host is down",
|
||||||
|
[EHOSTUNREACH] = "No route to host",
|
||||||
|
[EALREADY] = "Operation already in progress",
|
||||||
|
[EINPROGRESS] = "Operation now in progress",
|
||||||
|
[ESTALE] = "Stale file handle",
|
||||||
|
[EUCLEAN] = "Structure needs cleaning",
|
||||||
|
[ENOTNAM] = "Not a XENIX named type file",
|
||||||
|
[ENAVAIL] = "No XENIX semaphores available",
|
||||||
|
[EISNAM] = "Is a named type file",
|
||||||
|
[EREMOTEIO] = "Remote I/O error",
|
||||||
|
[EDQUOT] = "Disk quota exceeded",
|
||||||
|
[ENOMEDIUM] = "No medium found",
|
||||||
|
[EMEDIUMTYPE] = "Wrong medium type",
|
||||||
|
[ECANCELED] = "Operation canceled",
|
||||||
|
[ENOKEY] = "Required key not available",
|
||||||
|
[EKEYEXPIRED] = "Key has expired",
|
||||||
|
[EKEYREVOKED] = "Key has been revoked",
|
||||||
|
[EKEYREJECTED] = "Key was rejected by service",
|
||||||
|
[EOWNERDEAD] = "Owner died",
|
||||||
|
[ENOTRECOVERABLE] = "State not recoverable",
|
||||||
|
[ERFKILL] = "Operation not possible due to RF-kill",
|
||||||
|
[EHWPOISON] = "Memory page has hardware error",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The table spans 0..EHWPOISON exactly: the ABI gaps stay NULL entries. */
|
||||||
|
_Static_assert(sizeof errmsg / sizeof errmsg[0] == EHWPOISON + 1,
|
||||||
|
"strerror table must cover every E* value 0..EHWPOISON");
|
||||||
|
|
||||||
|
/* Shared storage for the unknown-value path (see the file-top comment). */
|
||||||
|
static char errbuf[32];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write "Unknown error <errnum>" into dst, truncating to cap bytes and always
|
||||||
|
* NUL-terminating when cap > 0. Hand-rolled so this file needs no stdio.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
format_unknown(int errnum, char *dst, size_t cap)
|
||||||
|
{
|
||||||
|
static const char prefix[] = "Unknown error ";
|
||||||
|
char digits[12]; /* enough for "-2147483648" */
|
||||||
|
size_t ndigits;
|
||||||
|
size_t i;
|
||||||
|
unsigned long mag;
|
||||||
|
|
||||||
|
if (cap == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Absolute value as unsigned long; INT_MIN negates safely in long. */
|
||||||
|
mag = (unsigned long)(errnum < 0 ? -(long)errnum : errnum);
|
||||||
|
|
||||||
|
/* Digits, least significant first. */
|
||||||
|
ndigits = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
digits[ndigits] = (char)('0' + (int)(mag % 10));
|
||||||
|
ndigits++;
|
||||||
|
mag /= 10;
|
||||||
|
} while (mag != 0);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i + 1 < cap && prefix[i] != '\0')
|
||||||
|
{
|
||||||
|
dst[i] = prefix[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i + 1 < cap && errnum < 0)
|
||||||
|
{
|
||||||
|
dst[i] = '-';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while (i + 1 < cap && ndigits > 0)
|
||||||
|
{
|
||||||
|
ndigits--;
|
||||||
|
dst[i] = digits[ndigits];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
dst[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the message for errnum, or NULL when it is unknown (out of table
|
||||||
|
* range or an ABI gap).
|
||||||
|
*/
|
||||||
|
static const char *
|
||||||
|
lookup(int errnum)
|
||||||
|
{
|
||||||
|
if (errnum >= 0 && errnum < (int)(sizeof errmsg / sizeof errmsg[0]))
|
||||||
|
{
|
||||||
|
return errmsg[errnum];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
strerror(int errnum)
|
||||||
|
{
|
||||||
|
const char *msg;
|
||||||
|
|
||||||
|
msg = lookup(errnum);
|
||||||
|
if (msg == NULL)
|
||||||
|
{
|
||||||
|
format_unknown(errnum, errbuf, sizeof errbuf);
|
||||||
|
msg = errbuf;
|
||||||
|
}
|
||||||
|
return (char *)msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if VLIBC_LEVEL_GE(2)
|
||||||
|
/*
|
||||||
|
* XSI strerror_r: copy the message for errnum into buf (truncated to buflen,
|
||||||
|
* always NUL-terminated when buflen > 0) and return 0. Unknown errnum values
|
||||||
|
* produce "Unknown error <errnum>" with the same success return; buf == NULL
|
||||||
|
* with buflen > 0 yields EINVAL; buflen == 0 writes nothing and returns 0.
|
||||||
|
* The GNU char*-returning semantics are deliberately not implemented.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
strerror_r(int errnum, char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
const char *msg;
|
||||||
|
char unknown[32];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (buflen == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (buf == NULL)
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = lookup(errnum);
|
||||||
|
if (msg == NULL)
|
||||||
|
{
|
||||||
|
format_unknown(errnum, unknown, sizeof unknown);
|
||||||
|
msg = unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i + 1 < buflen && msg[i] != '\0')
|
||||||
|
{
|
||||||
|
buf[i] = msg[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* VLIBC_LEVEL_GE(2) */
|
||||||
+10
-158
@@ -8,6 +8,14 @@
|
|||||||
* (TCB), addressed relative to the x86_64 FS thread pointer; there is no
|
* (TCB), addressed relative to the x86_64 FS thread pointer; there is no
|
||||||
* process-global errno object and no compiler-managed TLS (`__thread`) here.
|
* process-global errno object and no compiler-managed TLS (`__thread`) here.
|
||||||
*
|
*
|
||||||
|
* The public <errno.h> is the single canonical home for the errno macro, the
|
||||||
|
* __errno_location() declaration, and the E* constant table (1..133, with
|
||||||
|
* EAGAIN/EWOULDBLOCK and EDEADLK/EDEADLOCK aliases and no values 41/58).
|
||||||
|
* This header includes it instead of keeping a second copy, so the public
|
||||||
|
* and internal views of errno can never drift apart. What stays internal-
|
||||||
|
* only here is the errno TCB-slot offset, an ABI constant the public header
|
||||||
|
* must not expose.
|
||||||
|
*
|
||||||
* The offset of the errno slot inside the TCB is an ABI constant defined
|
* The offset of the errno slot inside the TCB is an ABI constant defined
|
||||||
* below and consumed by the authoritative TCB layout (see the startup todo,
|
* below and consumed by the authoritative TCB layout (see the startup todo,
|
||||||
* which owns the TCB/DTV layout). No other layer may re-derive errno's
|
* which owns the TCB/DTV layout). No other layer may re-derive errno's
|
||||||
@@ -23,163 +31,7 @@
|
|||||||
*/
|
*/
|
||||||
#define VLIBC_TCB_ERRNO_OFF 8
|
#define VLIBC_TCB_ERRNO_OFF 8
|
||||||
|
|
||||||
/*
|
/* errno, __errno_location(), and the E* table live in the public header. */
|
||||||
* Return the address of the calling thread's errno slot.
|
#include <errno.h>
|
||||||
*
|
|
||||||
* Requires the thread pointer (FS) to be initialized to a TCB whose first
|
|
||||||
* word is the TCB's own address — the startup todo owns that bootstrap and
|
|
||||||
* sets it before any code that can touch errno runs. This function itself
|
|
||||||
* performs no setup and no other TCB access.
|
|
||||||
*
|
|
||||||
* The name sits in the implementation-reserved namespace deliberately: it is
|
|
||||||
* this libc's private errno accessor, not public API.
|
|
||||||
*/
|
|
||||||
int *
|
|
||||||
__errno_location(void); // NOLINT(bugprone-reserved-identifier)
|
|
||||||
|
|
||||||
/* The conventional errno lvalue; resolves to the caller's TCB slot. */
|
|
||||||
#define errno (*__errno_location())
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Error numbers: the Linux errno ABI (asm-generic/errno-base.h plus
|
|
||||||
* asm-generic/errno.h, which is the table x86_64 uses), transcribed as
|
|
||||||
* kernel-ABI facts. These values are fixed and shared with the kernel. The
|
|
||||||
* public <errno.h> is owned by a later todo; this internal copy is what
|
|
||||||
* internal code and tests compile against.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EPERM 1 /* Operation not permitted */
|
|
||||||
#define ENOENT 2 /* No such file or directory */
|
|
||||||
#define ESRCH 3 /* No such process */
|
|
||||||
#define EINTR 4 /* Interrupted system call */
|
|
||||||
#define EIO 5 /* I/O error */
|
|
||||||
#define ENXIO 6 /* No such device or address */
|
|
||||||
#define E2BIG 7 /* Argument list too long */
|
|
||||||
#define ENOEXEC 8 /* Exec format error */
|
|
||||||
#define EBADF 9 /* Bad file descriptor */
|
|
||||||
#define ECHILD 10 /* No child processes */
|
|
||||||
#define EAGAIN 11 /* Try again */
|
|
||||||
#define ENOMEM 12 /* Out of memory */
|
|
||||||
#define EACCES 13 /* Permission denied */
|
|
||||||
#define EFAULT 14 /* Bad address */
|
|
||||||
#define ENOTBLK 15 /* Block device required */
|
|
||||||
#define EBUSY 16 /* Device or resource busy */
|
|
||||||
#define EEXIST 17 /* File exists */
|
|
||||||
#define EXDEV 18 /* Cross-device link */
|
|
||||||
#define ENODEV 19 /* No such device */
|
|
||||||
#define ENOTDIR 20 /* Not a directory */
|
|
||||||
#define EISDIR 21 /* Is a directory */
|
|
||||||
#define EINVAL 22 /* Invalid argument */
|
|
||||||
#define ENFILE 23 /* File table overflow */
|
|
||||||
#define EMFILE 24 /* Too many open files */
|
|
||||||
#define ENOTTY 25 /* Not a typewriter */
|
|
||||||
#define ETXTBSY 26 /* Text file busy */
|
|
||||||
#define EFBIG 27 /* File too large */
|
|
||||||
#define ENOSPC 28 /* No space left on device */
|
|
||||||
#define ESPIPE 29 /* Illegal seek */
|
|
||||||
#define EROFS 30 /* Read-only file system */
|
|
||||||
#define EMLINK 31 /* Too many links */
|
|
||||||
#define EPIPE 32 /* Broken pipe */
|
|
||||||
#define EDOM 33 /* Math argument out of domain of func */
|
|
||||||
#define ERANGE 34 /* Math result not representable */
|
|
||||||
#define EDEADLK 35 /* Resource deadlock would occur */
|
|
||||||
#define ENAMETOOLONG 36 /* File name too long */
|
|
||||||
#define ENOLCK 37 /* No record locks available */
|
|
||||||
#define ENOSYS 38 /* Invalid system call number */
|
|
||||||
#define ENOTEMPTY 39 /* Directory not empty */
|
|
||||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
|
||||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
|
||||||
#define ENOMSG 42 /* No message of desired type */
|
|
||||||
#define EIDRM 43 /* Identifier removed */
|
|
||||||
#define ECHRNG 44 /* Channel number out of range */
|
|
||||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
|
||||||
#define EL3HLT 46 /* Level 3 halted */
|
|
||||||
#define EL3RST 47 /* Level 3 reset */
|
|
||||||
#define ELNRNG 48 /* Link number out of range */
|
|
||||||
#define EUNATCH 49 /* Protocol driver not attached */
|
|
||||||
#define ENOCSI 50 /* No CSI structure available */
|
|
||||||
#define EL2HLT 51 /* Level 2 halted */
|
|
||||||
#define EBADE 52 /* Invalid exchange */
|
|
||||||
#define EBADR 53 /* Invalid request descriptor */
|
|
||||||
#define EXFULL 54 /* Exchange full */
|
|
||||||
#define ENOANO 55 /* No anode */
|
|
||||||
#define EBADRQC 56 /* Invalid request code */
|
|
||||||
#define EBADSLT 57 /* Invalid slot */
|
|
||||||
#define EDEADLOCK EDEADLK /* File locking deadlock error */
|
|
||||||
#define EBFONT 59 /* Bad font file format */
|
|
||||||
#define ENOSTR 60 /* Device not a stream */
|
|
||||||
#define ENODATA 61 /* No data available */
|
|
||||||
#define ETIME 62 /* Timer expired */
|
|
||||||
#define ENOSR 63 /* Out of streams resources */
|
|
||||||
#define ENONET 64 /* Machine is not on the network */
|
|
||||||
#define ENOPKG 65 /* Package not installed */
|
|
||||||
#define EREMOTE 66 /* Object is remote */
|
|
||||||
#define ENOLINK 67 /* Link has been severed */
|
|
||||||
#define EADV 68 /* Advertise error */
|
|
||||||
#define ESRMNT 69 /* Srmount error */
|
|
||||||
#define ECOMM 70 /* Communication error on send */
|
|
||||||
#define EPROTO 71 /* Protocol error */
|
|
||||||
#define EMULTIHOP 72 /* Multihop attempted */
|
|
||||||
#define EDOTDOT 73 /* RFS specific error */
|
|
||||||
#define EBADMSG 74 /* Not a data message */
|
|
||||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
|
||||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
|
||||||
#define EBADFD 77 /* File descriptor in bad state */
|
|
||||||
#define EREMCHG 78 /* Remote address changed */
|
|
||||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
|
||||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
|
||||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
|
||||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
|
||||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
|
||||||
#define EILSEQ 84 /* Illegal byte sequence */
|
|
||||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
|
||||||
#define ESTRPIPE 86 /* Streams pipe error */
|
|
||||||
#define EUSERS 87 /* Too many users */
|
|
||||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
|
||||||
#define EDESTADDRREQ 89 /* Destination address required */
|
|
||||||
#define EMSGSIZE 90 /* Message too long */
|
|
||||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
|
||||||
#define ENOPROTOOPT 92 /* Protocol not available */
|
|
||||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
|
||||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
|
||||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
|
||||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
|
||||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
|
||||||
#define EADDRINUSE 98 /* Address already in use */
|
|
||||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
|
||||||
#define ENETDOWN 100 /* Network is down */
|
|
||||||
#define ENETUNREACH 101 /* Network is unreachable */
|
|
||||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
|
||||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
|
||||||
#define ECONNRESET 104 /* Connection reset by peer */
|
|
||||||
#define ENOBUFS 105 /* No buffer space available */
|
|
||||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
|
||||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
|
||||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
|
||||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
|
||||||
#define ETIMEDOUT 110 /* Connection timed out */
|
|
||||||
#define ECONNREFUSED 111 /* Connection refused */
|
|
||||||
#define EHOSTDOWN 112 /* Host is down */
|
|
||||||
#define EHOSTUNREACH 113 /* No route to host */
|
|
||||||
#define EALREADY 114 /* Operation already in progress */
|
|
||||||
#define EINPROGRESS 115 /* Operation now in progress */
|
|
||||||
#define ESTALE 116 /* Stale file handle */
|
|
||||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
|
||||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
|
||||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
|
||||||
#define EISNAM 120 /* Is a named type file */
|
|
||||||
#define EREMOTEIO 121 /* Remote I/O error */
|
|
||||||
#define EDQUOT 122 /* Quota exceeded */
|
|
||||||
#define ENOMEDIUM 123 /* No medium found */
|
|
||||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
|
||||||
#define ECANCELED 125 /* Operation canceled */
|
|
||||||
#define ENOKEY 126 /* Required key not available */
|
|
||||||
#define EKEYEXPIRED 127 /* Key has expired */
|
|
||||||
#define EKEYREVOKED 128 /* Key has been revoked */
|
|
||||||
#define EKEYREJECTED 129 /* Key was rejected by service */
|
|
||||||
#define EOWNERDEAD 130 /* Owner died */
|
|
||||||
#define ENOTRECOVERABLE 131 /* State not recoverable */
|
|
||||||
#define ERFKILL 132 /* Operation not possible due to RF-kill */
|
|
||||||
#define EHWPOISON 133 /* Memory page has hardware error */
|
|
||||||
|
|
||||||
#endif /* VLIBC_INTERNAL_ERRNO_H */
|
#endif /* VLIBC_INTERNAL_ERRNO_H */
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* vlibc — strerror/strerror_r test (todo 2).
|
||||||
|
*
|
||||||
|
* Exercises the public <errno.h> end to end:
|
||||||
|
*
|
||||||
|
* 1. strerror(0) is "Success"; known values return the exact message and
|
||||||
|
* are non-NULL and distinct; aliases (EWOULDBLOCK/EDEADLOCK) resolve to
|
||||||
|
* their canonical entries; the last table value (EHWPOISON) is covered.
|
||||||
|
* 2. Unknown errno values never return NULL and never crash: 9999 and the
|
||||||
|
* ABI-gap value 41 format as "Unknown error <N>", negatives too.
|
||||||
|
* 3. strerror_r (XSI): returns 0 and fills buf with the right text; an
|
||||||
|
* unknown value still returns 0 with "Unknown error <N>"; truncation
|
||||||
|
* into a tiny buf stays NUL-terminated; buflen 0 writes nothing; a NULL
|
||||||
|
* buf with buflen > 0 returns EINVAL.
|
||||||
|
*
|
||||||
|
* The test deliberately never touches errno itself: under the host libc the
|
||||||
|
* TCB slot our errno macro addresses is glibc's private TLS state, and
|
||||||
|
* writing it would corrupt the host (see tests/syscall_test.c). All coverage
|
||||||
|
* here is through the errnum parameters.
|
||||||
|
*
|
||||||
|
* Not part of the library proper; compiled manually for this todo (the
|
||||||
|
* tests/ + make check wiring is owned by a later todo).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int failures;
|
||||||
|
|
||||||
|
static void
|
||||||
|
check(int cond, const char *what)
|
||||||
|
{
|
||||||
|
if (!cond)
|
||||||
|
{
|
||||||
|
printf("FAIL: %s\n", what);
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Failure scenario (-f): an unknown errno must yield "Unknown error 9999",
|
||||||
|
* non-NULL, without crashing. Prints the observed string; exits 0 only when
|
||||||
|
* the failure behaved exactly as specified.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
failure_scenario(void)
|
||||||
|
{
|
||||||
|
const char *s = strerror(9999);
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
{
|
||||||
|
printf("strerror(9999)=NULL\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("strerror(9999)=%s\n", s);
|
||||||
|
return strcmp(s, "Unknown error 9999") == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *a;
|
||||||
|
const char *b;
|
||||||
|
char buf[64];
|
||||||
|
char tiny[8];
|
||||||
|
char untouched[4];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'f')
|
||||||
|
{
|
||||||
|
return failure_scenario();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1. Known values: exact text, non-NULL, distinct. */
|
||||||
|
check(strcmp(strerror(0), "Success") == 0, "strerror(0) == \"Success\"");
|
||||||
|
check(strcmp(strerror(2), "No such file or directory") == 0,
|
||||||
|
"strerror(2) == \"No such file or directory\"");
|
||||||
|
check(strcmp(strerror(EINVAL), "Invalid argument") == 0,
|
||||||
|
"strerror(EINVAL) == \"Invalid argument\"");
|
||||||
|
check(strcmp(strerror(EPERM), "Operation not permitted") == 0,
|
||||||
|
"strerror(EPERM) == \"Operation not permitted\"");
|
||||||
|
|
||||||
|
a = strerror(EINVAL);
|
||||||
|
b = strerror(EPERM);
|
||||||
|
check(a != NULL && b != NULL, "known values non-NULL");
|
||||||
|
check(a != b, "known values distinct");
|
||||||
|
|
||||||
|
/* Aliases resolve to their canonical entries. */
|
||||||
|
check(strerror(EWOULDBLOCK) == strerror(EAGAIN), "EWOULDBLOCK == EAGAIN");
|
||||||
|
check(strerror(EDEADLOCK) == strerror(EDEADLK), "EDEADLOCK == EDEADLK");
|
||||||
|
|
||||||
|
/* Table ends: last defined value and ABI gap values. */
|
||||||
|
check(strerror(EHWPOISON) != NULL, "EHWPOISON (last value) non-NULL");
|
||||||
|
check(strcmp(strerror(41), "Unknown error 41") == 0, "ABI gap 41 unknown");
|
||||||
|
check(strcmp(strerror(58), "Unknown error 58") == 0, "ABI gap 58 unknown");
|
||||||
|
|
||||||
|
/* 2. Unknown values: never NULL, never crash, formatted. */
|
||||||
|
a = strerror(9999);
|
||||||
|
check(a != NULL, "strerror(9999) non-NULL");
|
||||||
|
check(strcmp(a, "Unknown error 9999") == 0, "strerror(9999) text");
|
||||||
|
|
||||||
|
a = strerror(-7);
|
||||||
|
check(a != NULL, "strerror(-7) non-NULL");
|
||||||
|
check(strcmp(a, "Unknown error -7") == 0, "strerror(-7) text");
|
||||||
|
|
||||||
|
/* 3. strerror_r: XSI int return, exact fill. */
|
||||||
|
r = strerror_r(EDOM, buf, sizeof buf);
|
||||||
|
check(r == 0, "strerror_r(EDOM) returns 0");
|
||||||
|
check(strcmp(buf, "Numerical argument out of domain") == 0, "strerror_r(EDOM) fills buf");
|
||||||
|
|
||||||
|
/* Unknown errno still succeeds and formats into buf (XSI). */
|
||||||
|
r = strerror_r(9999, buf, sizeof buf);
|
||||||
|
check(r == 0, "strerror_r(9999) returns 0 (XSI)");
|
||||||
|
check(strcmp(buf, "Unknown error 9999") == 0, "strerror_r(9999) text");
|
||||||
|
|
||||||
|
/* Truncation into a tiny buf stays NUL-terminated. */
|
||||||
|
r = strerror_r(ENAMETOOLONG, tiny, sizeof tiny);
|
||||||
|
check(r == 0, "strerror_r(ENAMETOOLONG, tiny) returns 0");
|
||||||
|
check(tiny[sizeof tiny - 1] == '\0', "tiny buf NUL-terminated");
|
||||||
|
check(strcmp(tiny, "File na") == 0, "tiny buf truncated prefix");
|
||||||
|
|
||||||
|
/* buflen 0: nothing written, still success. */
|
||||||
|
untouched[0] = 'X';
|
||||||
|
untouched[1] = 'X';
|
||||||
|
untouched[2] = 'X';
|
||||||
|
untouched[3] = '\0';
|
||||||
|
r = strerror_r(EDOM, untouched, 0);
|
||||||
|
check(r == 0, "strerror_r(EDOM, buf, 0) returns 0");
|
||||||
|
check(untouched[0] == 'X', "buflen 0 writes nothing");
|
||||||
|
|
||||||
|
/* NULL buf with buflen > 0: EINVAL. */
|
||||||
|
r = strerror_r(EDOM, NULL, 16);
|
||||||
|
check(r == EINVAL, "strerror_r(NULL buf) returns EINVAL");
|
||||||
|
|
||||||
|
if (failures > 0)
|
||||||
|
{
|
||||||
|
printf("FAILED\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("strerror ok\n");
|
||||||
|
}
|
||||||
|
return failures == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user