// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) // Copyright (c) 2020 Anton Protopopov #include #include #include #include #include #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 " " 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); }