How to convert errno in UNIX to corresponding string?

后端 未结 6 1493
悲哀的现实
悲哀的现实 2020-12-16 08:57

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

相关标签:
6条回答
  • 2020-12-16 09:40

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

    0 讨论(0)
  • 2020-12-16 09:43

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

    >>> import errno
    >>> errno.errorcode[errno.EIDRM]
    'EIDRM'
    
    0 讨论(0)
  • 2020-12-16 09:44

    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.

    0 讨论(0)
  • 2020-12-16 09:47

    There is no standard function to do this in UNIX.

    But I recently wrote the errnoname library that has an errnoname function which does exactly this.

    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 computer 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;
    }
    
    0 讨论(0)
  • 2020-12-16 09:53

    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.

    0 讨论(0)
  • 2020-12-16 10:01

    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.

    0 讨论(0)
提交回复
热议问题