1 /*****************************************************************************
2 *
3 * utils.c
4 *
5 * Library of useful functions for plugins
6 *
7 * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
8 * Copyright (c) 2006 Nagios Plugin Development Team
9 * License: GPL
10 *
11 * $Revision$
12 * $Date$
13 ****************************************************************************/
15 #define LOCAL_TIMEOUT_ALARM_HANDLER
17 #include "common.h"
18 #include "utils.h"
19 #include "utils_base.h"
20 #include <stdarg.h>
21 #include <limits.h>
23 #include <arpa/inet.h>
25 extern void print_usage (void);
26 extern const char *progname;
28 #define STRLEN 64
29 #define TXTBLK 128
31 /* **************************************************************************
32 * max_state(STATE_x, STATE_y)
33 * compares STATE_x to STATE_y and returns result based on the following
34 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
35 *
36 * Note that numerically the above does not hold
37 ****************************************************************************/
39 int
40 max_state (int a, int b)
41 {
42 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
43 return STATE_CRITICAL;
44 else if (a == STATE_WARNING || b == STATE_WARNING)
45 return STATE_WARNING;
46 else if (a == STATE_OK || b == STATE_OK)
47 return STATE_OK;
48 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
49 return STATE_UNKNOWN;
50 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
51 return STATE_DEPENDENT;
52 else
53 return max (a, b);
54 }
56 /* **************************************************************************
57 * max_state_alt(STATE_x, STATE_y)
58 * compares STATE_x to STATE_y and returns result based on the following
59 * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL
60 *
61 * The main difference between max_state_alt and max_state it that it doesn't
62 * allow setting a default to UNKNOWN. It will instead prioritixe any valid
63 * non-OK state.
64 ****************************************************************************/
66 int
67 max_state_alt (int a, int b)
68 {
69 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
70 return STATE_CRITICAL;
71 else if (a == STATE_WARNING || b == STATE_WARNING)
72 return STATE_WARNING;
73 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
74 return STATE_UNKNOWN;
75 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
76 return STATE_DEPENDENT;
77 else if (a == STATE_OK || b == STATE_OK)
78 return STATE_OK;
79 else
80 return max (a, b);
81 }
83 void usage (const char *msg)
84 {
85 printf ("%s\n", msg);
86 print_usage ();
87 exit (STATE_UNKNOWN);
88 }
90 void usage_va (const char *fmt, ...)
91 {
92 va_list ap;
93 printf("%s: ", progname);
94 va_start(ap, fmt);
95 vprintf(fmt, ap);
96 va_end(ap);
97 printf("\n");
98 exit (STATE_UNKNOWN);
99 }
101 void usage2(const char *msg, const char *arg)
102 {
103 printf ("%s: %s - %s\n", progname, msg, arg?arg:"(null)" );
104 print_usage ();
105 exit (STATE_UNKNOWN);
106 }
108 void
109 usage3 (const char *msg, int arg)
110 {
111 printf ("%s: %s - %c\n", progname, msg, arg);
112 print_usage();
113 exit (STATE_UNKNOWN);
114 }
116 void
117 usage4 (const char *msg)
118 {
119 printf ("%s: %s\n", progname, msg);
120 print_usage();
121 exit (STATE_UNKNOWN);
122 }
124 void
125 usage5 (void)
126 {
127 print_usage();
128 exit (STATE_UNKNOWN);
129 }
131 char *
132 clean_revstring (const char *revstring)
133 {
134 char plugin_revision[STRLEN];
135 plugin_revision[0] = 'v';
136 if (sscanf (revstring,"$Revision: %[0-9.]", plugin_revision + 1) == 1)
137 return strscpy (NULL, plugin_revision);
138 else
139 return strscpy (NULL, "N/A");
140 }
142 void
143 print_revision (const char *command_name, const char *revision_string)
144 {
145 char plugin_revision[STRLEN];
147 printf ("%s %s (%s %s)\n",
148 command_name, clean_revstring(revision_string), PACKAGE, VERSION);
149 }
151 const char *
152 state_text (int result)
153 {
154 switch (result) {
155 case STATE_OK:
156 return "OK";
157 case STATE_WARNING:
158 return "WARNING";
159 case STATE_CRITICAL:
160 return "CRITICAL";
161 case STATE_DEPENDENT:
162 return "DEPENDENT";
163 default:
164 return "UNKNOWN";
165 }
166 }
168 void
169 timeout_alarm_handler (int signo)
170 {
171 if (signo == SIGALRM) {
172 printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
173 timeout_interval);
174 exit (STATE_CRITICAL);
175 }
176 }
178 int
179 is_numeric (char *number)
180 {
181 char tmp[1];
182 float x;
184 if (!number)
185 return FALSE;
186 else if (sscanf (number, "%f%c", &x, tmp) == 1)
187 return TRUE;
188 else
189 return FALSE;
190 }
192 int
193 is_positive (char *number)
194 {
195 if (is_numeric (number) && atof (number) > 0.0)
196 return TRUE;
197 else
198 return FALSE;
199 }
201 int
202 is_negative (char *number)
203 {
204 if (is_numeric (number) && atof (number) < 0.0)
205 return TRUE;
206 else
207 return FALSE;
208 }
210 int
211 is_nonnegative (char *number)
212 {
213 if (is_numeric (number) && atof (number) >= 0.0)
214 return TRUE;
215 else
216 return FALSE;
217 }
219 int
220 is_percentage (char *number)
221 {
222 int x;
223 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
224 return TRUE;
225 else
226 return FALSE;
227 }
229 int
230 is_integer (char *number)
231 {
232 long int n;
234 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
235 return FALSE;
237 n = strtol (number, NULL, 10);
239 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
240 return TRUE;
241 else
242 return FALSE;
243 }
245 int
246 is_intpos (char *number)
247 {
248 if (is_integer (number) && atoi (number) > 0)
249 return TRUE;
250 else
251 return FALSE;
252 }
254 int
255 is_intneg (char *number)
256 {
257 if (is_integer (number) && atoi (number) < 0)
258 return TRUE;
259 else
260 return FALSE;
261 }
263 int
264 is_intnonneg (char *number)
265 {
266 if (is_integer (number) && atoi (number) >= 0)
267 return TRUE;
268 else
269 return FALSE;
270 }
272 int
273 is_intpercent (char *number)
274 {
275 int i;
276 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
277 return TRUE;
278 else
279 return FALSE;
280 }
282 int
283 is_option (char *str)
284 {
285 if (!str)
286 return FALSE;
287 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
288 return TRUE;
289 else
290 return FALSE;
291 }
293 #ifdef NEED_GETTIMEOFDAY
294 int
295 gettimeofday (struct timeval *tv, struct timezone *tz)
296 {
297 tv->tv_usec = 0;
298 tv->tv_sec = (long) time ((time_t) 0);
299 }
300 #endif
304 double
305 delta_time (struct timeval tv)
306 {
307 struct timeval now;
309 gettimeofday (&now, NULL);
310 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
311 }
315 long
316 deltime (struct timeval tv)
317 {
318 struct timeval now;
319 gettimeofday (&now, NULL);
320 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
321 }
326 void
327 strip (char *buffer)
328 {
329 size_t x;
330 int i;
332 for (x = strlen (buffer); x >= 1; x--) {
333 i = x - 1;
334 if (buffer[i] == ' ' ||
335 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
336 buffer[i] = '\0';
337 else
338 break;
339 }
340 return;
341 }
344 /******************************************************************************
345 *
346 * Copies one string to another. Any previously existing data in
347 * the destination string is lost.
348 *
349 * Example:
350 *
351 * char *str=NULL;
352 * str = strscpy("This is a line of text with no trailing newline");
353 *
354 *****************************************************************************/
356 char *
357 strscpy (char *dest, const char *src)
358 {
359 if (src == NULL)
360 return NULL;
362 asprintf (&dest, "%s", src);
364 return dest;
365 }
369 /******************************************************************************
370 *
371 * Returns a pointer to the next line of a multiline string buffer
372 *
373 * Given a pointer string, find the text following the next sequence
374 * of \r and \n characters. This has the effect of skipping blank
375 * lines as well
376 *
377 * Example:
378 *
379 * Given text as follows:
380 *
381 * ==============================
382 * This
383 * is
384 * a
385 *
386 * multiline string buffer
387 * ==============================
388 *
389 * int i=0;
390 * char *str=NULL;
391 * char *ptr=NULL;
392 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
393 * ptr = str;
394 * while (ptr) {
395 * printf("%d %s",i++,firstword(ptr));
396 * ptr = strnl(ptr);
397 * }
398 *
399 * Produces the following:
400 *
401 * 1 This
402 * 2 is
403 * 3 a
404 * 4 multiline
405 *
406 * NOTE: The 'firstword()' function is conceptual only and does not
407 * exist in this package.
408 *
409 * NOTE: Although the second 'ptr' variable is not strictly needed in
410 * this example, it is good practice with these utilities. Once
411 * the * pointer is advance in this manner, it may no longer be
412 * handled with * realloc(). So at the end of the code fragment
413 * above, * strscpy(str,"foo") work perfectly fine, but
414 * strscpy(ptr,"foo") will * cause the the program to crash with
415 * a segmentation fault.
416 *
417 *****************************************************************************/
419 char *
420 strnl (char *str)
421 {
422 size_t len;
423 if (str == NULL)
424 return NULL;
425 str = strpbrk (str, "\r\n");
426 if (str == NULL)
427 return NULL;
428 len = strspn (str, "\r\n");
429 if (str[len] == '\0')
430 return NULL;
431 str += len;
432 if (strlen (str) == 0)
433 return NULL;
434 return str;
435 }
438 /******************************************************************************
439 *
440 * Like strscpy, except only the portion of the source string up to
441 * the provided delimiter is copied.
442 *
443 * Example:
444 *
445 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
446 * printf("%s\n",str);
447 *
448 * Produces:
449 *
450 *This is a line of te
451 *
452 *****************************************************************************/
454 char *
455 strpcpy (char *dest, const char *src, const char *str)
456 {
457 size_t len;
459 if (src)
460 len = strcspn (src, str);
461 else
462 return NULL;
464 if (dest == NULL || strlen (dest) < len)
465 dest = realloc (dest, len + 1);
466 if (dest == NULL)
467 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
469 strncpy (dest, src, len);
470 dest[len] = '\0';
472 return dest;
473 }
477 /******************************************************************************
478 *
479 * Like strscat, except only the portion of the source string up to
480 * the provided delimiter is copied.
481 *
482 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
483 * str = strpcat(str,"This is a line of text with no trailing newline","x");
484 * printf("%s\n",str);
485 *
486 *This is a line of texThis is a line of tex
487 *
488 *****************************************************************************/
490 char *
491 strpcat (char *dest, const char *src, const char *str)
492 {
493 size_t len, l2;
495 if (dest)
496 len = strlen (dest);
497 else
498 len = 0;
500 if (src) {
501 l2 = strcspn (src, str);
502 }
503 else {
504 return dest;
505 }
507 dest = realloc (dest, len + l2 + 1);
508 if (dest == NULL)
509 die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
511 strncpy (dest + len, src, l2);
512 dest[len + l2] = '\0';
514 return dest;
515 }
517 /******************************************************************************
518 *
519 * Print perfdata in a standard format
520 *
521 ******************************************************************************/
523 char *perfdata (const char *label,
524 long int val,
525 const char *uom,
526 int warnp,
527 long int warn,
528 int critp,
529 long int crit,
530 int minp,
531 long int minv,
532 int maxp,
533 long int maxv)
534 {
535 char *data = NULL;
537 if (strpbrk (label, "'= "))
538 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
539 else
540 asprintf (&data, "%s=%ld%s;", label, val, uom);
542 if (warnp)
543 asprintf (&data, "%s%ld;", data, warn);
544 else
545 asprintf (&data, "%s;", data);
547 if (critp)
548 asprintf (&data, "%s%ld;", data, crit);
549 else
550 asprintf (&data, "%s;", data);
552 if (minp)
553 asprintf (&data, "%s%ld", data, minv);
555 if (maxp)
556 asprintf (&data, "%s;%ld", data, maxv);
558 return data;
559 }
562 char *fperfdata (const char *label,
563 double val,
564 const char *uom,
565 int warnp,
566 double warn,
567 int critp,
568 double crit,
569 int minp,
570 double minv,
571 int maxp,
572 double maxv)
573 {
574 char *data = NULL;
576 if (strpbrk (label, "'= "))
577 asprintf (&data, "'%s'=", label);
578 else
579 asprintf (&data, "%s=", label);
581 asprintf (&data, "%s%f", data, val);
582 asprintf (&data, "%s%s;", data, uom);
584 if (warnp)
585 asprintf (&data, "%s%f", data, warn);
587 asprintf (&data, "%s;", data);
589 if (critp)
590 asprintf (&data, "%s%f", data, crit);
592 asprintf (&data, "%s;", data);
594 if (minp)
595 asprintf (&data, "%s%f", data, minv);
597 if (maxp) {
598 asprintf (&data, "%s;", data);
599 asprintf (&data, "%s%f", data, maxv);
600 }
602 return data;
603 }