Linux, Convert Errno to Name

Linux, convert errno to name

I recently wrote the errnoname library that has an errnoname function which lets you do this.

There is unfortunately still no standard API to do this.

I try to keep it portable to all systems while covering all errno names on that system. So far that includes Linux, Darwin (macOS, iOS, etc), BSD (FreeBSD, NetBSD, OpenBSD, etc), several closed-source Unixes, Windows, and a few others.

The only "hard" part is getting the list of errno names and values to do the lookups, knowing which errno are even defined on the target system, and exhaustively handling all cases where multiple errno names might map to the same number. (For example, EWOULDBLOCK is equal to EAGAIN on some systems.)

So in my errnoname library you don't have to deal with any of that. I collect the errno names for many operating systems into a list as a separate step, then I generate the actual released C code from that. The C code uses #ifdef for each name, so it can compile on any system regardless of which errno names and values that system has. The compiled result is just simple and efficient code that doesn't have to call any programs or search for errno in library headers.

I also give you the option to compile it as either an array lookup or as a switch, since errno value are not guaranteed to be even close to contiguous, but on many system are contiguous enough to make an array lookup far better. (Although good modern compilers can automatically notice when it would be better to turn a switch into an array lookup.)

Anyway, since it 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.

Below is an old copy-paste of the function from my library, so that this answer is useful even if my repo link ever goes dead, but beware:

  1. The copy here only covers all errno names I could find as of start of August 2019 - I have found many others since then.

  2. I will keep updating the library to include errno names as I find them and as systems add them, add other improvements, and add duplicate protections as possible duplicates are discovered. But I will not (and last I checked, cannot, due to size limits on the answer) keep this answer's copy updated.

#include <errno.h>

char const * errnoname(int errno_)
{
switch(errno_)
{
#ifdef E2BIG
case E2BIG: return "E2BIG";
#endif
#ifdef EACCES
case EACCES: return "EACCES";
#endif
#ifdef EADDRINUSE
case EADDRINUSE: return "EADDRINUSE";
#endif
#ifdef EADDRNOTAVAIL
case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
#endif
#ifdef EADI
case EADI: return "EADI";
#endif
#ifdef EADV
case EADV: return "EADV";
#endif
#ifdef EAFNOSUPPORT
case EAFNOSUPPORT: return "EAFNOSUPPORT";
#endif
#ifdef EAGAIN
case EAGAIN: return "EAGAIN";
#endif
#ifdef EAIO
case EAIO: return "EAIO";
#endif
#ifdef EALIGN
case EALIGN: return "EALIGN";
#endif
#ifdef EALREADY
case EALREADY: return "EALREADY";
#endif
#ifdef EASYNC
case EASYNC: return "EASYNC";
#endif
#ifdef EAUTH
case EAUTH: return "EAUTH";
#endif
#ifdef EBADARCH
case EBADARCH: return "EBADARCH";
#endif
#ifdef EBADE
case EBADE: return "EBADE";
#endif
#ifdef EBADEXEC
case EBADEXEC: return "EBADEXEC";
#endif
#ifdef EBADF
case EBADF: return "EBADF";
#endif
#ifdef EBADFD
case EBADFD: return "EBADFD";
#endif
#ifdef EBADMACHO
case EBADMACHO: return "EBADMACHO";
#endif
#ifdef EBADMSG
case EBADMSG: return "EBADMSG";
#endif
#ifdef EBADR
case EBADR: return "EBADR";
#endif
#ifdef EBADRPC
case EBADRPC: return "EBADRPC";
#endif
#ifdef EBADRQC
case EBADRQC: return "EBADRQC";
#endif
#ifdef EBADSLT
case EBADSLT: return "EBADSLT";
#endif
#ifdef EBADVER
case EBADVER: return "EBADVER";
#endif
#ifdef EBFONT
case EBFONT: return "EBFONT";
#endif
#ifdef EBUSY
case EBUSY: return "EBUSY";
#endif
#ifdef ECANCELED
case ECANCELED: return "ECANCELED";
#endif
#if defined(ECANCELLED) && (!defined(ECANCELED) || ECANCELLED != ECANCELED)
case ECANCELLED: return "ECANCELLED";
#endif
#ifdef ECAPMODE
case ECAPMODE: return "ECAPMODE";
#endif
#ifdef ECHILD
case ECHILD: return "ECHILD";
#endif
#ifdef ECHRNG
case ECHRNG: return "ECHRNG";
#endif
#ifdef ECKPT
case ECKPT: return "ECKPT";
#endif
#ifdef ECLONEME
case ECLONEME: return "ECLONEME";
#endif
#ifdef ECOMM
case ECOMM: return "ECOMM";
#endif
#ifdef ECONFIG
case ECONFIG: return "ECONFIG";
#endif
#ifdef ECONNABORTED
case ECONNABORTED: return "ECONNABORTED";
#endif
#ifdef ECONNREFUSED
case ECONNREFUSED: return "ECONNREFUSED";
#endif
#ifdef ECONNRESET
case ECONNRESET: return "ECONNRESET";
#endif
#ifdef ECORRUPT
case ECORRUPT: return "ECORRUPT";
#endif
#ifdef ECVCERORR
case ECVCERORR: return "ECVCERORR";
#endif
#ifdef ECVPERORR
case ECVPERORR: return "ECVPERORR";
#endif
#ifdef EDEADLK
case EDEADLK: return "EDEADLK";
#endif
#if defined(EDEADLOCK) && (!defined(EDEADLK) || EDEADLOCK != EDEADLK)
case EDEADLOCK: return "EDEADLOCK";
#endif
#ifdef EDESTADDREQ
case EDESTADDREQ: return "EDESTADDREQ";
#endif
#ifdef EDESTADDRREQ
case EDESTADDRREQ: return "EDESTADDRREQ";
#endif
#ifdef EDEVERR
case EDEVERR: return "EDEVERR";
#endif
#ifdef EDIRIOCTL
case EDIRIOCTL: return "EDIRIOCTL";
#endif
#ifdef EDIRTY
case EDIRTY: return "EDIRTY";
#endif
#ifdef EDIST
case EDIST: return "EDIST";
#endif
#ifdef EDOM
case EDOM: return "EDOM";
#endif
#ifdef EDOOFUS
case EDOOFUS: return "EDOOFUS";
#endif
#ifdef EDOTDOT
case EDOTDOT: return "EDOTDOT";
#endif
#ifdef EDQUOT
case EDQUOT: return "EDQUOT";
#endif
#ifdef EDUPFD
case EDUPFD: return "EDUPFD";
#endif
#ifdef EDUPPKG
case EDUPPKG: return "EDUPPKG";
#endif
#ifdef EEXIST
case EEXIST: return "EEXIST";
#endif
#ifdef EFAIL
case EFAIL: return "EFAIL";
#endif
#ifdef EFAULT
case EFAULT: return "EFAULT";
#endif
#ifdef EFBIG
case EFBIG: return "EFBIG";
#endif
#ifdef EFORMAT
case EFORMAT: return "EFORMAT";
#endif
#ifdef EFSCORRUPTED
case EFSCORRUPTED: return "EFSCORRUPTED";
#endif
#ifdef EFTYPE
case EFTYPE: return "EFTYPE";
#endif
#ifdef EHOSTDOWN
case EHOSTDOWN: return "EHOSTDOWN";
#endif
#ifdef EHOSTUNREACH
case EHOSTUNREACH: return "EHOSTUNREACH";
#endif
#ifdef EHWPOISON
case EHWPOISON: return "EHWPOISON";
#endif
#ifdef EIDRM
case EIDRM: return "EIDRM";
#endif
#ifdef EILSEQ
case EILSEQ: return "EILSEQ";
#endif
#ifdef EINIT
case EINIT: return "EINIT";
#endif
#ifdef EINPROG
case EINPROG: return "EINPROG";
#endif
#ifdef EINPROGRESS
case EINPROGRESS: return "EINPROGRESS";
#endif
#ifdef EINTEGRITY
case EINTEGRITY: return "EINTEGRITY";
#endif
#ifdef EINTR
case EINTR: return "EINTR";
#endif
#ifdef EINVAL
case EINVAL: return "EINVAL";
#endif
#ifdef EIO
case EIO: return "EIO";
#endif
#ifdef EIPSEC
case EIPSEC: return "EIPSEC";
#endif
#ifdef EISCONN
case EISCONN: return "EISCONN";
#endif
#ifdef EISDIR
case EISDIR: return "EISDIR";
#endif
#ifdef EISNAM
case EISNAM: return "EISNAM";
#endif
#ifdef EJUSTRETURN
case EJUSTRETURN: return "EJUSTRETURN";
#endif
#ifdef EKEEPLOOKING
case EKEEPLOOKING: return "EKEEPLOOKING";
#endif
#ifdef EKEYEXPIRED
case EKEYEXPIRED: return "EKEYEXPIRED";
#endif
#ifdef EKEYREJECTED
case EKEYREJECTED: return "EKEYREJECTED";
#endif
#ifdef EKEYREVOKED
case EKEYREVOKED: return "EKEYREVOKED";
#endif
#ifdef EL2HLT
case EL2HLT: return "EL2HLT";
#endif
#ifdef EL2NSYNC
case EL2NSYNC: return "EL2NSYNC";
#endif
#ifdef EL3HLT
case EL3HLT: return "EL3HLT";
#endif
#ifdef EL3RST
case EL3RST: return "EL3RST";
#endif
#ifdef ELIBACC
case ELIBACC: return "ELIBACC";
#endif
#ifdef ELIBBAD
case ELIBBAD: return "ELIBBAD";
#endif
#ifdef ELIBEXEC
case ELIBEXEC: return "ELIBEXEC";
#endif
#ifdef ELIBMAX
case ELIBMAX: return "ELIBMAX";
#endif
#ifdef ELIBSCN
case ELIBSCN: return "ELIBSCN";
#endif
#ifdef ELNRNG
case ELNRNG: return "ELNRNG";
#endif
#ifdef ELOCKUNMAPPED
case ELOCKUNMAPPED: return "ELOCKUNMAPPED";
#endif
#ifdef ELOOP
case ELOOP: return "ELOOP";
#endif
#ifdef EMEDIA
case EMEDIA: return "EMEDIA";
#endif
#ifdef EMEDIUMTYPE
case EMEDIUMTYPE: return "EMEDIUMTYPE";
#endif
#ifdef EMFILE
case EMFILE: return "EMFILE";
#endif
#ifdef EMLINK
case EMLINK: return "EMLINK";
#endif
#ifdef EMOUNTEXIT
case EMOUNTEXIT: return "EMOUNTEXIT";
#endif
#ifdef EMOVEFD
case EMOVEFD: return "EMOVEFD";
#endif
#ifdef EMSGSIZE
case EMSGSIZE: return "EMSGSIZE";
#endif
#ifdef EMTIMERS
case EMTIMERS: return "EMTIMERS";
#endif
#ifdef EMULTIHOP
case EMULTIHOP: return "EMULTIHOP";
#endif
#ifdef ENAMETOOLONG
case ENAMETOOLONG: return "ENAMETOOLONG";
#endif
#ifdef ENAVAIL
case ENAVAIL: return "ENAVAIL";
#endif
#ifdef ENEEDAUTH
case ENEEDAUTH: return "ENEEDAUTH";
#endif
#ifdef ENETDOWN
case ENETDOWN: return "ENETDOWN";
#endif
#ifdef ENETRESET
case ENETRESET: return "ENETRESET";
#endif
#ifdef ENETUNREACH
case ENETUNREACH: return "ENETUNREACH";
#endif
#ifdef ENFILE
case ENFILE: return "ENFILE";
#endif
#ifdef ENFSREMOTE
case ENFSREMOTE: return "ENFSREMOTE";
#endif
#ifdef ENOANO
case ENOANO: return "ENOANO";
#endif
#ifdef ENOATTR
case ENOATTR: return "ENOATTR";
#endif
#ifdef ENOBUFS
case ENOBUFS: return "ENOBUFS";
#endif
#ifdef ENOCONNECT
case ENOCONNECT: return "ENOCONNECT";
#endif
#ifdef ENOCSI
case ENOCSI: return "ENOCSI";
#endif
#ifdef ENODATA
case ENODATA: return "ENODATA";
#endif
#ifdef ENODEV
case ENOEXEC: return "ENOEXEC";
#endif
#ifdef ENOIOCTL
case ENOIOCTL: return "ENOIOCTL";
#endif
#ifdef ENOKEY
case ENOKEY: return "ENOKEY";
#endif
#ifdef ENOLCK
case ENOLCK: return "ENOLCK";
#endif
#ifdef ENOLINK
case ENOLINK: return "ENOLINK";
#endif
#ifdef ENOLOAD
case ENOLOAD: return "ENOLOAD";
#endif
#ifdef ENOMATCH
case ENOMATCH: return "ENOMATCH";
#endif
#ifdef ENOMEDIUM
case ENOMEDIUM: return "ENOMEDIUM";
#endif
#ifdef ENOMEM
case ENOMEM: return "ENOMEM";
#endif
#ifdef ENOMSG
case ENOMSG: return "ENOMSG";
#endif
#ifdef ENONET
case ENONET: return "ENONET";
#endif
#ifdef ENOPKG
case ENOPKG: return "ENOPKG";
#endif
#ifdef ENOPOLICY
case ENOPOLICY: return "ENOPOLICY";
#endif
#ifdef ENOPROTOOPT
case ENOPROTOOPT: return "ENOPROTOOPT";
#endif
#ifdef ENOREG
case ENOREG: return "ENOREG";
#endif
#ifdef ENOSPC
case ENOSPC: return "ENOSPC";
#endif
#ifdef ENOSR
case ENOSR: return "ENOSR";
#endif
#ifdef ENOSTR
case ENOSTR: return "ENOSTR";
#endif
#ifdef ENOSYM
case ENOSYM: return "ENOSYM";
#endif
#ifdef ENOSYS
case ENOSYS: return "ENOSYS";
#endif
#ifdef ENOTACTIVE
case ENOTACTIVE: return "ENOTACTIVE";
#endif
#ifdef ENOTBLK
case ENOTBLK: return "ENOTBLK";
#endif
#ifdef ENOTCAPABLE
case ENOTCAPABLE: return "ENOTCAPABLE";
#endif
#ifdef ENOTCONN
case ENOTCONN: return "ENOTCONN";
#endif
#ifdef ENOTDIR
case ENOTDIR: return "ENOTDIR";
#endif
#ifdef ENOTEMPTY
case ENOTEMPTY: return "ENOTEMPTY";
#endif
#ifdef ENOTNAM
case ENOTNAM: return "ENOTNAM";
#endif
#ifdef ENOTREADY
case ENOTREADY: return "ENOTREADY";
#endif
#ifdef ENOTRECOVERABLE
case ENOTRECOVERABLE: return "ENOTRECOVERABLE";
#endif
#ifdef ENOTRUST
case ENOTRUST: return "ENOTRUST";
#endif
#ifdef ENOTSOCK
case ENOTSOCK: return "ENOTSOCK";
#endif
#ifdef ENOTSUP
case ENOTSUP: return "ENOTSUP";
#endif
#ifdef ENOTTY
case ENOTTY: return "ENOTTY";
#endif
#ifdef ENOTUNIQ
case ENOTUNIQ: return "ENOTUNIQ";
#endif
#ifdef ENOUNLD
case ENOUNLD: return "ENOUNLD";
#endif
#ifdef ENOUNREG
case ENOUNREG: return "ENOUNREG";
#endif
#ifdef ENXIO
case ENXIO: return "ENXIO";
#endif
#ifdef EOPCOMPLETE
case EOPCOMPLETE: return "EOPCOMPLETE";
#endif
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || EOPNOTSUPP != ENOTSUP)
case EOPNOTSUPP: return "EOPNOTSUPP";
#endif
#ifdef EOVERFLOW
case EOVERFLOW: return "EOVERFLOW";
#endif
#ifdef EOWNERDEAD
case EOWNERDEAD: return "EOWNERDEAD";
#endif
#ifdef EPASSTHROUGH
case EPASSTHROUGH: return "EPASSTHROUGH";
#endif
#ifdef EPATHREMOTE
case EPATHREMOTE: return "EPATHREMOTE";
#endif
#ifdef EPERM
case EPERM: return "EPERM";
#endif
#ifdef EPFNOSUPPORT
case EPFNOSUPPORT: return "EPFNOSUPPORT";
#endif
#ifdef EPIPE
case EPIPE: return "EPIPE";
#endif
#ifdef EPOWERF
case EPOWERF: return "EPOWERF";
#endif
#ifdef EPROCLIM
case EPROCLIM: return "EPROCLIM";
#endif
#ifdef EPROCUNAVAIL
case EPROCUNAVAIL: return "EPROCUNAVAIL";
#endif
#ifdef EPROGMISMATCH
case EPROGMISMATCH: return "EPROGMISMATCH";
#endif
#ifdef EPROGUNAVAIL
case EPROGUNAVAIL: return "EPROGUNAVAIL";
#endif
#ifdef EPROTO
case EPROTO: return "EPROTO";
#endif
#ifdef EPROTONOSUPPORT
case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
#endif
#ifdef EPROTOTYPE
case EPROTOTYPE: return "EPROTOTYPE";
#endif
#ifdef EPWROFF
case EPWROFF: return "EPWROFF";
#endif
#ifdef EQFULL
case EQFULL: return "EQFULL";
#endif
#ifdef EQSUSPENDED
case EQSUSPENDED: return "EQSUSPENDED";
#endif
#ifdef ERANGE
case ERANGE: return "ERANGE";
#endif
#ifdef ERECYCLE
case ERECYCLE: return "ERECYCLE";
#endif
#ifdef EREDRIVEOPEN
case EREDRIVEOPEN: return "EREDRIVEOPEN";
#endif
#ifdef EREFUSED
case EREFUSED: return "EREFUSED";
#endif
#ifdef ERELOC
case ERELOC: return "ERELOC";
#endif
#ifdef ERELOCATED
case ERELOCATED: return "ERELOCATED";
#endif
#ifdef ERELOOKUP
case ERELOOKUP: return "ERELOOKUP";
#endif
#ifdef EREMCHG
case EREMCHG: return "EREMCHG";
#endif
#ifdef EREMDEV
case EREMDEV: return "EREMDEV";
#endif
#ifdef EREMOTE
case EREMOTE: return "EREMOTE";
#endif
#ifdef EREMOTEIO
case EREMOTEIO: return "EREMOTEIO";
#endif
#ifdef EREMOTERELEASE
case EREMOTERELEASE: return "EREMOTERELEASE";
#endif
#ifdef ERESTART
case ERESTART: return "ERESTART";
#endif
#ifdef ERFKILL
case ERFKILL: return "ERFKILL";
#endif
#ifdef EROFS
case EROFS: return "EROFS";
#endif
#ifdef ERPCMISMATCH
case ERPCMISMATCH: return "ERPCMISMATCH";
#endif
#ifdef ESAD
case ESAD: return "ESAD";
#endif
#ifdef ESHLIBVERS
case ESHLIBVERS: return "ESHLIBVERS";
#endif
#ifdef ESHUTDOWN
case ESHUTDOWN: return "ESHUTDOWN";
#endif
#ifdef ESOCKTNOSUPPORT
case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
#endif
#ifdef ESOFT
case ESOFT: return "ESOFT";
#endif
#ifdef ESPIPE
case ESPIPE: return "ESPIPE";
#endif
#ifdef ESRCH
case ESRCH: return "ESRCH";
#endif
#ifdef ESRMNT
case ESRMNT: return "ESRMNT";
#endif
#ifdef ESTALE
case ESTALE: return "ESTALE";
#endif
#ifdef ESTART
case ESTART: return "ESTART";
#endif
#ifdef ESTRPIPE
case ESTRPIPE: return "ESTRPIPE";
#endif
#ifdef ESYSERROR
case ESYSERROR: return "ESYSERROR";
#endif
#ifdef ETIME
case ETIME: return "ETIME";
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT: return "ETIMEDOUT";
#endif
#ifdef ETOOMANYREFS
case ETOOMANYREFS: return "ETOOMANYREFS";
#endif
#ifdef ETXTBSY
case ETXTBSY: return "ETXTBSY";
#endif
#ifdef EUCLEAN
case EUCLEAN: return "EUCLEAN";
#endif
#ifdef EUNATCH
case EUNATCH: return "EUNATCH";
#endif
#ifdef EUSERS
case EUSERS: return "EUSERS";
#endif
#ifdef EVERSION
case EVERSION: return "EVERSION";
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK: return "EWOULDBLOCK";
#endif
#ifdef EWRONGFS
case EWRONGFS: return "EWRONGFS";
#endif
#ifdef EWRPROTECT
case EWRPROTECT: return "EWRPROTECT";
#endif
#ifdef EXDEV
case EXDEV: return "EXDEV";
#endif
#ifdef EXFULL
case EXFULL: return "EXFULL";
#endif
}
return 0;
}

How to convert errno in UNIX to corresponding string?

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.

Is there a function that will return a symbol name, such as `EIO`, for an `errno` value?

I very much doubt that pure POSIX provides facilities to accomplish that in a portable fashion. In most cases I personally just open the /usr/include/errno.h file in editor and browse it from there. (On Linux that eventually leads to /usr/include/asm-generic/errno-base.h and /usr/include/asm-generic/errno.h files where the codes are actually specified.)

Also, for systems with GCC (or clang), I could come up with the scriptlet like this:

gcc -dM -E - < /usr/include/errno.h  |
grep 'define E\w\+ [0-9]\+$' |
sort -k3 -n

The GNU preprocessor has an option (-dM) to print all defines it encounters to the output. That can be used to help parse the /usr/include/errno.h file to extract the error codes.

How to know what the 'errno' means?

You can use strerror() to get a human-readable string for the error number. This is the same string printed by perror() but it's useful if you're formatting the error message for something other than standard error output.

For example:

#include <errno.h>
#include <string.h>

/* ... */

if(read(fd, buf, 1)==-1) {
printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
}

Linux also supports the explicitly-threadsafe variant strerror_r().

Convert errno to exit codes

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

How to check the value of errno?

I assume you are using Linux, and I suppose that you don't directly use the system call, but some of the (simple) wrappers (from your C library) listed in syscalls(2). Notice that some weird system calls are not wrapped by the C library (a well known example of unwrapped system call would be sigreturn(2) which you probably should never use). Quite often the C library is GNU glibc, but it might be musl-libc etc. Notice also that kernel raw system calls have different calling conventions than ordinary C function (so in practice a libc wrapper is required, and is in charge of dealing with errno). Notice also that errno(3) is generally a macro (almost behaving as some variable).

The msgrcv(2) man page documents that errno could be one of E2BIG, EACCES , EFAULT ... ENOMSG, ENOSYS ... (refer to that man page to get the list of all possible errors).

So you would code something like

ssize_t siz = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
if (siz<0) { // msgrcv failed and has set errno
if (errno == ENOMSG)
dosomething();
else if (errno == EAGAIN)
dosomethingelse();
/// etc
else {
syslog(LOG_DAEMON|LOG_ERR, "msgrcv failure with %s\n",
strerror(errno));
exit(EXIT_FAILURE);
};
};

Is the statement if (errno == ENOMSG) .... valid?

Yes it is; you want to test errno only after some system call failure (e.g. when siz<0).

Is there such a variable errno?

Not any more. Please read carefully errno(3) documentation. You should not declare extern int errno; (this was possible in the 1980s, not in 21st century) but you should always #include <errno.h> and use errno as if it was a variable, but it is almost always some macro (whose definition appears in /usr/include/bits/errno.h which is included by /usr/include/errno.h).

BTW, SysV-style facilities tend to become obsolete and are not always available. I recommend using POSIX message queues facilities, read mq_overview(7).

You might want to read the freely downloadable Advanced Linux Programming (an old book; you can buy something better & newer) and/or all the man pages reachable from intro(2) & syscalls(2) & intro(3).

Symbolic errno to String

AFAIK, there isn't a standard tool that does the job. At one level, it wouldn't be particularly hard to write one - the messiest parts are finding the correct file to parse (is is often, but by no means always, /usr/include/sys/errno.h) and then taking the data from that to do the mapping of names to numbers. I have not found a system that uses enum values rather than #define values, but it is probably only a matter of time. It is also a moot point whether to generate a triple consisting of token number (EINTR, etc), token name ("EINTR", etc) and error message ("Interrupted system call", etc), or whether to use just the number and name and leave it to 'strerror()' to supply the message.


As I said, it isn't particularly hard. I already had a program called 'errno' that accepted pure numeric values and printed the corresponding error messages:

$ errno 1:10 20
1: Operation not permitted
2: No such file or directory
3: No such process
4: Interrupted system call
5: Input/output error
6: Device not configured
7: Argument list too long
8: Exec format error
9: Bad file descriptor
10: No child processes
20: Not a directory
$

I've written a Perl script and hacked the program to handle symbolic error numbers too:

$ errno 1:4 EINTR ENOTDIR
1 (EPERM): Operation not permitted
2 (ENOENT): No such file or directory
3 (ESRCH): No such process
4 (EINTR): Interrupted system call
EINTR (4): Interrupted system call
ENOTDIR (20): Not a directory
$

It does not handle ranges of symbolic error numbers (exercise for the reader).

generrno.pl

#!/usr/bin/perl -w
#
# @(#)$Id: generrno.pl,v 1.1 2010/02/07 18:39:18 jleffler Exp jleffler $
#
# Generate table of error number constants from given file(s)

use strict;

my %symlist;
my $maxsymlen = 0;
my $maxmsglen = 0;

while (<>)
{
next unless m%^\s*#\s*define\s+(E[A-Z0-9a-z]+)\s+(\d+)\s*/\*\s*([A-Za-z].*\S)\s*\*/%;
$symlist{$1} = { number => $2, message => $3 };
$maxsymlen = length($1) if length($1) > $maxsymlen;
$maxmsglen = length($3) if length($3) > $maxmsglen;
}

my $format = sprintf " { %%-%ds %%-%ds %%-5s %%-%ds },\n", $maxsymlen + 3, $maxsymlen + 1, $maxmsglen + 2;

foreach my $key (sort keys %symlist)
{
my $name = qq{"$key",};
my $symbol = qq{$key,};
my $number = qq{$symlist{$key}->{number},};
my $message = qq{"$symlist{$key}->{message}"};

printf $format, $name, $symbol, $number, $message;
}

errno.c

/*
@(#)File: $RCSfile: errno.c,v $
@(#)Version: $Revision: 2.2 $
@(#)Last changed: $Date: 2010/02/07 19:22:37 $
@(#)Purpose: Print messages corresponding to errno values or name
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 2003,2005,2008,2010
*/

/*TABSTOP=4*/

#define MAIN_PROGRAM

/* Need O/S specific messages as well as POSIX messages */
//#if __STDC_VERSION__ >= 199901L
//#define _XOPEN_SOURCE 600
//#else
//#define _XOPEN_SOURCE 500
//#endif /* __STDC_VERSION__ */

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* getopt() on MacOS X 10.2 */
#include "stderr.h"
#include "range.h"

typedef struct err_info
{
const char *errsym; /* Error symbol - "EINTR" */
int errnum; /* Error number - EINTR */
int errdef; /* Error define - 4 */
const char *errmsg; /* Error message - Interrupted system call */
} err_info;

/*
** Generate generrno.h using:
** perl generrno.pl /usr/include/sys/errno.h > generrno.h
** NB: list must be sorted alphabetically on symbol name
*/
static const err_info err_msgs[] =
{
#include "generrno.h"
};

static const char usestr[] = "[-qV] [--] lo[:hi] ...";

#define DIM(x) (sizeof(x)/sizeof(*(x)))

static const err_info *err_nums[DIM(err_msgs)];

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_errno_c[] = "@(#)$Id: errno.c,v 2.2 2010/02/07 19:22:37 jleffler Exp $";
#endif /* lint */

static int cmp_err_number(const void *v1, const void *v2)
{
int e1 = (*((const err_info * const *)v1))->errnum;
int e2 = (*((const err_info * const *)v2))->errnum;
return(e1 - e2);
}

static void map_numbers(void)
{
int i;

for (i = 0; i < DIM(err_msgs); i++)
err_nums[i] = &err_msgs[i];
qsort(err_nums, DIM(err_nums), sizeof(*err_nums), cmp_err_number);
}

static const char *err_symbol(int num)
{
const char *sym = "<UNKNOWN>";
err_info lookfor = { 0, num, 0, 0 };
err_info *lookptr = &lookfor;
const err_info **found = bsearch(&lookptr, err_nums, DIM(err_nums), sizeof(*err_nums), cmp_err_number);
if (found != 0)
sym = (*found)->errsym;
return(sym);
}


Related Topics



Leave a reply



Submit