summaryrefslogtreecommitdiffstats
path: root/src/util/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/msg.c')
-rw-r--r--src/util/msg.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/src/util/msg.c b/src/util/msg.c
new file mode 100644
index 0000000..70c6eab
--- /dev/null
+++ b/src/util/msg.c
@@ -0,0 +1,340 @@
+/*++
+/* NAME
+/* msg 3
+/* SUMMARY
+/* diagnostic interface
+/* SYNOPSIS
+/* #include <msg.h>
+/*
+/* int msg_verbose;
+/*
+/* void msg_info(format, ...)
+/* const char *format;
+/*
+/* void vmsg_info(format, ap)
+/* const char *format;
+/* va_list ap;
+/*
+/* void msg_warn(format, ...)
+/* const char *format;
+/*
+/* void vmsg_warn(format, ap)
+/* const char *format;
+/* va_list ap;
+/*
+/* void msg_error(format, ...)
+/* const char *format;
+/*
+/* void vmsg_error(format, ap)
+/* const char *format;
+/* va_list ap;
+/*
+/* NORETURN msg_fatal(format, ...)
+/* const char *format;
+/*
+/* NORETURN vmsg_fatal(format, ap)
+/* const char *format;
+/* va_list ap;
+/*
+/* NORETURN msg_fatal_status(status, format, ...)
+/* int status;
+/* const char *format;
+/*
+/* NORETURN vmsg_fatal_status(status, format, ap)
+/* int status;
+/* const char *format;
+/* va_list ap;
+/*
+/* NORETURN msg_panic(format, ...)
+/* const char *format;
+/*
+/* NORETURN vmsg_panic(format, ap)
+/* const char *format;
+/* va_list ap;
+/*
+/* MSG_CLEANUP_FN msg_cleanup(cleanup)
+/* void (*cleanup)(void);
+/* AUXILIARY FUNCTIONS
+/* int msg_error_limit(count)
+/* int count;
+/*
+/* void msg_error_clear()
+/* DESCRIPTION
+/* This module reports diagnostics. By default, diagnostics are sent
+/* to the standard error stream, but the disposition can be changed
+/* by the user. See the hints below in the SEE ALSO section.
+/*
+/* msg_info(), msg_warn(), msg_error(), msg_fatal*() and msg_panic()
+/* produce a one-line record with the program name, a severity code
+/* (except for msg_info()), and an informative message. The program
+/* name must have been set by calling one of the msg_XXX_init()
+/* functions (see the SEE ALSO section).
+/*
+/* msg_error() reports a recoverable error and increments the error
+/* counter. When the error count exceeds a pre-set limit (default: 13)
+/* the program terminates by calling msg_fatal().
+/*
+/* msg_fatal() reports an unrecoverable error and terminates the program
+/* with a non-zero exit status.
+/*
+/* msg_fatal_status() reports an unrecoverable error and terminates the
+/* program with the specified exit status.
+/*
+/* msg_panic() reports an internal inconsistency, terminates the
+/* program immediately (i.e. without calling the optional user-specified
+/* cleanup routine), and forces a core dump when possible.
+/*
+/* msg_cleanup() specifies a function that msg_fatal[_status]() should
+/* invoke before terminating the program, and returns the
+/* current function pointer. Specify a null argument to disable
+/* this feature.
+/*
+/* msg_error_limit() sets the error message count limit, and returns.
+/* the old limit.
+/*
+/* msg_error_clear() sets the error message count to zero.
+/*
+/* msg_verbose is a global flag that can be set to make software
+/* more verbose about what it is doing. By default the flag is zero.
+/* By convention, a larger value means more noise.
+/* REENTRANCY
+/* .ad
+/* .fi
+/* The msg_info() etc. output routines are protected against
+/* ordinary recursive calls and against re-entry by signal
+/* handlers.
+/*
+/* Protection against re-entry by signal handlers is subject
+/* to the following limitations:
+/* .IP \(bu
+/* The signal handlers must never return. In other words, the
+/* signal handlers must do one or more of the following: call
+/* _exit(), kill the process with a signal, and permanently block
+/* the process.
+/* .IP \(bu
+/* The signal handlers must invoke msg_info() etc. not until
+/* after the msg_XXX_init() functions complete initialization,
+/* and not until after the first formatted output to a VSTRING
+/* or VSTREAM.
+/* .IP \(bu
+/* Each msg_cleanup() call-back function, and each Postfix or
+/* system function invoked by that call-back function, either
+/* protects itself against recursive calls and re-entry by a
+/* terminating signal handler, or is called exclusively by the
+/* msg(3) module.
+/* .PP
+/* When re-entrancy is detected, the requested output and
+/* optional cleanup operations are skipped. Skipping the output
+/* operations prevents memory corruption of VSTREAM_ERR data
+/* structures, and prevents deadlock on Linux releases that
+/* use mutexes within system library routines such as syslog().
+/* This protection exists under the condition that these
+/* specific resources are accessed exclusively via the msg_info()
+/* etc. functions.
+/* SEE ALSO
+/* msg_output(3) specify diagnostics disposition
+/* msg_stdio(3) direct diagnostics to standard I/O stream
+/* msg_vstream(3) direct diagnostics to VSTREAM.
+/* msg_syslog(3) direct diagnostics to syslog daemon
+/* BUGS
+/* Some output functions may suffer from intentional or accidental
+/* record length restrictions that are imposed by library routines
+/* and/or by the runtime environment.
+/*
+/* Code that spawns a child process should almost always reset
+/* the cleanup handler. The exception is when the parent exits
+/* immediately and the child continues.
+/*
+/* msg_cleanup() may be unsafe in code that changes process
+/* privileges, because the call-back routine may run with the
+/* wrong privileges.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+/* Application-specific. */
+
+#include "msg.h"
+#include "msg_output.h"
+
+ /*
+ * Default is verbose logging off.
+ */
+int msg_verbose = 0;
+
+ /*
+ * Private state.
+ */
+static MSG_CLEANUP_FN msg_cleanup_fn = 0;
+static int msg_error_count = 0;
+static int msg_error_bound = 13;
+
+ /*
+ * The msg_exiting flag prevents us from recursively reporting an error with
+ * msg_fatal*() or msg_panic(), and provides a first-level safety net for
+ * optional cleanup actions against signal handler re-entry problems. Note
+ * that msg_vprintf() implements its own guard against re-entry.
+ *
+ * XXX We specify global scope, to discourage the compiler from doing smart
+ * things.
+ */
+volatile int msg_exiting = 0;
+
+/* msg_info - report informative message */
+
+void msg_info(const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg_info(fmt, ap);
+ va_end(ap);
+}
+
+void vmsg_info(const char *fmt, va_list ap)
+{
+ msg_vprintf(MSG_INFO, fmt, ap);
+}
+
+/* msg_warn - report warning message */
+
+void msg_warn(const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg_warn(fmt, ap);
+ va_end(ap);
+}
+
+void vmsg_warn(const char *fmt, va_list ap)
+{
+ msg_vprintf(MSG_WARN, fmt, ap);
+}
+
+/* msg_error - report recoverable error */
+
+void msg_error(const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg_error(fmt, ap);
+ va_end(ap);
+}
+
+void vmsg_error(const char *fmt, va_list ap)
+{
+ msg_vprintf(MSG_ERROR, fmt, ap);
+ if (++msg_error_count >= msg_error_bound)
+ msg_fatal("too many errors - program terminated");
+}
+
+/* msg_fatal - report error and terminate gracefully */
+
+NORETURN msg_fatal(const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg_fatal(fmt, ap);
+ /* NOTREACHED */
+}
+
+NORETURN vmsg_fatal(const char *fmt, va_list ap)
+{
+ if (msg_exiting++ == 0) {
+ msg_vprintf(MSG_FATAL, fmt, ap);
+ if (msg_cleanup_fn)
+ msg_cleanup_fn();
+ }
+ sleep(1);
+ /* In case we're running as a signal handler. */
+ _exit(1);
+}
+
+/* msg_fatal_status - report error and terminate gracefully */
+
+NORETURN msg_fatal_status(int status, const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg_fatal_status(status, fmt, ap);
+ /* NOTREACHED */
+}
+
+NORETURN vmsg_fatal_status(int status, const char *fmt, va_list ap)
+{
+ if (msg_exiting++ == 0) {
+ msg_vprintf(MSG_FATAL, fmt, ap);
+ if (msg_cleanup_fn)
+ msg_cleanup_fn();
+ }
+ sleep(1);
+ /* In case we're running as a signal handler. */
+ _exit(status);
+}
+
+/* msg_panic - report error and dump core */
+
+NORETURN msg_panic(const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg_panic(fmt, ap);
+ /* NOTREACHED */
+}
+
+NORETURN vmsg_panic(const char *fmt, va_list ap)
+{
+ if (msg_exiting++ == 0) {
+ msg_vprintf(MSG_PANIC, fmt, ap);
+ }
+ sleep(1);
+ abort(); /* Die! */
+ /* In case we're running as a signal handler. */
+ _exit(1); /* DIE!! */
+}
+
+/* msg_cleanup - specify cleanup routine */
+
+MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
+{
+ MSG_CLEANUP_FN old_fn = msg_cleanup_fn;
+
+ msg_cleanup_fn = cleanup_fn;
+ return (old_fn);
+}
+
+/* msg_error_limit - set error message counter limit */
+
+int msg_error_limit(int limit)
+{
+ int old = msg_error_bound;
+
+ msg_error_bound = limit;
+ return (old);
+}
+
+/* msg_error_clear - reset error message counter */
+
+void msg_error_clear(void)
+{
+ msg_error_count = 0;
+}