How to check the value of errno?

前端 未结 3 786
野性不改
野性不改 2020-12-09 21:44

I am using a system call and in case it fails, I need to do different things for different errnos.

I need to write code that looks something like this:



        
相关标签:
3条回答
  • 2020-12-09 22:29

    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).

    0 讨论(0)
  • 2020-12-09 22:33

    How to check the value of errno:

    1. You will need to #include <errno.h>.
    2. Yes, you can definitely say things like if(errno == ENOENT) { ... }, and that is the common and recommended way of doing it.
    3. In general, do not use errno to determine that an error has occurred. Check the return value of the function, and if the return value indicates an error, then check errno to see what the error was. (More on this below.)
    4. errno looks like a variable, but it actually isn't. This doesn't concern you as long as you just say things like if(errno == ENOENT) { ... }. But you probably shouldn't try to do something like int errno_ptr = &errno;.
    5. You can use functions like perror() and strerror() to get human-readable error strings corresponding to errno values. But, yes, the strings you get are generally things like "No such file or directory". There is no good way that I know of to convert the errno value ENOENT to the string "ENOENT".

    To say a little more about #3. Sometimes it's tempting to say something like

    errno = 0;
    printf("Hello, world!\n");
    if(errno != 0) {
        fprintf(stderr, "printf failed!\n");
    }
    

    But don't do that. Instead do

    errno = 0;
    int retval = printf("Hello, world!\n");
    if(retval < 0) {
        fprintf(stderr, "printf failed!\n");
    }
    

    The reason is that, somewhere in the process of doing its job, printf might have done something that resulted in an error, something that set errno, but printf might have recovered from that error and gone on to complete successfully.

    There are a very few library functions that are guaranteed not to touch errno if there wasn't an error (I think one example might be atoi), but in general, this is something you have to be careful of.

    To say a little more about #4. errno looks like a variable, and more specifically, it looks like a global variable. But of course global variables are bad. But errno has been around forever; there are tens of millions of lines of code that use it; it's still basically pretty convenient; it's too late to "fix" it. So, instead, if you peek behind the curtain, you'll find that most implementations do something like

    extern int __errno_pointer;
    #define errno (*__errno_pointer)
    

    or

    extern int *__errno_pointer_function();
    #define errno (*__errno_function())
    

    In this way, they can arrange for errno to work reasonably properly even in, say, multithreaded code.

    0 讨论(0)
  • 2020-12-09 22:33

    Include errno.h

    Some examples:

    // Error codes
    #define EPERM        1  /* Operation not permitted */
    #define ENOENT       2  /* No such file or directory */
    #define ESRCH        3  /* No such process */
    #define EINTR        4  /* Interrupted system call */
    #define EIO          5  /* I/O error */
    #define ENXIO        6  /* No such device or address */
    #define E2BIG        7  /* Argument list too long */
    #define ENOEXEC      8  /* Exec format error */
    #define EBADF        9  /* Bad file number */
    #define ECHILD      10  /* No child processes */
    #define EAGAIN      11  /* Try again */
    #define ENOMEM      12  /* Out of memory */
    #define EACCES      13  /* Permission denied */
    #define EFAULT      14  /* Bad address */
    #define ENOTBLK     15  /* Block device required */
    #define EBUSY       16  /* Device or resource busy */
    #define EEXIST      17  /* File exists */
    #define EXDEV       18  /* Cross-device link */
    #define ENODEV      19  /* No such device */
    #define ENOTDIR     20  /* Not a directory */
    #define EISDIR      21  /* Is a directory */
    #define EINVAL      22  /* Invalid argument */
    #define ENFILE      23  /* File table overflow */
    #define EMFILE      24  /* Too many open files */
    #define ENOTTY      25  /* Not a typewriter */
    #define ETXTBSY     26  /* Text file busy */
    #define EFBIG       27  /* File too large */
    #define ENOSPC      28  /* No space left on device */
    #define ESPIPE      29  /* Illegal seek */
    #define EROFS       30  /* Read-only file system */
    #define EMLINK      31  /* Too many links */
    #define EPIPE       32  /* Broken pipe */
    #define EDOM        33  /* Math argument out of domain of func */
    #define ERANGE      34  /* Math result not representable */
    

    Your implementation may have more errno includes, like for example /usr/include/asm-generic/errno.h.

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