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;
21 extern const char *progname;
23 void support (void);
24 char *clean_revstring (const char *);
25 void print_revision (const 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 /* **************************************************************************
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 int
69 max_state (int a, int b)
70 {
71 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
72 return STATE_CRITICAL;
73 else if (a == STATE_WARNING || b == STATE_WARNING)
74 return STATE_WARNING;
75 else if (a == STATE_OK || b == STATE_OK)
76 return STATE_OK;
77 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
78 return STATE_UNKNOWN;
79 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
80 return STATE_DEPENDENT;
81 else
82 return max (a, b);
83 }
85 void usage (char *msg)
86 {
87 printf (msg);
88 print_usage ();
89 exit (STATE_UNKNOWN);
90 }
92 void usage2(char *msg, char *arg)
93 {
94 printf ("%s: %s - %s\n",progname,msg,arg);
95 print_usage ();
96 exit (STATE_UNKNOWN);
97 }
99 void
100 usage3 (char *msg, char arg)
101 {
102 printf ("%s: %s - %c\n", progname, msg, arg);
103 print_usage();
104 exit (STATE_UNKNOWN);
105 }
108 void
109 support (void)
110 {
111 printf
112 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
113 "regarding use of this software. To submit patches or suggest improvements,\n"
114 "send email to nagiosplug-devel@lists.sourceforge.net\n");
115 }
118 char *
119 clean_revstring (const char *revstring)
120 {
121 char plugin_revision[STRLEN];
122 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
123 return strscpy (NULL, plugin_revision);
124 else
125 return strscpy (NULL, "N/A");
126 }
128 void
129 print_revision (const char *command_name, const char *revision_string)
130 {
131 char plugin_revision[STRLEN];
133 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
134 strncpy (plugin_revision, "N/A", STRLEN);
135 printf ("%s (nagios-plugins %s) %s\n",
136 progname, VERSION, plugin_revision);
137 printf
138 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
139 "copies of the plugins under the terms of the GNU General Public License.\n"
140 "For more information about these matters, see the file named COPYING.\n");
142 }
145 void
146 terminate (int result, const char *fmt, ...)
147 {
148 va_list ap;
149 va_start (ap, fmt);
150 vprintf (fmt, ap);
151 va_end (ap);
152 exit (result);
153 }
155 void
156 timeout_alarm_handler (int signo)
157 {
158 if (signo == SIGALRM) {
159 printf ("CRITICAL - Plugin timed out after %d seconds\n",
160 timeout_interval);
161 exit (STATE_CRITICAL);
162 }
163 }
165 int
166 is_host (char *address)
167 {
168 if (is_dotted_quad (address) || is_hostname (address))
169 return (TRUE);
170 return (FALSE);
171 }
173 int
174 is_dotted_quad (char *address)
175 {
176 int o1, o2, o3, o4;
177 char c[1];
179 if (!address)
180 return FALSE;
182 if (sscanf (address, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, c) != 4)
183 return FALSE;
184 else if (o1 > 255 || o2 > 255 || o3 > 255 || o4 > 255)
185 return FALSE;
186 else if (o1 < 0 || o2 < 0 || o3 < 0 || o4 < 0)
187 return FALSE;
188 else
189 return TRUE;
190 }
192 /* from RFC-1035
193 *
194 * The labels must follow the rules for ARPANET host names. They must
195 * start with a letter, end with a letter or digit, and have as interior
196 * characters only letters, digits, and hyphen. There are also some
197 * restrictions on the length. Labels must be 63 characters or less. */
199 int
200 is_hostname (char *s1)
201 {
202 if (!s1 || strlen (s1) > 63) {
203 return FALSE;
204 }
205 if (strcspn (s1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789-.") != 0) {
206 return FALSE;
207 }
208 if (strspn (s1, "0123456789-.") == 1) {
209 return FALSE;
210 }
211 while ((s1 = index (s1, '.'))) {
212 s1++;
213 if (strspn (s1, "0123456789-.") == 1) {
214 return FALSE;
215 }
216 }
217 return TRUE;
218 }
220 int
221 is_numeric (char *number)
222 {
223 char tmp[1];
224 float x;
226 if (!number)
227 return FALSE;
228 else if (sscanf (number, "%f%c", &x, tmp) == 1)
229 return TRUE;
230 else
231 return FALSE;
232 }
234 int
235 is_positive (char *number)
236 {
237 if (is_numeric (number) && atof (number) > 0.0)
238 return TRUE;
239 else
240 return FALSE;
241 }
243 int
244 is_negative (char *number)
245 {
246 if (is_numeric (number) && atof (number) < 0.0)
247 return TRUE;
248 else
249 return FALSE;
250 }
252 int
253 is_nonnegative (char *number)
254 {
255 if (is_numeric (number) && atof (number) >= 0.0)
256 return TRUE;
257 else
258 return FALSE;
259 }
261 int
262 is_percentage (char *number)
263 {
264 int x;
265 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
266 return TRUE;
267 else
268 return FALSE;
269 }
271 int
272 is_integer (char *number)
273 {
274 long int n;
276 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
277 return FALSE;
279 n = strtol (number, NULL, 10);
281 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
282 return TRUE;
283 else
284 return FALSE;
285 }
287 int
288 is_intpos (char *number)
289 {
290 if (is_integer (number) && atoi (number) > 0)
291 return TRUE;
292 else
293 return FALSE;
294 }
296 int
297 is_intneg (char *number)
298 {
299 if (is_integer (number) && atoi (number) < 0)
300 return TRUE;
301 else
302 return FALSE;
303 }
305 int
306 is_intnonneg (char *number)
307 {
308 if (is_integer (number) && atoi (number) >= 0)
309 return TRUE;
310 else
311 return FALSE;
312 }
314 int
315 is_intpercent (char *number)
316 {
317 int i;
318 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
319 return TRUE;
320 else
321 return FALSE;
322 }
324 int
325 is_option (char *str)
326 {
327 if (!str)
328 return FALSE;
329 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
330 return TRUE;
331 else
332 return FALSE;
333 }
337 #ifdef NEED_GETTIMEOFDAY
338 int
339 gettimeofday (struct timeval *tv, struct timezone *tz)
340 {
341 tv->tv_usec = 0;
342 tv->tv_sec = (long) time ((time_t) 0);
343 }
344 #endif
348 double
349 delta_time (struct timeval tv)
350 {
351 struct timeval now;
353 gettimeofday (&now, NULL);
354 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
355 }
360 void
361 strip (char *buffer)
362 {
363 size_t x;
364 int i;
366 for (x = strlen (buffer); x >= 1; x--) {
367 i = x - 1;
368 if (buffer[i] == ' ' ||
369 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
370 buffer[i] = '\0';
371 else
372 break;
373 }
374 return;
375 }
381 /******************************************************************************
382 *
383 * Copies one string to another. Any previously existing data in
384 * the destination string is lost.
385 *
386 * Example:
387 *
388 * char *str=NULL;
389 * str = strscpy("This is a line of text with no trailing newline");
390 *
391 *****************************************************************************/
393 char *
394 strscpy (char *dest, const char *src)
395 {
396 if (src == NULL)
397 return NULL;
399 asprintf (&dest, "%s", src);
401 return dest;
402 }
408 /******************************************************************************
409 *
410 * Concatenates one string to the end of another
411 *
412 * Given a pointer destination string, which may or may not already
413 * hold some text, and a source string with additional text (possibly
414 * NULL or empty), returns a pointer to a string that is the first
415 * string with the second concatenated to it. Uses realloc to free
416 * memory held by the dest argument if new storage space is required.
417 *
418 * Example:
419 *
420 * char *str=NULL;
421 * str = strscpy("This is a line of text with no trailing newline");
422 * str = strscat(str,"\n");
423 *
424 *****************************************************************************/
426 char *
427 strscat (char *dest, char *src)
428 {
430 if (dest == NULL)
431 return src;
432 if (src != NULL)
433 asprintf (&dest, "%s%s", dest, src);
435 return dest;
436 }
442 /******************************************************************************
443 *
444 * Returns a pointer to the next line of a multiline string buffer
445 *
446 * Given a pointer string, find the text following the next sequence
447 * of \r and \n characters. This has the effect of skipping blank
448 * lines as well
449 *
450 * Example:
451 *
452 * Given text as follows:
453 *
454 * ==============================
455 * This
456 * is
457 * a
458 *
459 * multiline string buffer
460 * ==============================
461 *
462 * int i=0;
463 * char *str=NULL;
464 * char *ptr=NULL;
465 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
466 * ptr = str;
467 * while (ptr) {
468 * printf("%d %s",i++,firstword(ptr));
469 * ptr = strnl(ptr);
470 * }
471 *
472 * Produces the following:
473 *
474 * 1 This
475 * 2 is
476 * 3 a
477 * 4 multiline
478 *
479 * NOTE: The 'firstword()' function is conceptual only and does not
480 * exist in this package.
481 *
482 * NOTE: Although the second 'ptr' variable is not strictly needed in
483 * this example, it is good practice with these utilities. Once
484 * the * pointer is advance in this manner, it may no longer be
485 * handled with * realloc(). So at the end of the code fragment
486 * above, * strscpy(str,"foo") work perfectly fine, but
487 * strscpy(ptr,"foo") will * cause the the program to crash with
488 * a segmentation fault.
489 *
490 *****************************************************************************/
492 char *
493 strnl (char *str)
494 {
495 size_t len;
496 if (str == NULL)
497 return NULL;
498 str = strpbrk (str, "\r\n");
499 if (str == NULL)
500 return NULL;
501 len = strspn (str, "\r\n");
502 if (str[len] == '\0')
503 return NULL;
504 str += len;
505 if (strlen (str) == 0)
506 return NULL;
507 return str;
508 }
514 /******************************************************************************
515 *
516 * Like strscpy, except only the portion of the source string up to
517 * the provided delimiter is copied.
518 *
519 * Example:
520 *
521 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
522 * printf("%s\n",str);
523 *
524 * Produces:
525 *
526 *This is a line of te
527 *
528 *****************************************************************************/
530 char *
531 strpcpy (char *dest, const char *src, const char *str)
532 {
533 size_t len;
535 if (src)
536 len = strcspn (src, str);
537 else
538 return NULL;
540 if (dest == NULL || strlen (dest) < len)
541 dest = realloc (dest, len + 1);
542 if (dest == NULL)
543 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
545 strncpy (dest, src, len);
546 dest[len] = '\0';
548 return dest;
549 }
555 /******************************************************************************
556 *
557 * Like strscat, except only the portion of the source string up to
558 * the provided delimiter is copied.
559 *
560 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
561 * str = strpcat(str,"This is a line of text with no trailing newline","x");
562 * printf("%s\n",str);
563 *
564 *This is a line of texThis is a line of tex
565 *
566 *****************************************************************************/
568 char *
569 strpcat (char *dest, const char *src, const char *str)
570 {
571 size_t len, l2;
573 if (dest)
574 len = strlen (dest);
575 else
576 len = 0;
578 if (src) {
579 l2 = strcspn (src, str);
580 }
581 else {
582 return dest;
583 }
585 dest = realloc (dest, len + l2 + 1);
586 if (dest == NULL)
587 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
589 strncpy (dest + len, src, l2);
590 dest[len + l2] = '\0';
592 return dest;
593 }