diff --git a/stdio/perror.c b/stdio/perror.c index 4f842ccd..69ae5100 100644 --- a/stdio/perror.c +++ b/stdio/perror.c @@ -5,7 +5,7 @@ * * perror.c * - * Copyright 2022 Phoenix Systems + * Copyright 2022, 2023 Phoenix Systems * Author: Aleksander Kaminski * * This file is part of Phoenix-RTOS. @@ -17,7 +17,12 @@ #include #include + void perror(const char *str) { - fprintf(stderr, "%s: %s\n", str, strerror(errno)); + char errstr[64]; + + (void)strerror_r(errno, errstr, sizeof(errstr)); + + fprintf(stderr, "%s: %s\n", str, errstr); } diff --git a/string/Makefile b/string/Makefile index 343a5a52..e68bf73e 100644 --- a/string/Makefile +++ b/string/Makefile @@ -1,38 +1,8 @@ # # Makefile for libphoenix/string # -# Copyright 2017, 2020 Phoenix Systems +# Copyright 2017, 2020, 2023 Phoenix Systems # Author: Pawel Pisarczyk # -INCS := errno.str.inc errno.tab.inc gaierr.str.inc gaierr.tab.inc - - -ERR_EXTRACT := $(SED) -En -e '/^\s*\#\s*define\s+E\w+\s+[[:digit:]]+/{s/^[^d]*define\s+(\w+)\s+([[:digit:]]+).*/\2\t\1/;p;d}' \ - -e '/^\s*E\w+\s*=\s*-?[[:digit:]]+/{s/^\s*(\w+)\s*=\s*-?([[:digit:]]+).*/\2\t\1/;p;d}' - - -%/errno.list: $(SYSROOT)/usr/include/phoenix/errno.h include/errno.h - @(printf "GEN %-24s \n" "$(@F)") - $(SIL)$(ERR_EXTRACT) $^ | sort -n > $@ - - -%/gaierr.list: include/netdb.h Makefile - @(printf "GEN %-24s \n" "$(@F)") - $(SIL)$(ERR_EXTRACT) $^ | sort -n > $@ - - -%.str.inc: %.list Makefile - @(printf "GEN %-24s \n" "$(@F)") - $(SIL)$(SED) -e 's/^.*\t\(.*\)$$/"\1\\0"/' $< > $@ - - -%.tab.inc: %.list Makefile - @(printf "GEN %-24s \n" "$(@F)") - $(SIL)bash -c 'o=0; while read num name; do echo "{ $$num, $$o },"; o=$$((o+$${#name}+1)); done' < $< > $@ - - -$(PREFIX_O)string/strerror.o: $(patsubst %,string/%,$(INCS)) - - OBJS += $(addprefix $(PREFIX_O)string/, string.o strdup.o strerror.o strsignal.o) diff --git a/string/strerror.c b/string/strerror.c index be719142..30e89771 100644 --- a/string/strerror.c +++ b/string/strerror.c @@ -5,7 +5,7 @@ * * string/strerror (errno names) * - * Copyright 2018 Phoenix Systems + * Copyright 2018, 2023 Phoenix Systems * Author: Michal Miroslaw, Aleksander Kaminski * * This file is part of Phoenix-RTOS. @@ -18,60 +18,162 @@ #include #include #include - - -typedef struct { - uint16_t errnum; - uint16_t offset; -} errinfo_t; - - -static const char errnames[] = { - #include "errno.str.inc" -}; - -static const errinfo_t errtab[] = { - #include "errno.tab.inc" +#include + + +/* clang-format off */ +static const char *__errmsgtab[] = { + /* EOK */ "Operation succeeded", + /* EPERM */ "Operation not permitted", + /* ENOENT */ "No such file or directory", + /* ESRCH */ "No such process", + /* EINTR */ "Interrupted system call", + /* EIO */ "I/O error", + /* ENXIO */ "No such device or address", + /* E2BIG */ "Argument list too long", + /* ENOEXEC */ "Executable format error", + /* EBADF */ "Bad file number", + /* ECHILD */ "No child processes", + /* EAGAIN */ "Try again", + /* ENOMEM */ "Out of memory", + /* EACCES */ "Permission denied", + /* EFAULT */ "Bad address", + /* ENOTBLK */ "Block device required", + /* EBUSY */ "Device or resource busy", + /* EEXIST */ "File exists", + /* EXDEV */ "Cross-device link", + /* ENODEV */ "No such device", + /* ENOTDIR */ "Not a directory", + /* EISDIR */ "Is a directory", + /* EINVAL */ "Invalid argument", + /* ENFILE */ "File table overflow", + /* EMFILE */ "Too many open files", + /* ENOTTY */ "Not a typewriter", + /* 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 */ "Argument out of domain", + /* ERANGE */ "Result not representable", + /* ENOSYS */ "Function not implemented", + /* ENAMETOOLONG */ "Name too long", + /* ETIME */ "Timer expired", + /* EDEADLK */ "Resource deadlock avoided", + /* ENOTEMPTY */ "Directory not empty", + /* ELOOP */ "Too many levels of symbolic links", + NULL, + /* ENOMSG */ "No message of the desired type", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + /* EUNATCH */ "Protocol driver not attached", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + /* ENODATA */ "No message is available on the STREAM head read queue", + NULL, + NULL, + /* ENONET */ "Machine is not on the network.", + NULL, + /* EBADFD */ "File descriptor in bad state", + NULL, + NULL, + NULL, + NULL, + /* EPROTO */ "Protocol error", + NULL, + NULL, + /* EBADMSG */ "Bad message", + /* EOVERFLOW */ "Value too large to be stored in data type", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + /* EILSEQ */ "Invalid or incomplete multibyte or wide character", + NULL, + NULL, + NULL, + /* ENOTSOCK */ "Not a socket", + /* EDESTADDRREQ */ "Destination address required", + /* EMSGSIZE */ "Message too long", + /* EPROTOTYPE */ "Protocol wrong type for socket", + /* ENOPROTOOPT */ "Protocol not available", + /* EPROTONOSUPPORT */ "Protocol not supported", + NULL, + /* EOPNOTSUPP */ "Operation not supported on socket", + /* EPFNOSUPPORT */ "Protocol family not supported", + /* EAFNOSUPPORT */ "Address family not supported", + /* EADDRINUSE */ "Address already in use", + /* EADDRNOTAVAIL */ "Address not available", + /* ENETDOWN */ "Network is down", + /* ENETUNREACH */ "Network unreachable", + /* ENETRESET */ "Connection aborted by network", + /* ECONNABORTED */ "Connection aborted", + /* ECONNRESET */ "Connection reset", + /* ENOBUFS */ "No buffer space available", + /* EISCONN */ "Socket is connected", + /* ENOTCONN */ "The socket is not connected", + NULL, + NULL, + /* ETIMEDOUT */ "Connection timed out", + /* ECONNREFUSED */ "Connection refused", + /* EHOSTDOWN */ "Host is down", + /* EHOSTUNREACH */ "Host is unreachable", + /* EALREADY */ "Connection already in progress", + /* EINPROGRESS */ "Operation in progress", + /* ENOLCK */ "No locks available", + /* EUCLEAN */ "Structure needs cleaning", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + /* ENOTRECOVERABLE */ "State not recoverable" }; - -static const char gainames[] = { - #include "gaierr.str.inc" -}; - -static const errinfo_t gaitab[] = { - #include "gaierr.tab.inc" -}; - -// static assert: 16-bit offset -static const char assert_errnames_size[-(sizeof(errnames) > 0xFFFF)] __attribute__((unused)); -static const char assert_gainames_size[-(sizeof(gainames) > 0xFFFF)] __attribute__((unused)); +/* clang-format on */ -static int err_cmp(const void *key, const void *elem) +static inline const char *strerror_(int errnum, char *buff, size_t bufflen, int *err) { - const errinfo_t *p = elem; - long err = (long)key; + const char *str = NULL; - return err - (long)p->errnum; -} - - -static inline const char *strerror_(const errinfo_t *tab, size_t tabsz, const char *names, int errnum, char *buff, size_t bufflen, int *err) -{ - const errinfo_t *e; - - if (errnum < 0) { - errnum = -errnum; + if ((errnum >= 0) && (errnum < (int)(sizeof(__errmsgtab) / sizeof(*__errmsgtab)))) { + str = __errmsgtab[errnum]; } - e = bsearch((void *)(long)errnum, tab, tabsz / sizeof(*tab), sizeof(*tab), err_cmp); - if (e == NULL) { + if (str == NULL) { (void)snprintf(buff, bufflen, "Unknown error %d", errnum); *err = EINVAL; - return buff; + str = buff; } - return names + e->offset; + return str; } @@ -81,7 +183,7 @@ char *strerror(int errnum) const char *str; int err = 0; - str = strerror_(errtab, sizeof(errtab), errnames, errnum, unknownMsg, sizeof(unknownMsg), &err); + str = strerror_(errnum, unknownMsg, sizeof(unknownMsg), &err); if (err != 0) { errno = err; } @@ -97,7 +199,7 @@ int strerror_r(int errnum, char *buf, size_t buflen) int ret = 0; size_t len; - str = strerror_(errtab, sizeof(errtab), errnames, errnum, unknownMsg, sizeof(unknownMsg), &ret); + str = strerror_(errnum, unknownMsg, sizeof(unknownMsg), &ret); len = strlen(str); if (buflen > len) { memcpy(buf, str, len + 1); @@ -113,13 +215,32 @@ int strerror_r(int errnum, char *buf, size_t buflen) const char *gai_strerror(int errnum) { static char unknownMsg[32]; - const char *str; - int err = 0; - str = strerror_(gaitab, sizeof(gaitab), gainames, errnum, unknownMsg, sizeof(unknownMsg), &err); - if (err != 0) { - errno = err; + switch (errnum) { + case EAI_AGAIN: + return "Name could not be resolved at this time"; + case EAI_BADFLAGS: + return "Flags parameter had an invalid value"; + case EAI_FAIL: + return "Non-recoverable failure in name resolution"; + case EAI_FAMILY: + return "Address family was not recognized"; + case EAI_MEMORY: + return "Memory allocation failure"; + case EAI_NODATA: + return "No address associated with hostname"; + case EAI_NONAME: + return "Name does not resolve"; + case EAI_OVERFLOW: + return "Argument buffer overflow"; + case EAI_SERVICE: + return "Service was not recognized for socket type"; + case EAI_SOCKTYPE: + return "Intended socket type was not recognized"; + case EAI_SYSTEM: + return "System error returned in errno"; + default: + (void)snprintf(unknownMsg, sizeof(unknownMsg), "Unknown error %d", errnum); + return unknownMsg; } - - return (char *)str; }