xref: /aosp_15_r20/external/bcc/libbpf-tools/errno_helpers.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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