45

Is there any function in UNIX to the convert errno to its corresponding string for e.g. EIDRM to "EIDRM". Its very annoying to debug to check for errors with these integer errnos.

avd
  • 13,993
  • 32
  • 78
  • 99

6 Answers6

78

strerror() should do it. http://linux.die.net/man/3/strerror

FYI, so that you can find these things more easily, yourself: If you type man errno (or whatever function you're investigating), and look at the very bottom of the man page, you'll see a list of related functions. If you man each of those (taking a guess about which one(s) to do first based on their names) you'll often find the answer to similar questions.

atk
  • 9,244
  • 3
  • 32
  • 32
  • 1
    strerror will actually turn them into much more useful strings than just "EIDRM" as the op asked, but that's the answer I would have given too. – Paul Tomblin Oct 10 '09 at 02:48
  • 4
    those strings are actually not that useful, because the man pages for the system calls often specify error behaviors in terms of the enum code. The string is at best a hint. – orm Jan 06 '16 at 21:05
  • 2
    Danger, Will Robinson! `strerror()`'s strings are _localised_, as I found out when I was checking an error string for "No such file or directory" but my user's platform was returning "Arquivo ou diretório não encontrado" instead. (This was in a language where the errno value itself wasn't exposed.) – David Given Feb 25 '16 at 23:21
  • @orm Yeah, those strings are very useful for beginner users in the common cases, but beyond a certain point those hints can be unhelpful or even misleading. – mtraceur Aug 11 '19 at 07:11
  • @davidgiven It sounds like you ran into exactly the kind of uses that led me to write [the `errnoname` library](https://github.com/mentalisttraceur/errnoname): having to parse error strings programmatically because that was the only form that the error information was being made available in. For me the biggest offenders are tools like `rm`, `mv`, and the iproute2 commands, all of which lack other ways to distinguish for example errors that actually mean idempotent success from other errors. Now we just have to convince everyone to put `errno` names in parsable ways into their error messages. – mtraceur Aug 11 '19 at 07:18
14

Just another solution that solves exactly the problem you have, but in Python instead of C:

>>> import errno
>>> errno.errorcode[errno.EIDRM]
'EIDRM'
Andrey Vlasovskikh
  • 16,489
  • 7
  • 44
  • 62
  • 1
    This is a good answer, but worth knowing that Python only includes a subset of all possible `errno` values, so on some systems, it won't have entries for all of them. For typical cases this is a non-issue, but if you are using this as a generic way to look up error codes, you may run into this. – mtraceur Aug 11 '19 at 07:23
  • Thanks! I was looking for this urgently... – pugi Jul 19 '22 at 15:47
12

There's now an errno utility distributed with the moreutils package.

$ errno -h
Usage: errno [-lsS] [--list] [--search] [--search-all-locales] [keyword]

$ errno -l
EPERM 1 Operation not permitted
ENOENT 2 No such file or directory
ESRCH 3 No such process
EINTR 4 Interrupted system call
EIO 5 Input/output error
ENXIO 6 No such device or address
E2BIG 7 Argument list too long
ENOEXEC 8 Exec format error
...

$ errno 11
EAGAIN 11 Resource temporarily unavailable

$ errno -s Ouput
EIO 5 Input/output error
G. David
  • 5
  • 3
Stephen Niedzielski
  • 2,497
  • 1
  • 28
  • 34
4

I'm not sure about such enum-style names, but for debugging and error reporting purposes you may use perror(3) or strerror(3) C functions that return a human-readable representation of the error code. Please refer to the man pages for more details.

Andrey Vlasovskikh
  • 16,489
  • 7
  • 44
  • 62
  • I thought perror() just prints to STDERR rather than converting the number to a value. Do I misremember (and misread the man page)? – atk Oct 10 '09 at 02:53
  • Yes, `perror` is a debugging facility for `errno`-related issues and it writes its messages to `STDERR`. – Andrey Vlasovskikh Oct 10 '09 at 02:55
3

If you do indeed want EIDRM and not its error string: no. However, on OpenBSD,

man errno|egrep ' [0-9]+ E[A-Z]+'|sed 's/^ *//'|cut -d' ' -f1,2

prints out a nice table of "...\n89 EIDM\n..." that you can convert further into a data structure for the programming language that you'd like to have this function in.

ayrnieu
  • 1,839
  • 14
  • 15
3

I recently wrote errnoname to do this.

There is no standard function to do this in UNIX. (GNU's glibc has strerrorname_np, but no other C library currently provides it, so it's not even available on all Linux distros, let alone anywhere else.)

strerror (also strerror_r, strerror_l, perror) print a "human friendly" hint about what the error was, but their outputs are

  • usually undocumented,
  • not standardized,
  • not guaranteed to follow any constrains on length or format,
  • often different depending on locale settings, and
  • do not always make sense in all situations (for example they tend to print File exists for EEXIST, even though that error is often returned for things that are not files).

Which means that they are superficially user-friendly but

  • other code cannot parse them as reliably (worse for automation, monitoring, scripting, wrapper programs, etc),
  • can mislead in the edge cases, and
  • get in the way of technical experienced users.

Ironically there is nothing preventing those functions from just using the errno symbolic name as their error string in all circumstances - it would be within the letter of the standard, especially if they only did it for a specific locale, like the special C locale. But no libc I know of does this.

Anyway, since my errnoname is released under the "Zero-Clause BSD license" (0BSD), which is a permissive license, or more accurately a public-domain-equivalent license, you can do whatever you want with it.

To make this answer stand alone, while still fitting within the answer character limits, below are two abbreviated variants of the errnoname function.

In errnoname they are both implemented, but here I've separated out the gist of each to make them more readable.

Couple of notes:

  1. This covers all or most of errno names for Linux, Darwin (Mac OS X and iOS X), FreeBSD, NetBSD, OpenBSD, DragonflyBSD, and several closed source Unixes, as of start of January 2020.

  2. It returns a null pointer if you give it an errno value it does not know the name of.

Variant 1: Simple, Universal

This one is very portable and simple with no edge-cases to worry about. It will compile with just about any C89 or better compiler you can throw at it. (Probably even C++ compilers, which is becoming more rare as the languages diverge.)

This variant can compile to very efficient code (an array lookup instead of a switch statement) on modern compilers when the optimizations are turned up high enough, but might not depending on the exact situation.

#include <errno.h>

char const * errnoname(int errno_)
{
    switch(errno_)
    {
#ifdef E2BIG
        case E2BIG: return "E2BIG";
#endif
#ifdef EACCES
        case EACCES: return "EACCES";
#endif
/*
    repeat for the other 100+ errno names,
    don't forget to handle possible duplicates
    like EAGAIN and EWOULDBLOCK
*/
    }
    return 0;
}

Variant 2: Explicitly Efficient, Good For Most Systems

This one is more obviously efficient, and will compile to efficient code very reliably, because it makes the array lookup explicit and does not depend on the compiler's optimizations.

It is safe to use so long as the system has positive, relatively small, and reasonably contiguous errno values.

Can only compile on compilers that implement out-of-order designated initializers for arrays (C99 or better, excluding all C++ versions so far.)

#include <errno.h>

char const * errnoname(int errno_)
{
    static char const * const names[] =
    {
#ifdef E2BIG
        [E2BIG] = "E2BIG",
#endif
#ifdef EACCES
        [EACCES] = "EACCES",
#endif
/*
    repeat for the other 100+ errno names,
    don't forget to handle possible duplicates
    like EAGAIN and EWOULDBLOCK
*/
    };
    if(errno_ >= 0 && errno_ < (sizeof(names) / sizeof(*names)))
    {
        return names[errno_];
    }
    return 0;
}
mtraceur
  • 3,254
  • 24
  • 33
  • Nice idea to have an errnoname() function but too bad it's using a switch-case. For error-handling it might be good, BUT for other purposes like a tracer it's unnecessarily sub-optimal. You should have created a big array, using errno codes as indexes. I mean, using the syntax { ..., [index] = value, ... }. Of course you can have holes there as well. – vvaltchev Dec 29 '19 at 18:29
  • 1
    @vvaltchev I've now added an array-based implementation as an option (activated by defining `ERRNONAME_SAFE_TO_USE_ARRAY` when compiling) to [errnoname](https://github.com/mentalisttraceur/errnoname). (Documented in the [Optimization](https://github.com/mentalisttraceur/errnoname#optimization) section.) Thank you for bringing it up. I was waiting to hear if there was demand for the array-based approach before revisting how I wanted to tackle it. – mtraceur Dec 30 '19 at 11:35
  • Good job, man! Your project earned its first GitHub star :-) I implemented a custom solution for my case (I needed only Linux errno codes), but it's still is good to know that you added that feature. Anyway, yeah, I understand the concern that *theoretically* there might exist big errno codes on some system, but in practice on all the UNIX systems I've ever seen in my life, they are just almost sequential numbers, typically less than a few hundred in total. @mtraceur – vvaltchev Dec 30 '19 at 17:13
  • @vvaltchev On further testing: I have a gcc 4.8.5 (released five years ago) lying around, and it manages to optimise the switch version into an array lookup automatically with either `-O2`, `-O3`, or `-Os` optimization flags. (This is on an ARMv7 Linux device, where `errno` are strictly contiguous. It hilariously then fails to combine a pair of `sub r0, r0, #1` and `cmp r0, #132` instructions into one `cmp r0, #133` instruction, but other than that the switch-based and array-based C code generate identical machine code.) – mtraceur Jan 19 '20 at 16:11
  • I think that one instruction difference is because it decided to make the array 132 elements, where the 0th index is the 1st errno, instead of the manual array version where the 1st index is the 1st errno. Notably, manually adding a `case 0: return 0` did not change the result - so I guess the optimizer is making its decision on an abstract form of the logic which has already recognized that the zero-case is the same as any other out-of-bounds case, and which precludes it from heuristically noticing that one extra array entry is probably more efficient than one always-executed instruction. – mtraceur Jan 19 '20 at 16:33
  • Modern clang 9.0.1 for aarch64 Linux exhibits the same behavior - identical code, but for the choice of the array starting from the first errno and thus needing `sub` then `cmp` instead of just `cmp`. – mtraceur Jan 19 '20 at 17:08
  • @vvaltchev I just realized I never actually said "thank you!" to your "good job!" compliment. So yeah, thanks! I appreciated it at the time, and still do! (Oh, re: non-contiguous `errno` - I think for user space code on a mainstream OS you're totally right, but if we go outside of that, I've actually found several among the ones I gathered for `errnoname` which have chunks of errno values in the high thousands, and then if you want to use it in kernel code some of them have negative errno values.) – mtraceur Mar 25 '23 at 01:35
  • Typically the syscalls return the errno values as -errno, because 0 means SUCCESS and > 0 might have another meaning (e.g. bytes written). Therefore, don't worry for the negative case: the errors are the same. Also, thousands is probably OK as well. Unless you have a very sparse errno space, the array is fine. For a spare errno space, not typical on POSIX systems, you'll need to use a dedicated data structure. – vvaltchev Apr 01 '23 at 18:58
  • @vvaltchev That's not what I mean. In some kernels, kernel-internal errno values are negative *relative to* the normal (positive) errno values. For just one example, see the FreeBSD kernel (`src/blob/master/sys/sys/errno`), but you'll find this pattern in many of the systems that `errnoname` sources names from. ... hmm, actually, in the case of GNU Hurd, which has `-3xx` errors for errors from the "MIG" interface to Mach (can be found in glibc's `sysdeps/mach/hurd/bits/errno.h`), I think it's in principle possible for these errors to show up in userspace too. – mtraceur Apr 01 '23 at 22:54
  • @vvaltchev As for sparse `errno` space, I agree - it's not even close to typical on POSIX systems. Of the systems I've looked at for `errnoname`, I can think of only two with `errno` above 200: zOS has several the 1000+ range, and Darwin XNU (macOS, iOS, etc) have exactly two internal-to-the-kernel: 256 and 512. I have memories of seeing some errno list that had `errno` way up at something like 8000, but I can't remember which one it is and I can't find it again. So I think it's fair to say that those might as well not exist for mot people for most purposes. – mtraceur Apr 01 '23 at 23:14