Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions stdio/perror.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -17,7 +17,16 @@
#include <errno.h>
#include <string.h>


void perror(const char *str)
{
fprintf(stderr, "%s: %s\n", str, strerror(errno));
char errstr[64];

(void)strerror_r(errno, errstr, sizeof(errstr));

if (str != NULL) {
fprintf(stderr, "%s: ", str);
}

fprintf(stderr, "%s\n", errstr);
}
32 changes: 1 addition & 31 deletions string/Makefile
Original file line number Diff line number Diff line change
@@ -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)
227 changes: 174 additions & 53 deletions string/strerror.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -18,60 +18,162 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>


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 <netdb.h>


/* 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;
}


Expand All @@ -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;
}
Expand All @@ -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);
Expand All @@ -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;
}