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 void usage (const char *msg)
57 {
58 printf ("%s\n", msg);
59 print_usage ();
60 exit (STATE_UNKNOWN);
61 }
63 void usage_va (const char *fmt, ...)
64 {
65 va_list ap;
66 printf("%s: ", progname);
67 va_start(ap, fmt);
68 vprintf(fmt, ap);
69 va_end(ap);
70 printf("\n");
71 exit (STATE_UNKNOWN);
72 }
74 void usage2(const char *msg, const char *arg)
75 {
76 printf ("%s: %s - %s\n", progname, msg, arg?arg:"(null)" );
77 print_usage ();
78 exit (STATE_UNKNOWN);
79 }
81 void
82 usage3 (const char *msg, int arg)
83 {
84 printf ("%s: %s - %c\n", progname, msg, arg);
85 print_usage();
86 exit (STATE_UNKNOWN);
87 }
89 void
90 usage4 (const char *msg)
91 {
92 printf ("%s: %s\n", progname, msg);
93 print_usage();
94 exit (STATE_UNKNOWN);
95 }
97 char *
98 clean_revstring (const char *revstring)
99 {
100 char plugin_revision[STRLEN];
101 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
102 return strscpy (NULL, plugin_revision);
103 else
104 return strscpy (NULL, "N/A");
105 }
107 void
108 print_revision (const char *command_name, const char *revision_string)
109 {
110 char plugin_revision[STRLEN];
112 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
113 strncpy (plugin_revision, "N/A", STRLEN);
114 printf ("%s (%s %s) %s\n",
115 command_name, PACKAGE, VERSION, plugin_revision);
116 }
118 const char *
119 state_text (int result)
120 {
121 switch (result) {
122 case STATE_OK:
123 return "OK";
124 case STATE_WARNING:
125 return "WARNING";
126 case STATE_CRITICAL:
127 return "CRITICAL";
128 case STATE_DEPENDENT:
129 return "DEPENDENT";
130 default:
131 return "UNKNOWN";
132 }
133 }
135 void
136 timeout_alarm_handler (int signo)
137 {
138 if (signo == SIGALRM) {
139 printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
140 timeout_interval);
141 exit (STATE_CRITICAL);
142 }
143 }
145 int
146 is_numeric (char *number)
147 {
148 char tmp[1];
149 float x;
151 if (!number)
152 return FALSE;
153 else if (sscanf (number, "%f%c", &x, tmp) == 1)
154 return TRUE;
155 else
156 return FALSE;
157 }
159 int
160 is_positive (char *number)
161 {
162 if (is_numeric (number) && atof (number) > 0.0)
163 return TRUE;
164 else
165 return FALSE;
166 }
168 int
169 is_negative (char *number)
170 {
171 if (is_numeric (number) && atof (number) < 0.0)
172 return TRUE;
173 else
174 return FALSE;
175 }
177 int
178 is_nonnegative (char *number)
179 {
180 if (is_numeric (number) && atof (number) >= 0.0)
181 return TRUE;
182 else
183 return FALSE;
184 }
186 int
187 is_percentage (char *number)
188 {
189 int x;
190 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
191 return TRUE;
192 else
193 return FALSE;
194 }
196 int
197 is_integer (char *number)
198 {
199 long int n;
201 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
202 return FALSE;
204 n = strtol (number, NULL, 10);
206 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
207 return TRUE;
208 else
209 return FALSE;
210 }
212 int
213 is_intpos (char *number)
214 {
215 if (is_integer (number) && atoi (number) > 0)
216 return TRUE;
217 else
218 return FALSE;
219 }
221 int
222 is_intneg (char *number)
223 {
224 if (is_integer (number) && atoi (number) < 0)
225 return TRUE;
226 else
227 return FALSE;
228 }
230 int
231 is_intnonneg (char *number)
232 {
233 if (is_integer (number) && atoi (number) >= 0)
234 return TRUE;
235 else
236 return FALSE;
237 }
239 int
240 is_intpercent (char *number)
241 {
242 int i;
243 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
244 return TRUE;
245 else
246 return FALSE;
247 }
249 int
250 is_option (char *str)
251 {
252 if (!str)
253 return FALSE;
254 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
255 return TRUE;
256 else
257 return FALSE;
258 }
260 #ifdef NEED_GETTIMEOFDAY
261 int
262 gettimeofday (struct timeval *tv, struct timezone *tz)
263 {
264 tv->tv_usec = 0;
265 tv->tv_sec = (long) time ((time_t) 0);
266 }
267 #endif
271 double
272 delta_time (struct timeval tv)
273 {
274 struct timeval now;
276 gettimeofday (&now, NULL);
277 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
278 }
282 long
283 deltime (struct timeval tv)
284 {
285 struct timeval now;
286 gettimeofday (&now, NULL);
287 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
288 }
293 void
294 strip (char *buffer)
295 {
296 size_t x;
297 int i;
299 for (x = strlen (buffer); x >= 1; x--) {
300 i = x - 1;
301 if (buffer[i] == ' ' ||
302 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
303 buffer[i] = '\0';
304 else
305 break;
306 }
307 return;
308 }
311 /******************************************************************************
312 *
313 * Copies one string to another. Any previously existing data in
314 * the destination string is lost.
315 *
316 * Example:
317 *
318 * char *str=NULL;
319 * str = strscpy("This is a line of text with no trailing newline");
320 *
321 *****************************************************************************/
323 char *
324 strscpy (char *dest, const char *src)
325 {
326 if (src == NULL)
327 return NULL;
329 asprintf (&dest, "%s", src);
331 return dest;
332 }
336 /******************************************************************************
337 *
338 * Returns a pointer to the next line of a multiline string buffer
339 *
340 * Given a pointer string, find the text following the next sequence
341 * of \r and \n characters. This has the effect of skipping blank
342 * lines as well
343 *
344 * Example:
345 *
346 * Given text as follows:
347 *
348 * ==============================
349 * This
350 * is
351 * a
352 *
353 * multiline string buffer
354 * ==============================
355 *
356 * int i=0;
357 * char *str=NULL;
358 * char *ptr=NULL;
359 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
360 * ptr = str;
361 * while (ptr) {
362 * printf("%d %s",i++,firstword(ptr));
363 * ptr = strnl(ptr);
364 * }
365 *
366 * Produces the following:
367 *
368 * 1 This
369 * 2 is
370 * 3 a
371 * 4 multiline
372 *
373 * NOTE: The 'firstword()' function is conceptual only and does not
374 * exist in this package.
375 *
376 * NOTE: Although the second 'ptr' variable is not strictly needed in
377 * this example, it is good practice with these utilities. Once
378 * the * pointer is advance in this manner, it may no longer be
379 * handled with * realloc(). So at the end of the code fragment
380 * above, * strscpy(str,"foo") work perfectly fine, but
381 * strscpy(ptr,"foo") will * cause the the program to crash with
382 * a segmentation fault.
383 *
384 *****************************************************************************/
386 char *
387 strnl (char *str)
388 {
389 size_t len;
390 if (str == NULL)
391 return NULL;
392 str = strpbrk (str, "\r\n");
393 if (str == NULL)
394 return NULL;
395 len = strspn (str, "\r\n");
396 if (str[len] == '\0')
397 return NULL;
398 str += len;
399 if (strlen (str) == 0)
400 return NULL;
401 return str;
402 }
405 /******************************************************************************
406 *
407 * Like strscpy, except only the portion of the source string up to
408 * the provided delimiter is copied.
409 *
410 * Example:
411 *
412 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
413 * printf("%s\n",str);
414 *
415 * Produces:
416 *
417 *This is a line of te
418 *
419 *****************************************************************************/
421 char *
422 strpcpy (char *dest, const char *src, const char *str)
423 {
424 size_t len;
426 if (src)
427 len = strcspn (src, str);
428 else
429 return NULL;
431 if (dest == NULL || strlen (dest) < len)
432 dest = realloc (dest, len + 1);
433 if (dest == NULL)
434 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
436 strncpy (dest, src, len);
437 dest[len] = '\0';
439 return dest;
440 }
444 /******************************************************************************
445 *
446 * Like strscat, except only the portion of the source string up to
447 * the provided delimiter is copied.
448 *
449 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
450 * str = strpcat(str,"This is a line of text with no trailing newline","x");
451 * printf("%s\n",str);
452 *
453 *This is a line of texThis is a line of tex
454 *
455 *****************************************************************************/
457 char *
458 strpcat (char *dest, const char *src, const char *str)
459 {
460 size_t len, l2;
462 if (dest)
463 len = strlen (dest);
464 else
465 len = 0;
467 if (src) {
468 l2 = strcspn (src, str);
469 }
470 else {
471 return dest;
472 }
474 dest = realloc (dest, len + l2 + 1);
475 if (dest == NULL)
476 die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
478 strncpy (dest + len, src, l2);
479 dest[len + l2] = '\0';
481 return dest;
482 }
484 /******************************************************************************
485 *
486 * Print perfdata in a standard format
487 *
488 ******************************************************************************/
490 char *perfdata (const char *label,
491 long int val,
492 const char *uom,
493 int warnp,
494 long int warn,
495 int critp,
496 long int crit,
497 int minp,
498 long int minv,
499 int maxp,
500 long int maxv)
501 {
502 char *data = NULL;
504 if (strpbrk (label, "'= "))
505 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
506 else
507 asprintf (&data, "%s=%ld%s;", label, val, uom);
509 if (warnp)
510 asprintf (&data, "%s%ld;", data, warn);
511 else
512 asprintf (&data, "%s;", data);
514 if (critp)
515 asprintf (&data, "%s%ld;", data, crit);
516 else
517 asprintf (&data, "%s;", data);
519 if (minp)
520 asprintf (&data, "%s%ld", data, minv);
522 if (maxp)
523 asprintf (&data, "%s;%ld", data, maxv);
525 return data;
526 }
529 char *fperfdata (const char *label,
530 double val,
531 const char *uom,
532 int warnp,
533 double warn,
534 int critp,
535 double crit,
536 int minp,
537 double minv,
538 int maxp,
539 double maxv)
540 {
541 char *data = NULL;
543 if (strpbrk (label, "'= "))
544 asprintf (&data, "'%s'=", label);
545 else
546 asprintf (&data, "%s=", label);
548 asprintf (&data, "%s%f", data, val);
549 asprintf (&data, "%s%s;", data, uom);
551 if (warnp)
552 asprintf (&data, "%s%f", data, warn);
554 asprintf (&data, "%s;", data);
556 if (critp)
557 asprintf (&data, "%s%f", data, crit);
559 asprintf (&data, "%s;", data);
561 if (minp)
562 asprintf (&data, "%s%f", data, minv);
564 if (maxp) {
565 asprintf (&data, "%s;", data);
566 asprintf (&data, "%s%f", data, maxv);
567 }
569 return data;
570 }