da9cceddd7fa8a95287124f76c7c348ecec3c36c
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 (sscanf (address, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, c) != 4)
169 return FALSE;
170 else if (o1 > 255 || o2 > 255 || o3 > 255 || o4 > 255)
171 return FALSE;
172 else if (o1 < 0 || o2 < 0 || o3 < 0 || o4 < 0)
173 return FALSE;
174 else
175 return TRUE;
176 }
178 /* from RFC-1035
179 *
180 * The labels must follow the rules for ARPANET host names. They must
181 * start with a letter, end with a letter or digit, and have as interior
182 * characters only letters, digits, and hyphen. There are also some
183 * restrictions on the length. Labels must be 63 characters or less. */
185 int
186 is_hostname (char *s1)
187 {
188 if (strlen (s1) > 63)
189 return FALSE;
190 if (strcspn
191 (s1,
192 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789-.") !=
193 0) return FALSE;
194 if (strspn (s1, "0123456789-.") == 1)
195 return FALSE;
196 while ((s1 = index (s1, '.'))) {
197 s1++;
198 if (strspn (s1, "0123456789-.") == 1) {
199 printf ("%s\n", s1);
200 return FALSE;
201 }
202 }
203 return TRUE;
204 }
206 int
207 is_numeric (char *number)
208 {
209 char tmp[1];
210 float x;
211 if (sscanf (number, "%f%c", &x, tmp) == 1)
212 return (TRUE);
213 return (FALSE);
214 }
216 int
217 is_positive (char *number)
218 {
219 if (is_numeric (number) && atof (number) > 0.0)
220 return (TRUE);
221 return (FALSE);
222 }
224 int
225 is_negative (char *number)
226 {
227 if (is_numeric (number) && atof (number) < 0.0)
228 return (TRUE);
229 return (FALSE);
230 }
232 int
233 is_nonnegative (char *number)
234 {
235 if (is_numeric (number) && atof (number) >= 0.0)
236 return (TRUE);
237 return (FALSE);
238 }
240 int
241 is_percentage (char *number)
242 {
243 int x;
244 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
245 return (TRUE);
246 return (FALSE);
247 }
249 int
250 is_integer (char *number)
251 {
252 long int n;
254 if (strspn (number, "-0123456789 ") != strlen (number))
255 return (FALSE);
257 n = strtol (number, NULL, 10);
258 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
259 return (TRUE);
260 return (FALSE);
261 }
263 int
264 is_intpos (char *number)
265 {
266 if (is_integer (number) && atoi (number) > 0)
267 return (TRUE);
268 return (FALSE);
269 }
271 int
272 is_intneg (char *number)
273 {
274 if (is_integer (number) && atoi (number) < 0)
275 return (TRUE);
276 return (FALSE);
277 }
279 int
280 is_intnonneg (char *number)
281 {
282 if (is_integer (number) && atoi (number) >= 0)
283 return (TRUE);
284 return (FALSE);
285 }
287 int
288 is_intpercent (char *number)
289 {
290 int i;
291 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
292 return (TRUE);
293 return (FALSE);
294 }
296 int
297 is_option (char *str)
298 {
299 if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
300 return TRUE;
301 return FALSE;
302 }
306 #ifdef NEED_GETTIMEOFDAY
307 int
308 gettimeofday (struct timeval *tv, struct timezone *tz)
309 {
310 tv->tv_usec = 0;
311 tv->tv_sec = (long) time ((time_t) 0);
312 }
313 #endif
317 double
318 delta_time (struct timeval tv)
319 {
320 struct timeval now;
322 gettimeofday (&now, NULL);
323 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
324 }
329 void
330 strip (char *buffer)
331 {
332 size_t x;
333 int i;
335 for (x = strlen (buffer); x >= 1; x--) {
336 i = x - 1;
337 if (buffer[i] == ' ' ||
338 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
339 buffer[i] = '\0';
340 else
341 break;
342 }
343 return;
344 }
350 /******************************************************************************
351 *
352 * Copies one string to another. Any previously existing data in
353 * the destination string is lost.
354 *
355 * Example:
356 *
357 * char *str=NULL;
358 * str = strscpy("This is a line of text with no trailing newline");
359 *
360 *****************************************************************************/
362 char *
363 strscpy (char *dest, const char *src)
364 {
365 if (src == NULL)
366 return NULL;
368 asprintf (&dest, "%s", src);
370 return dest;
371 }
377 /******************************************************************************
378 *
379 * Concatenates one string to the end of another
380 *
381 * Given a pointer destination string, which may or may not already
382 * hold some text, and a source string with additional text (possibly
383 * NULL or empty), returns a pointer to a string that is the first
384 * string with the second concatenated to it. Uses realloc to free
385 * memory held by the dest argument if new storage space is required.
386 *
387 * Example:
388 *
389 * char *str=NULL;
390 * str = strscpy("This is a line of text with no trailing newline");
391 * str = strscat(str,"\n");
392 *
393 *****************************************************************************/
395 char *
396 strscat (char *dest, char *src)
397 {
399 if (dest == NULL)
400 return src;
401 if (src != NULL)
402 asprintf (&dest, "%s%s", dest, src);
404 return dest;
405 }
411 /******************************************************************************
412 *
413 * Returns a pointer to the next line of a multiline string buffer
414 *
415 * Given a pointer string, find the text following the next sequence
416 * of \r and \n characters. This has the effect of skipping blank
417 * lines as well
418 *
419 * Example:
420 *
421 * Given text as follows:
422 *
423 * ==============================
424 * This
425 * is
426 * a
427 *
428 * multiline string buffer
429 * ==============================
430 *
431 * int i=0;
432 * char *str=NULL;
433 * char *ptr=NULL;
434 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
435 * ptr = str;
436 * while (ptr) {
437 * printf("%d %s",i++,firstword(ptr));
438 * ptr = strnl(ptr);
439 * }
440 *
441 * Produces the following:
442 *
443 * 1 This
444 * 2 is
445 * 3 a
446 * 4 multiline
447 *
448 * NOTE: The 'firstword()' function is conceptual only and does not
449 * exist in this package.
450 *
451 * NOTE: Although the second 'ptr' variable is not strictly needed in
452 * this example, it is good practice with these utilities. Once
453 * the * pointer is advance in this manner, it may no longer be
454 * handled with * realloc(). So at the end of the code fragment
455 * above, * strscpy(str,"foo") work perfectly fine, but
456 * strscpy(ptr,"foo") will * cause the the program to crash with
457 * a segmentation fault.
458 *
459 *****************************************************************************/
461 char *
462 strnl (char *str)
463 {
464 size_t len;
465 if (str == NULL)
466 return NULL;
467 str = strpbrk (str, "\r\n");
468 if (str == NULL)
469 return NULL;
470 len = strspn (str, "\r\n");
471 if (str[len] == '\0')
472 return NULL;
473 str += len;
474 if (strlen (str) == 0)
475 return NULL;
476 return str;
477 }
483 /******************************************************************************
484 *
485 * Like strscpy, except only the portion of the source string up to
486 * the provided delimiter is copied.
487 *
488 * Example:
489 *
490 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
491 * printf("%s\n",str);
492 *
493 * Produces:
494 *
495 *This is a line of te
496 *
497 *****************************************************************************/
499 char *
500 strpcpy (char *dest, const char *src, const char *str)
501 {
502 size_t len;
504 if (src)
505 len = strcspn (src, str);
506 else
507 return NULL;
509 if (dest == NULL || strlen (dest) < len)
510 dest = realloc (dest, len + 1);
511 if (dest == NULL)
512 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
514 strncpy (dest, src, len);
515 dest[len] = '\0';
517 return dest;
518 }
524 /******************************************************************************
525 *
526 * Like strscat, except only the portion of the source string up to
527 * the provided delimiter is copied.
528 *
529 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
530 * str = strpcat(str,"This is a line of text with no trailing newline","x");
531 * printf("%s\n",str);
532 *
533 *This is a line of texThis is a line of tex
534 *
535 *****************************************************************************/
537 char *
538 strpcat (char *dest, const char *src, const char *str)
539 {
540 size_t len, l2;
542 if (dest)
543 len = strlen (dest);
544 else
545 len = 0;
547 if (src) {
548 l2 = strcspn (src, str);
549 }
550 else {
551 return dest;
552 }
554 dest = realloc (dest, len + l2 + 1);
555 if (dest == NULL)
556 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
558 strncpy (dest + len, src, l2);
559 dest[len + l2] = '\0';
561 return dest;
562 }