Skip to content

Commit 4dd2ecd

Browse files
committed
strerror, strerror_r, gai_strerror, perror: Add full implementation
DONE: RTOS-569
1 parent d1a034b commit 4dd2ecd

File tree

3 files changed

+182
-86
lines changed

3 files changed

+182
-86
lines changed

stdio/perror.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* perror.c
77
*
8-
* Copyright 2022 Phoenix Systems
8+
* Copyright 2022, 2023 Phoenix Systems
99
* Author: Aleksander Kaminski
1010
*
1111
* This file is part of Phoenix-RTOS.
@@ -17,7 +17,12 @@
1717
#include <errno.h>
1818
#include <string.h>
1919

20+
2021
void perror(const char *str)
2122
{
22-
fprintf(stderr, "%s: %s\n", str, strerror(errno));
23+
char errstr[48];
24+
25+
(void)strerror_r(errno, errstr, sizeof(errstr));
26+
27+
fprintf(stderr, "%s: %s\n", str, errstr);
2328
}

string/Makefile

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,8 @@
11
#
22
# Makefile for libphoenix/string
33
#
4-
# Copyright 2017, 2020 Phoenix Systems
4+
# Copyright 2017, 2020, 2023 Phoenix Systems
55
# Author: Pawel Pisarczyk
66
#
77

8-
INCS := errno.str.inc errno.tab.inc gaierr.str.inc gaierr.tab.inc
9-
10-
11-
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}' \
12-
-e '/^\s*E\w+\s*=\s*-?[[:digit:]]+/{s/^\s*(\w+)\s*=\s*-?([[:digit:]]+).*/\2\t\1/;p;d}'
13-
14-
15-
%/errno.list: $(SYSROOT)/usr/include/phoenix/errno.h include/errno.h
16-
@(printf "GEN %-24s \n" "$(@F)")
17-
$(SIL)$(ERR_EXTRACT) $^ | sort -n > $@
18-
19-
20-
%/gaierr.list: include/netdb.h Makefile
21-
@(printf "GEN %-24s \n" "$(@F)")
22-
$(SIL)$(ERR_EXTRACT) $^ | sort -n > $@
23-
24-
25-
%.str.inc: %.list Makefile
26-
@(printf "GEN %-24s \n" "$(@F)")
27-
$(SIL)$(SED) -e 's/^.*\t\(.*\)$$/"\1\\0"/' $< > $@
28-
29-
30-
%.tab.inc: %.list Makefile
31-
@(printf "GEN %-24s \n" "$(@F)")
32-
$(SIL)bash -c 'o=0; while read num name; do echo "{ $$num, $$o },"; o=$$((o+$${#name}+1)); done' < $< > $@
33-
34-
35-
$(PREFIX_O)string/strerror.o: $(patsubst %,string/%,$(INCS))
36-
37-
388
OBJS += $(addprefix $(PREFIX_O)string/, string.o strdup.o strerror.o strsignal.o)

string/strerror.c

Lines changed: 174 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* string/strerror (errno names)
77
*
8-
* Copyright 2018 Phoenix Systems
8+
* Copyright 2018, 2023 Phoenix Systems
99
* Author: Michal Miroslaw, Aleksander Kaminski
1010
*
1111
* This file is part of Phoenix-RTOS.
@@ -18,60 +18,162 @@
1818
#include <stdio.h>
1919
#include <string.h>
2020
#include <errno.h>
21-
22-
23-
typedef struct {
24-
uint16_t errnum;
25-
uint16_t offset;
26-
} errinfo_t;
27-
28-
29-
static const char errnames[] = {
30-
#include "errno.str.inc"
31-
};
32-
33-
static const errinfo_t errtab[] = {
34-
#include "errno.tab.inc"
21+
#include <netdb.h>
22+
23+
24+
/* clang-format off */
25+
static const char *__errmsgtab[] = {
26+
/* EOK */ "Operation succeeded",
27+
/* EPERM */ "Operation not permitted",
28+
/* ENOENT */ "No such file or directory",
29+
/* ESRCH */ "No such process",
30+
/* EINTR */ "Interrupted system call",
31+
/* EIO */ "I/O error",
32+
/* ENXIO */ "No such device or address",
33+
/* E2BIG */ "Argument list too long",
34+
/* ENOEXEC */ "Executable format error",
35+
/* EBADF */ "Bad file number",
36+
/* ECHILD */ "No child processes",
37+
/* EAGAIN */ "Try again",
38+
/* ENOMEM */ "Out of memory",
39+
/* EACCES */ "Permission denied",
40+
/* EFAULT */ "Bad address",
41+
/* ENOTBLK */ "Block device required",
42+
/* EBUSY */ "Device or resource busy",
43+
/* EEXIST */ "File exists",
44+
/* EXDEV */ "Cross-device link",
45+
/* ENODEV */ "No such device",
46+
/* ENOTDIR */ "Not a directory",
47+
/* EISDIR */ "Is a directory",
48+
/* EINVAL */ "Invalid argument",
49+
/* ENFILE */ "File table overflow",
50+
/* EMFILE */ "Too many open files",
51+
/* ENOTTY */ "Not a typewriter",
52+
/* ETXTBSY */ "Text file busy",
53+
/* EFBIG */ "File too large",
54+
/* ENOSPC */ "No space left on device",
55+
/* ESPIPE */ "Illegal seek",
56+
/* EROFS */ "Read-only file system",
57+
/* EMLINK */ "Too many links",
58+
/* EPIPE */ "Broken pipe",
59+
/* EDOM */ "Argument out of domain",
60+
/* ERANGE */ "Result not representable",
61+
/* ENOSYS */ "Function not implemented",
62+
/* ENAMETOOLONG */ "Name too long",
63+
/* ETIME */ "Timer expired",
64+
/* EDEADLK */ "Resource deadlock avoided",
65+
/* ENOTEMPTY */ "Directory not empty",
66+
/* ELOOP */ "Too many levels of symbolic links",
67+
NULL,
68+
/* ENOMSG */ "No message of the desired type",
69+
NULL,
70+
NULL,
71+
NULL,
72+
NULL,
73+
NULL,
74+
NULL,
75+
/* EUNATCH */ "Protocol driver not attached",
76+
NULL,
77+
NULL,
78+
NULL,
79+
NULL,
80+
NULL,
81+
NULL,
82+
NULL,
83+
NULL,
84+
NULL,
85+
NULL,
86+
NULL,
87+
/* ENODATA */ "No message is available on the STREAM head read queue",
88+
NULL,
89+
NULL,
90+
/* ENONET */ "Machine is not on the network.",
91+
NULL,
92+
/* EBADFD */ "File descriptor in bad state",
93+
NULL,
94+
NULL,
95+
NULL,
96+
NULL,
97+
/* EPROTO */ "Protocol error",
98+
NULL,
99+
NULL,
100+
/* EBADMSG */ "Bad message",
101+
/* EOVERFLOW */ "Value too large to be stored in data type",
102+
NULL,
103+
NULL,
104+
NULL,
105+
NULL,
106+
NULL,
107+
NULL,
108+
NULL,
109+
NULL,
110+
/* EILSEQ */ "Invalid or incomplete multibyte or wide character",
111+
NULL,
112+
NULL,
113+
NULL,
114+
/* ENOTSOCK */ "Not a socket",
115+
/* EDESTADDRREQ */ "Destination address required",
116+
/* EMSGSIZE */ "Message too long",
117+
/* EPROTOTYPE */ "Protocol wrong type for socket",
118+
/* ENOPROTOOPT */ "Protocol not available",
119+
/* EPROTONOSUPPORT */ "Protocol not supported",
120+
NULL,
121+
/* EOPNOTSUPP */ "Operation not supported on socket",
122+
/* EPFNOSUPPORT */ "Protocol family not supported",
123+
/* EAFNOSUPPORT */ "Address family not supported",
124+
/* EADDRINUSE */ "Address already in use",
125+
/* EADDRNOTAVAIL */ "Address not available",
126+
/* ENETDOWN */ "Network is down",
127+
/* ENETUNREACH */ "Network unreachable",
128+
/* ENETRESET */ "Connection aborted by network",
129+
/* ECONNABORTED */ "Connection aborted",
130+
/* ECONNRESET */ "Connection reset",
131+
/* ENOBUFS */ "No buffer space available",
132+
/* EISCONN */ "Socket is connected",
133+
/* ENOTCONN */ "The socket is not connected",
134+
NULL,
135+
NULL,
136+
/* ETIMEDOUT */ "Connection timed out",
137+
/* ECONNREFUSED */ "Connection refused",
138+
/* EHOSTDOWN */ "Host is down",
139+
/* EHOSTUNREACH */ "Host is unreachable",
140+
/* EALREADY */ "Connection already in progress",
141+
/* EINPROGRESS */ "Operation in progress",
142+
/* ENOLCK */ "No locks available",
143+
/* EUCLEAN */ "Structure needs cleaning",
144+
NULL,
145+
NULL,
146+
NULL,
147+
NULL,
148+
NULL,
149+
NULL,
150+
NULL,
151+
NULL,
152+
NULL,
153+
NULL,
154+
NULL,
155+
NULL,
156+
NULL,
157+
/* ENOTRECOVERABLE */ "State not recoverable"
35158
};
36-
37-
static const char gainames[] = {
38-
#include "gaierr.str.inc"
39-
};
40-
41-
static const errinfo_t gaitab[] = {
42-
#include "gaierr.tab.inc"
43-
};
44-
45-
// static assert: 16-bit offset
46-
static const char assert_errnames_size[-(sizeof(errnames) > 0xFFFF)] __attribute__((unused));
47-
static const char assert_gainames_size[-(sizeof(gainames) > 0xFFFF)] __attribute__((unused));
159+
/* clang-format on */
48160

49161

50-
static int err_cmp(const void *key, const void *elem)
162+
static inline const char *strerror_(int errnum, char *buff, size_t bufflen, int *err)
51163
{
52-
const errinfo_t *p = elem;
53-
long err = (long)key;
164+
const char *str = NULL;
54165

55-
return err - (long)p->errnum;
56-
}
57-
58-
59-
static inline const char *strerror_(const errinfo_t *tab, size_t tabsz, const char *names, int errnum, char *buff, size_t bufflen, int *err)
60-
{
61-
const errinfo_t *e;
62-
63-
if (errnum < 0) {
64-
errnum = -errnum;
166+
if ((errnum >= 0) && (errnum < (int)(sizeof(__errmsgtab) / sizeof(*__errmsgtab)))) {
167+
str = __errmsgtab[errnum];
65168
}
66169

67-
e = bsearch((void *)(long)errnum, tab, tabsz / sizeof(*tab), sizeof(*tab), err_cmp);
68-
if (e == NULL) {
170+
if (str == NULL) {
69171
(void)snprintf(buff, bufflen, "Unknown error %d", errnum);
70172
*err = EINVAL;
71-
return buff;
173+
str = buff;
72174
}
73175

74-
return names + e->offset;
176+
return str;
75177
}
76178

77179

@@ -81,7 +183,7 @@ char *strerror(int errnum)
81183
const char *str;
82184
int err = 0;
83185

84-
str = strerror_(errtab, sizeof(errtab), errnames, errnum, unknownMsg, sizeof(unknownMsg), &err);
186+
str = strerror_(errnum, unknownMsg, sizeof(unknownMsg), &err);
85187
if (err != 0) {
86188
errno = err;
87189
}
@@ -97,7 +199,7 @@ int strerror_r(int errnum, char *buf, size_t buflen)
97199
int ret = 0;
98200
size_t len;
99201

100-
str = strerror_(errtab, sizeof(errtab), errnames, errnum, unknownMsg, sizeof(unknownMsg), &ret);
202+
str = strerror_(errnum, unknownMsg, sizeof(unknownMsg), &ret);
101203
len = strlen(str);
102204
if (buflen > len) {
103205
memcpy(buf, str, len + 1);
@@ -113,13 +215,32 @@ int strerror_r(int errnum, char *buf, size_t buflen)
113215
const char *gai_strerror(int errnum)
114216
{
115217
static char unknownMsg[32];
116-
const char *str;
117-
int err = 0;
118218

119-
str = strerror_(gaitab, sizeof(gaitab), gainames, errnum, unknownMsg, sizeof(unknownMsg), &err);
120-
if (err != 0) {
121-
errno = err;
219+
switch (errnum) {
220+
case EAI_AGAIN:
221+
return "Name could not be resolved at this time";
222+
case EAI_BADFLAGS:
223+
return "Flags parameter had an invalid value";
224+
case EAI_FAIL:
225+
return "Non-recoverable failure in name resolution";
226+
case EAI_FAMILY:
227+
return "Address family was not recognized";
228+
case EAI_MEMORY:
229+
return "Memory allocation failure";
230+
case EAI_NODATA:
231+
return "No address associated with hostname";
232+
case EAI_NONAME:
233+
return "Name does not resolve";
234+
case EAI_OVERFLOW:
235+
return "Argument buffer overflow";
236+
case EAI_SERVICE:
237+
return "Service was not recognized for socket type";
238+
case EAI_SOCKTYPE:
239+
return "Intended socket type was not recognized";
240+
case EAI_SYSTEM:
241+
return "System error returned in errno";
242+
default:
243+
(void)snprintf(unknownMsg, sizeof(unknownMsg), "Unknown error %d", errnum);
244+
return unknownMsg;
122245
}
123-
124-
return (char *)str;
125246
}

0 commit comments

Comments
 (0)