1 /*****************************************************************************
2 *
3 * utils.c
4 *
5 * Library of useful functions for plugins
6 *
7 * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
8 * License: GPL
9 *
10 * $Revision$
11 * $Date$
12 ****************************************************************************/
14 #define LOCAL_TIMEOUT_ALARM_HANDLER
16 #include "common.h"
17 #include "utils.h"
18 #include <stdarg.h>
19 #include <limits.h>
21 #include <arpa/inet.h>
23 extern void print_usage (void);
24 extern const char *progname;
26 #define STRLEN 64
27 #define TXTBLK 128
29 /* **************************************************************************
30 * max_state(STATE_x, STATE_y)
31 * compares STATE_x to STATE_y and returns result based on the following
32 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
33 *
34 * Note that numerically the above does not hold
35 ****************************************************************************/
37 int
38 max_state (int a, int b)
39 {
40 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
41 return STATE_CRITICAL;
42 else if (a == STATE_WARNING || b == STATE_WARNING)
43 return STATE_WARNING;
44 else if (a == STATE_OK || b == STATE_OK)
45 return STATE_OK;
46 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
47 return STATE_UNKNOWN;
48 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
49 return STATE_DEPENDENT;
50 else
51 return max (a, b);
52 }
54 void usage (const char *msg)
55 {
56 printf ("%s", msg);
57 print_usage ();
58 exit (STATE_UNKNOWN);
59 }
61 void usage2(const char *msg, const char *arg)
62 {
63 printf ("%s: %s - %s\n",progname,msg,arg);
64 print_usage ();
65 exit (STATE_UNKNOWN);
66 }
68 void
69 usage3 (const char *msg, int arg)
70 {
71 printf ("%s: %s - %c\n", progname, msg, arg);
72 print_usage();
73 exit (STATE_UNKNOWN);
74 }
76 void
77 usage4 (const char *msg)
78 {
79 printf ("%s: %s\n", progname, msg);
80 print_usage();
81 exit (STATE_UNKNOWN);
82 }
84 void
85 support (void)
86 {
87 printf (_("\n\
88 Send email to nagios-users@lists.sourceforge.net if you have questions\n\
89 regarding use of this software. To submit patches or suggest improvements,\n\
90 send email to nagiosplug-devel@lists.sourceforge.net\n"));
91 }
94 char *
95 clean_revstring (const char *revstring)
96 {
97 char plugin_revision[STRLEN];
98 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
99 return strscpy (NULL, plugin_revision);
100 else
101 return strscpy (NULL, "N/A");
102 }
104 void
105 print_revision (const char *command_name, const char *revision_string)
106 {
107 char plugin_revision[STRLEN];
109 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
110 strncpy (plugin_revision, "N/A", STRLEN);
111 printf ("%s (%s %s) %s\n",
112 command_name, PACKAGE, VERSION, plugin_revision);
113 printf (_("\
114 The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
115 copies of the plugins under the terms of the GNU General Public License.\n\
116 For more information about these matters, see the file named COPYING.\n"));
118 }
120 const char *
121 state_text (int result)
122 {
123 switch (result) {
124 case STATE_OK:
125 return "OK";
126 case STATE_WARNING:
127 return "WARNING";
128 case STATE_CRITICAL:
129 return "CRITICAL";
130 case STATE_DEPENDENT:
131 return "DEPENDENT";
132 default:
133 return "UNKNOWN";
134 }
135 }
137 void
138 die (int result, const char *fmt, ...)
139 {
140 va_list ap;
141 va_start (ap, fmt);
142 vprintf (fmt, ap);
143 va_end (ap);
144 exit (result);
145 }
147 void
148 timeout_alarm_handler (int signo)
149 {
150 if (signo == SIGALRM) {
151 printf ("CRITICAL - Plugin timed out after %d seconds\n",
152 timeout_interval);
153 exit (STATE_CRITICAL);
154 }
155 }
157 int
158 is_numeric (char *number)
159 {
160 char tmp[1];
161 float x;
163 if (!number)
164 return FALSE;
165 else if (sscanf (number, "%f%c", &x, tmp) == 1)
166 return TRUE;
167 else
168 return FALSE;
169 }
171 int
172 is_positive (char *number)
173 {
174 if (is_numeric (number) && atof (number) > 0.0)
175 return TRUE;
176 else
177 return FALSE;
178 }
180 int
181 is_negative (char *number)
182 {
183 if (is_numeric (number) && atof (number) < 0.0)
184 return TRUE;
185 else
186 return FALSE;
187 }
189 int
190 is_nonnegative (char *number)
191 {
192 if (is_numeric (number) && atof (number) >= 0.0)
193 return TRUE;
194 else
195 return FALSE;
196 }
198 int
199 is_percentage (char *number)
200 {
201 int x;
202 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
203 return TRUE;
204 else
205 return FALSE;
206 }
208 int
209 is_integer (char *number)
210 {
211 long int n;
213 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
214 return FALSE;
216 n = strtol (number, NULL, 10);
218 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
219 return TRUE;
220 else
221 return FALSE;
222 }
224 int
225 is_intpos (char *number)
226 {
227 if (is_integer (number) && atoi (number) > 0)
228 return TRUE;
229 else
230 return FALSE;
231 }
233 int
234 is_intneg (char *number)
235 {
236 if (is_integer (number) && atoi (number) < 0)
237 return TRUE;
238 else
239 return FALSE;
240 }
242 int
243 is_intnonneg (char *number)
244 {
245 if (is_integer (number) && atoi (number) >= 0)
246 return TRUE;
247 else
248 return FALSE;
249 }
251 int
252 is_intpercent (char *number)
253 {
254 int i;
255 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
256 return TRUE;
257 else
258 return FALSE;
259 }
261 int
262 is_option (char *str)
263 {
264 if (!str)
265 return FALSE;
266 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
267 return TRUE;
268 else
269 return FALSE;
270 }
274 #ifdef NEED_GETTIMEOFDAY
275 int
276 gettimeofday (struct timeval *tv, struct timezone *tz)
277 {
278 tv->tv_usec = 0;
279 tv->tv_sec = (long) time ((time_t) 0);
280 }
281 #endif
285 double
286 delta_time (struct timeval tv)
287 {
288 struct timeval now;
290 gettimeofday (&now, NULL);
291 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
292 }
296 long
297 deltime (struct timeval tv)
298 {
299 struct timeval now;
300 gettimeofday (&now, NULL);
301 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
302 }
307 void
308 strip (char *buffer)
309 {
310 size_t x;
311 int i;
313 for (x = strlen (buffer); x >= 1; x--) {
314 i = x - 1;
315 if (buffer[i] == ' ' ||
316 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
317 buffer[i] = '\0';
318 else
319 break;
320 }
321 return;
322 }
325 /******************************************************************************
326 *
327 * Copies one string to another. Any previously existing data in
328 * the destination string is lost.
329 *
330 * Example:
331 *
332 * char *str=NULL;
333 * str = strscpy("This is a line of text with no trailing newline");
334 *
335 *****************************************************************************/
337 char *
338 strscpy (char *dest, const char *src)
339 {
340 if (src == NULL)
341 return NULL;
343 asprintf (&dest, "%s", src);
345 return dest;
346 }
350 /******************************************************************************
351 *
352 * Returns a pointer to the next line of a multiline string buffer
353 *
354 * Given a pointer string, find the text following the next sequence
355 * of \r and \n characters. This has the effect of skipping blank
356 * lines as well
357 *
358 * Example:
359 *
360 * Given text as follows:
361 *
362 * ==============================
363 * This
364 * is
365 * a
366 *
367 * multiline string buffer
368 * ==============================
369 *
370 * int i=0;
371 * char *str=NULL;
372 * char *ptr=NULL;
373 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
374 * ptr = str;
375 * while (ptr) {
376 * printf("%d %s",i++,firstword(ptr));
377 * ptr = strnl(ptr);
378 * }
379 *
380 * Produces the following:
381 *
382 * 1 This
383 * 2 is
384 * 3 a
385 * 4 multiline
386 *
387 * NOTE: The 'firstword()' function is conceptual only and does not
388 * exist in this package.
389 *
390 * NOTE: Although the second 'ptr' variable is not strictly needed in
391 * this example, it is good practice with these utilities. Once
392 * the * pointer is advance in this manner, it may no longer be
393 * handled with * realloc(). So at the end of the code fragment
394 * above, * strscpy(str,"foo") work perfectly fine, but
395 * strscpy(ptr,"foo") will * cause the the program to crash with
396 * a segmentation fault.
397 *
398 *****************************************************************************/
400 char *
401 strnl (char *str)
402 {
403 size_t len;
404 if (str == NULL)
405 return NULL;
406 str = strpbrk (str, "\r\n");
407 if (str == NULL)
408 return NULL;
409 len = strspn (str, "\r\n");
410 if (str[len] == '\0')
411 return NULL;
412 str += len;
413 if (strlen (str) == 0)
414 return NULL;
415 return str;
416 }
419 /******************************************************************************
420 *
421 * Like strscpy, except only the portion of the source string up to
422 * the provided delimiter is copied.
423 *
424 * Example:
425 *
426 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
427 * printf("%s\n",str);
428 *
429 * Produces:
430 *
431 *This is a line of te
432 *
433 *****************************************************************************/
435 char *
436 strpcpy (char *dest, const char *src, const char *str)
437 {
438 size_t len;
440 if (src)
441 len = strcspn (src, str);
442 else
443 return NULL;
445 if (dest == NULL || strlen (dest) < len)
446 dest = realloc (dest, len + 1);
447 if (dest == NULL)
448 die (STATE_UNKNOWN, "failed realloc in strpcpy\n");
450 strncpy (dest, src, len);
451 dest[len] = '\0';
453 return dest;
454 }
458 /******************************************************************************
459 *
460 * Like strscat, except only the portion of the source string up to
461 * the provided delimiter is copied.
462 *
463 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
464 * str = strpcat(str,"This is a line of text with no trailing newline","x");
465 * printf("%s\n",str);
466 *
467 *This is a line of texThis is a line of tex
468 *
469 *****************************************************************************/
471 char *
472 strpcat (char *dest, const char *src, const char *str)
473 {
474 size_t len, l2;
476 if (dest)
477 len = strlen (dest);
478 else
479 len = 0;
481 if (src) {
482 l2 = strcspn (src, str);
483 }
484 else {
485 return dest;
486 }
488 dest = realloc (dest, len + l2 + 1);
489 if (dest == NULL)
490 die (STATE_UNKNOWN, "failed malloc in strscat\n");
492 strncpy (dest + len, src, l2);
493 dest[len + l2] = '\0';
495 return dest;
496 }
499 /******************************************************************************
500 *
501 * Print perfdata in a standard format
502 *
503 ******************************************************************************/
505 char *perfdata (const char *label,
506 long int val,
507 const char *uom,
508 int warnp,
509 long int warn,
510 int critp,
511 long int crit,
512 int minp,
513 long int minv,
514 int maxp,
515 long int maxv)
516 {
517 char *data = NULL;
519 if (strpbrk (label, "'= "))
520 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
521 else
522 asprintf (&data, "%s=%ld%s;", label, val, uom);
524 if (warnp)
525 asprintf (&data, "%s%ld;", data, warn);
526 else
527 asprintf (&data, "%s;", data);
529 if (critp)
530 asprintf (&data, "%s%ld;", data, crit);
531 else
532 asprintf (&data, "%s;", data);
534 if (minp)
535 asprintf (&data, "%s%ld", data, minv);
537 if (maxp)
538 asprintf (&data, "%s;%ld", data, maxv);
540 return data;
541 }
544 char *fperfdata (const char *label,
545 double val,
546 const char *uom,
547 int warnp,
548 double warn,
549 int critp,
550 double crit,
551 int minp,
552 double minv,
553 int maxp,
554 double maxv)
555 {
556 char *data = NULL;
558 if (strpbrk (label, "'= "))
559 asprintf (&data, "'%s'=", label);
560 else
561 asprintf (&data, "%s=", label);
563 asprintf (&data, "%s%f", data, val);
564 asprintf (&data, "%s%s;", data, uom);
566 if (warnp)
567 asprintf (&data, "%s%f", data, warn);
569 asprintf (&data, "%s;", data);
571 if (critp)
572 asprintf (&data, "%s%f", data, crit);
574 asprintf (&data, "%s;", data);
576 if (minp)
577 asprintf (&data, "%s%f", data, minv);
579 if (maxp) {
580 asprintf (&data, "%s;", data);
581 asprintf (&data, "%s%f", data, maxv);
582 }
584 return data;
585 }