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 die (int result, const char *fmt, ...);
28 void terminate (int result, const char *fmt, ...);
29 RETSIGTYPE timeout_alarm_handler (int);
31 int is_integer (char *);
32 int is_intpos (char *);
33 int is_intneg (char *);
34 int is_intnonneg (char *);
35 int is_intpercent (char *);
37 int is_numeric (char *);
38 int is_positive (char *);
39 int is_negative (char *);
40 int is_nonnegative (char *);
41 int is_percentage (char *);
43 int is_option (char *str);
45 double delta_time (struct timeval tv);
47 void strip (char *);
48 char *strscpy (char *dest, const char *src);
49 char *strscat (char *dest, char *src);
50 char *strnl (char *str);
51 char *strpcpy (char *dest, const char *src, const char *str);
52 char *strpcat (char *dest, const char *src, const char *str);
54 char *state_text (int result);
56 #define STRLEN 64
57 #define TXTBLK 128
59 /* **************************************************************************
60 /* max_state(STATE_x, STATE_y)
61 * compares STATE_x to STATE_y and returns result based on the following
62 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
63 *
64 * Note that numerically the above does not hold
65 ****************************************************************************/
67 #define max(a,b) (((a)>(b))?(a):(b))
69 int
70 max_state (int a, int b)
71 {
72 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
73 return STATE_CRITICAL;
74 else if (a == STATE_WARNING || b == STATE_WARNING)
75 return STATE_WARNING;
76 else if (a == STATE_OK || b == STATE_OK)
77 return STATE_OK;
78 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
79 return STATE_UNKNOWN;
80 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
81 return STATE_DEPENDENT;
82 else
83 return max (a, b);
84 }
86 void usage (char *msg)
87 {
88 printf (msg);
89 print_usage ();
90 exit (STATE_UNKNOWN);
91 }
93 void usage2(char *msg, char *arg)
94 {
95 printf ("%s: %s - %s\n",progname,msg,arg);
96 print_usage ();
97 exit (STATE_UNKNOWN);
98 }
100 void
101 usage3 (char *msg, char arg)
102 {
103 printf ("%s: %s - %c\n", progname, msg, arg);
104 print_usage();
105 exit (STATE_UNKNOWN);
106 }
109 void
110 support (void)
111 {
112 printf
113 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
114 "regarding use of this software. To submit patches or suggest improvements,\n"
115 "send email to nagiosplug-devel@lists.sourceforge.net\n");
116 }
119 char *
120 clean_revstring (const char *revstring)
121 {
122 char plugin_revision[STRLEN];
123 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
124 return strscpy (NULL, plugin_revision);
125 else
126 return strscpy (NULL, "N/A");
127 }
129 void
130 print_revision (const char *command_name, const char *revision_string)
131 {
132 char plugin_revision[STRLEN];
134 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
135 strncpy (plugin_revision, "N/A", STRLEN);
136 printf ("%s (%s %s) %s\n",
137 progname, PACKAGE, VERSION, plugin_revision);
138 printf
139 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
140 "copies of the plugins under the terms of the GNU General Public License.\n"
141 "For more information about these matters, see the file named COPYING.\n");
143 }
145 char *
146 state_text (int result)
147 {
148 switch (result) {
149 case STATE_OK:
150 return "OK";
151 case STATE_WARNING:
152 return "WARNING";
153 case STATE_CRITICAL:
154 return "CRITICAL";
155 case STATE_DEPENDENT:
156 return "DEPENDENT";
157 default:
158 return "UNKNOWN";
159 }
160 }
162 void
163 die (int result, const char *fmt, ...)
164 {
165 va_list ap;
166 printf ("%s %s: ", sizeof (char) + index(progname, '_'), state_text(result));
167 va_start (ap, fmt);
168 vprintf (fmt, ap);
169 va_end (ap);
170 exit (result);
171 }
173 void
174 terminate (int result, const char *fmt, ...)
175 {
176 va_list ap;
177 va_start (ap, fmt);
178 vprintf (fmt, ap);
179 va_end (ap);
180 exit (result);
181 }
183 void
184 timeout_alarm_handler (int signo)
185 {
186 if (signo == SIGALRM) {
187 printf ("CRITICAL - Plugin timed out after %d seconds\n",
188 timeout_interval);
189 exit (STATE_CRITICAL);
190 }
191 }
193 int
194 is_numeric (char *number)
195 {
196 char tmp[1];
197 float x;
199 if (!number)
200 return FALSE;
201 else if (sscanf (number, "%f%c", &x, tmp) == 1)
202 return TRUE;
203 else
204 return FALSE;
205 }
207 int
208 is_positive (char *number)
209 {
210 if (is_numeric (number) && atof (number) > 0.0)
211 return TRUE;
212 else
213 return FALSE;
214 }
216 int
217 is_negative (char *number)
218 {
219 if (is_numeric (number) && atof (number) < 0.0)
220 return TRUE;
221 else
222 return FALSE;
223 }
225 int
226 is_nonnegative (char *number)
227 {
228 if (is_numeric (number) && atof (number) >= 0.0)
229 return TRUE;
230 else
231 return FALSE;
232 }
234 int
235 is_percentage (char *number)
236 {
237 int x;
238 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
239 return TRUE;
240 else
241 return FALSE;
242 }
244 int
245 is_integer (char *number)
246 {
247 long int n;
249 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
250 return FALSE;
252 n = strtol (number, NULL, 10);
254 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
255 return TRUE;
256 else
257 return FALSE;
258 }
260 int
261 is_intpos (char *number)
262 {
263 if (is_integer (number) && atoi (number) > 0)
264 return TRUE;
265 else
266 return FALSE;
267 }
269 int
270 is_intneg (char *number)
271 {
272 if (is_integer (number) && atoi (number) < 0)
273 return TRUE;
274 else
275 return FALSE;
276 }
278 int
279 is_intnonneg (char *number)
280 {
281 if (is_integer (number) && atoi (number) >= 0)
282 return TRUE;
283 else
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 else
294 return FALSE;
295 }
297 int
298 is_option (char *str)
299 {
300 if (!str)
301 return FALSE;
302 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
303 return TRUE;
304 else
305 return FALSE;
306 }
310 #ifdef NEED_GETTIMEOFDAY
311 int
312 gettimeofday (struct timeval *tv, struct timezone *tz)
313 {
314 tv->tv_usec = 0;
315 tv->tv_sec = (long) time ((time_t) 0);
316 }
317 #endif
321 double
322 delta_time (struct timeval tv)
323 {
324 struct timeval now;
326 gettimeofday (&now, NULL);
327 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
328 }
333 void
334 strip (char *buffer)
335 {
336 size_t x;
337 int i;
339 for (x = strlen (buffer); x >= 1; x--) {
340 i = x - 1;
341 if (buffer[i] == ' ' ||
342 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
343 buffer[i] = '\0';
344 else
345 break;
346 }
347 return;
348 }
354 /******************************************************************************
355 *
356 * Copies one string to another. Any previously existing data in
357 * the destination string is lost.
358 *
359 * Example:
360 *
361 * char *str=NULL;
362 * str = strscpy("This is a line of text with no trailing newline");
363 *
364 *****************************************************************************/
366 char *
367 strscpy (char *dest, const char *src)
368 {
369 if (src == NULL)
370 return NULL;
372 asprintf (&dest, "%s", src);
374 return dest;
375 }
381 /******************************************************************************
382 *
383 * Concatenates one string to the end of another
384 *
385 * Given a pointer destination string, which may or may not already
386 * hold some text, and a source string with additional text (possibly
387 * NULL or empty), returns a pointer to a string that is the first
388 * string with the second concatenated to it. Uses realloc to free
389 * memory held by the dest argument if new storage space is required.
390 *
391 * Example:
392 *
393 * char *str=NULL;
394 * str = strscpy("This is a line of text with no trailing newline");
395 * str = strscat(str,"\n");
396 *
397 *****************************************************************************/
399 char *
400 strscat (char *dest, char *src)
401 {
403 if (dest == NULL)
404 return src;
405 if (src != NULL)
406 asprintf (&dest, "%s%s", dest, src);
408 return dest;
409 }
415 /******************************************************************************
416 *
417 * Returns a pointer to the next line of a multiline string buffer
418 *
419 * Given a pointer string, find the text following the next sequence
420 * of \r and \n characters. This has the effect of skipping blank
421 * lines as well
422 *
423 * Example:
424 *
425 * Given text as follows:
426 *
427 * ==============================
428 * This
429 * is
430 * a
431 *
432 * multiline string buffer
433 * ==============================
434 *
435 * int i=0;
436 * char *str=NULL;
437 * char *ptr=NULL;
438 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
439 * ptr = str;
440 * while (ptr) {
441 * printf("%d %s",i++,firstword(ptr));
442 * ptr = strnl(ptr);
443 * }
444 *
445 * Produces the following:
446 *
447 * 1 This
448 * 2 is
449 * 3 a
450 * 4 multiline
451 *
452 * NOTE: The 'firstword()' function is conceptual only and does not
453 * exist in this package.
454 *
455 * NOTE: Although the second 'ptr' variable is not strictly needed in
456 * this example, it is good practice with these utilities. Once
457 * the * pointer is advance in this manner, it may no longer be
458 * handled with * realloc(). So at the end of the code fragment
459 * above, * strscpy(str,"foo") work perfectly fine, but
460 * strscpy(ptr,"foo") will * cause the the program to crash with
461 * a segmentation fault.
462 *
463 *****************************************************************************/
465 char *
466 strnl (char *str)
467 {
468 size_t len;
469 if (str == NULL)
470 return NULL;
471 str = strpbrk (str, "\r\n");
472 if (str == NULL)
473 return NULL;
474 len = strspn (str, "\r\n");
475 if (str[len] == '\0')
476 return NULL;
477 str += len;
478 if (strlen (str) == 0)
479 return NULL;
480 return str;
481 }
487 /******************************************************************************
488 *
489 * Like strscpy, except only the portion of the source string up to
490 * the provided delimiter is copied.
491 *
492 * Example:
493 *
494 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
495 * printf("%s\n",str);
496 *
497 * Produces:
498 *
499 *This is a line of te
500 *
501 *****************************************************************************/
503 char *
504 strpcpy (char *dest, const char *src, const char *str)
505 {
506 size_t len;
508 if (src)
509 len = strcspn (src, str);
510 else
511 return NULL;
513 if (dest == NULL || strlen (dest) < len)
514 dest = realloc (dest, len + 1);
515 if (dest == NULL)
516 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
518 strncpy (dest, src, len);
519 dest[len] = '\0';
521 return dest;
522 }
528 /******************************************************************************
529 *
530 * Like strscat, except only the portion of the source string up to
531 * the provided delimiter is copied.
532 *
533 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
534 * str = strpcat(str,"This is a line of text with no trailing newline","x");
535 * printf("%s\n",str);
536 *
537 *This is a line of texThis is a line of tex
538 *
539 *****************************************************************************/
541 char *
542 strpcat (char *dest, const char *src, const char *str)
543 {
544 size_t len, l2;
546 if (dest)
547 len = strlen (dest);
548 else
549 len = 0;
551 if (src) {
552 l2 = strcspn (src, str);
553 }
554 else {
555 return dest;
556 }
558 dest = realloc (dest, len + l2 + 1);
559 if (dest == NULL)
560 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
562 strncpy (dest + len, src, l2);
563 dest[len + l2] = '\0';
565 return dest;
566 }