Sunday, August 3, 2014

Unix Prog: Unix System Overview - Error Handling

1. errno

Whenever a system call failed, it will return the related code to indicate the error, also, it will setup the errno to a corresponding value.

errno definition in ubuntu:
1) Open the /usr/include/errno.h, define errno as l-value integer
2) Open the bits/errno.h, provide the support for multithreading, then forward to linux/errno.h
3) Open the linux/errno.h, it includes asm/errno.h
4) Open the asm/errno.h, it includes asm-generic/errno.h
5) Open the asm-generic/errno.h, it includes the whole list of errno information.
 ubuntu@ip-172-31-23-227:~$ less /usr/include/errno.h  
   
 ......  
   
 /* Get the error number constants from the system-specific file.  
   This file will test __need_Emath and _ERRNO_H. */  
 #include <bits/errno.h>  
 #undef __need_Emath  
   
 #ifdef _ERRNO_H  
   
 /* Declare the `errno' variable, unless it's defined as a macro by  
   bits/errno.h. This is the case in GNU, where it is a per-thread  
   variable. This redeclaration using the macro still works, but it  
   will be a function declaration without a prototype and may trigger  
   a -Wstrict-prototypes warning. */  
 #ifndef errno  
 extern int errno;  
 #endif  
   
 ......  
   
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/errno.h  
   
 ......  
   
 # include <linux/errno.h>  
   
 ......  
   
 /* Function to get address of global `errno' variable. */  
 extern int *__errno_location (void) __THROW __attribute__ ((__const__));  
   
 # if !defined _LIBC || defined _LIBC_REENTRANT  
 /* When using threads, errno is a per-thread value. */  
 #  define errno (*__errno_location ())  
 # endif  
 # endif /* !__ASSEMBLER__ */  
 #endif /* _ERRNO_H */  
   
 ......  
   
 ubuntu@ip-172-31-23-227:~$ less /usr/include/linux/errno.h  
 #include <asm/errno.h>  
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/asm/errno.h  
 #include <asm-generic/errno.h>  
 ubuntu@ip-172-31-23-227:~$ less /usr/include/asm-generic/errno.h  
 #ifndef _ASM_GENERIC_ERRNO_H  
 #define _ASM_GENERIC_ERRNO_H  
   
 #include <asm-generic/errno-base.h>  
   
 #define EDEADLK     35   /* Resource deadlock would occur */  
 #define ENAMETOOLONG  36   /* File name too long */  
 #define ENOLCK     37   /* No record locks available */  
 #define ENOSYS     38   /* Function not implemented */  
 #define ENOTEMPTY    39   /* Directory not empty */  
 #define ELOOP      40   /* Too many symbolic links encountered */  
 #define EWOULDBLOCK   EAGAIN /* Operation would block */  
 #define ENOMSG     42   /* No message of desired type */  
 #define EIDRM      43   /* Identifier removed */  
 #define ECHRNG     44   /* Channel number out of range */  
 ......  

Unix doesn't provide the facility to clear up errno information, so errno could only be read right after making the system call.

2. Print out the description related with errno
errinfo.c:
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <string.h>  
 #include <errno.h>  
   
 int main(int argc, char* argv[])  
 {  
  // Use strerror to return a string(char*), which is a description  
  // of EACCES and ENOENT code.  
  printf("EACCES: %s\n", strerror(EACCES));  
  printf("ENOENT: %s\n", strerror(ENOENT));  
   
  // perror will read the global variable errno's value, it will  
  // output the string specified by its argument then followed by  
  // description of error code in "errno"  
  errno = EDEADLK;  
  perror(argv[0]);  
  exit(0);  
 }  

shell:
It will firstly output the description string for EACCES
Then output the description string for ENOENT
Finally the description string for EDEADLK
 ubuntu@ip-172-31-23-227:~$ ./errinfo.out  
 EACCES: Permission denied  
 ENOENT: No such file or directory  
 ./errinfo.out: Resource deadlock avoided  

Explanation:
EACCESS and ENOENT and EDEADLK are defined at asm-generic/errno.h, which is described above. strerrror is defined at "string.h", perror is defined at "stdio.h"
 ubuntu@ip-172-31-23-227:~$ less /usr/include/stdio.h

 ......

 __BEGIN_NAMESPACE_STD  
 /* Print a message describing the meaning of the value of errno.  
   
   This function is a possible cancellation point and therefore not  
   marked with __THROW. */  
 extern void perror (const char *__s);  
 __END_NAMESPACE_STD  

 ......

 ubuntu@ip-172-31-23-227:~$ less /usr/include/string.h

 ......

 __BEGIN_NAMESPACE_STD
 /* Return a string describing the meaning of the `errno' code in ERRNUM.  */
 extern char *strerror (int __errnum) __THROW;
 __END_NAMESPACE_STD

 ......

errno can be categorized into: fatal error and non-fatal error.
fatal error: normally system will print out a message and terminate the process.
non-fatal error: normally system will delay for a while and try again.

No comments:

Post a Comment