summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Weiss <hweiss@users.sourceforge.net>2009-04-22 00:28:53 +0200
committerHolger Weiss <hweiss@users.sourceforge.net>2009-05-10 13:37:35 +0200
commit006597a12d28d9cd752b3eeb56dff3bc97049f4c (patch)
tree26e322d4b996b901e0d928e11bba46658646b30f
parentdd52d7e5e7acfd42243bc1ce173a0bf5d62fe347 (diff)
downloadmonitoring-plugins-refs/heads/hw/output/functions.tar.gz
Make C plugin output format configurablehw/output/functions
The development guidelines¹ currently state that the plugin output should be in the format "SERVICE STATUS: Information text". However, the SERVICE and STATUS information is redundant, as the plugin caller (e.g., Nagios) should know which SERVICE is checked and the STATUS is returned via the plugin's exit code. After discussing² this issue on the development list, we decided to make the plugin output configurable at compile time (separately for "normal" and "verbose" output). ¹ http://nagiosplug.sf.net/developer-guidelines.html ² http://thread.gmane.org/gmane.network.nagios.plugins.devel/5155 Signed-off-by: Holger Weiss <hweiss@users.sourceforge.net>
-rw-r--r--configure.in38
-rw-r--r--lib/utils_base.c205
-rw-r--r--lib/utils_base.h20
-rw-r--r--plugins/utils.c17
-rw-r--r--plugins/utils.h2
5 files changed, 263 insertions, 19 deletions
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"
39INSTALL_STRIP_PROGRAM="$INSTALL_STRIP_PROGRAM $extra_install_args" 39INSTALL_STRIP_PROGRAM="$INSTALL_STRIP_PROGRAM $extra_install_args"
40AC_SUBST(INSTALL) 40AC_SUBST(INSTALL)
41 41
42dnl Configure the plugin output format
43default_output_format="%s %x: %i\n"
44AC_ARG_WITH([standard_output_format],
45 [AS_HELP_STRING([--with-standard-output-format=FORMAT],
46 [specify the standard plugin output FORMAT; %p, %s, %x, and %m
47 will be replaced by the plugin name, the service name, the
48 status string, and the information message, respectively; tabs
49 or newlines can be inserted using \t or \n
50 @<:@default="%s %x: %m\n"@:>@])],
51 [standard_output_format=$withval],
52 [standard_output_format="yes"])
53AC_ARG_WITH([verbose_output_format],
54 [AS_HELP_STRING([--with-verbose-output-format=FORMAT],
55 [specify the verbose plugin output FORMAT; %p, %s, %x, and %m
56 will be replaced by the plugin name, the service name, the
57 status string, and the information message, respectively; tabs
58 or newlines can be inserted using \t or \n
59 @<:@default="%s %x: %m\n"@:>@])],
60 [verbose_output_format=$withval],
61 [verbose_output_format="yes"])
62AS_IF([test "$standard_output_format" = yes],
63 [standard_output_format=$default_output_format],
64 [test "$standard_output_format" = no],
65 [standard_output_format=""],
66 [test "$verbose_output_format" = yes],
67 [verbose_output_format=$default_output_format],
68 [test "$verbose_output_format" = no],
69 [verbose_output_format=""])
70AC_DEFINE_UNQUOTED([STANDARD_OUTPUT_FORMAT], ["$standard_output_format"],
71 [Define the standard plugin output format.])
72AC_DEFINE_UNQUOTED([VERBOSE_OUTPUT_FORMAT], ["$verbose_output_format"],
73 [Define the verbose plugin output format.])
74
42AC_PROG_CC 75AC_PROG_CC
43gl_EARLY 76gl_EARLY
44AC_PROG_GCC_TRADITIONAL 77AC_PROG_GCC_TRADITIONAL
@@ -150,6 +183,11 @@ AC_CHECK_LIB(socket,socket,SOCKETLIBS="$SOCKETLIBS -lsocket")
150AC_CHECK_LIB(resolv,main,SOCKETLIBS="$SOCKETLIBS -lresolv") 183AC_CHECK_LIB(resolv,main,SOCKETLIBS="$SOCKETLIBS -lresolv")
151AC_SUBST(SOCKETLIBS) 184AC_SUBST(SOCKETLIBS)
152 185
186dnl check for basename(3) which needs -lgen on some systems (e.g. IRIX)
187AC_CHECK_HEADERS([libgen.h])
188AC_SEARCH_LIBS([basename], [gen])
189AC_CHECK_FUNCS([basename])
190
153dnl 191dnl
154dnl check for math-related functions needing -lm 192dnl check for math-related functions needing -lm
155AC_CHECK_HEADERS(math.h) 193AC_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 @@
24* 24*
25*****************************************************************************/ 25*****************************************************************************/
26 26
27#if HAVE_LIBGEN_H
28#include <libgen.h> /* basename(3) */
29#endif
30#include <stdarg.h>
27#include "common.h" 31#include "common.h"
28#include <stdarg.h> 32#include <stdarg.h>
29#include "utils_base.h" 33#include "utils_base.h"
30 34
35#define PRINT_OUTPUT(fmt, ap) \
36 do { \
37 fmt = insert_syserr(fmt); \
38 va_start(ap, fmt); \
39 vprintf(fmt, ap); \
40 va_end(ap); \
41 } while (/* CONSTCOND */ 0)
42
43static char *insert_syserr(const char *);
44
45extern int errno;
46static int verbosity_level = -2;
47static const char *program_name = NULL;
48static const char *service_name = NULL;
49
50/*
51 * Set static variables for use in output functions. Usually, argv[0] may be
52 * used as progname, since we call basename(3) ourselves. If a verbosity value
53 * of -2 is specified, the verbosity_level won't be set. Currently, no flags
54 * are implemented.
55 */
56void
57np_set_output(const char *progname, const char *servname, int verbosity,
58 int flags __attribute__((unused)))
59{
60 static char pathbuf[128], progbuf[128], servbuf[32];
61
62 if (progname != NULL) {
63#if HAVE_BASENAME
64 /*
65 * Copy the progname into a temporary buffer in order to cope
66 * with basename(3) implementations which modify their argument.
67 * TODO: Maybe we should implement an np_basename()? Gnulib's
68 * base_name() dies on error, writing a message to stderr, which
69 * is probably not what we want. Once we have some replacement,
70 * the libgen-/basename(3)-related checks can be removed from
71 * configure.in.
72 */
73 strncpy(pathbuf, progname, sizeof(pathbuf) - 1);
74 pathbuf[sizeof(pathbuf) - 1] = '\0';
75 progname = basename(pathbuf);
76#endif
77 strncpy(progbuf, progname, sizeof(progbuf) - 1);
78 progbuf[sizeof(progbuf) - 1] = '\0';
79 program_name = progbuf;
80 }
81 if (servname != NULL) {
82 strncpy(servbuf, servname, sizeof(servbuf) - 1);
83 servbuf[sizeof(servbuf) - 1] = '\0';
84 service_name = servbuf;
85 }
86 if (verbosity != -2)
87 verbosity_level = verbosity;
88}
89
90int
91np_adjust_verbosity(int by)
92{
93 if (verbosity_level == -2)
94 verbosity_level = by;
95 else
96 verbosity_level += by;
97
98 /* We don't support verbosity levels < -1. */
99 if (verbosity_level < -1)
100 verbosity_level = -1;
101
102 return verbosity_level;
103}
104
105void
106np_debug(int verbosity, const char *fmt, ...)
107{
108 va_list ap;
109
110 if (verbosity_level != -1 && verbosity >= verbosity_level)
111 PRINT_OUTPUT(fmt, ap);
112}
113
114void
115np_verbose(const char *fmt, ...)
116{
117 va_list ap;
118
119 if (verbosity_level >= 1) {
120 PRINT_OUTPUT(fmt, ap);
121 putchar('\n');
122 }
123}
124
125void
126np_die(int status, const char *fmt, ...)
127{
128 va_list ap;
129 const char *p;
130
131 if (program_name == NULL || service_name == NULL)
132 PRINT_OUTPUT(fmt, ap);
133
134 for (p = (verbosity_level > 0) ?
135 VERBOSE_OUTPUT_FORMAT : STANDARD_OUTPUT_FORMAT;
136 *p != '\0'; p++) {
137 if (*p == '%') {
138 if (*++p == '\0')
139 break;
140 switch (*p) {
141 case 'm':
142 PRINT_OUTPUT(fmt, ap);
143 continue;
144 case 'p':
145 fputs(program_name, stdout);
146 continue;
147 case 's':
148 fputs(service_name, stdout);
149 continue;
150 case 'x':
151 fputs(state_text(status), stdout);
152 continue;
153 }
154 } else if (*p == '\\') {
155 if (*++p == '\0')
156 break;
157 switch (*p) {
158 case 'n':
159 putchar('\n');
160 continue;
161 case 't':
162 putchar('\t');
163 continue;
164 }
165 }
166 putchar(*p);
167 }
168 exit(status);
169}
170
171/* TODO: die() can be removed as soon as all plugins use np_die() instead. */
31void 172void
32die (int result, const char *fmt, ...) 173die (int result, const char *fmt, ...)
33{ 174{
@@ -308,3 +449,67 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
308 return value; 449 return value;
309} 450}
310 451
452/*
453 * Replace occurrences of "%m" by strerror(errno). Other printf(3)-style
454 * conversion specifications will be copied verbatim, including "%%", even if
455 * followed by an "m". Returns a pointer to a static buffer in order to not
456 * fail on memory allocation error.
457 */
458static char *
459insert_syserr(const char *buf)
460{
461 static char newbuf[8192];
462 char *errstr = strerror(errno);
463 size_t errlen = strlen(errstr);
464 size_t copylen;
465 unsigned i, j;
466
467 for (i = 0, j = 0; buf[i] != '\0' && j < sizeof(newbuf) - 2; i++, j++) {
468 if (buf[i] == '%') {
469 if (buf[++i] == 'm') {
470 copylen = (errlen > sizeof(newbuf) - j - 1) ?
471 sizeof(newbuf) - j - 1 : errlen;
472 memcpy(newbuf + j, errstr, copylen);
473 /*
474 * As we'll increment j by 1 after the iteration
475 * anyway, we only increment j by the number of
476 * copied bytes - 1.
477 */
478 j += copylen - 1;
479 continue;
480 } else {
481 /*
482 * The possibility to run into this block is the
483 * reason we checked for j < sizeof(newbuf) - 2
484 * instead of j < sizeof(newbuf) - 1.
485 */
486 newbuf[j++] = '%';
487 if (buf[i] == '\0')
488 break;
489 }
490 }
491 newbuf[j] = buf[i];
492 }
493 newbuf[j] = '\0';
494 return newbuf;
495}
496
497/*
498 * Given a numerical status, return a pointer to the according string.
499 */
500const char *
501state_text(int result)
502{
503 switch (result) {
504 case STATE_OK:
505 return "OK";
506 case STATE_WARNING:
507 return "WARNING";
508 case STATE_CRITICAL:
509 return "CRITICAL";
510 case STATE_DEPENDENT:
511 return "DEPENDENT";
512 default:
513 return "UNKNOWN";
514 }
515}
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 *);
37 37
38char *np_escaped_string (const char *); 38char *np_escaped_string (const char *);
39 39
40void np_set_output(const char *, const char *, int, int);
41int np_adjust_verbosity(int);
42void np_debug(int, const char *, ...)
43 __attribute__((format(printf, 2, 3)));
44void np_verbose(const char *, ...)
45 __attribute__((format(printf, 1, 2)));
46void np_die(int, const char *, ...)
47 __attribute__((noreturn, format(printf, 2, 3)));
48
49#define np_verbatim(s) np_verbose("%s", s)
50#define np_increase_verbosity(i) np_adjust_verbosity(i)
51#define np_decrease_verbosity(i) np_adjust_verbosity(-i)
52#define np_get_verbosity() np_adjust_verbosity(0)
53#define np_set_verbosity(v) np_set_output(NULL, NULL, v, 0)
54#define np_set_mynames(p, s) np_set_output(p, s, -2, 0)
55
56/* TODO: die() can be removed as soon as all plugins use np_die() instead. */
40void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); 57void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3)));
41 58
42/* Return codes for _set_thresholds */ 59/* Return codes for _set_thresholds */
@@ -64,4 +81,7 @@ char *np_extract_value(const char*, const char*, char);
64 */ 81 */
65#define np_extract_ntpvar(l, n) np_extract_value(l, n, ',') 82#define np_extract_ntpvar(l, n) np_extract_value(l, n, ',')
66 83
84/* Given a numerical status, return a pointer to the according string. */
85const char *state_text(int);
86
67#endif /* _UTILS_BASE_ */ 87#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)
147 command_name, revision, PACKAGE, VERSION); 147 command_name, revision, PACKAGE, VERSION);
148} 148}
149 149
150const char *
151state_text (int result)
152{
153 switch (result) {
154 case STATE_OK:
155 return "OK";
156 case STATE_WARNING:
157 return "WARNING";
158 case STATE_CRITICAL:
159 return "CRITICAL";
160 case STATE_DEPENDENT:
161 return "DEPENDENT";
162 default:
163 return "UNKNOWN";
164 }
165}
166
167void 150void
168timeout_alarm_handler (int signo) 151timeout_alarm_handler (int signo)
169{ 152{
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));
92void usage5(void) __attribute__((noreturn)); 92void usage5(void) __attribute__((noreturn));
93void usage_va(const char *fmt, ...) __attribute__((noreturn)); 93void usage_va(const char *fmt, ...) __attribute__((noreturn));
94 94
95const char *state_text (int);
96
97#define max(a,b) (((a)>(b))?(a):(b)) 95#define max(a,b) (((a)>(b))?(a):(b))
98#define min(a,b) (((a)<(b))?(a):(b)) 96#define min(a,b) (((a)<(b))?(a):(b))
99 97