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 void
98 usage5 (void)
99 {
100 print_usage();
101 exit (STATE_UNKNOWN);
102 }
104 char *
105 clean_revstring (const char *revstring)
106 {
107 char plugin_revision[STRLEN];
108 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
109 return strscpy (NULL, plugin_revision);
110 else
111 return strscpy (NULL, "N/A");
112 }
114 void
115 print_revision (const char *command_name, const char *revision_string)
116 {
117 char plugin_revision[STRLEN];
119 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
120 strncpy (plugin_revision, "N/A", STRLEN);
121 printf ("%s (%s %s) %s\n",
122 command_name, PACKAGE, VERSION, plugin_revision);
123 }
125 const char *
126 state_text (int result)
127 {
128 switch (result) {
129 case STATE_OK:
130 return "OK";
131 case STATE_WARNING:
132 return "WARNING";
133 case STATE_CRITICAL:
134 return "CRITICAL";
135 case STATE_DEPENDENT:
136 return "DEPENDENT";
137 default:
138 return "UNKNOWN";
139 }
140 }
142 void
143 timeout_alarm_handler (int signo)
144 {
145 if (signo == SIGALRM) {
146 printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
147 timeout_interval);
148 exit (STATE_CRITICAL);
149 }
150 }
152 int
153 is_numeric (char *number)
154 {
155 char tmp[1];
156 float x;
158 if (!number)
159 return FALSE;
160 else if (sscanf (number, "%f%c", &x, tmp) == 1)
161 return TRUE;
162 else
163 return FALSE;
164 }
166 int
167 is_positive (char *number)
168 {
169 if (is_numeric (number) && atof (number) > 0.0)
170 return TRUE;
171 else
172 return FALSE;
173 }
175 int
176 is_negative (char *number)
177 {
178 if (is_numeric (number) && atof (number) < 0.0)
179 return TRUE;
180 else
181 return FALSE;
182 }
184 int
185 is_nonnegative (char *number)
186 {
187 if (is_numeric (number) && atof (number) >= 0.0)
188 return TRUE;
189 else
190 return FALSE;
191 }
193 int
194 is_percentage (char *number)
195 {
196 int x;
197 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
198 return TRUE;
199 else
200 return FALSE;
201 }
203 int
204 is_integer (char *number)
205 {
206 long int n;
208 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
209 return FALSE;
211 n = strtol (number, NULL, 10);
213 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
214 return TRUE;
215 else
216 return FALSE;
217 }
219 int
220 is_intpos (char *number)
221 {
222 if (is_integer (number) && atoi (number) > 0)
223 return TRUE;
224 else
225 return FALSE;
226 }
228 int
229 is_intneg (char *number)
230 {
231 if (is_integer (number) && atoi (number) < 0)
232 return TRUE;
233 else
234 return FALSE;
235 }
237 int
238 is_intnonneg (char *number)
239 {
240 if (is_integer (number) && atoi (number) >= 0)
241 return TRUE;
242 else
243 return FALSE;
244 }
246 int
247 is_intpercent (char *number)
248 {
249 int i;
250 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
251 return TRUE;
252 else
253 return FALSE;
254 }
256 int
257 is_option (char *str)
258 {
259 if (!str)
260 return FALSE;
261 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
262 return TRUE;
263 else
264 return FALSE;
265 }
267 #ifdef NEED_GETTIMEOFDAY
268 int
269 gettimeofday (struct timeval *tv, struct timezone *tz)
270 {
271 tv->tv_usec = 0;
272 tv->tv_sec = (long) time ((time_t) 0);
273 }
274 #endif
278 double
279 delta_time (struct timeval tv)
280 {
281 struct timeval now;
283 gettimeofday (&now, NULL);
284 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
285 }
289 long
290 deltime (struct timeval tv)
291 {
292 struct timeval now;
293 gettimeofday (&now, NULL);
294 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
295 }
300 void
301 strip (char *buffer)
302 {
303 size_t x;
304 int i;
306 for (x = strlen (buffer); x >= 1; x--) {
307 i = x - 1;
308 if (buffer[i] == ' ' ||
309 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
310 buffer[i] = '\0';
311 else
312 break;
313 }
314 return;
315 }
318 /******************************************************************************
319 *
320 * Copies one string to another. Any previously existing data in
321 * the destination string is lost.
322 *
323 * Example:
324 *
325 * char *str=NULL;
326 * str = strscpy("This is a line of text with no trailing newline");
327 *
328 *****************************************************************************/
330 char *
331 strscpy (char *dest, const char *src)
332 {
333 if (src == NULL)
334 return NULL;
336 asprintf (&dest, "%s", src);
338 return dest;
339 }
343 /******************************************************************************
344 *
345 * Returns a pointer to the next line of a multiline string buffer
346 *
347 * Given a pointer string, find the text following the next sequence
348 * of \r and \n characters. This has the effect of skipping blank
349 * lines as well
350 *
351 * Example:
352 *
353 * Given text as follows:
354 *
355 * ==============================
356 * This
357 * is
358 * a
359 *
360 * multiline string buffer
361 * ==============================
362 *
363 * int i=0;
364 * char *str=NULL;
365 * char *ptr=NULL;
366 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
367 * ptr = str;
368 * while (ptr) {
369 * printf("%d %s",i++,firstword(ptr));
370 * ptr = strnl(ptr);
371 * }
372 *
373 * Produces the following:
374 *
375 * 1 This
376 * 2 is
377 * 3 a
378 * 4 multiline
379 *
380 * NOTE: The 'firstword()' function is conceptual only and does not
381 * exist in this package.
382 *
383 * NOTE: Although the second 'ptr' variable is not strictly needed in
384 * this example, it is good practice with these utilities. Once
385 * the * pointer is advance in this manner, it may no longer be
386 * handled with * realloc(). So at the end of the code fragment
387 * above, * strscpy(str,"foo") work perfectly fine, but
388 * strscpy(ptr,"foo") will * cause the the program to crash with
389 * a segmentation fault.
390 *
391 *****************************************************************************/
393 char *
394 strnl (char *str)
395 {
396 size_t len;
397 if (str == NULL)
398 return NULL;
399 str = strpbrk (str, "\r\n");
400 if (str == NULL)
401 return NULL;
402 len = strspn (str, "\r\n");
403 if (str[len] == '\0')
404 return NULL;
405 str += len;
406 if (strlen (str) == 0)
407 return NULL;
408 return str;
409 }
412 /******************************************************************************
413 *
414 * Like strscpy, except only the portion of the source string up to
415 * the provided delimiter is copied.
416 *
417 * Example:
418 *
419 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
420 * printf("%s\n",str);
421 *
422 * Produces:
423 *
424 *This is a line of te
425 *
426 *****************************************************************************/
428 char *
429 strpcpy (char *dest, const char *src, const char *str)
430 {
431 size_t len;
433 if (src)
434 len = strcspn (src, str);
435 else
436 return NULL;
438 if (dest == NULL || strlen (dest) < len)
439 dest = realloc (dest, len + 1);
440 if (dest == NULL)
441 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
443 strncpy (dest, src, len);
444 dest[len] = '\0';
446 return dest;
447 }
451 /******************************************************************************
452 *
453 * Like strscat, except only the portion of the source string up to
454 * the provided delimiter is copied.
455 *
456 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
457 * str = strpcat(str,"This is a line of text with no trailing newline","x");
458 * printf("%s\n",str);
459 *
460 *This is a line of texThis is a line of tex
461 *
462 *****************************************************************************/
464 char *
465 strpcat (char *dest, const char *src, const char *str)
466 {
467 size_t len, l2;
469 if (dest)
470 len = strlen (dest);
471 else
472 len = 0;
474 if (src) {
475 l2 = strcspn (src, str);
476 }
477 else {
478 return dest;
479 }
481 dest = realloc (dest, len + l2 + 1);
482 if (dest == NULL)
483 die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
485 strncpy (dest + len, src, l2);
486 dest[len + l2] = '\0';
488 return dest;
489 }
491 /******************************************************************************
492 *
493 * Print perfdata in a standard format
494 *
495 ******************************************************************************/
497 char *perfdata (const char *label,
498 long int val,
499 const char *uom,
500 int warnp,
501 long int warn,
502 int critp,
503 long int crit,
504 int minp,
505 long int minv,
506 int maxp,
507 long int maxv)
508 {
509 char *data = NULL;
511 if (strpbrk (label, "'= "))
512 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
513 else
514 asprintf (&data, "%s=%ld%s;", label, val, uom);
516 if (warnp)
517 asprintf (&data, "%s%ld;", data, warn);
518 else
519 asprintf (&data, "%s;", data);
521 if (critp)
522 asprintf (&data, "%s%ld;", data, crit);
523 else
524 asprintf (&data, "%s;", data);
526 if (minp)
527 asprintf (&data, "%s%ld", data, minv);
529 if (maxp)
530 asprintf (&data, "%s;%ld", data, maxv);
532 return data;
533 }
536 char *fperfdata (const char *label,
537 double val,
538 const char *uom,
539 int warnp,
540 double warn,
541 int critp,
542 double crit,
543 int minp,
544 double minv,
545 int maxp,
546 double maxv)
547 {
548 char *data = NULL;
550 if (strpbrk (label, "'= "))
551 asprintf (&data, "'%s'=", label);
552 else
553 asprintf (&data, "%s=", label);
555 asprintf (&data, "%s%f", data, val);
556 asprintf (&data, "%s%s;", data, uom);
558 if (warnp)
559 asprintf (&data, "%s%f", data, warn);
561 asprintf (&data, "%s;", data);
563 if (critp)
564 asprintf (&data, "%s%f", data, crit);
566 asprintf (&data, "%s;", data);
568 if (minp)
569 asprintf (&data, "%s%f", data, minv);
571 if (maxp) {
572 asprintf (&data, "%s;", data);
573 asprintf (&data, "%s%f", data, maxv);
574 }
576 return data;
577 }