12.2. Error Handling: perror ()Most system calls are capable of failing in some way. For example, the open () system call will fail if you try to open a nonexistent file for reading. By convention, all system calls return -1 if an error occurs. However, this doesn't tell you much about why the error occurred; the open () system call can fail for one of several different reasons. If you want to deal with system call errors in a systematic way, you must know about two things:
Every process contains a global variable called errno, which is originally set to zero when the process is created. When a system call error occurs, errno is set to the numeric code associated with the cause of the error. For example, if you try to open a file that doesn't exist for reading, errno is set to 2. These predefined error codes are defined in a C program by including the file "/usr/include/errno.h" (which itself includes other platform-specific files). The names of the error codes are also listed in the errno man page. Here's a snippet of the file "/usr/include/asm/errno.h" on my system, where the error constants are defined: #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 */ The value of errno only has a meaning following an unsuccessful system call which overwrites the current value of errno. A successful system call is not guaranteed to leave errno unmodified (as it is in some versions of UNIX). To access errno from your program, include <errno.h>. The perror () subroutine converts the current value of errno into a text description (Figure 12-4).
Your program should check system calls for a return value of -1 and then deal with the error. One of the first things to do in these situations, especially during debugging, is to call perror () for a description of the error. In the following example, I forced a couple of system call errors to demonstrate perror (), and then demonstrated that errno did not retain the last system call error code after a subsequent successful call was made. Don't worry about how open () works; I'll describe it later in this chapter. $ cat showErrno.c #include <stdio.h> #include <fcntl.h> #include <errno.h> main () { int fd; /* Open a nonexistent file to cause an error */ fd = open ("nonexist.txt", O_RDONLY); if (fd == -1) /* fd == -1 =, an error occurred */ { printf ("errno = %d\n", errno); perror ("main"); } fd = open ("/", O_WRONLY); /* Force a different error */ if (fd == -1) { printf ("errno = %d\n", errno); perror ("main"); } /* Execute a successful system call */ fd = open ("nonexist.txt", O_RDONLY | O_CREAT, 0644); printf ("errno = %d\n", errno); /* Display after successful call */ perror ("main"); errno = 0; /* Manually reset error variable */ perror ("main"); } Here's the output from the program shown above: $ ./showErrno ...run the program. errno = 2 main: No such file or directory errno = 21 main: Is a directory errno = 29 ...even after a successful call main: Illegal seek main: Success ...after we reset manually. $ _ |