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