summaryrefslogtreecommitdiffstats
path: root/lib/utils_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils_base.c')
-rw-r--r--lib/utils_base.c496
1 files changed, 103 insertions, 393 deletions
diff --git a/lib/utils_base.c b/lib/utils_base.c
index 90a4aaa5..28e6dc47 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -25,6 +25,7 @@
25 *****************************************************************************/ 25 *****************************************************************************/
26 26
27#include "../plugins/common.h" 27#include "../plugins/common.h"
28#include "states.h"
28#include <stdarg.h> 29#include <stdarg.h>
29#include "utils_base.h" 30#include "utils_base.h"
30#include <ctype.h> 31#include <ctype.h>
@@ -33,20 +34,20 @@
33#include <unistd.h> 34#include <unistd.h>
34#include <sys/types.h> 35#include <sys/types.h>
35 36
36#define np_free(ptr) \ 37#define np_free(ptr) \
37 { \ 38 { \
38 if (ptr) { \ 39 if (ptr) { \
39 free(ptr); \ 40 free(ptr); \
40 ptr = NULL; \ 41 ptr = NULL; \
41 } \ 42 } \
42 } 43 }
43 44
44monitoring_plugin *this_monitoring_plugin = NULL; 45monitoring_plugin *this_monitoring_plugin = NULL;
45 46
46int timeout_state = STATE_CRITICAL; 47mp_state_enum timeout_state = STATE_CRITICAL;
47unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; 48unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
48 49
49bool _np_state_read_file(FILE *); 50bool _np_state_read_file(FILE *state_file);
50 51
51void np_init(char *plugin_name, int argc, char **argv) { 52void np_init(char *plugin_name, int argc, char **argv) {
52 if (this_monitoring_plugin == NULL) { 53 if (this_monitoring_plugin == NULL) {
@@ -55,31 +56,25 @@ void np_init(char *plugin_name, int argc, char **argv) {
55 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); 56 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
56 } 57 }
57 this_monitoring_plugin->plugin_name = strdup(plugin_name); 58 this_monitoring_plugin->plugin_name = strdup(plugin_name);
58 if (this_monitoring_plugin->plugin_name == NULL) 59 if (this_monitoring_plugin->plugin_name == NULL) {
59 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 60 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
61 }
60 this_monitoring_plugin->argc = argc; 62 this_monitoring_plugin->argc = argc;
61 this_monitoring_plugin->argv = argv; 63 this_monitoring_plugin->argv = argv;
62 } 64 }
63} 65}
64 66
65void np_set_args(int argc, char **argv) { 67void np_set_args(int argc, char **argv) {
66 if (this_monitoring_plugin == NULL) 68 if (this_monitoring_plugin == NULL) {
67 die(STATE_UNKNOWN, _("This requires np_init to be called")); 69 die(STATE_UNKNOWN, _("This requires np_init to be called"));
70 }
68 71
69 this_monitoring_plugin->argc = argc; 72 this_monitoring_plugin->argc = argc;
70 this_monitoring_plugin->argv = argv; 73 this_monitoring_plugin->argv = argv;
71} 74}
72 75
73void np_cleanup() { 76void np_cleanup(void) {
74 if (this_monitoring_plugin != NULL) { 77 if (this_monitoring_plugin != NULL) {
75 if (this_monitoring_plugin->state != NULL) {
76 if (this_monitoring_plugin->state->state_data) {
77 np_free(this_monitoring_plugin->state->state_data->data);
78 np_free(this_monitoring_plugin->state->state_data);
79 }
80 np_free(this_monitoring_plugin->state->name);
81 np_free(this_monitoring_plugin->state);
82 }
83 np_free(this_monitoring_plugin->plugin_name); 78 np_free(this_monitoring_plugin->plugin_name);
84 np_free(this_monitoring_plugin); 79 np_free(this_monitoring_plugin);
85 } 80 }
@@ -151,7 +146,8 @@ range *parse_range_string(char *str) {
151 set_range_end(temp_range, end); 146 set_range_end(temp_range, end);
152 } 147 }
153 148
154 if (temp_range->start_infinity == true || temp_range->end_infinity == true || temp_range->start <= temp_range->end) { 149 if (temp_range->start_infinity || temp_range->end_infinity ||
150 temp_range->start <= temp_range->end) {
155 return temp_range; 151 return temp_range;
156 } 152 }
157 free(temp_range); 153 free(temp_range);
@@ -162,8 +158,9 @@ range *parse_range_string(char *str) {
162int _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) { 158int _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) {
163 thresholds *temp_thresholds = NULL; 159 thresholds *temp_thresholds = NULL;
164 160
165 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) 161 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) {
166 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); 162 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
163 }
167 164
168 temp_thresholds->warning = NULL; 165 temp_thresholds->warning = NULL;
169 temp_thresholds->critical = NULL; 166 temp_thresholds->critical = NULL;
@@ -202,12 +199,14 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
202 printf("Threshold not set"); 199 printf("Threshold not set");
203 } else { 200 } else {
204 if (my_threshold->warning) { 201 if (my_threshold->warning) {
205 printf("Warning: start=%g end=%g; ", my_threshold->warning->start, my_threshold->warning->end); 202 printf("Warning: start=%g end=%g; ", my_threshold->warning->start,
203 my_threshold->warning->end);
206 } else { 204 } else {
207 printf("Warning not set; "); 205 printf("Warning not set; ");
208 } 206 }
209 if (my_threshold->critical) { 207 if (my_threshold->critical) {
210 printf("Critical: start=%g end=%g", my_threshold->critical->start, my_threshold->critical->end); 208 printf("Critical: start=%g end=%g", my_threshold->critical->start,
209 my_threshold->critical->end);
211 } else { 210 } else {
212 printf("Critical not set"); 211 printf("Critical not set");
213 } 212 }
@@ -215,6 +214,36 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
215 printf("\n"); 214 printf("\n");
216} 215}
217 216
217/* Returns true if alert should be raised based on the range, false otherwise */
218bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
219 bool is_inside = false;
220
221 if (!my_range.end_infinity && !my_range.start_infinity) {
222 // range: .........|---inside---|...........
223 // value
224 is_inside = ((cmp_perfdata_value(value, my_range.start) >= 0) &&
225 (cmp_perfdata_value(value, my_range.end) <= 0));
226 } else if (!my_range.start_infinity && my_range.end_infinity) {
227 // range: .........|---inside---------
228 // value
229 is_inside = (cmp_perfdata_value(value, my_range.start) >= 0);
230 } else if (my_range.start_infinity && !my_range.end_infinity) {
231 // range: -inside--------|....................
232 // value
233 is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
234 } else {
235 // range from -inf to inf, so always inside
236 is_inside = true;
237 }
238
239 if ((is_inside && my_range.alert_on_inside_range == INSIDE) ||
240 (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
241 return true;
242 }
243
244 return false;
245}
246
218/* Returns true if alert should be raised based on the range */ 247/* Returns true if alert should be raised based on the range */
219bool check_range(double value, range *my_range) { 248bool check_range(double value, range *my_range) {
220 bool no = false; 249 bool no = false;
@@ -225,38 +254,38 @@ bool check_range(double value, range *my_range) {
225 yes = false; 254 yes = false;
226 } 255 }
227 256
228 if (my_range->end_infinity == false && my_range->start_infinity == false) { 257 if (!my_range->end_infinity && !my_range->start_infinity) {
229 if ((my_range->start <= value) && (value <= my_range->end)) { 258 if ((my_range->start <= value) && (value <= my_range->end)) {
230 return no; 259 return no;
231 } else {
232 return yes;
233 } 260 }
234 } else if (my_range->start_infinity == false && my_range->end_infinity == true) { 261 return yes;
262 }
263
264 if (!my_range->start_infinity && my_range->end_infinity) {
235 if (my_range->start <= value) { 265 if (my_range->start <= value) {
236 return no; 266 return no;
237 } else {
238 return yes;
239 } 267 }
240 } else if (my_range->start_infinity == true && my_range->end_infinity == false) { 268 return yes;
269 }
270
271 if (my_range->start_infinity && !my_range->end_infinity) {
241 if (value <= my_range->end) { 272 if (value <= my_range->end) {
242 return no; 273 return no;
243 } else {
244 return yes;
245 } 274 }
246 } else { 275 return yes;
247 return no;
248 } 276 }
277 return no;
249} 278}
250 279
251/* Returns status */ 280/* Returns status */
252int get_status(double value, thresholds *my_thresholds) { 281mp_state_enum get_status(double value, thresholds *my_thresholds) {
253 if (my_thresholds->critical != NULL) { 282 if (my_thresholds->critical != NULL) {
254 if (check_range(value, my_thresholds->critical) == true) { 283 if (check_range(value, my_thresholds->critical)) {
255 return STATE_CRITICAL; 284 return STATE_CRITICAL;
256 } 285 }
257 } 286 }
258 if (my_thresholds->warning != NULL) { 287 if (my_thresholds->warning != NULL) {
259 if (check_range(value, my_thresholds->warning) == true) { 288 if (check_range(value, my_thresholds->warning)) {
260 return STATE_WARNING; 289 return STATE_WARNING;
261 } 290 }
262 } 291 }
@@ -265,31 +294,31 @@ int get_status(double value, thresholds *my_thresholds) {
265 294
266char *np_escaped_string(const char *string) { 295char *np_escaped_string(const char *string) {
267 char *data; 296 char *data;
268 int i, j = 0; 297 int write_index = 0;
269 data = strdup(string); 298 data = strdup(string);
270 for (i = 0; data[i]; i++) { 299 for (int i = 0; data[i]; i++) {
271 if (data[i] == '\\') { 300 if (data[i] == '\\') {
272 switch (data[++i]) { 301 switch (data[++i]) {
273 case 'n': 302 case 'n':
274 data[j++] = '\n'; 303 data[write_index++] = '\n';
275 break; 304 break;
276 case 'r': 305 case 'r':
277 data[j++] = '\r'; 306 data[write_index++] = '\r';
278 break; 307 break;
279 case 't': 308 case 't':
280 data[j++] = '\t'; 309 data[write_index++] = '\t';
281 break; 310 break;
282 case '\\': 311 case '\\':
283 data[j++] = '\\'; 312 data[write_index++] = '\\';
284 break; 313 break;
285 default: 314 default:
286 data[j++] = data[i]; 315 data[write_index++] = data[i];
287 } 316 }
288 } else { 317 } else {
289 data[j++] = data[i]; 318 data[write_index++] = data[i];
290 } 319 }
291 } 320 }
292 data[j] = '\0'; 321 data[write_index] = '\0';
293 return data; 322 return data;
294} 323}
295 324
@@ -302,38 +331,43 @@ int np_check_if_root(void) { return (geteuid() == 0); }
302 * data strings. 331 * data strings.
303 */ 332 */
304char *np_extract_value(const char *varlist, const char *name, char sep) { 333char *np_extract_value(const char *varlist, const char *name, char sep) {
305 char *tmp = NULL, *value = NULL; 334 char *tmp = NULL;
306 int i; 335 char *value = NULL;
307 336
308 while (1) { 337 while (true) {
309 /* Strip any leading space */ 338 /* Strip any leading space */
310 for (; isspace(varlist[0]); varlist++) 339 for (; isspace(varlist[0]); varlist++) {
311 ; 340 ;
341 }
312 342
313 if (strncmp(name, varlist, strlen(name)) == 0) { 343 if (strncmp(name, varlist, strlen(name)) == 0) {
314 varlist += strlen(name); 344 varlist += strlen(name);
315 /* strip trailing spaces */ 345 /* strip trailing spaces */
316 for (; isspace(varlist[0]); varlist++) 346 for (; isspace(varlist[0]); varlist++) {
317 ; 347 ;
348 }
318 349
319 if (varlist[0] == '=') { 350 if (varlist[0] == '=') {
320 /* We matched the key, go past the = sign */ 351 /* We matched the key, go past the = sign */
321 varlist++; 352 varlist++;
322 /* strip leading spaces */ 353 /* strip leading spaces */
323 for (; isspace(varlist[0]); varlist++) 354 for (; isspace(varlist[0]); varlist++) {
324 ; 355 ;
356 }
325 357
326 if ((tmp = index(varlist, sep))) { 358 if ((tmp = index(varlist, sep))) {
327 /* Value is delimited by a comma */ 359 /* Value is delimited by a comma */
328 if (tmp - varlist == 0) 360 if (tmp - varlist == 0) {
329 continue; 361 continue;
330 value = (char *)calloc(1, tmp - varlist + 1); 362 }
331 strncpy(value, varlist, tmp - varlist); 363 value = (char *)calloc(1, (unsigned long)(tmp - varlist + 1));
364 strncpy(value, varlist, (unsigned long)(tmp - varlist));
332 value[tmp - varlist] = '\0'; 365 value[tmp - varlist] = '\0';
333 } else { 366 } else {
334 /* Value is delimited by a \0 */ 367 /* Value is delimited by a \0 */
335 if (strlen(varlist) == 0) 368 if (strlen(varlist) == 0) {
336 continue; 369 continue;
370 }
337 value = (char *)calloc(1, strlen(varlist) + 1); 371 value = (char *)calloc(1, strlen(varlist) + 1);
338 strncpy(value, varlist, strlen(varlist)); 372 strncpy(value, varlist, strlen(varlist));
339 value[strlen(varlist)] = '\0'; 373 value[strlen(varlist)] = '\0';
@@ -351,14 +385,16 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
351 } 385 }
352 386
353 /* Clean-up trailing spaces/newlines */ 387 /* Clean-up trailing spaces/newlines */
354 if (value) 388 if (value) {
355 for (i = strlen(value) - 1; isspace(value[i]); i--) 389 for (unsigned long i = strlen(value) - 1; isspace(value[i]); i--) {
356 value[i] = '\0'; 390 value[i] = '\0';
391 }
392 }
357 393
358 return value; 394 return value;
359} 395}
360 396
361const char *state_text(int result) { 397const char *state_text(mp_state_enum result) {
362 switch (result) { 398 switch (result) {
363 case STATE_OK: 399 case STATE_OK:
364 return "OK"; 400 return "OK";
@@ -378,343 +414,17 @@ const char *state_text(int result) {
378 * return the corresponding STATE_ value or ERROR) 414 * return the corresponding STATE_ value or ERROR)
379 */ 415 */
380int mp_translate_state(char *state_text) { 416int mp_translate_state(char *state_text) {
381 if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) 417 if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) {
382 return STATE_OK; 418 return STATE_OK;
383 if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1"))
384 return STATE_WARNING;
385 if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2"))
386 return STATE_CRITICAL;
387 if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3"))
388 return STATE_UNKNOWN;
389 return ERROR;
390}
391
392/*
393 * Returns a string to use as a keyname, based on an md5 hash of argv, thus
394 * hopefully a unique key per service/plugin invocation. Use the extra-opts
395 * parse of argv, so that uniqueness in parameters are reflected there.
396 */
397char *_np_state_generate_key() {
398 int i;
399 char **argv = this_monitoring_plugin->argv;
400 char keyname[41];
401 char *p = NULL;
402
403 unsigned char result[256];
404
405#ifdef USE_OPENSSL
406 /*
407 * This code path is chosen if openssl is available (which should be the most common
408 * scenario). Alternatively, the gnulib implementation/
409 *
410 */
411 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
412
413 EVP_DigestInit(ctx, EVP_sha256());
414
415 for (i = 0; i < this_monitoring_plugin->argc; i++) {
416 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
417 }
418
419 EVP_DigestFinal(ctx, result, NULL);
420#else
421
422 struct sha256_ctx ctx;
423
424 for (i = 0; i < this_monitoring_plugin->argc; i++) {
425 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
426 }
427
428 sha256_finish_ctx(&ctx, result);
429#endif // FOUNDOPENSSL
430
431 for (i = 0; i < 20; ++i) {
432 sprintf(&keyname[2 * i], "%02x", result[i]);
433 }
434
435 keyname[40] = '\0';
436
437 p = strdup(keyname);
438 if (p == NULL) {
439 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
440 }
441 return p;
442}
443
444void _cleanup_state_data() {
445 if (this_monitoring_plugin->state->state_data != NULL) {
446 np_free(this_monitoring_plugin->state->state_data->data);
447 np_free(this_monitoring_plugin->state->state_data);
448 }
449}
450
451/*
452 * Internal function. Returns either:
453 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
454 * statically compiled shared state directory
455 */
456char *_np_state_calculate_location_prefix() {
457 char *env_dir;
458
459 /* Do not allow passing MP_STATE_PATH in setuid plugins
460 * for security reasons */
461 if (!mp_suid()) {
462 env_dir = getenv("MP_STATE_PATH");
463 if (env_dir && env_dir[0] != '\0')
464 return env_dir;
465 /* This is the former ENV, for backward-compatibility */
466 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
467 if (env_dir && env_dir[0] != '\0')
468 return env_dir;
469 }
470
471 return NP_STATE_DIR_PREFIX;
472}
473
474/*
475 * Initiatializer for state routines.
476 * Sets variables. Generates filename. Returns np_state_key. die with
477 * UNKNOWN if exception
478 */
479void np_enable_state(char *keyname, int expected_data_version) {
480 state_key *this_state = NULL;
481 char *temp_filename = NULL;
482 char *temp_keyname = NULL;
483 char *p = NULL;
484 int ret;
485
486 if (this_monitoring_plugin == NULL)
487 die(STATE_UNKNOWN, _("This requires np_init to be called"));
488
489 this_state = (state_key *)calloc(1, sizeof(state_key));
490 if (this_state == NULL)
491 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
492
493 if (keyname == NULL) {
494 temp_keyname = _np_state_generate_key();
495 } else {
496 temp_keyname = strdup(keyname);
497 if (temp_keyname == NULL)
498 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
499 } 419 }
500 /* Die if invalid characters used for keyname */ 420 if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1")) {
501 p = temp_keyname; 421 return STATE_WARNING;
502 while (*p != '\0') {
503 if (!(isalnum(*p) || *p == '_')) {
504 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
505 }
506 p++;
507 }
508 this_state->name = temp_keyname;
509 this_state->plugin_name = this_monitoring_plugin->plugin_name;
510 this_state->data_version = expected_data_version;
511 this_state->state_data = NULL;
512
513 /* Calculate filename */
514 ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
515 this_monitoring_plugin->plugin_name, this_state->name);
516 if (ret < 0)
517 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
518
519 this_state->_filename = temp_filename;
520
521 this_monitoring_plugin->state = this_state;
522}
523
524/*
525 * Will return NULL if no data is available (first run). If key currently
526 * exists, read data. If state file format version is not expected, return
527 * as if no data. Get state data version number and compares to expected.
528 * If numerically lower, then return as no previous state. die with UNKNOWN
529 * if exceptional error.
530 */
531state_data *np_state_read() {
532 state_data *this_state_data = NULL;
533 FILE *statefile;
534 bool rc = false;
535
536 if (this_monitoring_plugin == NULL)
537 die(STATE_UNKNOWN, _("This requires np_init to be called"));
538
539 /* Open file. If this fails, no previous state found */
540 statefile = fopen(this_monitoring_plugin->state->_filename, "r");
541 if (statefile != NULL) {
542
543 this_state_data = (state_data *)calloc(1, sizeof(state_data));
544 if (this_state_data == NULL)
545 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
546
547 this_state_data->data = NULL;
548 this_monitoring_plugin->state->state_data = this_state_data;
549
550 rc = _np_state_read_file(statefile);
551
552 fclose(statefile);
553 }
554
555 if (!rc) {
556 _cleanup_state_data();
557 }
558
559 return this_monitoring_plugin->state->state_data;
560}
561
562/*
563 * Read the state file
564 */
565bool _np_state_read_file(FILE *f) {
566 bool status = false;
567 size_t pos;
568 char *line;
569 int i;
570 int failure = 0;
571 time_t current_time, data_time;
572 enum {
573 STATE_FILE_VERSION,
574 STATE_DATA_VERSION,
575 STATE_DATA_TIME,
576 STATE_DATA_TEXT,
577 STATE_DATA_END
578 } expected = STATE_FILE_VERSION;
579
580 time(&current_time);
581
582 /* Note: This introduces a limit of 1024 bytes in the string data */
583 line = (char *)calloc(1, 1024);
584 if (line == NULL)
585 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
586
587 while (!failure && (fgets(line, 1024, f)) != NULL) {
588 pos = strlen(line);
589 if (line[pos - 1] == '\n') {
590 line[pos - 1] = '\0';
591 }
592
593 if (line[0] == '#')
594 continue;
595
596 switch (expected) {
597 case STATE_FILE_VERSION:
598 i = atoi(line);
599 if (i != NP_STATE_FORMAT_VERSION)
600 failure++;
601 else
602 expected = STATE_DATA_VERSION;
603 break;
604 case STATE_DATA_VERSION:
605 i = atoi(line);
606 if (i != this_monitoring_plugin->state->data_version)
607 failure++;
608 else
609 expected = STATE_DATA_TIME;
610 break;
611 case STATE_DATA_TIME:
612 /* If time > now, error */
613 data_time = strtoul(line, NULL, 10);
614 if (data_time > current_time)
615 failure++;
616 else {
617 this_monitoring_plugin->state->state_data->time = data_time;
618 expected = STATE_DATA_TEXT;
619 }
620 break;
621 case STATE_DATA_TEXT:
622 this_monitoring_plugin->state->state_data->data = strdup(line);
623 if (this_monitoring_plugin->state->state_data->data == NULL)
624 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
625 expected = STATE_DATA_END;
626 status = true;
627 break;
628 case STATE_DATA_END:;
629 }
630 }
631
632 np_free(line);
633 return status;
634}
635
636/*
637 * If time=NULL, use current time. Create state file, with state format
638 * version, default text. Writes version, time, and data. Avoid locking
639 * problems - use mv to write and then swap. Possible loss of state data if
640 * two things writing to same key at same time.
641 * Will die with UNKNOWN if errors
642 */
643void np_state_write_string(time_t data_time, char *data_string) {
644 FILE *fp;
645 char *temp_file = NULL;
646 int fd = 0, result = 0;
647 time_t current_time;
648 char *directories = NULL;
649 char *p = NULL;
650
651 if (data_time == 0)
652 time(&current_time);
653 else
654 current_time = data_time;
655
656 /* If file doesn't currently exist, create directories */
657 if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) {
658 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
659 if (result < 0)
660 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
661
662 for (p = directories + 1; *p; p++) {
663 if (*p == '/') {
664 *p = '\0';
665 if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) {
666 /* Can't free this! Otherwise error message is wrong! */
667 /* np_free(directories); */
668 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
669 }
670 *p = '/';
671 }
672 }
673 np_free(directories);
674 }
675
676 result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename);
677 if (result < 0)
678 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
679
680 if ((fd = mkstemp(temp_file)) == -1) {
681 np_free(temp_file);
682 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
683 }
684
685 fp = (FILE *)fdopen(fd, "w");
686 if (fp == NULL) {
687 close(fd);
688 unlink(temp_file);
689 np_free(temp_file);
690 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
691 } 422 }
692 423 if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2")) {
693 fprintf(fp, "# NP State file\n"); 424 return STATE_CRITICAL;
694 fprintf(fp, "%d\n", NP_STATE_FORMAT_VERSION);
695 fprintf(fp, "%d\n", this_monitoring_plugin->state->data_version);
696 fprintf(fp, "%lu\n", current_time);
697 fprintf(fp, "%s\n", data_string);
698
699 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
700
701 fflush(fp);
702
703 result = fclose(fp);
704
705 fsync(fd);
706
707 if (result != 0) {
708 unlink(temp_file);
709 np_free(temp_file);
710 die(STATE_UNKNOWN, _("Error writing temp file"));
711 } 425 }
712 426 if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3")) {
713 if (rename(temp_file, this_monitoring_plugin->state->_filename) != 0) { 427 return STATE_UNKNOWN;
714 unlink(temp_file);
715 np_free(temp_file);
716 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
717 } 428 }
718 429 return ERROR;
719 np_free(temp_file);
720} 430}