/************************************************************************** Copyright (C) Michael Kerrisk, 2014. * * * * This program is free software. You may use, modify, and redistribute it * * under the terms of the GNU Lesser General Public License as published * * by the Free Software Foundation, either version 3 or (at your option) * * any later version. This program is distributed without any warranty. * * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * \*************************************************************************/ /* error_functions.c Some standard error handling routines used by various programs. */ #include <stdarg.h> #include "error_functions.h" #include "tlpi_hdr.h" #include "ename.c.inc" /* Defines ename and MAX_ENAME */ #ifdef __GNUC__ /* Prevent ‘gcc -Wall‘ complaining */ __attribute__ ((__noreturn__)) /* if we call this function as last */ #endif /* statement in a non-void function */ static void terminate(Boolean useExit3) { char *s; /* Dump core if EF_DUMPCORE environment variable is defined and is a nonempty string; otherwise call exit(3) or _exit(2), depending on the value of ‘useExit3‘. */ s = getenv("EF_DUMPCORE"); if (s != NULL && *s != ‘\0‘) abort(); else if (useExit3) exit(EXIT_FAILURE); else _exit(EXIT_FAILURE); } /* Diagnose ‘errno‘ error by: * outputting a string containing the error name (if available in ‘ename‘ array) corresponding to the value in ‘err‘, along with the corresponding error message from strerror(), and * outputting the caller-supplied error message specified in ‘format‘ and ‘ap‘. */ static void outputError(Boolean useErr, int err, Boolean flushStdout, const char *format, va_list ap) { #define BUF_SIZE 500 char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE]; vsnprintf(userMsg, BUF_SIZE, format, ap); if (useErr) snprintf(errText, BUF_SIZE, " [%s %s]", (err > 0 && err <= MAX_ENAME) ? ename[err] : "?UNKNOWN?", strerror(err)); else snprintf(errText, BUF_SIZE, ":"); snprintf(buf, BUF_SIZE, "ERROR%s %s\n", errText, userMsg); if (flushStdout) fflush(stdout); /* Flush any pending stdout */ fputs(buf, stderr); fflush(stderr); /* In case stderr is not line-buffered */ } /* Display error message including ‘errno‘ diagnostic, and return to caller */ void errMsg(const char *format, ...) { va_list argList; int savedErrno; savedErrno = errno; /* In case we change it here */ va_start(argList, format); outputError(TRUE, errno, TRUE, format, argList); va_end(argList); errno = savedErrno; } /* Display error message including ‘errno‘ diagnostic, and terminate the process */ void errExit(const char *format, ...) { va_list argList; va_start(argList, format); outputError(TRUE, errno, TRUE, format, argList); va_end(argList); terminate(TRUE); } /* Display error message including ‘errno‘ diagnostic, and terminate the process by calling _exit(). The relationship between this function and errExit() is analogous to that between _exit(2) and exit(3): unlike errExit(), this function does not flush stdout and calls _exit(2) to terminate the process (rather than exit(3), which would cause exit handlers to be invoked). These differences make this function especially useful in a library function that creates a child process that must then terminate because of an error: the child must terminate without flushing stdio buffers that were partially filled by the caller and without invoking exit handlers that were established by the caller. */ void err_exit(const char *format, ...) { va_list argList; va_start(argList, format); outputError(TRUE, errno, FALSE, format, argList); va_end(argList); terminate(FALSE); } /* The following function does the same as errExit(), but expects the error number in ‘errnum‘ */ void errExitEN(int errnum, const char *format, ...) { va_list argList; va_start(argList, format); outputError(TRUE, errnum, TRUE, format, argList); va_end(argList); terminate(TRUE); } /* Print an error message (without an ‘errno‘ diagnostic) */ void fatal(const char *format, ...) { va_list argList; va_start(argList, format); outputError(FALSE, 0, TRUE, format, argList); va_end(argList); terminate(TRUE); } /* Print a command usage error message and terminate the process */ void usageErr(const char *format, ...) { va_list argList; fflush(stdout); /* Flush any pending stdout */ fprintf(stderr, "Usage: "); va_start(argList, format); vfprintf(stderr, format, argList); va_end(argList); fflush(stderr); /* In case stderr is not line-buffered */ exit(EXIT_FAILURE); } /* Diagnose an error in command-line arguments and terminate the process */ void cmdLineErr(const char *format, ...) { va_list argList; fflush(stdout); /* Flush any pending stdout */ fprintf(stderr, "Command-line usage error: "); va_start(argList, format); vfprintf(stderr, format, argList); va_end(argList); fflush(stderr); /* In case stderr is not line-buffered */ exit(EXIT_FAILURE); }
/************************************************************************** Copyright (C) Michael Kerrisk, 2014. * * * * This program is free software. You may use, modify, and redistribute it * * under the terms of the GNU Lesser General Public License as published * * by the Free Software Foundation, either version 3 or (at your option) * * any later version. This program is distributed without any warranty. * * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * \*************************************************************************/ /* error_functions.h Header file for error_functions.c. */ #ifndef ERROR_FUNCTIONS_H #define ERROR_FUNCTIONS_H /* Error diagnostic routines */ void errMsg(const char *format, ...); #ifdef __GNUC__ /* This macro stops ‘gcc -Wall‘ complaining that "control reaches end of non-void function" if we use the following functions to terminate main() or some other non-void function. */ #define NORETURN __attribute__ ((__noreturn__)) #else #define NORETURN #endif void errExit(const char *format, ...) NORETURN ; void err_exit(const char *format, ...) NORETURN ; void errExitEN(int errnum, const char *format, ...) NORETURN ; void fatal(const char *format, ...) NORETURN ; void usageErr(const char *format, ...) NORETURN ; void cmdLineErr(const char *format, ...) NORETURN ; #endif
时间: 2024-10-25 01:25:53