diff options
author | Holger Weiss <hweiss@users.sourceforge.net> | 2009-04-22 00:28:53 +0200 |
---|---|---|
committer | Holger Weiss <hweiss@users.sourceforge.net> | 2009-05-10 13:37:35 +0200 |
commit | 006597a12d28d9cd752b3eeb56dff3bc97049f4c (patch) | |
tree | 26e322d4b996b901e0d928e11bba46658646b30f /lib/utils_base.c | |
parent | dd52d7e5e7acfd42243bc1ce173a0bf5d62fe347 (diff) | |
download | monitoring-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>
Diffstat (limited to 'lib/utils_base.c')
-rw-r--r-- | lib/utils_base.c | 205 |
1 files changed, 205 insertions, 0 deletions
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 | |||
43 | static char *insert_syserr(const char *); | ||
44 | |||
45 | extern int errno; | ||
46 | static int verbosity_level = -2; | ||
47 | static const char *program_name = NULL; | ||
48 | static 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 | */ | ||
56 | void | ||
57 | np_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 | |||
90 | int | ||
91 | np_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 | |||
105 | void | ||
106 | np_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 | |||
114 | void | ||
115 | np_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 | |||
125 | void | ||
126 | np_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. */ | ||
31 | void | 172 | void |
32 | die (int result, const char *fmt, ...) | 173 | die (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 | */ | ||
458 | static char * | ||
459 | insert_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 | */ | ||
500 | const char * | ||
501 | state_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 | } | ||