B.2 Standard Error RoutinesTwo sets of error functions are used in most of the examples throughout the text to handle error conditions. One set begins with err_ and outputs an error message to standard error. The other set begins with log_ and is for daemon processes (Chapter 13) that probably have no controlling terminal. The reason for our own error functions is to let us write our error handling with a single line of C code, as in if (error condition) err_dump(printf format with any number of arguments); instead of if (error condition){ char buf[200]; sprintf(buf, printf format with any number of arguments); perror(buf); abort(); } Our error functions use the variable-length argument list facility from ISO C. See Section 7.3 of Kernighan and Ritchie [1988] for additional details. Be aware that this ISO C facility differs from the varargs facility provided by earlier systems (such as SVR3 and 4.3BSD). The names of the macros are the same, but the arguments to some of the macros have changed. Figure B.2 summarizes the differences between the various error functions.
Figure B.3 shows the error functions that output to standard error. Figure B.3. Error functions that output to standard error#include "apue.h" #include <errno.h> /* for definition of errno */ #include <stdarg.h> /* ISO C variable aruments */ static void err_doit(int, int, const char *, va_list); /* * Nonfatal error related to a system call. * Print a message and return. */ void err_ret(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, errno, fmt, ap); va_end(ap); } /* * Fatal error related to a system call. * Print a message and terminate. */ void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, errno, fmt, ap); va_end(ap); exit(1); } /* * Fatal error unrelated to a system call. * Error code passed as explict parameter. * Print a message and terminate. */ void err_exit(int error, const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, error, fmt, ap); va_end(ap); exit(1); } /* * Fatal error related to a system call. * Print a message, dump core, and terminate. */ void err_dump(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, errno, fmt, ap); va_end(ap); abort(); /* dump core and terminate */ exit(1); /* shouldn't get here */ } /* * Nonfatal error unrelated to a system call. * Print a message and return. */ void err_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, 0, fmt, ap); va_end(ap); } /* * Fatal error unrelated to a system call. * Print a message and terminate. */ void err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, 0, fmt, ap); va_end(ap); exit(1); } /* * Print a message and return to caller. * Caller specifies "errnoflag". */ static void err_doit(int errnoflag, int error, const char *fmt, va_list ap) { char buf[MAXLINE]; vsnprintf(buf, MAXLINE, fmt, ap); if (errnoflag) snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s", strerror(error)); strcat(buf, "\n"); fflush(stdout); /* in case stdout and stderr are the same */ fputs(buf, stderr); fflush(NULL); /* flushes all stdio output streams */ } Figure B.4 shows the log_XXX error functions. These require the caller to define the variable log_to_stderr and set it nonzero if the process is not running as a daemon. In this case, the error messages are sent to standard error. If the log_to_stderr flag is 0, the syslog facility (Section 13.4) is used. Figure B.4. Error functions for daemons/* * Error routines for programs that can run as a daemon. */ #include "apue.h" #include <errno.h> /* for definition of errno */ #include <stdarg.h> /* ISO C variable arguments */ #include <syslog.h> static void log_doit(int, int, const char *, va_list ap); /* * Caller must define and set this: nonzero if * interactive, zero if daemon */ extern int log_to_stderr; /* * Initialize syslog(), if running as daemon. */ void log_open(const char *ident, int option, int facility) { if (log_to_stderr == 0) openlog(ident, option, facility); } /* * Nonfatal error related to a system call. * Print a message with the system's errno value and return. */ void log_ret(const char *fmt, ...) { va_list ap; va_start(ap, fmt); log_doit(1, LOG_ERR, fmt, ap); va_end(ap); } /* * Fatal error related to a system call. * Print a message and terminate. */ void log_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); log_doit(1, LOG_ERR, fmt, ap); va_end(ap); exit(2); } /* * Nonfatal error unrelated to a system call. * Print a message and return. */ void log_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); log_doit(0, LOG_ERR, fmt, ap); va_end(ap); } /* * Fatal error unrelated to a system call. * Print a message and terminate. */ void log_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); log_doit(0, LOG_ERR, fmt, ap); va_end(ap); exit(2); } /* * Print a message and return to caller. * Caller specifies "errnoflag" and "priority". */ static void log_doit(int errnoflag, int priority, const char *fmt, va_list ap) { int errno_save; char buf[MAXLINE]; errno_save = errno; /* value caller might want printed */ vsnprintf(buf, MAXLINE, fmt, ap); if (errnoflag) snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s", strerror(errno_save)); strcat(buf, "\n"); if (log_to_stderr) { fflush(stdout); fputs(buf, stderr); fflush(stderr); } else { syslog(priority, buf); } } |