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