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 }
77 void
78 support (void)
79 {
80 printf (_("\n\
81 Send email to nagios-users@lists.sourceforge.net if you have questions\n\
82 regarding use of this software. To submit patches or suggest improvements,\n\
83 send email to nagiosplug-devel@lists.sourceforge.net\n"));
84 }
87 char *
88 clean_revstring (const char *revstring)
89 {
90 char plugin_revision[STRLEN];
91 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
92 return strscpy (NULL, plugin_revision);
93 else
94 return strscpy (NULL, "N/A");
95 }
97 void
98 print_revision (const char *command_name, const char *revision_string)
99 {
100 char plugin_revision[STRLEN];
102 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
103 strncpy (plugin_revision, "N/A", STRLEN);
104 printf ("%s (%s %s) %s\n",
105 command_name, PACKAGE, VERSION, plugin_revision);
106 printf (_("\
107 The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
108 copies of the plugins under the terms of the GNU General Public License.\n\
109 For more information about these matters, see the file named COPYING.\n"));
111 }
113 const char *
114 state_text (int result)
115 {
116 switch (result) {
117 case STATE_OK:
118 return "OK";
119 case STATE_WARNING:
120 return "WARNING";
121 case STATE_CRITICAL:
122 return "CRITICAL";
123 case STATE_DEPENDENT:
124 return "DEPENDENT";
125 default:
126 return "UNKNOWN";
127 }
128 }
130 void
131 die (int result, const char *fmt, ...)
132 {
133 va_list ap;
134 va_start (ap, fmt);
135 vprintf (fmt, ap);
136 va_end (ap);
137 exit (result);
138 }
140 void
141 timeout_alarm_handler (int signo)
142 {
143 if (signo == SIGALRM) {
144 printf ("CRITICAL - Plugin timed out after %d seconds\n",
145 timeout_interval);
146 exit (STATE_CRITICAL);
147 }
148 }
150 int
151 is_numeric (char *number)
152 {
153 char tmp[1];
154 float x;
156 if (!number)
157 return FALSE;
158 else if (sscanf (number, "%f%c", &x, tmp) == 1)
159 return TRUE;
160 else
161 return FALSE;
162 }
164 int
165 is_positive (char *number)
166 {
167 if (is_numeric (number) && atof (number) > 0.0)
168 return TRUE;
169 else
170 return FALSE;
171 }
173 int
174 is_negative (char *number)
175 {
176 if (is_numeric (number) && atof (number) < 0.0)
177 return TRUE;
178 else
179 return FALSE;
180 }
182 int
183 is_nonnegative (char *number)
184 {
185 if (is_numeric (number) && atof (number) >= 0.0)
186 return TRUE;
187 else
188 return FALSE;
189 }
191 int
192 is_percentage (char *number)
193 {
194 int x;
195 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
196 return TRUE;
197 else
198 return FALSE;
199 }
201 int
202 is_integer (char *number)
203 {
204 long int n;
206 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
207 return FALSE;
209 n = strtol (number, NULL, 10);
211 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
212 return TRUE;
213 else
214 return FALSE;
215 }
217 int
218 is_intpos (char *number)
219 {
220 if (is_integer (number) && atoi (number) > 0)
221 return TRUE;
222 else
223 return FALSE;
224 }
226 int
227 is_intneg (char *number)
228 {
229 if (is_integer (number) && atoi (number) < 0)
230 return TRUE;
231 else
232 return FALSE;
233 }
235 int
236 is_intnonneg (char *number)
237 {
238 if (is_integer (number) && atoi (number) >= 0)
239 return TRUE;
240 else
241 return FALSE;
242 }
244 int
245 is_intpercent (char *number)
246 {
247 int i;
248 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
249 return TRUE;
250 else
251 return FALSE;
252 }
254 int
255 is_option (char *str)
256 {
257 if (!str)
258 return FALSE;
259 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
260 return TRUE;
261 else
262 return FALSE;
263 }
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 }
321 /******************************************************************************
322 *
323 * Copies one string to another. Any previously existing data in
324 * the destination string is lost.
325 *
326 * Example:
327 *
328 * char *str=NULL;
329 * str = strscpy("This is a line of text with no trailing newline");
330 *
331 *****************************************************************************/
333 char *
334 strscpy (char *dest, const char *src)
335 {
336 if (src == NULL)
337 return NULL;
339 asprintf (&dest, "%s", src);
341 return dest;
342 }
348 /******************************************************************************
349 *
350 * Returns a pointer to the next line of a multiline string buffer
351 *
352 * Given a pointer string, find the text following the next sequence
353 * of \r and \n characters. This has the effect of skipping blank
354 * lines as well
355 *
356 * Example:
357 *
358 * Given text as follows:
359 *
360 * ==============================
361 * This
362 * is
363 * a
364 *
365 * multiline string buffer
366 * ==============================
367 *
368 * int i=0;
369 * char *str=NULL;
370 * char *ptr=NULL;
371 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
372 * ptr = str;
373 * while (ptr) {
374 * printf("%d %s",i++,firstword(ptr));
375 * ptr = strnl(ptr);
376 * }
377 *
378 * Produces the following:
379 *
380 * 1 This
381 * 2 is
382 * 3 a
383 * 4 multiline
384 *
385 * NOTE: The 'firstword()' function is conceptual only and does not
386 * exist in this package.
387 *
388 * NOTE: Although the second 'ptr' variable is not strictly needed in
389 * this example, it is good practice with these utilities. Once
390 * the * pointer is advance in this manner, it may no longer be
391 * handled with * realloc(). So at the end of the code fragment
392 * above, * strscpy(str,"foo") work perfectly fine, but
393 * strscpy(ptr,"foo") will * cause the the program to crash with
394 * a segmentation fault.
395 *
396 *****************************************************************************/
398 char *
399 strnl (char *str)
400 {
401 size_t len;
402 if (str == NULL)
403 return NULL;
404 str = strpbrk (str, "\r\n");
405 if (str == NULL)
406 return NULL;
407 len = strspn (str, "\r\n");
408 if (str[len] == '\0')
409 return NULL;
410 str += len;
411 if (strlen (str) == 0)
412 return NULL;
413 return str;
414 }
420 /******************************************************************************
421 *
422 * Like strscpy, except only the portion of the source string up to
423 * the provided delimiter is copied.
424 *
425 * Example:
426 *
427 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
428 * printf("%s\n",str);
429 *
430 * Produces:
431 *
432 *This is a line of te
433 *
434 *****************************************************************************/
436 char *
437 strpcpy (char *dest, const char *src, const char *str)
438 {
439 size_t len;
441 if (src)
442 len = strcspn (src, str);
443 else
444 return NULL;
446 if (dest == NULL || strlen (dest) < len)
447 dest = realloc (dest, len + 1);
448 if (dest == NULL)
449 die (STATE_UNKNOWN, "failed realloc in strpcpy\n");
451 strncpy (dest, src, len);
452 dest[len] = '\0';
454 return dest;
455 }
461 /******************************************************************************
462 *
463 * Like strscat, except only the portion of the source string up to
464 * the provided delimiter is copied.
465 *
466 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
467 * str = strpcat(str,"This is a line of text with no trailing newline","x");
468 * printf("%s\n",str);
469 *
470 *This is a line of texThis is a line of tex
471 *
472 *****************************************************************************/
474 char *
475 strpcat (char *dest, const char *src, const char *str)
476 {
477 size_t len, l2;
479 if (dest)
480 len = strlen (dest);
481 else
482 len = 0;
484 if (src) {
485 l2 = strcspn (src, str);
486 }
487 else {
488 return dest;
489 }
491 dest = realloc (dest, len + l2 + 1);
492 if (dest == NULL)
493 die (STATE_UNKNOWN, "failed malloc in strscat\n");
495 strncpy (dest + len, src, l2);
496 dest[len + l2] = '\0';
498 return dest;
499 }
504 /******************************************************************************
505 *
506 * Print perfdata in a standard format
507 *
508 ******************************************************************************/
510 char *perfdata (const char *label,
511 long int val,
512 const char *uom,
513 int warnp,
514 long int warn,
515 int critp,
516 long int crit,
517 int minp,
518 long int minv,
519 int maxp,
520 long int maxv)
521 {
522 char *data = NULL;
524 if (strpbrk (label, "'= "))
525 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
526 else
527 asprintf (&data, "%s=%ld%s;", label, val, uom);
529 if (warnp)
530 asprintf (&data, "%s%ld;", data, warn);
531 else
532 asprintf (&data, "%s;", data);
534 if (critp)
535 asprintf (&data, "%s%ld;", data, crit);
536 else
537 asprintf (&data, "%s;", data);
539 if (minp)
540 asprintf (&data, "%s%ld", data, minv);
542 if (maxp)
543 asprintf (&data, "%s;%ld", data, maxv);
545 return data;
546 }