diff --git a/configure.in b/configure.in index 68ac0a00..a4b5e968 100644 --- a/configure.in +++ b/configure.in @@ -39,6 +39,39 @@ INSTALL="$INSTALL $extra_install_args" INSTALL_STRIP_PROGRAM="$INSTALL_STRIP_PROGRAM $extra_install_args" AC_SUBST(INSTALL) +dnl Configure the plugin output format +default_output_format="%s %x: %i\n" +AC_ARG_WITH([standard_output_format], + [AS_HELP_STRING([--with-standard-output-format=FORMAT], + [specify the standard plugin output FORMAT; %p, %s, %x, and %m + will be replaced by the plugin name, the service name, the + status string, and the information message, respectively; tabs + or newlines can be inserted using \t or \n + @<:@default="%s %x: %m\n"@:>@])], + [standard_output_format=$withval], + [standard_output_format="yes"]) +AC_ARG_WITH([verbose_output_format], + [AS_HELP_STRING([--with-verbose-output-format=FORMAT], + [specify the verbose plugin output FORMAT; %p, %s, %x, and %m + will be replaced by the plugin name, the service name, the + status string, and the information message, respectively; tabs + or newlines can be inserted using \t or \n + @<:@default="%s %x: %m\n"@:>@])], + [verbose_output_format=$withval], + [verbose_output_format="yes"]) +AS_IF([test "$standard_output_format" = yes], + [standard_output_format=$default_output_format], + [test "$standard_output_format" = no], + [standard_output_format=""], + [test "$verbose_output_format" = yes], + [verbose_output_format=$default_output_format], + [test "$verbose_output_format" = no], + [verbose_output_format=""]) +AC_DEFINE_UNQUOTED([STANDARD_OUTPUT_FORMAT], ["$standard_output_format"], + [Define the standard plugin output format.]) +AC_DEFINE_UNQUOTED([VERBOSE_OUTPUT_FORMAT], ["$verbose_output_format"], + [Define the verbose plugin output format.]) + AC_PROG_CC gl_EARLY AC_PROG_GCC_TRADITIONAL @@ -150,6 +183,11 @@ AC_CHECK_LIB(socket,socket,SOCKETLIBS="$SOCKETLIBS -lsocket") AC_CHECK_LIB(resolv,main,SOCKETLIBS="$SOCKETLIBS -lresolv") AC_SUBST(SOCKETLIBS) +dnl check for basename(3) which needs -lgen on some systems (e.g. IRIX) +AC_CHECK_HEADERS([libgen.h]) +AC_SEARCH_LIBS([basename], [gen]) +AC_CHECK_FUNCS([basename]) + dnl dnl check for math-related functions needing -lm AC_CHECK_HEADERS(math.h) diff --git a/lib/utils_base.c b/lib/utils_base.c index 77700f5b..ba4f83b8 100644 --- a/lib/utils_base.c +++ b/lib/utils_base.c @@ -24,10 +24,151 @@ * *****************************************************************************/ +#if HAVE_LIBGEN_H +#include /* basename(3) */ +#endif +#include #include "common.h" #include #include "utils_base.h" +#define PRINT_OUTPUT(fmt, ap) \ + do { \ + fmt = insert_syserr(fmt); \ + va_start(ap, fmt); \ + vprintf(fmt, ap); \ + va_end(ap); \ + } while (/* CONSTCOND */ 0) + +static char *insert_syserr(const char *); + +extern int errno; +static int verbosity_level = -2; +static const char *program_name = NULL; +static const char *service_name = NULL; + +/* + * Set static variables for use in output functions. Usually, argv[0] may be + * used as progname, since we call basename(3) ourselves. If a verbosity value + * of -2 is specified, the verbosity_level won't be set. Currently, no flags + * are implemented. + */ +void +np_set_output(const char *progname, const char *servname, int verbosity, + int flags __attribute__((unused))) +{ + static char pathbuf[128], progbuf[128], servbuf[32]; + + if (progname != NULL) { +#if HAVE_BASENAME + /* + * Copy the progname into a temporary buffer in order to cope + * with basename(3) implementations which modify their argument. + * TODO: Maybe we should implement an np_basename()? Gnulib's + * base_name() dies on error, writing a message to stderr, which + * is probably not what we want. Once we have some replacement, + * the libgen-/basename(3)-related checks can be removed from + * configure.in. + */ + strncpy(pathbuf, progname, sizeof(pathbuf) - 1); + pathbuf[sizeof(pathbuf) - 1] = '\0'; + progname = basename(pathbuf); +#endif + strncpy(progbuf, progname, sizeof(progbuf) - 1); + progbuf[sizeof(progbuf) - 1] = '\0'; + program_name = progbuf; + } + if (servname != NULL) { + strncpy(servbuf, servname, sizeof(servbuf) - 1); + servbuf[sizeof(servbuf) - 1] = '\0'; + service_name = servbuf; + } + if (verbosity != -2) + verbosity_level = verbosity; +} + +int +np_adjust_verbosity(int by) +{ + if (verbosity_level == -2) + verbosity_level = by; + else + verbosity_level += by; + + /* We don't support verbosity levels < -1. */ + if (verbosity_level < -1) + verbosity_level = -1; + + return verbosity_level; +} + +void +np_debug(int verbosity, const char *fmt, ...) +{ + va_list ap; + + if (verbosity_level != -1 && verbosity >= verbosity_level) + PRINT_OUTPUT(fmt, ap); +} + +void +np_verbose(const char *fmt, ...) +{ + va_list ap; + + if (verbosity_level >= 1) { + PRINT_OUTPUT(fmt, ap); + putchar('\n'); + } +} + +void +np_die(int status, const char *fmt, ...) +{ + va_list ap; + const char *p; + + if (program_name == NULL || service_name == NULL) + PRINT_OUTPUT(fmt, ap); + + for (p = (verbosity_level > 0) ? + VERBOSE_OUTPUT_FORMAT : STANDARD_OUTPUT_FORMAT; + *p != '\0'; p++) { + if (*p == '%') { + if (*++p == '\0') + break; + switch (*p) { + case 'm': + PRINT_OUTPUT(fmt, ap); + continue; + case 'p': + fputs(program_name, stdout); + continue; + case 's': + fputs(service_name, stdout); + continue; + case 'x': + fputs(state_text(status), stdout); + continue; + } + } else if (*p == '\\') { + if (*++p == '\0') + break; + switch (*p) { + case 'n': + putchar('\n'); + continue; + case 't': + putchar('\t'); + continue; + } + } + putchar(*p); + } + exit(status); +} + +/* TODO: die() can be removed as soon as all plugins use np_die() instead. */ void die (int result, const char *fmt, ...) { @@ -308,3 +449,67 @@ char *np_extract_value(const char *varlist, const char *name, char sep) { return value; } +/* + * Replace occurrences of "%m" by strerror(errno). Other printf(3)-style + * conversion specifications will be copied verbatim, including "%%", even if + * followed by an "m". Returns a pointer to a static buffer in order to not + * fail on memory allocation error. + */ +static char * +insert_syserr(const char *buf) +{ + static char newbuf[8192]; + char *errstr = strerror(errno); + size_t errlen = strlen(errstr); + size_t copylen; + unsigned i, j; + + for (i = 0, j = 0; buf[i] != '\0' && j < sizeof(newbuf) - 2; i++, j++) { + if (buf[i] == '%') { + if (buf[++i] == 'm') { + copylen = (errlen > sizeof(newbuf) - j - 1) ? + sizeof(newbuf) - j - 1 : errlen; + memcpy(newbuf + j, errstr, copylen); + /* + * As we'll increment j by 1 after the iteration + * anyway, we only increment j by the number of + * copied bytes - 1. + */ + j += copylen - 1; + continue; + } else { + /* + * The possibility to run into this block is the + * reason we checked for j < sizeof(newbuf) - 2 + * instead of j < sizeof(newbuf) - 1. + */ + newbuf[j++] = '%'; + if (buf[i] == '\0') + break; + } + } + newbuf[j] = buf[i]; + } + newbuf[j] = '\0'; + return newbuf; +} + +/* + * Given a numerical status, return a pointer to the according string. + */ +const char * +state_text(int result) +{ + switch (result) { + case STATE_OK: + return "OK"; + case STATE_WARNING: + return "WARNING"; + case STATE_CRITICAL: + return "CRITICAL"; + case STATE_DEPENDENT: + return "DEPENDENT"; + default: + return "UNKNOWN"; + } +} diff --git a/lib/utils_base.h b/lib/utils_base.h index f40fdb0f..8d0b2124 100644 --- a/lib/utils_base.h +++ b/lib/utils_base.h @@ -37,6 +37,23 @@ int get_status(double, thresholds *); char *np_escaped_string (const char *); +void np_set_output(const char *, const char *, int, int); +int np_adjust_verbosity(int); +void np_debug(int, const char *, ...) + __attribute__((format(printf, 2, 3))); +void np_verbose(const char *, ...) + __attribute__((format(printf, 1, 2))); +void np_die(int, const char *, ...) + __attribute__((noreturn, format(printf, 2, 3))); + +#define np_verbatim(s) np_verbose("%s", s) +#define np_increase_verbosity(i) np_adjust_verbosity(i) +#define np_decrease_verbosity(i) np_adjust_verbosity(-i) +#define np_get_verbosity() np_adjust_verbosity(0) +#define np_set_verbosity(v) np_set_output(NULL, NULL, v, 0) +#define np_set_mynames(p, s) np_set_output(p, s, -2, 0) + +/* TODO: die() can be removed as soon as all plugins use np_die() instead. */ void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); /* Return codes for _set_thresholds */ @@ -64,4 +81,7 @@ char *np_extract_value(const char*, const char*, char); */ #define np_extract_ntpvar(l, n) np_extract_value(l, n, ',') +/* Given a numerical status, return a pointer to the according string. */ +const char *state_text(int); + #endif /* _UTILS_BASE_ */ diff --git a/plugins/utils.c b/plugins/utils.c index 45373909..91fa671f 100644 --- a/plugins/utils.c +++ b/plugins/utils.c @@ -147,23 +147,6 @@ print_revision (const char *command_name, const char *revision) command_name, revision, PACKAGE, VERSION); } -const char * -state_text (int result) -{ - switch (result) { - case STATE_OK: - return "OK"; - case STATE_WARNING: - return "WARNING"; - case STATE_CRITICAL: - return "CRITICAL"; - case STATE_DEPENDENT: - return "DEPENDENT"; - default: - return "UNKNOWN"; - } -} - void timeout_alarm_handler (int signo) { diff --git a/plugins/utils.h b/plugins/utils.h index d6e9c8f7..9912fbf2 100644 --- a/plugins/utils.h +++ b/plugins/utils.h @@ -92,8 +92,6 @@ void usage4(const char *) __attribute__((noreturn)); void usage5(void) __attribute__((noreturn)); void usage_va(const char *fmt, ...) __attribute__((noreturn)); -const char *state_text (int); - #define max(a,b) (((a)>(b))?(a):(b)) #define min(a,b) (((a)<(b))?(a):(b))