233 lines
5.5 KiB
C
233 lines
5.5 KiB
C
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
|
// Copyright (c) 2020 Anton Protopopov
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
|
|
#define warn(...) fprintf(stderr, __VA_ARGS__)
|
|
|
|
#ifdef __x86_64__
|
|
static int errno_by_name_x86_64(const char *errno_name)
|
|
{
|
|
|
|
#define strcase(X, N) if (!strcmp(errno_name, (X))) return N
|
|
|
|
strcase("EPERM", 1);
|
|
strcase("ENOENT", 2);
|
|
strcase("ESRCH", 3);
|
|
strcase("EINTR", 4);
|
|
strcase("EIO", 5);
|
|
strcase("ENXIO", 6);
|
|
strcase("E2BIG", 7);
|
|
strcase("ENOEXEC", 8);
|
|
strcase("EBADF", 9);
|
|
strcase("ECHILD", 10);
|
|
strcase("EAGAIN", 11);
|
|
strcase("EWOULDBLOCK", 11);
|
|
strcase("ENOMEM", 12);
|
|
strcase("EACCES", 13);
|
|
strcase("EFAULT", 14);
|
|
strcase("ENOTBLK", 15);
|
|
strcase("EBUSY", 16);
|
|
strcase("EEXIST", 17);
|
|
strcase("EXDEV", 18);
|
|
strcase("ENODEV", 19);
|
|
strcase("ENOTDIR", 20);
|
|
strcase("EISDIR", 21);
|
|
strcase("EINVAL", 22);
|
|
strcase("ENFILE", 23);
|
|
strcase("EMFILE", 24);
|
|
strcase("ENOTTY", 25);
|
|
strcase("ETXTBSY", 26);
|
|
strcase("EFBIG", 27);
|
|
strcase("ENOSPC", 28);
|
|
strcase("ESPIPE", 29);
|
|
strcase("EROFS", 30);
|
|
strcase("EMLINK", 31);
|
|
strcase("EPIPE", 32);
|
|
strcase("EDOM", 33);
|
|
strcase("ERANGE", 34);
|
|
strcase("EDEADLK", 35);
|
|
strcase("EDEADLOCK", 35);
|
|
strcase("ENAMETOOLONG", 36);
|
|
strcase("ENOLCK", 37);
|
|
strcase("ENOSYS", 38);
|
|
strcase("ENOTEMPTY", 39);
|
|
strcase("ELOOP", 40);
|
|
strcase("ENOMSG", 42);
|
|
strcase("EIDRM", 43);
|
|
strcase("ECHRNG", 44);
|
|
strcase("EL2NSYNC", 45);
|
|
strcase("EL3HLT", 46);
|
|
strcase("EL3RST", 47);
|
|
strcase("ELNRNG", 48);
|
|
strcase("EUNATCH", 49);
|
|
strcase("ENOCSI", 50);
|
|
strcase("EL2HLT", 51);
|
|
strcase("EBADE", 52);
|
|
strcase("EBADR", 53);
|
|
strcase("EXFULL", 54);
|
|
strcase("ENOANO", 55);
|
|
strcase("EBADRQC", 56);
|
|
strcase("EBADSLT", 57);
|
|
strcase("EBFONT", 59);
|
|
strcase("ENOSTR", 60);
|
|
strcase("ENODATA", 61);
|
|
strcase("ETIME", 62);
|
|
strcase("ENOSR", 63);
|
|
strcase("ENONET", 64);
|
|
strcase("ENOPKG", 65);
|
|
strcase("EREMOTE", 66);
|
|
strcase("ENOLINK", 67);
|
|
strcase("EADV", 68);
|
|
strcase("ESRMNT", 69);
|
|
strcase("ECOMM", 70);
|
|
strcase("EPROTO", 71);
|
|
strcase("EMULTIHOP", 72);
|
|
strcase("EDOTDOT", 73);
|
|
strcase("EBADMSG", 74);
|
|
strcase("EOVERFLOW", 75);
|
|
strcase("ENOTUNIQ", 76);
|
|
strcase("EBADFD", 77);
|
|
strcase("EREMCHG", 78);
|
|
strcase("ELIBACC", 79);
|
|
strcase("ELIBBAD", 80);
|
|
strcase("ELIBSCN", 81);
|
|
strcase("ELIBMAX", 82);
|
|
strcase("ELIBEXEC", 83);
|
|
strcase("EILSEQ", 84);
|
|
strcase("ERESTART", 85);
|
|
strcase("ESTRPIPE", 86);
|
|
strcase("EUSERS", 87);
|
|
strcase("ENOTSOCK", 88);
|
|
strcase("EDESTADDRREQ", 89);
|
|
strcase("EMSGSIZE", 90);
|
|
strcase("EPROTOTYPE", 91);
|
|
strcase("ENOPROTOOPT", 92);
|
|
strcase("EPROTONOSUPPORT", 93);
|
|
strcase("ESOCKTNOSUPPORT", 94);
|
|
strcase("ENOTSUP", 95);
|
|
strcase("EOPNOTSUPP", 95);
|
|
strcase("EPFNOSUPPORT", 96);
|
|
strcase("EAFNOSUPPORT", 97);
|
|
strcase("EADDRINUSE", 98);
|
|
strcase("EADDRNOTAVAIL", 99);
|
|
strcase("ENETDOWN", 100);
|
|
strcase("ENETUNREACH", 101);
|
|
strcase("ENETRESET", 102);
|
|
strcase("ECONNABORTED", 103);
|
|
strcase("ECONNRESET", 104);
|
|
strcase("ENOBUFS", 105);
|
|
strcase("EISCONN", 106);
|
|
strcase("ENOTCONN", 107);
|
|
strcase("ESHUTDOWN", 108);
|
|
strcase("ETOOMANYREFS", 109);
|
|
strcase("ETIMEDOUT", 110);
|
|
strcase("ECONNREFUSED", 111);
|
|
strcase("EHOSTDOWN", 112);
|
|
strcase("EHOSTUNREACH", 113);
|
|
strcase("EALREADY", 114);
|
|
strcase("EINPROGRESS", 115);
|
|
strcase("ESTALE", 116);
|
|
strcase("EUCLEAN", 117);
|
|
strcase("ENOTNAM", 118);
|
|
strcase("ENAVAIL", 119);
|
|
strcase("EISNAM", 120);
|
|
strcase("EREMOTEIO", 121);
|
|
strcase("EDQUOT", 122);
|
|
strcase("ENOMEDIUM", 123);
|
|
strcase("EMEDIUMTYPE", 124);
|
|
strcase("ECANCELED", 125);
|
|
strcase("ENOKEY", 126);
|
|
strcase("EKEYEXPIRED", 127);
|
|
strcase("EKEYREVOKED", 128);
|
|
strcase("EKEYREJECTED", 129);
|
|
strcase("EOWNERDEAD", 130);
|
|
strcase("ENOTRECOVERABLE", 131);
|
|
strcase("ERFKILL", 132);
|
|
strcase("EHWPOISON", 133);
|
|
|
|
#undef strcase
|
|
|
|
return -1;
|
|
|
|
}
|
|
#endif
|
|
|
|
/* Try to find the errno number using the errno(1) program */
|
|
static int errno_by_name_dynamic(const char *errno_name)
|
|
{
|
|
int i, len = strlen(errno_name);
|
|
int err, number = -1;
|
|
char buf[128];
|
|
char cmd[64];
|
|
char *end;
|
|
long val;
|
|
FILE *f;
|
|
|
|
/* sanity check to not call popen with random input */
|
|
for (i = 0; i < len; i++) {
|
|
if (errno_name[i] < 'A' || errno_name[i] > 'Z') {
|
|
warn("errno_name contains invalid char 0x%02x: %s\n",
|
|
errno_name[i], errno_name);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
snprintf(cmd, sizeof(cmd), "errno %s", errno_name);
|
|
f = popen(cmd, "r");
|
|
if (!f) {
|
|
warn("popen: %s: %s\n", cmd, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (!fgets(buf, sizeof(buf), f)) {
|
|
goto close;
|
|
} else if (ferror(f)) {
|
|
warn("fgets: %s\n", strerror(errno));
|
|
goto close;
|
|
}
|
|
|
|
// expecting "<name> <number> <description>"
|
|
if (strncmp(errno_name, buf, len) || strlen(buf) < len+2) {
|
|
warn("expected '%s': %s\n", errno_name, buf);
|
|
goto close;
|
|
}
|
|
errno = 0;
|
|
val = strtol(buf+len+2, &end, 10);
|
|
if (errno || end == (buf+len+2) || number < 0 || number > INT_MAX) {
|
|
warn("can't parse the second column, expected int: %s\n", buf);
|
|
goto close;
|
|
}
|
|
number = val;
|
|
|
|
close:
|
|
err = pclose(f);
|
|
if (err < 0)
|
|
warn("pclose: %s\n", strerror(errno));
|
|
#ifndef __x86_64__
|
|
/* Ignore the error for x86_64 where we have a table compiled in */
|
|
else if (err && WEXITSTATUS(err) == 127) {
|
|
warn("errno(1) required for errno name/number mapping\n");
|
|
} else if (err) {
|
|
warn("errno(1) exit status (see wait(2)): 0x%x\n", err);
|
|
}
|
|
#endif
|
|
return number;
|
|
}
|
|
|
|
int errno_by_name(const char *errno_name)
|
|
{
|
|
#ifdef __x86_64__
|
|
int err;
|
|
|
|
err = errno_by_name_x86_64(errno_name);
|
|
if (err >= 0)
|
|
return err;
|
|
#endif
|
|
|
|
return errno_by_name_dynamic(errno_name);
|
|
}
|