avd
avd

Reputation: 14451

How to convert errno in UNIX to corresponding string?

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.

Upvotes: 48

Views: 52874

Answers (6)

mtraceur
mtraceur

Reputation: 3736

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;
}

Upvotes: 4

Stephen Niedzielski
Stephen Niedzielski

Reputation: 2637

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

Upvotes: 14

ayrnieu
ayrnieu

Reputation: 1899

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.

Upvotes: 3

Andrey Vlasovskikh
Andrey Vlasovskikh

Reputation: 16848

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

>>> import errno
>>> errno.errorcode[errno.EIDRM]
'EIDRM'

Upvotes: 15

Andrey Vlasovskikh
Andrey Vlasovskikh

Reputation: 16848

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.

Upvotes: 4

atk
atk

Reputation: 9324

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.

Upvotes: 82

Related Questions