diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:47:14 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:47:14 +0000 |
commit | 3eaf4237194e25804f221af93c269d3d97e2809d (patch) | |
tree | cdedf3fc954b0727b0b34aa9b0b211cc18f854eb /src/messages.c | |
download | smartcardauth-3eaf4237194e25804f221af93c269d3d97e2809d.tar.gz smartcardauth-3eaf4237194e25804f221af93c269d3d97e2809d.zip |
Added my SmartCard login/session lock/unlock utility
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/smartcardauth@1097604 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/messages.c')
-rw-r--r-- | src/messages.c | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/src/messages.c b/src/messages.c new file mode 100644 index 0000000..7a54e0a --- /dev/null +++ b/src/messages.c @@ -0,0 +1,493 @@ +/* $Id: messages.c 5496 2002-06-07 13:59:06Z alexk $ +** +** Message and error reporting (possibly fatal). +** +** Usage: +** +** extern int cleanup(void); +** extern void log(int, const char *, va_list, int); +** +** message_fatal_cleanup = cleanup; +** message_program_name = argv[0]; +** +** warn("Something horrible happened at %lu", time); +** syswarn("Couldn't unlink temporary file %s", tmpfile); +** +** die("Something fatal happened at %lu", time); +** sysdie("open of %s failed", filename); +** +** debug("Some debugging message about %s", string); +** trace(TRACE_PROGRAM, "Program trace output"); +** notice("Informational notices"); +** +** message_handlers_warn(1, log); +** warn("This now goes through our log function"); +** +** These functions implement message reporting through user-configurable +** handler functions. debug() only does something if DEBUG is defined, +** trace() supports sending trace messages in one of a number of configurable +** classes of traces so that they can be turned on or off independently, and +** notice() and warn() just output messages as configured. die() similarly +** outputs a message but then exits, normally with a status of 1. +** +** The sys* versions do the same, but append a colon, a space, and the +** results of strerror(errno) to the end of the message. All functions +** accept printf-style formatting strings and arguments. +** +** If message_fatal_cleanup is non-NULL, it is called before exit by die and +** sysdie and its return value is used as the argument to exit. It is a +** pointer to a function taking no arguments and returning an int, and can be +** used to call cleanup functions or to exit in some alternate fashion (such +** as by calling _exit). +** +** If message_program_name is non-NULL, the string it points to, followed by +** a colon and a space, is prepended to all error messages logged through the +** message_log_stdout and message_log_stderr message handlers (the former is +** the default for notice, and the latter is the default for warn and die). +** +** Honoring error_program_name and printing to stderr is just the default +** handler; with message_handlers_* the handlers for any message function can +** be changed. By default, notice prints to stdout, warn and die print to +** stderr, and the others don't do anything at all. These functions take a +** count of handlers and then that many function pointers, each one to a +** function that takes a message length (the number of characters snprintf +** generates given the format and arguments), a format, an argument list as a +** va_list, and the applicable errno value (if any). +*/ + +/* Used for unused parameters to silence gcc warnings. */ +#define UNUSED __attribute__((__unused__)) + +/* Make available the bool type. */ +#if INN_HAVE_STDBOOL_H +# include <stdbool.h> +#else +# undef true +# undef false +# define true (1) +# define false (0) +# ifndef __cplusplus +# define bool int +# endif +#endif /* INN_HAVE_STDBOOL_H */ + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <errno.h> +#include <syslog.h> +#include <crypt.h> +#include <fcntl.h> +#include <pwd.h> +#include <grp.h> + +/* The functions are actually macros so that we can pick up the file and line + number information for debugging error messages without the user having to + pass those in every time. */ +#define xcalloc(n, size) x_calloc((n), (size), __FILE__, __LINE__) +#define xmalloc(size) x_malloc((size), __FILE__, __LINE__) +#define xrealloc(p, size) x_realloc((p), (size), __FILE__, __LINE__) +#define xstrdup(p) x_strdup((p), __FILE__, __LINE__) +#define xstrndup(p, size) x_strndup((p), (size), __FILE__, __LINE__) + +/* These are the currently-supported types of traces. */ +enum message_trace { + TRACE_NETWORK, /* Network traffic. */ + TRACE_PROGRAM, /* Stages of program execution. */ + TRACE_ALL /* All traces; this must be last. */ +}; + +/* The reporting functions. The ones prefaced by "sys" add a colon, a space, + and the results of strerror(errno) to the output and are intended for + reporting failures of system calls. */ +extern void trace(enum message_trace, const char *, ...) + __attribute__((__format__(printf, 2, 3))); +extern void notice(const char *, ...) + __attribute__((__format__(printf, 1, 2))); +extern void sysnotice(const char *, ...) + __attribute__((__format__(printf, 1, 2))); +extern void warn(const char *, ...) + __attribute__((__format__(printf, 1, 2))); +extern void syswarn(const char *, ...) + __attribute__((__format__(printf, 1, 2))); +extern void die(const char *, ...) + __attribute__((__noreturn__, __format__(printf, 1, 2))); +extern void sysdie(const char *, ...) + __attribute__((__noreturn__, __format__(printf, 1, 2))); + +/* Debug is handled specially, since we want to make the code disappear + completely unless we're built with -DDEBUG. We can only do that with + support for variadic macros, though; otherwise, the function just won't do + anything. */ +#if !defined(DEBUG) && (INN_HAVE_C99_VAMACROS || INN_HAVE_GNU_VAMACROS) +# if INN_HAVE_C99_VAMACROS +# define debug(format, ...) /* empty */ +# elif INN_HAVE_GNU_VAMACROS +# define debug(format, args...) /* empty */ +# endif +#else +extern void debug(const char *, ...) + __attribute__((__format__(printf, 1, 2))); +#endif + +/* Set the handlers for various message functions. All of these functions + take a count of the number of handlers and then function pointers for each + of those handlers. These functions are not thread-safe; they set global + variables. */ +extern void message_handlers_debug(int count, ...); +extern void message_handlers_trace(int count, ...); +extern void message_handlers_notice(int count, ...); +extern void message_handlers_warn(int count, ...); +extern void message_handlers_die(int count, ...); + +/* Enable or disable tracing for particular classes of messages. */ +extern void message_trace_enable(enum message_trace, bool); + +/* Some useful handlers, intended to be passed to message_handlers_*. All + handlers take the length of the formatted message, the format, a variadic + argument list, and the errno setting if any. */ +extern void message_log_stdout(int, const char *, va_list, int); +extern void message_log_stderr(int, const char *, va_list, int); +extern void message_log_syslog_debug(int, const char *, va_list, int); +extern void message_log_syslog_info(int, const char *, va_list, int); +extern void message_log_syslog_notice(int, const char *, va_list, int); +extern void message_log_syslog_warning(int, const char *, va_list, int); +extern void message_log_syslog_err(int, const char *, va_list, int); +extern void message_log_syslog_crit(int, const char *, va_list, int); + +/* The type of a message handler. */ +typedef void (*message_handler_func)(int, const char *, va_list, int); + +/* If non-NULL, called before exit and its return value passed to exit. */ +extern int (*message_fatal_cleanup)(void); + +/* If non-NULL, prepended (followed by ": ") to all messages printed by either + message_log_stdout or message_log_stderr. */ +extern const char *message_program_name; + +/* The default handler lists. */ +static message_handler_func stdout_handlers[2] = { + message_log_stdout, NULL +}; +static message_handler_func stderr_handlers[2] = { + message_log_stderr, NULL +}; + +/* The list of logging functions currently in effect. */ +static message_handler_func *debug_handlers = NULL; +static message_handler_func *trace_handlers = NULL; +static message_handler_func *notice_handlers = stdout_handlers; +static message_handler_func *warn_handlers = stderr_handlers; +static message_handler_func *die_handlers = stderr_handlers; + +/* If non-NULL, called before exit and its return value passed to exit. */ +int (*message_fatal_cleanup)(void) = NULL; + +/* If non-NULL, prepended (followed by ": ") to messages. */ +const char *message_program_name = NULL; + +/* Whether or not we're currently outputting a particular type of trace. */ +static bool tracing[TRACE_ALL] = { false /* false, ... */ }; + + +/* +** Set the handlers for a particular message function. Takes a pointer to +** the handler list, the count of handlers, and the argument list. +*/ +static void +message_handlers(message_handler_func **list, int count, va_list args) +{ + int i; + + if (*list != stdout_handlers && *list != stderr_handlers) + free(*list); + *list = xmalloc(sizeof(message_handler_func) * (count + 1)); + for (i = 0; i < count; i++) + (*list)[i] = (message_handler_func) va_arg(args, message_handler_func); + (*list)[count] = NULL; +} + + +/* +** There's no good way of writing these handlers without a bunch of code +** duplication since we can't assume variadic macros, but I can at least make +** it easier to write and keep them consistent. +*/ +#define HANDLER_FUNCTION(type) \ + void \ + message_handlers_ ## type(int count, ...) \ + { \ + va_list args; \ + \ + va_start(args, count); \ + message_handlers(& type ## _handlers, count, args); \ + va_end(args); \ + } +HANDLER_FUNCTION(debug) +HANDLER_FUNCTION(trace) +HANDLER_FUNCTION(notice) +HANDLER_FUNCTION(warn) +HANDLER_FUNCTION(die) + + +/* +** Print a message to stdout, supporting message_program_name. +*/ +void +message_log_stdout(int len UNUSED, const char *fmt, va_list args, int err) +{ + if (message_program_name != NULL) + fprintf(stdout, "%s: ", message_program_name); + vfprintf(stdout, fmt, args); + if (err) + fprintf(stdout, ": %s", strerror(err)); + fprintf(stdout, "\n"); +} + + +/* +** Print a message to stderr, supporting message_program_name. Also flush +** stdout so that errors and regular output occur in the right order. +*/ +void +message_log_stderr(int len UNUSED, const char *fmt, va_list args, int err) +{ + fflush(stdout); + if (message_program_name != NULL) + fprintf(stderr, "%s: ", message_program_name); + vfprintf(stderr, fmt, args); + if (err) + fprintf(stderr, ": %s", strerror(err)); + fprintf(stderr, "\n"); +} + + +/* +** Log a message to syslog. This is a helper function used to implement all +** of the syslog message log handlers. It takes the same arguments as a +** regular message handler function but with an additional priority +** argument. +*/ +static void +message_log_syslog(int pri, int len, const char *fmt, va_list args, int err) +{ + char *buffer; + + buffer = malloc(len + 1); + if (buffer == NULL) { + fprintf(stderr, "failed to malloc %u bytes at %s line %d: %s", + len + 1, __FILE__, __LINE__, strerror(errno)); + exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); + } + vsnprintf(buffer, len + 1, fmt, args); + syslog(pri, err ? "%s: %m" : "%s", buffer); + free(buffer); +} + + +/* +** Do the same sort of wrapper to generate all of the separate syslog logging +** functions. +*/ +#define SYSLOG_FUNCTION(name, type) \ + void \ + message_log_syslog_ ## name(int l, const char *f, va_list a, int e) \ + { \ + message_log_syslog(LOG_ ## type, l, f, a, e); \ + } +SYSLOG_FUNCTION(debug, DEBUG) +SYSLOG_FUNCTION(info, INFO) +SYSLOG_FUNCTION(notice, NOTICE) +SYSLOG_FUNCTION(warning, WARNING) +SYSLOG_FUNCTION(err, ERR) +SYSLOG_FUNCTION(crit, CRIT) + + +/* +** Enable or disable tracing for particular classes of messages. +*/ +void +message_trace_enable(enum message_trace type, bool enable) +{ + if (type > TRACE_ALL) + return; + if (type == TRACE_ALL) { + int i; + + for (i = 0; i < TRACE_ALL; i++) + tracing[i] = enable; + } else { + tracing[type] = enable; + } +} + + +/* +** All of the message handlers. There's a lot of code duplication here too, +** but each one is still *slightly* different and va_start has to be called +** multiple times, so it's hard to get rid of the duplication. +*/ + +#ifdef DEBUG +void +debug(const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + + if (debug_handlers == NULL) + return; + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length < 0) + return; + for (log = debug_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, 0); + va_end(args); + } +} +#elif !INN_HAVE_C99_VAMACROS && !INN_HAVE_GNU_VAMACROS +void debug(const char *format UNUSED, ...) { } +#endif + +void +trace(enum message_trace type, const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + + if (trace_handlers == NULL || !tracing[type]) + return; + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length < 0) + return; + for (log = trace_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, 0); + va_end(args); + } +} + +void +notice(const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length < 0) + return; + for (log = notice_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, 0); + va_end(args); + } +} + +void +sysnotice(const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + int error = errno; + + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length < 0) + return; + for (log = notice_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, error); + va_end(args); + } +} + +void +warn(const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length < 0) + return; + for (log = warn_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, 0); + va_end(args); + } +} + +void +syswarn(const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + int error = errno; + + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length < 0) + return; + for (log = warn_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, error); + va_end(args); + } +} + +void +die(const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length >= 0) + for (log = die_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, 0); + va_end(args); + } + exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); +} + +void +sysdie(const char *format, ...) +{ + va_list args; + message_handler_func *log; + int length; + int error = errno; + + va_start(args, format); + length = vsnprintf(NULL, 0, format, args); + va_end(args); + if (length >= 0) + for (log = die_handlers; *log != NULL; log++) { + va_start(args, format); + (**log)(length, format, args, error); + va_end(args); + } + exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); +} |