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 "version.h"
17 #include <stdarg.h>
18 #include <limits.h>
20 extern int timeout_interval;
22 char *my_basename (char *);
23 void support (void);
24 char *clean_revstring (const char *);
25 void print_revision (char *, const char *);
26 void terminate (int, const char *fmt, ...);
27 RETSIGTYPE timeout_alarm_handler (int);
29 int is_host (char *);
30 int is_dotted_quad (char *);
31 int is_hostname (char *);
33 int is_integer (char *);
34 int is_intpos (char *);
35 int is_intneg (char *);
36 int is_intnonneg (char *);
37 int is_intpercent (char *);
39 int is_numeric (char *);
40 int is_positive (char *);
41 int is_negative (char *);
42 int is_nonnegative (char *);
43 int is_percentage (char *);
45 int is_option (char *str);
47 double delta_time (struct timeval tv);
49 void strip (char *);
50 char *strscpy (char *dest, const char *src);
51 char *strscat (char *dest, char *src);
52 char *strnl (char *str);
53 char *strpcpy (char *dest, const char *src, const char *str);
54 char *strpcat (char *dest, const char *src, const char *str);
56 #define LABELLEN 63
57 #define STRLEN 64
58 #define TXTBLK 128
60 #define max(a,b) ((a)>(b))?(a):(b)
62 /* **************************************************************************
63 * max_state(STATE_x, STATE_y)
64 * compares STATE_x to STATE_y and returns result based on the following
65 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
66 *
67 * Note that numerically the above does not hold
68 ****************************************************************************/
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 char *
88 my_basename (char *path)
89 {
90 if (!strstr (path, "/"))
91 return path;
92 else
93 return 1 + strrchr (path, '/');
94 }
97 void
98 support (void)
99 {
100 printf
101 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
102 "regarding use of this software. To submit patches or suggest improvements,\n"
103 "send email to nagiosplug-devel@lists.sourceforge.net\n");
104 }
107 char *
108 clean_revstring (const char *revstring)
109 {
110 char plugin_revision[STRLEN];
111 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
112 return strscpy (NULL, plugin_revision);
113 else
114 return strscpy (NULL, "N/A");
115 }
117 void
118 print_revision (char *command_name, const char *revision_string)
119 {
120 char plugin_revision[STRLEN];
122 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
123 strncpy (plugin_revision, "N/A", STRLEN);
124 printf ("%s (nagios-plugins %s) %s\n",
125 my_basename (command_name), VERSION, plugin_revision);
126 printf
127 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
128 "copies of the plugins under the terms of the GNU General Public License.\n"
129 "For more information about these matters, see the file named COPYING.\n");
131 }
134 void
135 terminate (int result, const char *fmt, ...)
136 {
137 va_list ap;
138 va_start (ap, fmt);
139 vprintf (fmt, ap);
140 va_end (ap);
141 exit (result);
142 }
144 void
145 timeout_alarm_handler (int signo)
146 {
147 if (signo == SIGALRM) {
148 printf ("CRITICAL - Plugin timed out after %d seconds\n",
149 timeout_interval);
150 exit (STATE_CRITICAL);
151 }
152 }
154 int
155 is_host (char *address)
156 {
157 if (is_dotted_quad (address) || is_hostname (address))
158 return (TRUE);
159 return (FALSE);
160 }
162 int
163 is_dotted_quad (char *address)
164 {
165 int o1, o2, o3, o4;
166 char c[1];
168 if (!address)
169 return FALSE;
171 if (sscanf (address, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, c) != 4)
172 return FALSE;
173 else if (o1 > 255 || o2 > 255 || o3 > 255 || o4 > 255)
174 return FALSE;
175 else if (o1 < 0 || o2 < 0 || o3 < 0 || o4 < 0)
176 return FALSE;
177 else
178 return TRUE;
179 }
181 /* from RFC-1035
182 *
183 * The labels must follow the rules for ARPANET host names. They must
184 * start with a letter, end with a letter or digit, and have as interior
185 * characters only letters, digits, and hyphen. There are also some
186 * restrictions on the length. Labels must be 63 characters or less. */
188 int
189 is_hostname (char *s1)
190 {
191 if (!s1 || strlen (s1) > 63) {
192 return FALSE;
193 }
194 if (strcspn (s1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789-.") != 0) {
195 return FALSE;
196 }
197 if (strspn (s1, "0123456789-.") == 1) {
198 return FALSE;
199 }
200 while ((s1 = index (s1, '.'))) {
201 s1++;
202 if (strspn (s1, "0123456789-.") == 1) {
203 return FALSE;
204 }
205 }
206 return TRUE;
207 }
209 int
210 is_numeric (char *number)
211 {
212 char tmp[1];
213 float x;
215 if (!number)
216 return FALSE;
217 else if (sscanf (number, "%f%c", &x, tmp) == 1)
218 return TRUE;
219 else
220 return FALSE;
221 }
223 int
224 is_positive (char *number)
225 {
226 if (is_numeric (number) && atof (number) > 0.0)
227 return TRUE;
228 else
229 return FALSE;
230 }
232 int
233 is_negative (char *number)
234 {
235 if (is_numeric (number) && atof (number) < 0.0)
236 return TRUE;
237 else
238 return FALSE;
239 }
241 int
242 is_nonnegative (char *number)
243 {
244 if (is_numeric (number) && atof (number) >= 0.0)
245 return TRUE;
246 else
247 return FALSE;
248 }
250 int
251 is_percentage (char *number)
252 {
253 int x;
254 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
255 return TRUE;
256 else
257 return FALSE;
258 }
260 int
261 is_integer (char *number)
262 {
263 long int n;
265 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
266 return FALSE;
268 n = strtol (number, NULL, 10);
270 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
271 return TRUE;
272 else
273 return FALSE;
274 }
276 int
277 is_intpos (char *number)
278 {
279 if (is_integer (number) && atoi (number) > 0)
280 return TRUE;
281 else
282 return FALSE;
283 }
285 int
286 is_intneg (char *number)
287 {
288 if (is_integer (number) && atoi (number) < 0)
289 return TRUE;
290 else
291 return FALSE;
292 }
294 int
295 is_intnonneg (char *number)
296 {
297 if (is_integer (number) && atoi (number) >= 0)
298 return TRUE;
299 else
300 return FALSE;
301 }
303 int
304 is_intpercent (char *number)
305 {
306 int i;
307 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
308 return TRUE;
309 else
310 return FALSE;
311 }
313 int
314 is_option (char *str)
315 {
316 if (!str)
317 return FALSE;
318 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
319 return TRUE;
320 else
321 return FALSE;
322 }
326 #ifdef NEED_GETTIMEOFDAY
327 int
328 gettimeofday (struct timeval *tv, struct timezone *tz)
329 {
330 tv->tv_usec = 0;
331 tv->tv_sec = (long) time ((time_t) 0);
332 }
333 #endif
337 double
338 delta_time (struct timeval tv)
339 {
340 struct timeval now;
342 gettimeofday (&now, NULL);
343 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
344 }
349 void
350 strip (char *buffer)
351 {
352 size_t x;
353 int i;
355 for (x = strlen (buffer); x >= 1; x--) {
356 i = x - 1;
357 if (buffer[i] == ' ' ||
358 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
359 buffer[i] = '\0';
360 else
361 break;
362 }
363 return;
364 }
370 /******************************************************************************
371 *
372 * Copies one string to another. Any previously existing data in
373 * the destination string is lost.
374 *
375 * Example:
376 *
377 * char *str=NULL;
378 * str = strscpy("This is a line of text with no trailing newline");
379 *
380 *****************************************************************************/
382 char *
383 strscpy (char *dest, const char *src)
384 {
385 if (src == NULL)
386 return NULL;
388 asprintf (&dest, "%s", src);
390 return dest;
391 }
397 /******************************************************************************
398 *
399 * Concatenates one string to the end of another
400 *
401 * Given a pointer destination string, which may or may not already
402 * hold some text, and a source string with additional text (possibly
403 * NULL or empty), returns a pointer to a string that is the first
404 * string with the second concatenated to it. Uses realloc to free
405 * memory held by the dest argument if new storage space is required.
406 *
407 * Example:
408 *
409 * char *str=NULL;
410 * str = strscpy("This is a line of text with no trailing newline");
411 * str = strscat(str,"\n");
412 *
413 *****************************************************************************/
415 char *
416 strscat (char *dest, char *src)
417 {
419 if (dest == NULL)
420 return src;
421 if (src != NULL)
422 asprintf (&dest, "%s%s", dest, src);
424 return dest;
425 }
431 /******************************************************************************
432 *
433 * Returns a pointer to the next line of a multiline string buffer
434 *
435 * Given a pointer string, find the text following the next sequence
436 * of \r and \n characters. This has the effect of skipping blank
437 * lines as well
438 *
439 * Example:
440 *
441 * Given text as follows:
442 *
443 * ==============================
444 * This
445 * is
446 * a
447 *
448 * multiline string buffer
449 * ==============================
450 *
451 * int i=0;
452 * char *str=NULL;
453 * char *ptr=NULL;
454 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
455 * ptr = str;
456 * while (ptr) {
457 * printf("%d %s",i++,firstword(ptr));
458 * ptr = strnl(ptr);
459 * }
460 *
461 * Produces the following:
462 *
463 * 1 This
464 * 2 is
465 * 3 a
466 * 4 multiline
467 *
468 * NOTE: The 'firstword()' function is conceptual only and does not
469 * exist in this package.
470 *
471 * NOTE: Although the second 'ptr' variable is not strictly needed in
472 * this example, it is good practice with these utilities. Once
473 * the * pointer is advance in this manner, it may no longer be
474 * handled with * realloc(). So at the end of the code fragment
475 * above, * strscpy(str,"foo") work perfectly fine, but
476 * strscpy(ptr,"foo") will * cause the the program to crash with
477 * a segmentation fault.
478 *
479 *****************************************************************************/
481 char *
482 strnl (char *str)
483 {
484 size_t len;
485 if (str == NULL)
486 return NULL;
487 str = strpbrk (str, "\r\n");
488 if (str == NULL)
489 return NULL;
490 len = strspn (str, "\r\n");
491 if (str[len] == '\0')
492 return NULL;
493 str += len;
494 if (strlen (str) == 0)
495 return NULL;
496 return str;
497 }
503 /******************************************************************************
504 *
505 * Like strscpy, except only the portion of the source string up to
506 * the provided delimiter is copied.
507 *
508 * Example:
509 *
510 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
511 * printf("%s\n",str);
512 *
513 * Produces:
514 *
515 *This is a line of te
516 *
517 *****************************************************************************/
519 char *
520 strpcpy (char *dest, const char *src, const char *str)
521 {
522 size_t len;
524 if (src)
525 len = strcspn (src, str);
526 else
527 return NULL;
529 if (dest == NULL || strlen (dest) < len)
530 dest = realloc (dest, len + 1);
531 if (dest == NULL)
532 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
534 strncpy (dest, src, len);
535 dest[len] = '\0';
537 return dest;
538 }
544 /******************************************************************************
545 *
546 * Like strscat, except only the portion of the source string up to
547 * the provided delimiter is copied.
548 *
549 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
550 * str = strpcat(str,"This is a line of text with no trailing newline","x");
551 * printf("%s\n",str);
552 *
553 *This is a line of texThis is a line of tex
554 *
555 *****************************************************************************/
557 char *
558 strpcat (char *dest, const char *src, const char *str)
559 {
560 size_t len, l2;
562 if (dest)
563 len = strlen (dest);
564 else
565 len = 0;
567 if (src) {
568 l2 = strcspn (src, str);
569 }
570 else {
571 return dest;
572 }
574 dest = realloc (dest, len + l2 + 1);
575 if (dest == NULL)
576 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
578 strncpy (dest + len, src, l2);
579 dest[len + l2] = '\0';
581 return dest;
582 }