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