Search code examples
c++linuxerror-handlingerrnoqnx

Convert errno to exit codes


I'm working on lib which uses a lot of file system functions.

What I want is that my function returns various of error codes (not just -1 as error) depending on errno in case file system function fails.

Although I could use errno values directly but I want to create some abstraction layer between my functions error codes and system errno (e.g. my error values begins on -1000 and are negative whereas errno values are positive).

My question what is the best way to implement it.

For now I see two possible solution:

  1. use an enum with error codes and switch case function to translate, e.g.:
    typedef enum {
    MY_ERROR_EPERM  = -1104,  /* Operation not permitted                  */
    MY_ERROR_ENOENT = -1105,  /* No such file or directory                */
//  ...
    } MyReturnCodes_t;
int ErrnoToErrCode(unsigned int sysErrno) {
        int error = ENOSYS;
        switch(sysErrno) {
        case EPERM: error = MY_ERROR_EPERM; break;
        case ENOENT: error = MY_ERROR_ENOENT; break;
//      ...
        }
        return error;
}
  1. use translation directly in enum:
#define ERR_OFFSET -1000
typedef enum {
    MY_ERROR_EPERM  = ERR_OFFSET - EPERM,   /* Operation not permitted   */
    MY_ERROR_ENOENT = ERR_OFFSET - ENOENT,  /* No such file or directory */
    MY_ERROR_ESRCH  = ERR_OFFSET - ESRCH,   /* No such process           */
 //  ...
} MyReturnCodes_t;

Which way is more constant?

One more point: This library should be used both on QNX and Linux OS, what is the proper way to align errno codes (which different in some cases)?


Solution

  • I´d go for a std::map in a dedicated function. You don't have to care about gaps or anything as long as you use the provided error macros:

    #include <iostream>
    #include <errno.h>
    #include <map>
    
    namespace MyError
    {
        
    enum MyReturnCode: int 
    {
        MY_INVALID_VAL  = 0    ,  /* Invalid Mapping                          */
        MY_ERROR_EPERM  = -1104,  /* Operation not permitted                  */
        MY_ERROR_ENOENT = -1105,  /* No such file or directory                */
    };
    
    MyReturnCode fromErrno(int e)
    {
        static const std::map<int, MyReturnCode> mapping {
            { EPERM, MY_ERROR_EPERM},
            { ENOENT, MY_ERROR_ENOENT}
        };
        
        if(mapping.count(e))
            return mapping.at(e);
        else
            return MY_INVALID_VAL;
    }
    
    }
    
    int main()
    {
        std::cout << MyError::fromErrno(ENOENT) << std::endl;
        std::cout << MyError::fromErrno(42) << std::endl;
    
        return 0;
    }
    

    http://coliru.stacked-crooked.com/a/1da9fd44d88fb097