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 <stdarg.h>
17 #include <limits.h>
19 #include <arpa/inet.h>
21 extern int timeout_interval;
22 extern const char *progname;
24 void support (void);
25 char *clean_revstring (const char *);
26 void print_revision (const char *, const char *);
27 void terminate (int, const char *fmt, ...);
28 RETSIGTYPE timeout_alarm_handler (int);
30 int is_integer (char *);
31 int is_intpos (char *);
32 int is_intneg (char *);
33 int is_intnonneg (char *);
34 int is_intpercent (char *);
36 int is_numeric (char *);
37 int is_positive (char *);
38 int is_negative (char *);
39 int is_nonnegative (char *);
40 int is_percentage (char *);
42 int is_option (char *str);
44 double delta_time (struct timeval tv);
46 void strip (char *);
47 char *strscpy (char *dest, const char *src);
48 char *strscat (char *dest, char *src);
49 char *strnl (char *str);
50 char *strpcpy (char *dest, const char *src, const char *str);
51 char *strpcat (char *dest, const char *src, const char *str);
53 #define LABELLEN 63
54 #define STRLEN 64
55 #define TXTBLK 128
57 /* **************************************************************************
58 /* max_state(STATE_x, STATE_y)
59 * compares STATE_x to STATE_y and returns result based on the following
60 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
61 *
62 * Note that numerically the above does not hold
63 ****************************************************************************/
65 #define max(a,b) (((a)>(b))?(a):(b))
67 int
68 max_state (int a, int b)
69 {
70 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
71 return STATE_CRITICAL;
72 else if (a == STATE_WARNING || b == STATE_WARNING)
73 return STATE_WARNING;
74 else if (a == STATE_OK || b == STATE_OK)
75 return STATE_OK;
76 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
77 return STATE_UNKNOWN;
78 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
79 return STATE_DEPENDENT;
80 else
81 return max (a, b);
82 }
84 void usage (char *msg)
85 {
86 printf (msg);
87 print_usage ();
88 exit (STATE_UNKNOWN);
89 }
91 void usage2(char *msg, char *arg)
92 {
93 printf ("%s: %s - %s\n",progname,msg,arg);
94 print_usage ();
95 exit (STATE_UNKNOWN);
96 }
98 void
99 usage3 (char *msg, char arg)
100 {
101 printf ("%s: %s - %c\n", progname, msg, arg);
102 print_usage();
103 exit (STATE_UNKNOWN);
104 }
107 void
108 support (void)
109 {
110 printf
111 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
112 "regarding use of this software. To submit patches or suggest improvements,\n"
113 "send email to nagiosplug-devel@lists.sourceforge.net\n");
114 }
117 char *
118 clean_revstring (const char *revstring)
119 {
120 char plugin_revision[STRLEN];
121 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
122 return strscpy (NULL, plugin_revision);
123 else
124 return strscpy (NULL, "N/A");
125 }
127 void
128 print_revision (const char *command_name, const char *revision_string)
129 {
130 char plugin_revision[STRLEN];
132 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
133 strncpy (plugin_revision, "N/A", STRLEN);
134 printf ("%s (nagios-plugins %s) %s\n",
135 progname, VERSION, plugin_revision);
136 printf
137 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
138 "copies of the plugins under the terms of the GNU General Public License.\n"
139 "For more information about these matters, see the file named COPYING.\n");
141 }
144 void
145 terminate (int result, const char *fmt, ...)
146 {
147 va_list ap;
148 va_start (ap, fmt);
149 vprintf (fmt, ap);
150 va_end (ap);
151 exit (result);
152 }
154 void
155 timeout_alarm_handler (int signo)
156 {
157 if (signo == SIGALRM) {
158 printf ("CRITICAL - Plugin timed out after %d seconds\n",
159 timeout_interval);
160 exit (STATE_CRITICAL);
161 }
162 }
164 int
165 is_numeric (char *number)
166 {
167 char tmp[1];
168 float x;
170 if (!number)
171 return FALSE;
172 else if (sscanf (number, "%f%c", &x, tmp) == 1)
173 return TRUE;
174 else
175 return FALSE;
176 }
178 int
179 is_positive (char *number)
180 {
181 if (is_numeric (number) && atof (number) > 0.0)
182 return TRUE;
183 else
184 return FALSE;
185 }
187 int
188 is_negative (char *number)
189 {
190 if (is_numeric (number) && atof (number) < 0.0)
191 return TRUE;
192 else
193 return FALSE;
194 }
196 int
197 is_nonnegative (char *number)
198 {
199 if (is_numeric (number) && atof (number) >= 0.0)
200 return TRUE;
201 else
202 return FALSE;
203 }
205 int
206 is_percentage (char *number)
207 {
208 int x;
209 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
210 return TRUE;
211 else
212 return FALSE;
213 }
215 int
216 is_integer (char *number)
217 {
218 long int n;
220 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
221 return FALSE;
223 n = strtol (number, NULL, 10);
225 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
226 return TRUE;
227 else
228 return FALSE;
229 }
231 int
232 is_intpos (char *number)
233 {
234 if (is_integer (number) && atoi (number) > 0)
235 return TRUE;
236 else
237 return FALSE;
238 }
240 int
241 is_intneg (char *number)
242 {
243 if (is_integer (number) && atoi (number) < 0)
244 return TRUE;
245 else
246 return FALSE;
247 }
249 int
250 is_intnonneg (char *number)
251 {
252 if (is_integer (number) && atoi (number) >= 0)
253 return TRUE;
254 else
255 return FALSE;
256 }
258 int
259 is_intpercent (char *number)
260 {
261 int i;
262 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
263 return TRUE;
264 else
265 return FALSE;
266 }
268 int
269 is_option (char *str)
270 {
271 if (!str)
272 return FALSE;
273 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
274 return TRUE;
275 else
276 return FALSE;
277 }
281 #ifdef NEED_GETTIMEOFDAY
282 int
283 gettimeofday (struct timeval *tv, struct timezone *tz)
284 {
285 tv->tv_usec = 0;
286 tv->tv_sec = (long) time ((time_t) 0);
287 }
288 #endif
292 double
293 delta_time (struct timeval tv)
294 {
295 struct timeval now;
297 gettimeofday (&now, NULL);
298 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
299 }
304 void
305 strip (char *buffer)
306 {
307 size_t x;
308 int i;
310 for (x = strlen (buffer); x >= 1; x--) {
311 i = x - 1;
312 if (buffer[i] == ' ' ||
313 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
314 buffer[i] = '\0';
315 else
316 break;
317 }
318 return;
319 }
325 /******************************************************************************
326 *
327 * Copies one string to another. Any previously existing data in
328 * the destination string is lost.
329 *
330 * Example:
331 *
332 * char *str=NULL;
333 * str = strscpy("This is a line of text with no trailing newline");
334 *
335 *****************************************************************************/
337 char *
338 strscpy (char *dest, const char *src)
339 {
340 if (src == NULL)
341 return NULL;
343 asprintf (&dest, "%s", src);
345 return dest;
346 }
352 /******************************************************************************
353 *
354 * Concatenates one string to the end of another
355 *
356 * Given a pointer destination string, which may or may not already
357 * hold some text, and a source string with additional text (possibly
358 * NULL or empty), returns a pointer to a string that is the first
359 * string with the second concatenated to it. Uses realloc to free
360 * memory held by the dest argument if new storage space is required.
361 *
362 * Example:
363 *
364 * char *str=NULL;
365 * str = strscpy("This is a line of text with no trailing newline");
366 * str = strscat(str,"\n");
367 *
368 *****************************************************************************/
370 char *
371 strscat (char *dest, char *src)
372 {
374 if (dest == NULL)
375 return src;
376 if (src != NULL)
377 asprintf (&dest, "%s%s", dest, src);
379 return dest;
380 }
386 /******************************************************************************
387 *
388 * Returns a pointer to the next line of a multiline string buffer
389 *
390 * Given a pointer string, find the text following the next sequence
391 * of \r and \n characters. This has the effect of skipping blank
392 * lines as well
393 *
394 * Example:
395 *
396 * Given text as follows:
397 *
398 * ==============================
399 * This
400 * is
401 * a
402 *
403 * multiline string buffer
404 * ==============================
405 *
406 * int i=0;
407 * char *str=NULL;
408 * char *ptr=NULL;
409 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
410 * ptr = str;
411 * while (ptr) {
412 * printf("%d %s",i++,firstword(ptr));
413 * ptr = strnl(ptr);
414 * }
415 *
416 * Produces the following:
417 *
418 * 1 This
419 * 2 is
420 * 3 a
421 * 4 multiline
422 *
423 * NOTE: The 'firstword()' function is conceptual only and does not
424 * exist in this package.
425 *
426 * NOTE: Although the second 'ptr' variable is not strictly needed in
427 * this example, it is good practice with these utilities. Once
428 * the * pointer is advance in this manner, it may no longer be
429 * handled with * realloc(). So at the end of the code fragment
430 * above, * strscpy(str,"foo") work perfectly fine, but
431 * strscpy(ptr,"foo") will * cause the the program to crash with
432 * a segmentation fault.
433 *
434 *****************************************************************************/
436 char *
437 strnl (char *str)
438 {
439 size_t len;
440 if (str == NULL)
441 return NULL;
442 str = strpbrk (str, "\r\n");
443 if (str == NULL)
444 return NULL;
445 len = strspn (str, "\r\n");
446 if (str[len] == '\0')
447 return NULL;
448 str += len;
449 if (strlen (str) == 0)
450 return NULL;
451 return str;
452 }
458 /******************************************************************************
459 *
460 * Like strscpy, except only the portion of the source string up to
461 * the provided delimiter is copied.
462 *
463 * Example:
464 *
465 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
466 * printf("%s\n",str);
467 *
468 * Produces:
469 *
470 *This is a line of te
471 *
472 *****************************************************************************/
474 char *
475 strpcpy (char *dest, const char *src, const char *str)
476 {
477 size_t len;
479 if (src)
480 len = strcspn (src, str);
481 else
482 return NULL;
484 if (dest == NULL || strlen (dest) < len)
485 dest = realloc (dest, len + 1);
486 if (dest == NULL)
487 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
489 strncpy (dest, src, len);
490 dest[len] = '\0';
492 return dest;
493 }
499 /******************************************************************************
500 *
501 * Like strscat, except only the portion of the source string up to
502 * the provided delimiter is copied.
503 *
504 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
505 * str = strpcat(str,"This is a line of text with no trailing newline","x");
506 * printf("%s\n",str);
507 *
508 *This is a line of texThis is a line of tex
509 *
510 *****************************************************************************/
512 char *
513 strpcat (char *dest, const char *src, const char *str)
514 {
515 size_t len, l2;
517 if (dest)
518 len = strlen (dest);
519 else
520 len = 0;
522 if (src) {
523 l2 = strcspn (src, str);
524 }
525 else {
526 return dest;
527 }
529 dest = realloc (dest, len + l2 + 1);
530 if (dest == NULL)
531 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
533 strncpy (dest + len, src, l2);
534 dest[len + l2] = '\0';
536 return dest;
537 }