1/*++ 2/* NAME 3/* msg 3 4/* SUMMARY 5/* diagnostic interface 6/* SYNOPSIS 7/* #include <msg.h> 8/* 9/* int msg_verbose; 10/* 11/* void msg_info(format, ...) 12/* const char *format; 13/* 14/* void vmsg_info(format, ap) 15/* const char *format; 16/* va_list ap; 17/* 18/* void msg_warn(format, ...) 19/* const char *format; 20/* 21/* void vmsg_warn(format, ap) 22/* const char *format; 23/* va_list ap; 24/* 25/* void msg_error(format, ...) 26/* const char *format; 27/* 28/* void vmsg_error(format, ap) 29/* const char *format; 30/* va_list ap; 31/* 32/* NORETURN msg_fatal(format, ...) 33/* const char *format; 34/* 35/* NORETURN vmsg_fatal(format, ap) 36/* const char *format; 37/* va_list ap; 38/* 39/* NORETURN msg_fatal_status(status, format, ...) 40/* int status; 41/* const char *format; 42/* 43/* NORETURN vmsg_fatal_status(status, format, ap) 44/* int status; 45/* const char *format; 46/* va_list ap; 47/* 48/* NORETURN msg_panic(format, ...) 49/* const char *format; 50/* 51/* NORETURN vmsg_panic(format, ap) 52/* const char *format; 53/* va_list ap; 54/* 55/* MSG_CLEANUP_FN msg_cleanup(cleanup) 56/* void (*cleanup)(void); 57/* AUXILIARY FUNCTIONS 58/* int msg_error_limit(count) 59/* int count; 60/* 61/* void msg_error_clear() 62/* DESCRIPTION 63/* This module reports diagnostics. By default, diagnostics are sent 64/* to the standard error stream, but the disposition can be changed 65/* by the user. See the hints below in the SEE ALSO section. 66/* 67/* msg_info(), msg_warn(), msg_error(), msg_fatal*() and msg_panic() 68/* produce a one-line record with the program name, a severity code 69/* (except for msg_info()), and an informative message. The program 70/* name must have been set by calling one of the msg_XXX_init() 71/* functions (see the SEE ALSO section). 72/* 73/* msg_error() reports a recoverable error and increments the error 74/* counter. When the error count exceeds a pre-set limit (default: 13) 75/* the program terminates by calling msg_fatal(). 76/* 77/* msg_fatal() reports an unrecoverable error and terminates the program 78/* with a non-zero exit status. 79/* 80/* msg_fatal_status() reports an unrecoverable error and terminates the 81/* program with the specified exit status. 82/* 83/* msg_panic() reports an internal inconsistency, terminates the 84/* program immediately (i.e. without calling the optional user-specified 85/* cleanup routine), and forces a core dump when possible. 86/* 87/* msg_cleanup() specifies a function that msg_fatal[_status]() should 88/* invoke before terminating the program, and returns the 89/* current function pointer. Specify a null argument to disable 90/* this feature. 91/* 92/* msg_error_limit() sets the error message count limit, and returns. 93/* the old limit. 94/* 95/* msg_error_clear() sets the error message count to zero. 96/* 97/* msg_verbose is a global flag that can be set to make software 98/* more verbose about what it is doing. By default the flag is zero. 99/* By convention, a larger value means more noise. 100/* REENTRANCY 101/* .ad 102/* .fi 103/* The msg_info() etc. output routines are protected against 104/* ordinary recursive calls and against re-entry by signal 105/* handlers. 106/* 107/* Protection against re-entry by signal handlers is subject 108/* to the following limitations: 109/* .IP \(bu 110/* The signal handlers must never return. In other words, the 111/* signal handlers must do one or more of the following: call 112/* _exit(), kill the process with a signal, and permanently block 113/* the process. 114/* .IP \(bu 115/* The signal handlers must invoke msg_info() etc. not until 116/* after the msg_XXX_init() functions complete initialization, 117/* and not until after the first formatted output to a VSTRING 118/* or VSTREAM. 119/* .IP \(bu 120/* Each msg_cleanup() call-back function, and each Postfix or 121/* system function invoked by that call-back function, either 122/* protects itself against recursive calls and re-entry by a 123/* terminating signal handler, or is called exclusively by the 124/* msg(3) module. 125/* .PP 126/* When re-entrancy is detected, the requested output and 127/* optional cleanup operations are skipped. Skipping the output 128/* operations prevents memory corruption of VSTREAM_ERR data 129/* structures, and prevents deadlock on Linux releases that 130/* use mutexes within system library routines such as syslog(). 131/* This protection exists under the condition that these 132/* specific resources are accessed exclusively via the msg_info() 133/* etc. functions. 134/* SEE ALSO 135/* msg_output(3) specify diagnostics disposition 136/* msg_stdio(3) direct diagnostics to standard I/O stream 137/* msg_vstream(3) direct diagnostics to VSTREAM. 138/* msg_syslog(3) direct diagnostics to syslog daemon 139/* BUGS 140/* Some output functions may suffer from intentional or accidental 141/* record length restrictions that are imposed by library routines 142/* and/or by the runtime environment. 143/* 144/* Code that spawns a child process should almost always reset 145/* the cleanup handler. The exception is when the parent exits 146/* immediately and the child continues. 147/* 148/* msg_cleanup() may be unsafe in code that changes process 149/* privileges, because the call-back routine may run with the 150/* wrong privileges. 151/* LICENSE 152/* .ad 153/* .fi 154/* The Secure Mailer license must be distributed with this software. 155/* AUTHOR(S) 156/* Wietse Venema 157/* IBM T.J. Watson Research 158/* P.O. Box 704 159/* Yorktown Heights, NY 10598, USA 160/*--*/ 161 162/* System libraries. */ 163 164#include <sys_defs.h> 165#include <stdlib.h> 166#include <stdarg.h> 167#include <unistd.h> 168 169/* Application-specific. */ 170 171#include "msg.h" 172#include "msg_output.h" 173 174 /* 175 * Default is verbose logging off. 176 */ 177int msg_verbose = 0; 178 179 /* 180 * Private state. 181 */ 182static MSG_CLEANUP_FN msg_cleanup_fn = 0; 183static int msg_error_count = 0; 184static int msg_error_bound = 13; 185 186 /* 187 * The msg_exiting flag prevents us from recursively reporting an error with 188 * msg_fatal*() or msg_panic(), and provides a first-level safety net for 189 * optional cleanup actions against signal handler re-entry problems. Note 190 * that msg_vprintf() implements its own guard against re-entry. 191 * 192 * XXX We specify global scope, to discourage the compiler from doing smart 193 * things. 194 */ 195volatile int msg_exiting = 0; 196 197/* msg_info - report informative message */ 198 199void msg_info(const char *fmt,...) 200{ 201 va_list ap; 202 203 va_start(ap, fmt); 204 vmsg_info(fmt, ap); 205 va_end(ap); 206} 207 208void vmsg_info(const char *fmt, va_list ap) 209{ 210 msg_vprintf(MSG_INFO, fmt, ap); 211} 212 213/* msg_warn - report warning message */ 214 215void msg_warn(const char *fmt,...) 216{ 217 va_list ap; 218 219 va_start(ap, fmt); 220 vmsg_warn(fmt, ap); 221 va_end(ap); 222} 223 224void vmsg_warn(const char *fmt, va_list ap) 225{ 226 msg_vprintf(MSG_WARN, fmt, ap); 227} 228 229/* msg_error - report recoverable error */ 230 231void msg_error(const char *fmt,...) 232{ 233 va_list ap; 234 235 va_start(ap, fmt); 236 vmsg_error(fmt, ap); 237 va_end(ap); 238} 239 240void vmsg_error(const char *fmt, va_list ap) 241{ 242 msg_vprintf(MSG_ERROR, fmt, ap); 243 if (++msg_error_count >= msg_error_bound) 244 msg_fatal("too many errors - program terminated"); 245} 246 247/* msg_fatal - report error and terminate gracefully */ 248 249NORETURN msg_fatal(const char *fmt,...) 250{ 251 va_list ap; 252 253 va_start(ap, fmt); 254 vmsg_fatal(fmt, ap); 255 /* NOTREACHED */ 256} 257 258NORETURN vmsg_fatal(const char *fmt, va_list ap) 259{ 260 if (msg_exiting++ == 0) { 261 msg_vprintf(MSG_FATAL, fmt, ap); 262 if (msg_cleanup_fn) 263 msg_cleanup_fn(); 264 } 265 sleep(1); 266 /* In case we're running as a signal handler. */ 267 _exit(1); 268} 269 270/* msg_fatal_status - report error and terminate gracefully */ 271 272NORETURN msg_fatal_status(int status, const char *fmt,...) 273{ 274 va_list ap; 275 276 va_start(ap, fmt); 277 vmsg_fatal_status(status, fmt, ap); 278 /* NOTREACHED */ 279} 280 281NORETURN vmsg_fatal_status(int status, const char *fmt, va_list ap) 282{ 283 if (msg_exiting++ == 0) { 284 msg_vprintf(MSG_FATAL, fmt, ap); 285 if (msg_cleanup_fn) 286 msg_cleanup_fn(); 287 } 288 sleep(1); 289 /* In case we're running as a signal handler. */ 290 _exit(status); 291} 292 293/* msg_panic - report error and dump core */ 294 295NORETURN msg_panic(const char *fmt,...) 296{ 297 va_list ap; 298 299 va_start(ap, fmt); 300 vmsg_panic(fmt, ap); 301 /* NOTREACHED */ 302} 303 304NORETURN vmsg_panic(const char *fmt, va_list ap) 305{ 306 if (msg_exiting++ == 0) { 307 msg_vprintf(MSG_PANIC, fmt, ap); 308 } 309 sleep(1); 310 abort(); /* Die! */ 311 /* In case we're running as a signal handler. */ 312 _exit(1); /* DIE!! */ 313} 314 315/* msg_cleanup - specify cleanup routine */ 316 317MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn) 318{ 319 MSG_CLEANUP_FN old_fn = msg_cleanup_fn; 320 321 msg_cleanup_fn = cleanup_fn; 322 return (old_fn); 323} 324 325/* msg_error_limit - set error message counter limit */ 326 327int msg_error_limit(int limit) 328{ 329 int old = msg_error_bound; 330 331 msg_error_bound = limit; 332 return (old); 333} 334 335/* msg_error_clear - reset error message counter */ 336 337void msg_error_clear(void) 338{ 339 msg_error_count = 0; 340} 341