1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 // Copyright (c) 2020 Anton Protopopov
3 #include <stdlib.h>
4 #include <limits.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <stdio.h>
8
9 #define warn(...) fprintf(stderr, __VA_ARGS__)
10
11 #ifdef __x86_64__
errno_by_name_x86_64(const char * errno_name)12 static int errno_by_name_x86_64(const char *errno_name)
13 {
14
15 #define strcase(X, N) if (!strcmp(errno_name, (X))) return N
16
17 strcase("EPERM", 1);
18 strcase("ENOENT", 2);
19 strcase("ESRCH", 3);
20 strcase("EINTR", 4);
21 strcase("EIO", 5);
22 strcase("ENXIO", 6);
23 strcase("E2BIG", 7);
24 strcase("ENOEXEC", 8);
25 strcase("EBADF", 9);
26 strcase("ECHILD", 10);
27 strcase("EAGAIN", 11);
28 strcase("EWOULDBLOCK", 11);
29 strcase("ENOMEM", 12);
30 strcase("EACCES", 13);
31 strcase("EFAULT", 14);
32 strcase("ENOTBLK", 15);
33 strcase("EBUSY", 16);
34 strcase("EEXIST", 17);
35 strcase("EXDEV", 18);
36 strcase("ENODEV", 19);
37 strcase("ENOTDIR", 20);
38 strcase("EISDIR", 21);
39 strcase("EINVAL", 22);
40 strcase("ENFILE", 23);
41 strcase("EMFILE", 24);
42 strcase("ENOTTY", 25);
43 strcase("ETXTBSY", 26);
44 strcase("EFBIG", 27);
45 strcase("ENOSPC", 28);
46 strcase("ESPIPE", 29);
47 strcase("EROFS", 30);
48 strcase("EMLINK", 31);
49 strcase("EPIPE", 32);
50 strcase("EDOM", 33);
51 strcase("ERANGE", 34);
52 strcase("EDEADLK", 35);
53 strcase("EDEADLOCK", 35);
54 strcase("ENAMETOOLONG", 36);
55 strcase("ENOLCK", 37);
56 strcase("ENOSYS", 38);
57 strcase("ENOTEMPTY", 39);
58 strcase("ELOOP", 40);
59 strcase("ENOMSG", 42);
60 strcase("EIDRM", 43);
61 strcase("ECHRNG", 44);
62 strcase("EL2NSYNC", 45);
63 strcase("EL3HLT", 46);
64 strcase("EL3RST", 47);
65 strcase("ELNRNG", 48);
66 strcase("EUNATCH", 49);
67 strcase("ENOCSI", 50);
68 strcase("EL2HLT", 51);
69 strcase("EBADE", 52);
70 strcase("EBADR", 53);
71 strcase("EXFULL", 54);
72 strcase("ENOANO", 55);
73 strcase("EBADRQC", 56);
74 strcase("EBADSLT", 57);
75 strcase("EBFONT", 59);
76 strcase("ENOSTR", 60);
77 strcase("ENODATA", 61);
78 strcase("ETIME", 62);
79 strcase("ENOSR", 63);
80 strcase("ENONET", 64);
81 strcase("ENOPKG", 65);
82 strcase("EREMOTE", 66);
83 strcase("ENOLINK", 67);
84 strcase("EADV", 68);
85 strcase("ESRMNT", 69);
86 strcase("ECOMM", 70);
87 strcase("EPROTO", 71);
88 strcase("EMULTIHOP", 72);
89 strcase("EDOTDOT", 73);
90 strcase("EBADMSG", 74);
91 strcase("EOVERFLOW", 75);
92 strcase("ENOTUNIQ", 76);
93 strcase("EBADFD", 77);
94 strcase("EREMCHG", 78);
95 strcase("ELIBACC", 79);
96 strcase("ELIBBAD", 80);
97 strcase("ELIBSCN", 81);
98 strcase("ELIBMAX", 82);
99 strcase("ELIBEXEC", 83);
100 strcase("EILSEQ", 84);
101 strcase("ERESTART", 85);
102 strcase("ESTRPIPE", 86);
103 strcase("EUSERS", 87);
104 strcase("ENOTSOCK", 88);
105 strcase("EDESTADDRREQ", 89);
106 strcase("EMSGSIZE", 90);
107 strcase("EPROTOTYPE", 91);
108 strcase("ENOPROTOOPT", 92);
109 strcase("EPROTONOSUPPORT", 93);
110 strcase("ESOCKTNOSUPPORT", 94);
111 strcase("ENOTSUP", 95);
112 strcase("EOPNOTSUPP", 95);
113 strcase("EPFNOSUPPORT", 96);
114 strcase("EAFNOSUPPORT", 97);
115 strcase("EADDRINUSE", 98);
116 strcase("EADDRNOTAVAIL", 99);
117 strcase("ENETDOWN", 100);
118 strcase("ENETUNREACH", 101);
119 strcase("ENETRESET", 102);
120 strcase("ECONNABORTED", 103);
121 strcase("ECONNRESET", 104);
122 strcase("ENOBUFS", 105);
123 strcase("EISCONN", 106);
124 strcase("ENOTCONN", 107);
125 strcase("ESHUTDOWN", 108);
126 strcase("ETOOMANYREFS", 109);
127 strcase("ETIMEDOUT", 110);
128 strcase("ECONNREFUSED", 111);
129 strcase("EHOSTDOWN", 112);
130 strcase("EHOSTUNREACH", 113);
131 strcase("EALREADY", 114);
132 strcase("EINPROGRESS", 115);
133 strcase("ESTALE", 116);
134 strcase("EUCLEAN", 117);
135 strcase("ENOTNAM", 118);
136 strcase("ENAVAIL", 119);
137 strcase("EISNAM", 120);
138 strcase("EREMOTEIO", 121);
139 strcase("EDQUOT", 122);
140 strcase("ENOMEDIUM", 123);
141 strcase("EMEDIUMTYPE", 124);
142 strcase("ECANCELED", 125);
143 strcase("ENOKEY", 126);
144 strcase("EKEYEXPIRED", 127);
145 strcase("EKEYREVOKED", 128);
146 strcase("EKEYREJECTED", 129);
147 strcase("EOWNERDEAD", 130);
148 strcase("ENOTRECOVERABLE", 131);
149 strcase("ERFKILL", 132);
150 strcase("EHWPOISON", 133);
151
152 #undef strcase
153
154 return -1;
155
156 }
157 #endif
158
159 /* Try to find the errno number using the errno(1) program */
errno_by_name_dynamic(const char * errno_name)160 static int errno_by_name_dynamic(const char *errno_name)
161 {
162 int i, len = strlen(errno_name);
163 int err, number = -1;
164 char buf[128];
165 char cmd[64];
166 char *end;
167 long val;
168 FILE *f;
169
170 /* sanity check to not call popen with random input */
171 for (i = 0; i < len; i++) {
172 if (errno_name[i] < 'A' || errno_name[i] > 'Z') {
173 warn("errno_name contains invalid char 0x%02x: %s\n",
174 errno_name[i], errno_name);
175 return -1;
176 }
177 }
178
179 snprintf(cmd, sizeof(cmd), "errno %s", errno_name);
180 f = popen(cmd, "r");
181 if (!f) {
182 warn("popen: %s: %s\n", cmd, strerror(errno));
183 return -1;
184 }
185
186 if (!fgets(buf, sizeof(buf), f)) {
187 goto close;
188 } else if (ferror(f)) {
189 warn("fgets: %s\n", strerror(errno));
190 goto close;
191 }
192
193 // expecting "<name> <number> <description>"
194 if (strncmp(errno_name, buf, len) || strlen(buf) < len+2) {
195 warn("expected '%s': %s\n", errno_name, buf);
196 goto close;
197 }
198 errno = 0;
199 val = strtol(buf+len+2, &end, 10);
200 if (errno || end == (buf+len+2) || number < 0 || number > INT_MAX) {
201 warn("can't parse the second column, expected int: %s\n", buf);
202 goto close;
203 }
204 number = val;
205
206 close:
207 err = pclose(f);
208 if (err < 0)
209 warn("pclose: %s\n", strerror(errno));
210 #ifndef __x86_64__
211 /* Ignore the error for x86_64 where we have a table compiled in */
212 else if (err && WEXITSTATUS(err) == 127) {
213 warn("errno(1) required for errno name/number mapping\n");
214 } else if (err) {
215 warn("errno(1) exit status (see wait(2)): 0x%x\n", err);
216 }
217 #endif
218 return number;
219 }
220
errno_by_name(const char * errno_name)221 int errno_by_name(const char *errno_name)
222 {
223 #ifdef __x86_64__
224 int err;
225
226 err = errno_by_name_x86_64(errno_name);
227 if (err >= 0)
228 return err;
229 #endif
230
231 return errno_by_name_dynamic(errno_name);
232 }
233