blob: eb63d70ae1f35b629c6b7d95287067c52e4fb9ec [file] [log] [blame]
// 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);
}