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 #include <arpa/inet.h>
22 extern int timeout_interval;
23 extern const char *progname;
25 void support (void);
26 char *clean_revstring (const char *);
27 void print_revision (const char *, const char *);
28 void terminate (int, const char *fmt, ...);
29 RETSIGTYPE timeout_alarm_handler (int);
31 int is_host (char *);
32 int is_addr (char *);
33 int resolve_host_or_addr (char *, int);
34 int is_inet_addr (char *);
35 #ifdef USE_IPV6
36 int is_inet6_addr (char *);
37 #endif
38 int is_hostname (char *);
40 int is_integer (char *);
41 int is_intpos (char *);
42 int is_intneg (char *);
43 int is_intnonneg (char *);
44 int is_intpercent (char *);
46 int is_numeric (char *);
47 int is_positive (char *);
48 int is_negative (char *);
49 int is_nonnegative (char *);
50 int is_percentage (char *);
52 int is_option (char *str);
54 double delta_time (struct timeval tv);
56 void strip (char *);
57 char *strscpy (char *dest, const char *src);
58 char *strscat (char *dest, char *src);
59 char *strnl (char *str);
60 char *strpcpy (char *dest, const char *src, const char *str);
61 char *strpcat (char *dest, const char *src, const char *str);
63 #define LABELLEN 63
64 #define STRLEN 64
65 #define TXTBLK 128
67 /* **************************************************************************
68 /* max_state(STATE_x, STATE_y)
69 * compares STATE_x to STATE_y and returns result based on the following
70 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
71 *
72 * Note that numerically the above does not hold
73 ****************************************************************************/
75 #define max(a,b) (((a)>(b))?(a):(b))
77 int
78 max_state (int a, int b)
79 {
80 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
81 return STATE_CRITICAL;
82 else if (a == STATE_WARNING || b == STATE_WARNING)
83 return STATE_WARNING;
84 else if (a == STATE_OK || b == STATE_OK)
85 return STATE_OK;
86 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
87 return STATE_UNKNOWN;
88 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
89 return STATE_DEPENDENT;
90 else
91 return max (a, b);
92 }
94 void usage (char *msg)
95 {
96 printf (msg);
97 print_usage ();
98 exit (STATE_UNKNOWN);
99 }
101 void usage2(char *msg, char *arg)
102 {
103 printf ("%s: %s - %s\n",progname,msg,arg);
104 print_usage ();
105 exit (STATE_UNKNOWN);
106 }
108 void
109 usage3 (char *msg, char arg)
110 {
111 printf ("%s: %s - %c\n", progname, msg, arg);
112 print_usage();
113 exit (STATE_UNKNOWN);
114 }
117 void
118 support (void)
119 {
120 printf
121 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
122 "regarding use of this software. To submit patches or suggest improvements,\n"
123 "send email to nagiosplug-devel@lists.sourceforge.net\n");
124 }
127 char *
128 clean_revstring (const char *revstring)
129 {
130 char plugin_revision[STRLEN];
131 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
132 return strscpy (NULL, plugin_revision);
133 else
134 return strscpy (NULL, "N/A");
135 }
137 void
138 print_revision (const char *command_name, const char *revision_string)
139 {
140 char plugin_revision[STRLEN];
142 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
143 strncpy (plugin_revision, "N/A", STRLEN);
144 printf ("%s (nagios-plugins %s) %s\n",
145 progname, VERSION, plugin_revision);
146 printf
147 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
148 "copies of the plugins under the terms of the GNU General Public License.\n"
149 "For more information about these matters, see the file named COPYING.\n");
151 }
154 void
155 terminate (int result, const char *fmt, ...)
156 {
157 va_list ap;
158 va_start (ap, fmt);
159 vprintf (fmt, ap);
160 va_end (ap);
161 exit (result);
162 }
164 void
165 timeout_alarm_handler (int signo)
166 {
167 if (signo == SIGALRM) {
168 printf ("CRITICAL - Plugin timed out after %d seconds\n",
169 timeout_interval);
170 exit (STATE_CRITICAL);
171 }
172 }
174 int
175 is_host (char *address)
176 {
177 if (is_addr (address) || is_hostname (address))
178 return (TRUE);
180 return (FALSE);
181 }
183 int
184 is_addr (char *address)
185 {
186 #ifdef USE_IPV6
187 if (is_inet_addr (address) || is_inet6_addr (address))
188 #else
189 if (is_inet_addr (address))
190 #endif
191 return (TRUE);
193 return (FALSE);
194 }
196 int
197 resolve_host_or_addr (char *address, int family)
198 {
199 struct addrinfo hints;
200 struct addrinfo *res;
201 int retval;
203 memset (&hints, 0, sizeof (hints));
204 hints.ai_family = family;
205 retval = getaddrinfo (address, NULL, &hints, &res);
207 if (retval != 0)
208 return FALSE;
209 else {
210 freeaddrinfo (res);
211 return TRUE;
212 }
213 }
215 int
216 is_inet_addr (char *address)
217 {
218 return resolve_host_or_addr (address, AF_INET);
219 }
221 #ifdef USE_IPV6
222 int
223 is_inet6_addr (char *address)
224 {
225 return resolve_host_or_addr (address, AF_INET6);
226 }
227 #endif
229 /* from RFC-1035
230 *
231 * The labels must follow the rules for ARPANET host names. They must
232 * start with a letter, end with a letter or digit, and have as interior
233 * characters only letters, digits, and hyphen. There are also some
234 * restrictions on the length. Labels must be 63 characters or less. */
236 int
237 is_hostname (char *s1)
238 {
239 #ifdef USE_IPV6
240 return resolve_host_or_addr (s1, AF_UNSPEC);
241 #else
242 return resolve_host_or_addr (s1, AF_INET);
243 #endif
244 }
246 int
247 is_numeric (char *number)
248 {
249 char tmp[1];
250 float x;
252 if (!number)
253 return FALSE;
254 else if (sscanf (number, "%f%c", &x, tmp) == 1)
255 return TRUE;
256 else
257 return FALSE;
258 }
260 int
261 is_positive (char *number)
262 {
263 if (is_numeric (number) && atof (number) > 0.0)
264 return TRUE;
265 else
266 return FALSE;
267 }
269 int
270 is_negative (char *number)
271 {
272 if (is_numeric (number) && atof (number) < 0.0)
273 return TRUE;
274 else
275 return FALSE;
276 }
278 int
279 is_nonnegative (char *number)
280 {
281 if (is_numeric (number) && atof (number) >= 0.0)
282 return TRUE;
283 else
284 return FALSE;
285 }
287 int
288 is_percentage (char *number)
289 {
290 int x;
291 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
292 return TRUE;
293 else
294 return FALSE;
295 }
297 int
298 is_integer (char *number)
299 {
300 long int n;
302 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
303 return FALSE;
305 n = strtol (number, NULL, 10);
307 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
308 return TRUE;
309 else
310 return FALSE;
311 }
313 int
314 is_intpos (char *number)
315 {
316 if (is_integer (number) && atoi (number) > 0)
317 return TRUE;
318 else
319 return FALSE;
320 }
322 int
323 is_intneg (char *number)
324 {
325 if (is_integer (number) && atoi (number) < 0)
326 return TRUE;
327 else
328 return FALSE;
329 }
331 int
332 is_intnonneg (char *number)
333 {
334 if (is_integer (number) && atoi (number) >= 0)
335 return TRUE;
336 else
337 return FALSE;
338 }
340 int
341 is_intpercent (char *number)
342 {
343 int i;
344 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
345 return TRUE;
346 else
347 return FALSE;
348 }
350 int
351 is_option (char *str)
352 {
353 if (!str)
354 return FALSE;
355 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
356 return TRUE;
357 else
358 return FALSE;
359 }
363 #ifdef NEED_GETTIMEOFDAY
364 int
365 gettimeofday (struct timeval *tv, struct timezone *tz)
366 {
367 tv->tv_usec = 0;
368 tv->tv_sec = (long) time ((time_t) 0);
369 }
370 #endif
374 double
375 delta_time (struct timeval tv)
376 {
377 struct timeval now;
379 gettimeofday (&now, NULL);
380 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
381 }
386 void
387 strip (char *buffer)
388 {
389 size_t x;
390 int i;
392 for (x = strlen (buffer); x >= 1; x--) {
393 i = x - 1;
394 if (buffer[i] == ' ' ||
395 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
396 buffer[i] = '\0';
397 else
398 break;
399 }
400 return;
401 }
407 /******************************************************************************
408 *
409 * Copies one string to another. Any previously existing data in
410 * the destination string is lost.
411 *
412 * Example:
413 *
414 * char *str=NULL;
415 * str = strscpy("This is a line of text with no trailing newline");
416 *
417 *****************************************************************************/
419 char *
420 strscpy (char *dest, const char *src)
421 {
422 if (src == NULL)
423 return NULL;
425 asprintf (&dest, "%s", src);
427 return dest;
428 }
434 /******************************************************************************
435 *
436 * Concatenates one string to the end of another
437 *
438 * Given a pointer destination string, which may or may not already
439 * hold some text, and a source string with additional text (possibly
440 * NULL or empty), returns a pointer to a string that is the first
441 * string with the second concatenated to it. Uses realloc to free
442 * memory held by the dest argument if new storage space is required.
443 *
444 * Example:
445 *
446 * char *str=NULL;
447 * str = strscpy("This is a line of text with no trailing newline");
448 * str = strscat(str,"\n");
449 *
450 *****************************************************************************/
452 char *
453 strscat (char *dest, char *src)
454 {
456 if (dest == NULL)
457 return src;
458 if (src != NULL)
459 asprintf (&dest, "%s%s", dest, src);
461 return dest;
462 }
468 /******************************************************************************
469 *
470 * Returns a pointer to the next line of a multiline string buffer
471 *
472 * Given a pointer string, find the text following the next sequence
473 * of \r and \n characters. This has the effect of skipping blank
474 * lines as well
475 *
476 * Example:
477 *
478 * Given text as follows:
479 *
480 * ==============================
481 * This
482 * is
483 * a
484 *
485 * multiline string buffer
486 * ==============================
487 *
488 * int i=0;
489 * char *str=NULL;
490 * char *ptr=NULL;
491 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
492 * ptr = str;
493 * while (ptr) {
494 * printf("%d %s",i++,firstword(ptr));
495 * ptr = strnl(ptr);
496 * }
497 *
498 * Produces the following:
499 *
500 * 1 This
501 * 2 is
502 * 3 a
503 * 4 multiline
504 *
505 * NOTE: The 'firstword()' function is conceptual only and does not
506 * exist in this package.
507 *
508 * NOTE: Although the second 'ptr' variable is not strictly needed in
509 * this example, it is good practice with these utilities. Once
510 * the * pointer is advance in this manner, it may no longer be
511 * handled with * realloc(). So at the end of the code fragment
512 * above, * strscpy(str,"foo") work perfectly fine, but
513 * strscpy(ptr,"foo") will * cause the the program to crash with
514 * a segmentation fault.
515 *
516 *****************************************************************************/
518 char *
519 strnl (char *str)
520 {
521 size_t len;
522 if (str == NULL)
523 return NULL;
524 str = strpbrk (str, "\r\n");
525 if (str == NULL)
526 return NULL;
527 len = strspn (str, "\r\n");
528 if (str[len] == '\0')
529 return NULL;
530 str += len;
531 if (strlen (str) == 0)
532 return NULL;
533 return str;
534 }
540 /******************************************************************************
541 *
542 * Like strscpy, except only the portion of the source string up to
543 * the provided delimiter is copied.
544 *
545 * Example:
546 *
547 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
548 * printf("%s\n",str);
549 *
550 * Produces:
551 *
552 *This is a line of te
553 *
554 *****************************************************************************/
556 char *
557 strpcpy (char *dest, const char *src, const char *str)
558 {
559 size_t len;
561 if (src)
562 len = strcspn (src, str);
563 else
564 return NULL;
566 if (dest == NULL || strlen (dest) < len)
567 dest = realloc (dest, len + 1);
568 if (dest == NULL)
569 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
571 strncpy (dest, src, len);
572 dest[len] = '\0';
574 return dest;
575 }
581 /******************************************************************************
582 *
583 * Like strscat, except only the portion of the source string up to
584 * the provided delimiter is copied.
585 *
586 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
587 * str = strpcat(str,"This is a line of text with no trailing newline","x");
588 * printf("%s\n",str);
589 *
590 *This is a line of texThis is a line of tex
591 *
592 *****************************************************************************/
594 char *
595 strpcat (char *dest, const char *src, const char *str)
596 {
597 size_t len, l2;
599 if (dest)
600 len = strlen (dest);
601 else
602 len = 0;
604 if (src) {
605 l2 = strcspn (src, str);
606 }
607 else {
608 return dest;
609 }
611 dest = realloc (dest, len + l2 + 1);
612 if (dest == NULL)
613 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
615 strncpy (dest + len, src, l2);
616 dest[len + l2] = '\0';
618 return dest;
619 }