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 #include "config.h"
15 #include "common.h"
16 #include <stdarg.h>
17 #include <limits.h>
19 #include <arpa/inet.h>
21 extern int timeout_interval;
22 extern const char *progname;
24 void support (void);
25 char *clean_revstring (const char *);
26 void print_revision (const char *, const char *);
27 void die (int result, const char *fmt, ...);
28 void terminate (int result, const char *fmt, ...);
29 RETSIGTYPE timeout_alarm_handler (int);
31 int is_integer (char *);
32 int is_intpos (char *);
33 int is_intneg (char *);
34 int is_intnonneg (char *);
35 int is_intpercent (char *);
37 int is_numeric (char *);
38 int is_positive (char *);
39 int is_negative (char *);
40 int is_nonnegative (char *);
41 int is_percentage (char *);
43 int is_option (char *str);
45 double delta_time (struct timeval tv);
47 void strip (char *);
48 char *strscpy (char *dest, const char *src);
49 char *strscat (char *dest, char *src);
50 char *strnl (char *str);
51 char *strpcpy (char *dest, const char *src, const char *str);
52 char *strpcat (char *dest, const char *src, const char *str);
54 char *state_text (int result);
56 #define LABELLEN 63
57 #define STRLEN 64
58 #define TXTBLK 128
60 /* **************************************************************************
61 /* max_state(STATE_x, STATE_y)
62 * compares STATE_x to STATE_y and returns result based on the following
63 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
64 *
65 * Note that numerically the above does not hold
66 ****************************************************************************/
68 #define max(a,b) (((a)>(b))?(a):(b))
70 int
71 max_state (int a, int b)
72 {
73 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
74 return STATE_CRITICAL;
75 else if (a == STATE_WARNING || b == STATE_WARNING)
76 return STATE_WARNING;
77 else if (a == STATE_OK || b == STATE_OK)
78 return STATE_OK;
79 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
80 return STATE_UNKNOWN;
81 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
82 return STATE_DEPENDENT;
83 else
84 return max (a, b);
85 }
87 void usage (char *msg)
88 {
89 printf (msg);
90 print_usage ();
91 exit (STATE_UNKNOWN);
92 }
94 void usage2(char *msg, char *arg)
95 {
96 printf ("%s: %s - %s\n",progname,msg,arg);
97 print_usage ();
98 exit (STATE_UNKNOWN);
99 }
101 void
102 usage3 (char *msg, char arg)
103 {
104 printf ("%s: %s - %c\n", progname, msg, arg);
105 print_usage();
106 exit (STATE_UNKNOWN);
107 }
110 void
111 support (void)
112 {
113 printf
114 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
115 "regarding use of this software. To submit patches or suggest improvements,\n"
116 "send email to nagiosplug-devel@lists.sourceforge.net\n");
117 }
120 char *
121 clean_revstring (const char *revstring)
122 {
123 char plugin_revision[STRLEN];
124 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
125 return strscpy (NULL, plugin_revision);
126 else
127 return strscpy (NULL, "N/A");
128 }
130 void
131 print_revision (const char *command_name, const char *revision_string)
132 {
133 char plugin_revision[STRLEN];
135 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
136 strncpy (plugin_revision, "N/A", STRLEN);
137 printf ("%s (nagios-plugins %s) %s\n",
138 progname, VERSION, plugin_revision);
139 printf
140 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
141 "copies of the plugins under the terms of the GNU General Public License.\n"
142 "For more information about these matters, see the file named COPYING.\n");
144 }
146 char *
147 state_text (int result)
148 {
149 switch (result) {
150 case STATE_OK:
151 return "OK";
152 case STATE_WARNING:
153 return "WARNING";
154 case STATE_CRITICAL:
155 return "CRITICAL";
156 case STATE_DEPENDENT:
157 return "DEPENDENT";
158 default:
159 return "UNKNOWN";
160 }
161 }
163 void
164 die (int result, const char *fmt, ...)
165 {
166 va_list ap;
167 printf ("%s %s: ", sizeof (char) + index(progname, '_'), state_text(result));
168 va_start (ap, fmt);
169 vprintf (fmt, ap);
170 va_end (ap);
171 exit (result);
172 }
174 void
175 terminate (int result, const char *fmt, ...)
176 {
177 va_list ap;
178 va_start (ap, fmt);
179 vprintf (fmt, ap);
180 va_end (ap);
181 exit (result);
182 }
184 void
185 timeout_alarm_handler (int signo)
186 {
187 if (signo == SIGALRM) {
188 printf ("CRITICAL - Plugin timed out after %d seconds\n",
189 timeout_interval);
190 exit (STATE_CRITICAL);
191 }
192 }
194 int
195 is_numeric (char *number)
196 {
197 char tmp[1];
198 float x;
200 if (!number)
201 return FALSE;
202 else if (sscanf (number, "%f%c", &x, tmp) == 1)
203 return TRUE;
204 else
205 return FALSE;
206 }
208 int
209 is_positive (char *number)
210 {
211 if (is_numeric (number) && atof (number) > 0.0)
212 return TRUE;
213 else
214 return FALSE;
215 }
217 int
218 is_negative (char *number)
219 {
220 if (is_numeric (number) && atof (number) < 0.0)
221 return TRUE;
222 else
223 return FALSE;
224 }
226 int
227 is_nonnegative (char *number)
228 {
229 if (is_numeric (number) && atof (number) >= 0.0)
230 return TRUE;
231 else
232 return FALSE;
233 }
235 int
236 is_percentage (char *number)
237 {
238 int x;
239 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
240 return TRUE;
241 else
242 return FALSE;
243 }
245 int
246 is_integer (char *number)
247 {
248 long int n;
250 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
251 return FALSE;
253 n = strtol (number, NULL, 10);
255 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
256 return TRUE;
257 else
258 return FALSE;
259 }
261 int
262 is_intpos (char *number)
263 {
264 if (is_integer (number) && atoi (number) > 0)
265 return TRUE;
266 else
267 return FALSE;
268 }
270 int
271 is_intneg (char *number)
272 {
273 if (is_integer (number) && atoi (number) < 0)
274 return TRUE;
275 else
276 return FALSE;
277 }
279 int
280 is_intnonneg (char *number)
281 {
282 if (is_integer (number) && atoi (number) >= 0)
283 return TRUE;
284 else
285 return FALSE;
286 }
288 int
289 is_intpercent (char *number)
290 {
291 int i;
292 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
293 return TRUE;
294 else
295 return FALSE;
296 }
298 int
299 is_option (char *str)
300 {
301 if (!str)
302 return FALSE;
303 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
304 return TRUE;
305 else
306 return FALSE;
307 }
311 #ifdef NEED_GETTIMEOFDAY
312 int
313 gettimeofday (struct timeval *tv, struct timezone *tz)
314 {
315 tv->tv_usec = 0;
316 tv->tv_sec = (long) time ((time_t) 0);
317 }
318 #endif
322 double
323 delta_time (struct timeval tv)
324 {
325 struct timeval now;
327 gettimeofday (&now, NULL);
328 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
329 }
334 void
335 strip (char *buffer)
336 {
337 size_t x;
338 int i;
340 for (x = strlen (buffer); x >= 1; x--) {
341 i = x - 1;
342 if (buffer[i] == ' ' ||
343 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
344 buffer[i] = '\0';
345 else
346 break;
347 }
348 return;
349 }
355 /******************************************************************************
356 *
357 * Copies one string to another. Any previously existing data in
358 * the destination string is lost.
359 *
360 * Example:
361 *
362 * char *str=NULL;
363 * str = strscpy("This is a line of text with no trailing newline");
364 *
365 *****************************************************************************/
367 char *
368 strscpy (char *dest, const char *src)
369 {
370 if (src == NULL)
371 return NULL;
373 asprintf (&dest, "%s", src);
375 return dest;
376 }
382 /******************************************************************************
383 *
384 * Concatenates one string to the end of another
385 *
386 * Given a pointer destination string, which may or may not already
387 * hold some text, and a source string with additional text (possibly
388 * NULL or empty), returns a pointer to a string that is the first
389 * string with the second concatenated to it. Uses realloc to free
390 * memory held by the dest argument if new storage space is required.
391 *
392 * Example:
393 *
394 * char *str=NULL;
395 * str = strscpy("This is a line of text with no trailing newline");
396 * str = strscat(str,"\n");
397 *
398 *****************************************************************************/
400 char *
401 strscat (char *dest, char *src)
402 {
404 if (dest == NULL)
405 return src;
406 if (src != NULL)
407 asprintf (&dest, "%s%s", dest, src);
409 return dest;
410 }
416 /******************************************************************************
417 *
418 * Returns a pointer to the next line of a multiline string buffer
419 *
420 * Given a pointer string, find the text following the next sequence
421 * of \r and \n characters. This has the effect of skipping blank
422 * lines as well
423 *
424 * Example:
425 *
426 * Given text as follows:
427 *
428 * ==============================
429 * This
430 * is
431 * a
432 *
433 * multiline string buffer
434 * ==============================
435 *
436 * int i=0;
437 * char *str=NULL;
438 * char *ptr=NULL;
439 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
440 * ptr = str;
441 * while (ptr) {
442 * printf("%d %s",i++,firstword(ptr));
443 * ptr = strnl(ptr);
444 * }
445 *
446 * Produces the following:
447 *
448 * 1 This
449 * 2 is
450 * 3 a
451 * 4 multiline
452 *
453 * NOTE: The 'firstword()' function is conceptual only and does not
454 * exist in this package.
455 *
456 * NOTE: Although the second 'ptr' variable is not strictly needed in
457 * this example, it is good practice with these utilities. Once
458 * the * pointer is advance in this manner, it may no longer be
459 * handled with * realloc(). So at the end of the code fragment
460 * above, * strscpy(str,"foo") work perfectly fine, but
461 * strscpy(ptr,"foo") will * cause the the program to crash with
462 * a segmentation fault.
463 *
464 *****************************************************************************/
466 char *
467 strnl (char *str)
468 {
469 size_t len;
470 if (str == NULL)
471 return NULL;
472 str = strpbrk (str, "\r\n");
473 if (str == NULL)
474 return NULL;
475 len = strspn (str, "\r\n");
476 if (str[len] == '\0')
477 return NULL;
478 str += len;
479 if (strlen (str) == 0)
480 return NULL;
481 return str;
482 }
488 /******************************************************************************
489 *
490 * Like strscpy, except only the portion of the source string up to
491 * the provided delimiter is copied.
492 *
493 * Example:
494 *
495 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
496 * printf("%s\n",str);
497 *
498 * Produces:
499 *
500 *This is a line of te
501 *
502 *****************************************************************************/
504 char *
505 strpcpy (char *dest, const char *src, const char *str)
506 {
507 size_t len;
509 if (src)
510 len = strcspn (src, str);
511 else
512 return NULL;
514 if (dest == NULL || strlen (dest) < len)
515 dest = realloc (dest, len + 1);
516 if (dest == NULL)
517 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
519 strncpy (dest, src, len);
520 dest[len] = '\0';
522 return dest;
523 }
529 /******************************************************************************
530 *
531 * Like strscat, except only the portion of the source string up to
532 * the provided delimiter is copied.
533 *
534 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
535 * str = strpcat(str,"This is a line of text with no trailing newline","x");
536 * printf("%s\n",str);
537 *
538 *This is a line of texThis is a line of tex
539 *
540 *****************************************************************************/
542 char *
543 strpcat (char *dest, const char *src, const char *str)
544 {
545 size_t len, l2;
547 if (dest)
548 len = strlen (dest);
549 else
550 len = 0;
552 if (src) {
553 l2 = strcspn (src, str);
554 }
555 else {
556 return dest;
557 }
559 dest = realloc (dest, len + l2 + 1);
560 if (dest == NULL)
561 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
563 strncpy (dest + len, src, l2);
564 dest[len + l2] = '\0';
566 return dest;
567 }