summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am18
-rw-r--r--lib/extra_opts.c149
-rw-r--r--lib/extra_opts.h1
-rw-r--r--lib/maxfd.c32
-rw-r--r--lib/maxfd.h6
-rw-r--r--lib/monitoringplug.h7
-rw-r--r--lib/output.c535
-rw-r--r--lib/output.h85
-rw-r--r--lib/parse_ini.c135
-rw-r--r--lib/parse_ini.h1
-rw-r--r--lib/perfdata.c516
-rw-r--r--lib/perfdata.h203
-rw-r--r--lib/states.h71
-rw-r--r--lib/tests/Makefile.am6
-rw-r--r--lib/tests/test_base64.c308
-rw-r--r--lib/tests/test_cmd.c261
-rw-r--r--lib/tests/test_disk.c180
-rwxr-xr-xlib/tests/test_generic_outputbin0 -> 143808 bytes
-rw-r--r--lib/tests/test_generic_output.c315
-rw-r--r--lib/tests/test_generic_output.t6
-rw-r--r--lib/tests/test_ini1.c116
-rw-r--r--lib/tests/test_ini3.c37
-rw-r--r--lib/tests/test_opts1.c105
-rw-r--r--lib/tests/test_opts2.c124
-rw-r--r--lib/tests/test_opts3.c37
-rw-r--r--lib/tests/test_tcp.c48
-rw-r--r--lib/tests/test_utils.c491
-rw-r--r--lib/thresholds.c59
-rw-r--r--lib/thresholds.h28
-rw-r--r--lib/utils_base.c554
-rw-r--r--lib/utils_base.h69
-rw-r--r--lib/utils_cmd.c280
-rw-r--r--lib/utils_cmd.h20
-rw-r--r--lib/utils_disk.c397
-rw-r--r--lib/utils_disk.h66
-rw-r--r--lib/utils_tcp.c78
-rw-r--r--lib/utils_tcp.h11
-rw-r--r--lib/vendor/cJSON/cJSON.c3165
-rw-r--r--lib/vendor/cJSON/cJSON.h306
39 files changed, 7006 insertions, 1820 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index dc3ee893..e41201c4 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -7,8 +7,21 @@ noinst_LIBRARIES = libmonitoringplug.a
7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins 8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
9 9
10libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c 10libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c
11EXTRA_DIST = utils_base.h utils_disk.h utils_tcp.h utils_cmd.h parse_ini.h extra_opts.h maxfd.h 11
12EXTRA_DIST = utils_base.h \
13 utils_disk.h \
14 utils_tcp.h \
15 utils_cmd.h \
16 parse_ini.h \
17 extra_opts.h \
18 maxfd.h \
19 perfdata.h \
20 output.h \
21 thresholds.h \
22 states.h \
23 vendor/cJSON/cJSON.h \
24 monitoringplug.h
12 25
13if USE_PARSE_INI 26if USE_PARSE_INI
14libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c 27libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c
@@ -16,4 +29,3 @@ endif USE_PARSE_INI
16 29
17test test-debug: 30test test-debug:
18 cd tests && make $@ 31 cd tests && make $@
19
diff --git a/lib/extra_opts.c b/lib/extra_opts.c
index 771621d8..88787336 100644
--- a/lib/extra_opts.c
+++ b/lib/extra_opts.c
@@ -1,24 +1,24 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins extra_opts library 3 * Monitoring Plugins extra_opts library
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2007 Monitoring Plugins Development Team 6 * Copyright (c) 2007 - 2024 Monitoring Plugins Development Team
7* 7 *
8* This program is free software: you can redistribute it and/or modify 8 * This program is free software: you can redistribute it and/or modify
9* it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
10* the Free Software Foundation, either version 3 of the License, or 10 * the Free Software Foundation, either version 3 of the License, or
11* (at your option) any later version. 11 * (at your option) any later version.
12* 12 *
13* This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details. 16 * GNU General Public License for more details.
17* 17 *
18* You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19* along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20* 20 *
21*****************************************************************************/ 21 *****************************************************************************/
22 22
23#include "common.h" 23#include "common.h"
24#include "utils_base.h" 24#include "utils_base.h"
@@ -26,110 +26,115 @@
26#include "extra_opts.h" 26#include "extra_opts.h"
27 27
28/* FIXME: copied from utils.h; we should move a bunch of libs! */ 28/* FIXME: copied from utils.h; we should move a bunch of libs! */
29bool is_option2 (char *str) 29bool is_option2(char *str) {
30{
31 if (!str) 30 if (!str)
32 return false; 31 return false;
33 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2) 32 else if (strspn(str, "-") == 1 || strspn(str, "-") == 2)
34 return true; 33 return true;
35 else 34 else
36 return false; 35 return false;
37} 36}
38 37
39/* this is the externally visible function used by plugins */ 38/* this is the externally visible function used by plugins */
40char **np_extra_opts(int *argc, char **argv, const char *plugin_name){ 39char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
41 np_arg_list *extra_args=NULL, *ea1=NULL, *ea_tmp=NULL; 40 np_arg_list *extra_args = NULL, *ea1 = NULL, *ea_tmp = NULL;
42 char **argv_new=NULL; 41 char **argv_new = NULL;
43 char *argptr=NULL; 42 char *argptr = NULL;
44 int i, j, optfound, argc_new, ea_num=*argc; 43 int i, j, optfound, argc_new, ea_num = *argc;
45 44
46 if(*argc<2) { 45 if (*argc < 2) {
47 /* No arguments provided */ 46 /* No arguments provided */
48 return argv; 47 return argv;
49 } 48 }
50 49
51 for(i=1; i<*argc; i++){ 50 for (i = 1; i < *argc; i++) {
52 argptr=NULL; 51 argptr = NULL;
53 optfound=0; 52 optfound = 0;
54 53
55 /* Do we have an extra-opts parameter? */ 54 /* Do we have an extra-opts parameter? */
56 if(strncmp(argv[i], "--extra-opts=", 13)==0){ 55 if (strncmp(argv[i], "--extra-opts=", 13) == 0) {
57 /* It is a single argument with value */ 56 /* It is a single argument with value */
58 argptr=argv[i]+13; 57 argptr = argv[i] + 13;
59 /* Delete the extra opts argument */ 58 /* Delete the extra opts argument */
60 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 59 for (j = i; j < *argc; j++)
60 argv[j] = argv[j + 1];
61 i--; 61 i--;
62 *argc-=1; 62 *argc -= 1;
63 }else if(strcmp(argv[i], "--extra-opts")==0){ 63 } else if (strcmp(argv[i], "--extra-opts") == 0) {
64 if((i+1<*argc)&&!is_option2(argv[i+1])){ 64 if ((i + 1 < *argc) && !is_option2(argv[i + 1])) {
65 /* It is a argument with separate value */ 65 /* It is a argument with separate value */
66 argptr=argv[i+1]; 66 argptr = argv[i + 1];
67 /* Delete the extra-opts argument/value */ 67 /* Delete the extra-opts argument/value */
68 for(j=i;j<*argc-1;j++) argv[j]=argv[j+2]; 68 for (j = i; j < *argc - 1; j++)
69 i-=2; 69 argv[j] = argv[j + 2];
70 *argc-=2; 70 i -= 2;
71 *argc -= 2;
71 ea_num--; 72 ea_num--;
72 }else{ 73 } else {
73 /* It has no value */ 74 /* It has no value */
74 optfound=1; 75 optfound = 1;
75 /* Delete the extra opts argument */ 76 /* Delete the extra opts argument */
76 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 77 for (j = i; j < *argc; j++)
78 argv[j] = argv[j + 1];
77 i--; 79 i--;
78 *argc-=1; 80 *argc -= 1;
79 } 81 }
80 } 82 }
81 83
82 /* If we found extra-opts, expand them and store them for later*/ 84 /* If we found extra-opts, expand them and store them for later*/
83 if(argptr||optfound){ 85 if (argptr || optfound) {
84 /* Process ini section, returning a linked list of arguments */ 86 /* Process ini section, returning a linked list of arguments */
85 ea1=np_get_defaults(argptr, plugin_name); 87 ea1 = np_get_defaults(argptr, plugin_name);
86 if(ea1==NULL) { 88 if (ea1 == NULL) {
87 /* no extra args (empty section)? */ 89 /* no extra args (empty section)? */
88 ea_num--; 90 ea_num--;
89 continue; 91 continue;
90 } 92 }
91 93
92 /* append the list to extra_args */ 94 /* append the list to extra_args */
93 if(extra_args==NULL){ 95 if (extra_args == NULL) {
94 extra_args=ea1; 96 extra_args = ea1;
95 while((ea1 = ea1->next)) ea_num++; 97 while ((ea1 = ea1->next))
96 }else{ 98 ea_num++;
97 ea_tmp=extra_args; 99 } else {
98 while(ea_tmp->next) { 100 ea_tmp = extra_args;
99 ea_tmp=ea_tmp->next; 101 while (ea_tmp->next) {
102 ea_tmp = ea_tmp->next;
100 } 103 }
101 ea_tmp->next=ea1; 104 ea_tmp->next = ea1;
102 while((ea1 = ea1->next)) ea_num++; 105 while ((ea1 = ea1->next))
106 ea_num++;
103 } 107 }
104 ea1=ea_tmp=NULL; 108 ea1 = ea_tmp = NULL;
105 } 109 }
106 } /* lather, rince, repeat */ 110 } /* lather, rince, repeat */
107 111
108 if(ea_num==*argc && extra_args==NULL){ 112 if (ea_num == *argc && extra_args == NULL) {
109 /* No extra-opts */ 113 /* No extra-opts */
110 return argv; 114 return argv;
111 } 115 }
112 116
113 /* done processing arguments. now create a new argv array... */ 117 /* done processing arguments. now create a new argv array... */
114 argv_new=(char**)malloc((ea_num+1)*sizeof(char**)); 118 argv_new = (char **)malloc((ea_num + 1) * sizeof(char **));
115 if(argv_new==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); 119 if (argv_new == NULL)
120 die(STATE_UNKNOWN, _("malloc() failed!\n"));
116 121
117 /* starting with program name */ 122 /* starting with program name */
118 argv_new[0]=argv[0]; 123 argv_new[0] = argv[0];
119 argc_new=1; 124 argc_new = 1;
120 /* then parsed ini opts (frying them up in the same run) */ 125 /* then parsed ini opts (frying them up in the same run) */
121 while(extra_args){ 126 while (extra_args) {
122 argv_new[argc_new++]=extra_args->arg; 127 argv_new[argc_new++] = extra_args->arg;
123 ea1=extra_args; 128 ea1 = extra_args;
124 extra_args=extra_args->next; 129 extra_args = extra_args->next;
125 free(ea1); 130 free(ea1);
126 } 131 }
127 /* finally the rest of the argv array */ 132 /* finally the rest of the argv array */
128 for (i=1; i<*argc; i++) argv_new[argc_new++]=argv[i]; 133 for (i = 1; i < *argc; i++)
129 *argc=argc_new; 134 argv_new[argc_new++] = argv[i];
135 *argc = argc_new;
130 /* and terminate. */ 136 /* and terminate. */
131 argv_new[argc_new]=NULL; 137 argv_new[argc_new] = NULL;
132 138
133 return argv_new; 139 return argv_new;
134} 140}
135
diff --git a/lib/extra_opts.h b/lib/extra_opts.h
index 8ff14a16..3f64360f 100644
--- a/lib/extra_opts.h
+++ b/lib/extra_opts.h
@@ -20,4 +20,3 @@
20char **np_extra_opts(int *argc, char **argv, const char *plugin_name); 20char **np_extra_opts(int *argc, char **argv, const char *plugin_name);
21 21
22#endif /* _EXTRA_OPTS_H_ */ 22#endif /* _EXTRA_OPTS_H_ */
23
diff --git a/lib/maxfd.c b/lib/maxfd.c
index 529b3568..ca5b6e54 100644
--- a/lib/maxfd.c
+++ b/lib/maxfd.c
@@ -1,7 +1,27 @@
1/*****************************************************************************
2 *
3 * License: GPL
4 * Copyright (c) 2024 Monitoring Plugins Development Team
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 *****************************************************************************/
20
1#include "./maxfd.h" 21#include "./maxfd.h"
2#include <errno.h> 22#include <errno.h>
3 23
4long mp_open_max (void) { 24long mp_open_max(void) {
5 long maxfd = 0L; 25 long maxfd = 0L;
6 /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX. 26 /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
7 * If that fails and the macro isn't defined, we fall back to an educated 27 * If that fails and the macro isn't defined, we fall back to an educated
@@ -10,17 +30,17 @@ long mp_open_max (void) {
10 30
11#ifdef _SC_OPEN_MAX 31#ifdef _SC_OPEN_MAX
12 errno = 0; 32 errno = 0;
13 if ((maxfd = sysconf (_SC_OPEN_MAX)) < 0) { 33 if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
14 if (errno == 0) 34 if (errno == 0)
15 maxfd = DEFAULT_MAXFD; /* it's indeterminate */ 35 maxfd = DEFAULT_MAXFD; /* it's indeterminate */
16 else 36 else
17 die (STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n")); 37 die(STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n"));
18 } 38 }
19#elif defined(OPEN_MAX) 39#elif defined(OPEN_MAX)
20 return OPEN_MAX 40 return OPEN_MAX
21#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */ 41#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
22 return DEFAULT_MAXFD; 42 return DEFAULT_MAXFD;
23#endif 43#endif
24 44
25 return(maxfd); 45 return (maxfd);
26} 46}
diff --git a/lib/maxfd.h b/lib/maxfd.h
index 45218d0f..8fcd62d3 100644
--- a/lib/maxfd.h
+++ b/lib/maxfd.h
@@ -1,9 +1,9 @@
1#ifndef _MAXFD_ 1#ifndef _MAXFD_
2#define _MAXFD_ 2#define _MAXFD_
3 3
4#define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */ 4#define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */
5#define MAXFD_LIMIT 8192 /* upper limit of open files */ 5#define MAXFD_LIMIT 8192 /* upper limit of open files */
6 6
7long mp_open_max (void); 7long mp_open_max(void);
8 8
9#endif // _MAXFD_ 9#endif // _MAXFD_
diff --git a/lib/monitoringplug.h b/lib/monitoringplug.h
new file mode 100644
index 00000000..a555d736
--- /dev/null
+++ b/lib/monitoringplug.h
@@ -0,0 +1,7 @@
1#pragma once
2
3#include "./states.h"
4#include "./utils_base.h"
5#include "./thresholds.h"
6#include "./maxfd.h"
7#include "./output.h"
diff --git a/lib/output.c b/lib/output.c
new file mode 100644
index 00000000..17919afc
--- /dev/null
+++ b/lib/output.c
@@ -0,0 +1,535 @@
1#include "./output.h"
2#include "./utils_base.h"
3#include "../plugins/utils.h"
4
5#include <assert.h>
6#include <stdlib.h>
7#include <string.h>
8#include <strings.h>
9// #include <cjson/cJSON.h>
10#include "./vendor/cJSON/cJSON.h"
11#include "perfdata.h"
12#include "states.h"
13
14// == Prototypes ==
15static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation);
16static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
17
18// == Implementation ==
19
20/*
21 * Generate output string for a mp_subcheck object
22 */
23static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
24 char *result = strdup("");
25 int added = 0;
26
27 if (check.perfdata != NULL) {
28 added = asprintf(&result, "%s", pd_list_to_string(*check.perfdata));
29 }
30
31 if (check.subchecks == NULL) {
32 // No subchecks, return here
33 return result;
34 }
35
36 mp_subcheck_list *subchecks = check.subchecks;
37
38 while (subchecks != NULL) {
39 if (added > 0) {
40 added = asprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck));
41 } else {
42 // TODO free previous result here?
43 added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
44 }
45
46 subchecks = subchecks->next;
47 }
48
49 return result;
50}
51
52/*
53 * Initialiser for a mp_check object. Always use this to get a new one!
54 * It sets useful defaults
55 */
56mp_check mp_check_init(void) {
57 mp_check check = {0};
58 check.format = MP_FORMAT_DEFAULT;
59 return check;
60}
61
62/*
63 * Initialiser for a mp_subcheck object. Always use this to get a new one!
64 * It sets useful defaults
65 */
66mp_subcheck mp_subcheck_init(void) {
67 mp_subcheck tmp = {0};
68 tmp.default_state = STATE_UNKNOWN; // Default state is unknown
69 tmp.state_set_explicitly = false;
70 return tmp;
71}
72
73/*
74 * Add a subcheck to a (the one and only) check object
75 */
76int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck subcheck) {
77 assert(subcheck.output != NULL); // There must be output in a subcheck
78
79 mp_subcheck_list *tmp = NULL;
80
81 if (check->subchecks == NULL) {
82 check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
83 if (check->subchecks == NULL) {
84 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
85 }
86
87 check->subchecks->subcheck = subcheck;
88 check->subchecks->next = NULL;
89 } else {
90 // Search for the end
91 tmp = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
92 if (tmp == NULL) {
93 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
94 }
95
96 tmp->subcheck = subcheck;
97 tmp->next = check->subchecks;
98
99 check->subchecks = tmp;
100 }
101
102 return 0;
103}
104
105/*
106 * Add a mp_perfdata data point to a mp_subcheck object
107 */
108void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata perfData) {
109 if (check->perfdata == NULL) {
110 check->perfdata = pd_list_init();
111 }
112 pd_list_append(check->perfdata, perfData);
113}
114
115/*
116 * Add a mp_subcheck object to another one. The seconde mp_subcheck (argument) is the lower in the
117 * hierarchy
118 */
119int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) {
120 if (subcheck.output == NULL) {
121 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "Sub check output is NULL");
122 }
123
124 mp_subcheck_list *tmp = NULL;
125
126 if (check->subchecks == NULL) {
127 check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
128 if (check->subchecks == NULL) {
129 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
130 }
131
132 tmp = check->subchecks;
133 } else {
134 // Search for the end
135 tmp = check->subchecks;
136
137 while (tmp->next != NULL) {
138 tmp = tmp->next;
139 }
140
141 tmp->next = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
142 if (tmp->next == NULL) {
143 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
144 }
145
146 tmp = tmp->next;
147 }
148
149 tmp->subcheck = subcheck;
150
151 return 0;
152}
153
154/*
155 * Add a manual summary to a mp_check object, effectively replacing
156 * the autogenerated one
157 */
158void mp_add_summary(mp_check check[static 1], char *summary) { check->summary = summary; }
159
160/*
161 * Generate the summary string of a mp_check object based on it's subchecks
162 */
163char *get_subcheck_summary(mp_check check) {
164 mp_subcheck_list *subchecks = check.subchecks;
165
166 unsigned int ok = 0;
167 unsigned int warning = 0;
168 unsigned int critical = 0;
169 unsigned int unknown = 0;
170 while (subchecks != NULL) {
171 switch (subchecks->subcheck.state) {
172 case STATE_OK:
173 ok++;
174 break;
175 case STATE_WARNING:
176 warning++;
177 break;
178 case STATE_CRITICAL:
179 critical++;
180 break;
181 case STATE_UNKNOWN:
182 unknown++;
183 break;
184 default:
185 die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary");
186 }
187 subchecks = subchecks->next;
188 }
189 char *result = NULL;
190 asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown);
191 return result;
192}
193
194/*
195 * Generate the result state of a mp_subcheck object based on it's own state and it's subchecks states
196 */
197mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
198 if (check.state_set_explicitly) {
199 return check.state;
200 }
201
202 mp_subcheck_list *scl = check.subchecks;
203 mp_state_enum result = check.default_state;
204
205 while (scl != NULL) {
206 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
207 scl = scl->next;
208 }
209
210 return result;
211}
212
213/*
214 * Generate the result state of a mp_check object based on it's own state and it's subchecks states
215 */
216mp_state_enum mp_compute_check_state(const mp_check check) {
217 assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here
218
219 mp_subcheck_list *scl = check.subchecks;
220 mp_state_enum result = STATE_OK;
221
222 while (scl != NULL) {
223 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
224 scl = scl->next;
225 }
226
227 return result;
228}
229
230/*
231 * Generate output string for a mp_check object
232 * Non static to be available for testing functions
233 */
234char *mp_fmt_output(mp_check check) {
235 char *result = NULL;
236
237 switch (check.format) {
238 case MP_FORMAT_MULTI_LINE: {
239 if (check.summary == NULL) {
240 check.summary = get_subcheck_summary(check);
241 }
242
243 asprintf(&result, "[%s] - %s", state_text(mp_compute_check_state(check)), check.summary);
244
245 mp_subcheck_list *subchecks = check.subchecks;
246
247 while (subchecks != NULL) {
248 asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
249 subchecks = subchecks->next;
250 }
251
252 char *pd_string = NULL;
253 subchecks = check.subchecks;
254
255 while (subchecks != NULL) {
256 if (pd_string == NULL) {
257 asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
258 } else {
259 asprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck));
260 }
261
262 subchecks = subchecks->next;
263 }
264
265 if (pd_string != NULL && strlen(pd_string) > 0) {
266 asprintf(&result, "%s|%s", result, pd_string);
267 }
268
269 break;
270 }
271 case MP_FORMAT_TEST_JSON: {
272 cJSON *resultObject = cJSON_CreateObject();
273 if (resultObject == NULL) {
274 die(STATE_UNKNOWN, "cJSON_CreateObject failed");
275 }
276
277 cJSON *resultState = cJSON_CreateString(state_text(mp_compute_check_state(check)));
278 cJSON_AddItemToObject(resultObject, "state", resultState);
279
280 if (check.summary == NULL) {
281 check.summary = get_subcheck_summary(check);
282 }
283
284 cJSON *summary = cJSON_CreateString(check.summary);
285 cJSON_AddItemToObject(resultObject, "summary", summary);
286
287 if (check.subchecks != NULL) {
288 cJSON *subchecks = cJSON_CreateArray();
289
290 mp_subcheck_list *sc = check.subchecks;
291
292 while (sc != NULL) {
293 cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
294 cJSON_AddItemToArray(subchecks, sc_json);
295 sc = sc->next;
296 }
297
298 cJSON_AddItemToObject(resultObject, "checks", subchecks);
299 }
300
301 result = cJSON_PrintUnformatted(resultObject);
302 break;
303 }
304 default:
305 die(STATE_UNKNOWN, "Invalid format");
306 }
307
308 return result;
309}
310
311/*
312 * Helper function to properly indent the output lines when using multiline
313 * formats
314 */
315static char *generate_indentation_string(unsigned int indentation) {
316 char *result = calloc(indentation + 1, sizeof(char));
317
318 for (unsigned int i = 0; i < indentation; i++) {
319 result[i] = '\t';
320 }
321
322 return result;
323}
324
325/*
326 * Helper function to generate the output string of mp_subcheck
327 */
328static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation) {
329 char *result = NULL;
330 mp_subcheck_list *subchecks = NULL;
331
332 switch (output_format) {
333 case MP_FORMAT_MULTI_LINE:
334 asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)),
335 check.output);
336
337 subchecks = check.subchecks;
338
339 while (subchecks != NULL) {
340 asprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
341 subchecks = subchecks->next;
342 }
343 return result;
344 default:
345 die(STATE_UNKNOWN, "Invalid format");
346 }
347}
348
349static inline cJSON *json_serialise_pd_value(mp_perfdata_value value) {
350 cJSON *result = cJSON_CreateObject();
351
352 switch (value.type) {
353 case PD_TYPE_DOUBLE:
354 cJSON_AddStringToObject(result, "type", "double");
355 break;
356 case PD_TYPE_INT:
357 cJSON_AddStringToObject(result, "type", "int");
358 break;
359 case PD_TYPE_UINT:
360 cJSON_AddStringToObject(result, "type", "uint");
361 break;
362 case PD_TYPE_NONE:
363 die(STATE_UNKNOWN, "Perfdata type was None in json_serialise_pd_value");
364 }
365 cJSON_AddStringToObject(result, "value", pd_value_to_string(value));
366
367 return result;
368}
369
370static inline cJSON *json_serialise_range(mp_range range) {
371 cJSON *result = cJSON_CreateObject();
372
373 if (range.alert_on_inside_range) {
374 cJSON_AddBoolToObject(result, "alert_on_inside", true);
375 } else {
376 cJSON_AddBoolToObject(result, "alert_on_inside", false);
377 }
378
379 if (range.end_infinity) {
380 cJSON_AddStringToObject(result, "end", "inf");
381 } else {
382 cJSON_AddItemToObject(result, "end", json_serialise_pd_value(range.end));
383 }
384
385 if (range.start_infinity) {
386 cJSON_AddStringToObject(result, "start", "inf");
387 } else {
388 cJSON_AddItemToObject(result, "start", json_serialise_pd_value(range.end));
389 }
390
391 return result;
392}
393
394static inline cJSON *json_serialise_pd(mp_perfdata pd_val) {
395 cJSON *result = cJSON_CreateObject();
396
397 // Label
398 cJSON_AddStringToObject(result, "label", pd_val.label);
399
400 // Value
401 cJSON_AddItemToObject(result, "value", json_serialise_pd_value(pd_val.value));
402
403 // Uom
404 cJSON_AddStringToObject(result, "uom", pd_val.uom);
405
406 // Warn/Crit
407 if (pd_val.warn_present) {
408 cJSON *warn = json_serialise_range(pd_val.warn);
409 cJSON_AddItemToObject(result, "warn", warn);
410 }
411 if (pd_val.crit_present) {
412 cJSON *crit = json_serialise_range(pd_val.crit);
413 cJSON_AddItemToObject(result, "crit", crit);
414 }
415
416 if (pd_val.min_present) {
417 cJSON_AddItemToObject(result, "min", json_serialise_pd_value(pd_val.min));
418 }
419 if (pd_val.max_present) {
420 cJSON_AddItemToObject(result, "max", json_serialise_pd_value(pd_val.max));
421 }
422
423 return result;
424}
425
426static inline cJSON *json_serialise_pd_list(pd_list *list) {
427 cJSON *result = cJSON_CreateArray();
428
429 do {
430 cJSON *pd_value = json_serialise_pd(list->data);
431 cJSON_AddItemToArray(result, pd_value);
432 list = list->next;
433 } while (list != NULL);
434
435 return result;
436}
437
438static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck) {
439 cJSON *result = cJSON_CreateObject();
440
441 // Human readable output
442 cJSON *output = cJSON_CreateString(subcheck.output);
443 cJSON_AddItemToObject(result, "output", output);
444
445 // Test state (aka Exit Code)
446 cJSON *state = cJSON_CreateString(state_text(mp_compute_subcheck_state(subcheck)));
447 cJSON_AddItemToObject(result, "state", state);
448
449 // Perfdata
450 if (subcheck.perfdata != NULL) {
451 cJSON *perfdata = json_serialise_pd_list(subcheck.perfdata);
452 cJSON_AddItemToObject(result, "perfdata", perfdata);
453 }
454
455 if (subcheck.subchecks != NULL) {
456 cJSON *subchecks = cJSON_CreateArray();
457
458 mp_subcheck_list *sc = subcheck.subchecks;
459
460 while (sc != NULL) {
461 cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
462 cJSON_AddItemToArray(subchecks, sc_json);
463 sc = sc->next;
464 }
465
466 cJSON_AddItemToObject(result, "checks", subchecks);
467 }
468
469 return result;
470}
471
472/*
473 * Wrapper function to print the output string of a mp_check object
474 * Use this in concrete plugins.
475 */
476void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); }
477
478/*
479 * Convenience function to print the output string of a mp_check object and exit
480 * the program with the resulting state.
481 * Intended to be used to exit a monitoring plugin.
482 */
483void mp_exit(mp_check check) {
484 mp_print_output(check);
485 if (check.format == MP_FORMAT_TEST_JSON) {
486 exit(0);
487 }
488
489 exit(mp_compute_check_state(check));
490}
491
492/*
493 * Function to set the result state of a mp_subcheck object explicitly.
494 * This will overwrite the default state AND states derived from it's subchecks
495 */
496mp_subcheck mp_set_subcheck_state(mp_subcheck check, mp_state_enum state) {
497 check.state = state;
498 check.state_set_explicitly = true;
499 return check;
500}
501
502/*
503 * Function to set the default result state of a mp_subcheck object. This state
504 * will be used if neither an explicit state is set (see *mp_set_subcheck_state*)
505 * nor does it include other subchecks
506 */
507mp_subcheck mp_set_subcheck_default_state(mp_subcheck check, mp_state_enum state) {
508 check.default_state = state;
509 return check;
510}
511
512char *mp_output_format_map[] = {
513 [MP_FORMAT_MULTI_LINE] = "multi-line",
514 [MP_FORMAT_TEST_JSON] = "mp-test-json",
515};
516
517/*
518 * Function to parse the output from a string
519 */
520parsed_output_format mp_parse_output_format(char *format_string) {
521 parsed_output_format result = {
522 .parsing_success = false,
523 .output_format = MP_FORMAT_DEFAULT,
524 };
525
526 for (mp_output_format i = 0; i < (sizeof(mp_output_format_map) / sizeof(char *)); i++) {
527 if (strcasecmp(mp_output_format_map[i], format_string) == 0) {
528 result.parsing_success = true;
529 result.output_format = i;
530 break;
531 }
532 }
533
534 return result;
535}
diff --git a/lib/output.h b/lib/output.h
new file mode 100644
index 00000000..ffc36f53
--- /dev/null
+++ b/lib/output.h
@@ -0,0 +1,85 @@
1#pragma once
2
3#include "../config.h"
4#include "./perfdata.h"
5#include "./states.h"
6
7/*
8 * A partial check result
9 */
10typedef struct {
11 mp_state_enum state; // OK, Warning, Critical ... set explicitly
12 mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly
13 bool state_set_explicitly; // was the state set explicitly (or should it be derived from subchecks)
14
15 char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP connection to..")
16 pd_list *perfdata; // Performance data for this check
17 struct subcheck_list *subchecks; // subchecks deeper in the hierarchy
18} mp_subcheck;
19
20/*
21 * A list of subchecks, used in subchecks and the main check
22 */
23typedef struct subcheck_list {
24 mp_subcheck subcheck;
25 struct subcheck_list *next;
26} mp_subcheck_list;
27
28/*
29 * Possible output formats
30 */
31typedef enum output_format {
32 MP_FORMAT_MULTI_LINE,
33 MP_FORMAT_TEST_JSON,
34} mp_output_format;
35
36#define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE
37
38/*
39 * The main state object of a plugin. Exists only ONCE per plugin.
40 * This is the "root" of a tree of singular checks.
41 * The final result is always derived from the children and the "worst" state
42 * in the first layer of subchecks
43 */
44typedef struct {
45 mp_output_format format; // The output format
46 char *summary; // Overall summary, if not set a summary will be automatically generated
47 mp_subcheck_list *subchecks;
48} mp_check;
49
50mp_check mp_check_init(void);
51mp_subcheck mp_subcheck_init(void);
52
53mp_subcheck mp_set_subcheck_state(mp_subcheck, mp_state_enum);
54mp_subcheck mp_set_subcheck_default_state(mp_subcheck, mp_state_enum);
55
56int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck);
57int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck);
58
59void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], mp_perfdata);
60
61void mp_add_summary(mp_check check[static 1], char *summary);
62
63mp_state_enum mp_compute_check_state(mp_check);
64mp_state_enum mp_compute_subcheck_state(mp_subcheck);
65
66typedef struct {
67 bool parsing_success;
68 mp_output_format output_format;
69} parsed_output_format;
70parsed_output_format mp_parse_output_format(char *format_string);
71
72// TODO free and stuff
73// void mp_cleanup_check(mp_check check[static 1]);
74
75char *mp_fmt_output(mp_check);
76
77void mp_print_output(mp_check);
78
79/*
80 * ==================
81 * Exit functionality
82 * ==================
83 */
84
85void mp_exit(mp_check) __attribute__((noreturn));
diff --git a/lib/parse_ini.c b/lib/parse_ini.c
index 09c0dc4f..1289aae2 100644
--- a/lib/parse_ini.c
+++ b/lib/parse_ini.c
@@ -1,25 +1,25 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins parse_ini library 3 * Monitoring Plugins parse_ini library
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2007 Monitoring Plugins Development Team 6 * Copyright (c) 2007 - 2024 Monitoring Plugins Development Team
7* 7 *
8* This program is free software: you can redistribute it and/or modify 8 * This program is free software: you can redistribute it and/or modify
9* it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
10* the Free Software Foundation, either version 3 of the License, or 10 * the Free Software Foundation, either version 3 of the License, or
11* (at your option) any later version. 11 * (at your option) any later version.
12* 12 *
13* This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details. 16 * GNU General Public License for more details.
17* 17 *
18* You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19* along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20* 20 *
21* 21 *
22*****************************************************************************/ 22 *****************************************************************************/
23 23
24#include "common.h" 24#include "common.h"
25#include "idpriv.h" 25#include "idpriv.h"
@@ -40,31 +40,20 @@ typedef struct {
40 char *stanza; 40 char *stanza;
41} np_ini_info; 41} np_ini_info;
42 42
43static char *default_ini_file_names[] = { 43static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini", "nagios-plugins.ini", NULL};
44 "monitoring-plugins.ini",
45 "plugins.ini",
46 "nagios-plugins.ini",
47 NULL
48};
49 44
50static char *default_ini_path_names[] = { 45static char *default_ini_path_names[] = {
51 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", 46 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", "/usr/local/etc/monitoring-plugins.ini",
52 "/usr/local/etc/monitoring-plugins.ini", 47 "/etc/monitoring-plugins/monitoring-plugins.ini", "/etc/monitoring-plugins.ini",
53 "/etc/monitoring-plugins/monitoring-plugins.ini",
54 "/etc/monitoring-plugins.ini",
55 /* deprecated path names (for backward compatibility): */ 48 /* deprecated path names (for backward compatibility): */
56 "/etc/nagios/plugins.ini", 49 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini", "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini",
57 "/usr/local/nagios/etc/plugins.ini", 50 "/etc/nagios-plugins.ini", "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL};
58 "/usr/local/etc/nagios/plugins.ini",
59 "/etc/opt/nagios/plugins.ini",
60 "/etc/nagios-plugins.ini",
61 "/usr/local/etc/nagios-plugins.ini",
62 "/etc/opt/nagios-plugins.ini",
63 NULL
64};
65 51
66/* eat all characters from a FILE pointer until n is encountered */ 52/* eat all characters from a FILE pointer until n is encountered */
67#define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) 53#define GOBBLE_TO(f, c, n) \
54 do { \
55 (c) = fgetc((f)); \
56 } while ((c) != EOF && (c) != (n))
68 57
69/* internal function that returns the constructed defaults options */ 58/* internal function that returns the constructed defaults options */
70static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); 59static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts);
@@ -81,9 +70,7 @@ static char *default_file_in_path(void);
81 * [stanza][@filename] 70 * [stanza][@filename]
82 * into its separate parts. 71 * into its separate parts.
83 */ 72 */
84static void 73static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) {
85parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
86{
87 size_t locator_len = 0, stanza_len = 0; 74 size_t locator_len = 0, stanza_len = 0;
88 75
89 /* if locator is NULL we'll use default values */ 76 /* if locator is NULL we'll use default values */
@@ -96,7 +83,7 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
96 i->stanza = malloc(sizeof(char) * (stanza_len + 1)); 83 i->stanza = malloc(sizeof(char) * (stanza_len + 1));
97 strncpy(i->stanza, locator, stanza_len); 84 strncpy(i->stanza, locator, stanza_len);
98 i->stanza[stanza_len] = '\0'; 85 i->stanza[stanza_len] = '\0';
99 } else {/* otherwise we use the default stanza */ 86 } else { /* otherwise we use the default stanza */
100 i->stanza = strdup(def_stanza); 87 i->stanza = strdup(def_stanza);
101 } 88 }
102 89
@@ -105,7 +92,7 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
105 92
106 /* check whether there's an @file part */ 93 /* check whether there's an @file part */
107 if (stanza_len == locator_len) { 94 if (stanza_len == locator_len) {
108 i->file = default_file(); 95 i->file = default_file();
109 i->file_string_on_heap = false; 96 i->file_string_on_heap = false;
110 } else { 97 } else {
111 i->file = strdup(&(locator[stanza_len + 1])); 98 i->file = strdup(&(locator[stanza_len + 1]));
@@ -113,35 +100,28 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
113 } 100 }
114 101
115 if (i->file == NULL || i->file[0] == '\0') 102 if (i->file == NULL || i->file[0] == '\0')
116 die(STATE_UNKNOWN, 103 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n"));
117 _("Cannot find config file in any standard location.\n"));
118} 104}
119 105
120/* 106/*
121 * This is the externally visible function used by extra_opts. 107 * This is the externally visible function used by extra_opts.
122 */ 108 */
123np_arg_list * 109np_arg_list *np_get_defaults(const char *locator, const char *default_section) {
124np_get_defaults(const char *locator, const char *default_section)
125{
126 FILE *inifile = NULL; 110 FILE *inifile = NULL;
127 np_arg_list *defaults = NULL; 111 np_arg_list *defaults = NULL;
128 np_ini_info i; 112 np_ini_info i;
129 int is_suid_plugin = mp_suid(); 113 int is_suid_plugin = mp_suid();
130 114
131 if (is_suid_plugin && idpriv_temp_drop() == -1) 115 if (is_suid_plugin && idpriv_temp_drop() == -1)
132 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), 116 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno));
133 strerror(errno));
134 117
135 parse_locator(locator, default_section, &i); 118 parse_locator(locator, default_section, &i);
136 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); 119 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r");
137 120
138 if (inifile == NULL) 121 if (inifile == NULL)
139 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), 122 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno));
140 strerror(errno));
141 if (!read_defaults(inifile, i.stanza, &defaults)) 123 if (!read_defaults(inifile, i.stanza, &defaults))
142 die(STATE_UNKNOWN, 124 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), i.stanza, i.file);
143 _("Invalid section '%s' in config file '%s'\n"), i.stanza,
144 i.file);
145 125
146 if (i.file_string_on_heap) { 126 if (i.file_string_on_heap) {
147 free(i.file); 127 free(i.file);
@@ -151,8 +131,7 @@ np_get_defaults(const char *locator, const char *default_section)
151 fclose(inifile); 131 fclose(inifile);
152 free(i.stanza); 132 free(i.stanza);
153 if (is_suid_plugin && idpriv_temp_restore() == -1) 133 if (is_suid_plugin && idpriv_temp_restore() == -1)
154 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), 134 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno));
155 strerror(errno));
156 135
157 return defaults; 136 return defaults;
158} 137}
@@ -164,13 +143,15 @@ np_get_defaults(const char *locator, const char *default_section)
164 * be extra careful about user-supplied input (i.e. avoiding possible 143 * be extra careful about user-supplied input (i.e. avoiding possible
165 * format string vulnerabilities, etc). 144 * format string vulnerabilities, etc).
166 */ 145 */
167static int 146static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) {
168read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
169{
170 int c = 0; 147 int c = 0;
171 bool status = false; 148 bool status = false;
172 size_t i, stanza_len; 149 size_t i, stanza_len;
173 enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate = NOSTANZA; 150 enum {
151 NOSTANZA,
152 WRONGSTANZA,
153 RIGHTSTANZA
154 } stanzastate = NOSTANZA;
174 155
175 stanza_len = strlen(stanza); 156 stanza_len = strlen(stanza);
176 157
@@ -217,8 +198,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
217 * we're dealing with a config error 198 * we're dealing with a config error
218 */ 199 */
219 case NOSTANZA: 200 case NOSTANZA:
220 die(STATE_UNKNOWN, "%s\n", 201 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
221 _("Config file error"));
222 /* we're in a stanza, but for a different plugin */ 202 /* we're in a stanza, but for a different plugin */
223 case WRONGSTANZA: 203 case WRONGSTANZA:
224 GOBBLE_TO(f, c, '\n'); 204 GOBBLE_TO(f, c, '\n');
@@ -227,8 +207,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
227 case RIGHTSTANZA: 207 case RIGHTSTANZA:
228 ungetc(c, f); 208 ungetc(c, f);
229 if (add_option(f, opts)) { 209 if (add_option(f, opts)) {
230 die(STATE_UNKNOWN, "%s\n", 210 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
231 _("Config file error"));
232 } 211 }
233 status = true; 212 status = true;
234 break; 213 break;
@@ -246,9 +225,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
246 * --option[=value] 225 * --option[=value]
247 * appending it to the linked list optbuf. 226 * appending it to the linked list optbuf.
248 */ 227 */
249static int 228static int add_option(FILE *f, np_arg_list **optlst) {
250add_option(FILE *f, np_arg_list **optlst)
251{
252 np_arg_list *opttmp = *optlst, *optnew; 229 np_arg_list *opttmp = *optlst, *optnew;
253 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; 230 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL;
254 char *eqptr = NULL, *valptr = NULL, *valend = NULL; 231 char *eqptr = NULL, *valptr = NULL, *valend = NULL;
@@ -295,8 +272,7 @@ add_option(FILE *f, np_arg_list **optlst)
295 if (optptr == eqptr) 272 if (optptr == eqptr)
296 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 273 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
297 /* continue from '=' to start of value or EOL */ 274 /* continue from '=' to start of value or EOL */
298 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); 275 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++)
299 valptr++)
300 continue; 276 continue;
301 /* continue to the end of value */ 277 /* continue to the end of value */
302 for (valend = valptr; valend < lineend; valend++) 278 for (valend = valptr; valend < lineend; valend++)
@@ -365,13 +341,10 @@ add_option(FILE *f, np_arg_list **optlst)
365 return 0; 341 return 0;
366} 342}
367 343
368static char * 344static char *default_file(void) {
369default_file(void) 345 char *ini_file;
370{
371 char *ini_file;
372 346
373 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || 347 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || (ini_file = default_file_in_path()) != NULL) {
374 (ini_file = default_file_in_path()) != NULL) {
375 return ini_file; 348 return ini_file;
376 } 349 }
377 350
@@ -383,9 +356,7 @@ default_file(void)
383 return NULL; 356 return NULL;
384} 357}
385 358
386static char * 359static char *default_file_in_path(void) {
387default_file_in_path(void)
388{
389 char *config_path, **file; 360 char *config_path, **file;
390 char *dir, *ini_file, *tokens; 361 char *dir, *ini_file, *tokens;
391 362
diff --git a/lib/parse_ini.h b/lib/parse_ini.h
index e37601b5..d17409e3 100644
--- a/lib/parse_ini.h
+++ b/lib/parse_ini.h
@@ -19,4 +19,3 @@ typedef struct np_arg_el {
19np_arg_list *np_get_defaults(const char *locator, const char *default_section); 19np_arg_list *np_get_defaults(const char *locator, const char *default_section);
20 20
21#endif /* _PARSE_INI_H_ */ 21#endif /* _PARSE_INI_H_ */
22
diff --git a/lib/perfdata.c b/lib/perfdata.c
new file mode 100644
index 00000000..661756c5
--- /dev/null
+++ b/lib/perfdata.c
@@ -0,0 +1,516 @@
1#include "./perfdata.h"
2#include "../plugins/common.h"
3#include "../plugins/utils.h"
4#include "utils_base.h"
5
6#include <assert.h>
7#include <limits.h>
8#include <stdlib.h>
9
10char *pd_value_to_string(const mp_perfdata_value pd) {
11 char *result = NULL;
12
13 assert(pd.type != PD_TYPE_NONE);
14
15 switch (pd.type) {
16 case PD_TYPE_INT:
17 asprintf(&result, "%lli", pd.pd_int);
18 break;
19 case PD_TYPE_UINT:
20 asprintf(&result, "%llu", pd.pd_int);
21 break;
22 case PD_TYPE_DOUBLE:
23 asprintf(&result, "%f", pd.pd_double);
24 break;
25 default:
26 // die here
27 die(STATE_UNKNOWN, "Invalid mp_perfdata mode\n");
28 }
29
30 return result;
31}
32
33char *pd_to_string(mp_perfdata pd) {
34 assert(pd.label != NULL);
35 char *result = NULL;
36 asprintf(&result, "%s=", pd.label);
37
38 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
39
40 if (pd.uom != NULL) {
41 asprintf(&result, "%s%s", result, pd.uom);
42 }
43
44 if (pd.warn_present) {
45 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn));
46 } else {
47 asprintf(&result, "%s;", result);
48 }
49
50 if (pd.crit_present) {
51 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit));
52 } else {
53 asprintf(&result, "%s;", result);
54 }
55 if (pd.min_present) {
56 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min));
57 } else {
58 asprintf(&result, "%s;", result);
59 }
60
61 if (pd.max_present) {
62 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max));
63 }
64
65 /*printf("pd_to_string: %s\n", result); */
66
67 return result;
68}
69
70char *pd_list_to_string(const pd_list pd) {
71 char *result = pd_to_string(pd.data);
72
73 for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) {
74 asprintf(&result, "%s %s", result, pd_to_string(elem->data));
75 }
76
77 return result;
78}
79
80mp_perfdata perfdata_init() {
81 mp_perfdata pd = {};
82 return pd;
83}
84
85pd_list *pd_list_init() {
86 pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list));
87 if (tmp == NULL) {
88 die(STATE_UNKNOWN, "calloc failed\n");
89 }
90 tmp->next = NULL;
91 return tmp;
92}
93
94mp_range mp_range_init() {
95 mp_range result = {
96 .alert_on_inside_range = OUTSIDE,
97 .start = {},
98 .start_infinity = true,
99 .end = {},
100 .end_infinity = true,
101 };
102
103 return result;
104}
105
106mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) {
107 input.start = perf_val;
108 input.start_infinity = false;
109 return input;
110}
111
112mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) {
113 input.end = perf_val;
114 input.end_infinity = false;
115 return input;
116}
117
118void pd_list_append(pd_list pdl[1], const mp_perfdata pd) {
119 assert(pdl != NULL);
120
121 if (pdl->data.value.type == PD_TYPE_NONE) {
122 // first entry is still empty
123 pdl->data = pd;
124 } else {
125 // find last element in the list
126 pd_list *curr = pdl;
127 pd_list *next = pdl->next;
128
129 while (next != NULL) {
130 curr = next;
131 next = next->next;
132 }
133
134 if (curr->data.value.type == PD_TYPE_NONE) {
135 // still empty
136 curr->data = pd;
137 } else {
138 // new a new one
139 curr->next = pd_list_init();
140 curr->next->data = pd;
141 }
142 }
143}
144
145void pd_list_free(pd_list pdl[1]) {
146 while (pdl != NULL) {
147 pd_list *old = pdl;
148 pdl = pdl->next;
149 free(old);
150 }
151}
152
153/*
154 * returns -1 if a < b, 0 if a == b, 1 if a > b
155 */
156int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) {
157 // Test if types are different
158 if (a.type == b.type) {
159
160 switch (a.type) {
161 case PD_TYPE_UINT:
162 if (a.pd_uint < b.pd_uint) {
163 return -1;
164 } else if (a.pd_uint == b.pd_uint) {
165 return 0;
166 } else {
167 return 1;
168 }
169 break;
170 case PD_TYPE_INT:
171 if (a.pd_int < b.pd_int) {
172 return -1;
173 } else if (a.pd_int == b.pd_int) {
174 return 0;
175 } else {
176 return 1;
177 }
178 break;
179 case PD_TYPE_DOUBLE:
180 if (a.pd_int < b.pd_int) {
181 return -1;
182 } else if (a.pd_int == b.pd_int) {
183 return 0;
184 } else {
185 return 1;
186 }
187 break;
188 default:
189 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
190 }
191 }
192
193 // Get dirty here
194 long double floating_a = 0;
195
196 switch (a.type) {
197 case PD_TYPE_UINT:
198 floating_a = a.pd_uint;
199 break;
200 case PD_TYPE_INT:
201 floating_a = a.pd_int;
202 break;
203 case PD_TYPE_DOUBLE:
204 floating_a = a.pd_double;
205 break;
206 default:
207 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
208 }
209
210 long double floating_b = 0;
211 switch (b.type) {
212 case PD_TYPE_UINT:
213 floating_b = b.pd_uint;
214 break;
215 case PD_TYPE_INT:
216 floating_b = b.pd_int;
217 break;
218 case PD_TYPE_DOUBLE:
219 floating_b = b.pd_double;
220 break;
221 default:
222 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
223 }
224
225 if (floating_a < floating_b) {
226 return -1;
227 }
228 if (floating_a == floating_b) {
229 return 0;
230 }
231 return 1;
232}
233
234char *mp_range_to_string(const mp_range input) {
235 char *result = "";
236 if (input.alert_on_inside_range == INSIDE) {
237 asprintf(&result, "@");
238 }
239
240 if (input.start_infinity) {
241 asprintf(&result, "%s~:", result);
242 } else {
243 asprintf(&result, "%s%s:", result, pd_value_to_string(input.start));
244 }
245
246 if (!input.end_infinity) {
247 asprintf(&result, "%s%s", result, pd_value_to_string(input.end));
248 }
249 return result;
250}
251
252mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); }
253
254mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
255 pd.value.pd_double = value;
256 pd.value.type = PD_TYPE_DOUBLE;
257 return pd;
258}
259
260mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); }
261
262mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
263
264mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); }
265
266mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
267 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
268}
269
270mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) {
271 pd.value.pd_int = value;
272 pd.value.type = PD_TYPE_INT;
273 return pd;
274}
275
276mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) {
277 pd.value.pd_uint = value;
278 pd.value.type = PD_TYPE_UINT;
279 return pd;
280}
281
282mp_perfdata_value mp_create_pd_value_double(double value) {
283 mp_perfdata_value res = {0};
284 res.type = PD_TYPE_DOUBLE;
285 res.pd_double = value;
286 return res;
287}
288
289mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); }
290
291mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); }
292
293mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
294
295mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); }
296
297mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
298
299mp_perfdata_value mp_create_pd_value_long_long(long long value) {
300 mp_perfdata_value res = {0};
301 res.type = PD_TYPE_INT;
302 res.pd_int = value;
303 return res;
304}
305
306mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) {
307 mp_perfdata_value res = {0};
308 res.type = PD_TYPE_UINT;
309 res.pd_uint = value;
310 return res;
311}
312
313char *fmt_range(range foo) { return foo.text; }
314
315typedef struct integer_parser_wrapper {
316 int error;
317 mp_perfdata_value value;
318} integer_parser_wrapper;
319
320typedef struct double_parser_wrapper {
321 int error;
322 mp_perfdata_value value;
323} double_parser_wrapper;
324
325typedef struct perfdata_value_parser_wrapper {
326 int error;
327 mp_perfdata_value value;
328} perfdata_value_parser_wrapper;
329
330double_parser_wrapper parse_double(const char *input);
331integer_parser_wrapper parse_integer(const char *input);
332perfdata_value_parser_wrapper parse_pd_value(const char *input);
333
334mp_range_parsed mp_parse_range_string(const char *input) {
335 if (input == NULL) {
336 mp_range_parsed result = {
337 .error = MP_RANGE_PARSING_FAILURE,
338 };
339 return result;
340 }
341
342 if (strlen(input) == 0) {
343 mp_range_parsed result = {
344 .error = MP_RANGE_PARSING_FAILURE,
345 };
346 return result;
347 }
348
349 mp_range_parsed result = {
350 .range = mp_range_init(),
351 .error = MP_PARSING_SUCCES,
352 };
353
354 if (input[0] == '@') {
355 // found an '@' at beginning, so invert the range logic
356 result.range.alert_on_inside_range = INSIDE;
357
358 // advance the pointer one symbol
359 input++;
360 }
361
362 char *working_copy = strdup(input);
363 input = working_copy;
364
365 char *separator = index(working_copy, ':');
366 if (separator != NULL) {
367 // Found a separator
368 // set the separator to 0, so we have two different strings
369 *separator = '\0';
370
371 if (input[0] == '~') {
372 // the beginning starts with '~', so it might be infinity
373 if (&input[1] != separator) {
374 // the next symbol after '~' is not the separator!
375 // so input is probably wrong
376 result.error = MP_RANGE_PARSING_FAILURE;
377 free(working_copy);
378 return result;
379 }
380
381 result.range.start_infinity = true;
382 } else {
383 // No '~' at the beginning, so this should be a number
384 result.range.start_infinity = false;
385 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
386
387 if (parsed_pd.error != MP_PARSING_SUCCES) {
388 result.error = parsed_pd.error;
389 free(working_copy);
390 return result;
391 }
392
393 result.range.start = parsed_pd.value;
394 result.range.start_infinity = false;
395 }
396 // got the first part now
397 // advance the pointer
398 input = separator + 1;
399 }
400
401 // End part or no separator
402 if (input[0] == '\0') {
403 // the end is infinite
404 result.range.end_infinity = true;
405 } else {
406 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
407
408 if (parsed_pd.error != MP_PARSING_SUCCES) {
409 result.error = parsed_pd.error;
410 return result;
411 }
412 result.range.end = parsed_pd.value;
413 result.range.end_infinity = false;
414 }
415 free(working_copy);
416 return result;
417}
418
419double_parser_wrapper parse_double(const char *input) {
420 double_parser_wrapper result = {
421 .error = MP_PARSING_SUCCES,
422 };
423
424 if (input == NULL) {
425 result.error = MP_PARSING_FAILURE;
426 return result;
427 }
428
429 char *endptr = NULL;
430 errno = 0;
431 double tmp = strtod(input, &endptr);
432
433 if (input == endptr) {
434 // man 3 strtod says, no conversion performed
435 result.error = MP_PARSING_FAILURE;
436 return result;
437 }
438
439 if (errno) {
440 // some other error
441 // TODO maybe differentiate a little bit
442 result.error = MP_PARSING_FAILURE;
443 return result;
444 }
445
446 result.value = mp_create_pd_value(tmp);
447 return result;
448}
449
450integer_parser_wrapper parse_integer(const char *input) {
451 integer_parser_wrapper result = {
452 .error = MP_PARSING_SUCCES,
453 };
454
455 if (input == NULL) {
456 result.error = MP_PARSING_FAILURE;
457 return result;
458 }
459
460 char *endptr = NULL;
461 errno = 0;
462 long long tmp = strtoll(input, &endptr, 0);
463
464 // validating *sigh*
465 if (*endptr != '\0') {
466 // something went wrong in strtoll
467 if (tmp == LLONG_MIN) {
468 // underflow
469 result.error = MP_RANGE_PARSING_UNDERFLOW;
470 return result;
471 }
472
473 if (tmp == LLONG_MAX) {
474 // overflow
475 result.error = MP_RANGE_PARSING_OVERFLOW;
476 return result;
477 }
478
479 // still wrong, but not sure why, probably invalid characters
480 if (errno == EINVAL) {
481 result.error = MP_RANGE_PARSING_INVALID_CHAR;
482 return result;
483 }
484
485 // some other error, do catch all here
486 result.error = MP_RANGE_PARSING_FAILURE;
487 return result;
488 }
489
490 // no error, should be fine
491 result.value = mp_create_pd_value(tmp);
492 return result;
493}
494
495perfdata_value_parser_wrapper parse_pd_value(const char *input) {
496 // try integer first
497 integer_parser_wrapper tmp_int = parse_integer(input);
498
499 if (tmp_int.error == MP_PARSING_SUCCES) {
500 perfdata_value_parser_wrapper result = {
501 .error = tmp_int.error,
502 .value = tmp_int.value,
503 };
504 return result;
505 }
506
507 double_parser_wrapper tmp_double = parse_double(input);
508 perfdata_value_parser_wrapper result = {};
509 if (tmp_double.error == MP_PARSING_SUCCES) {
510 result.error = tmp_double.error;
511 result.value = tmp_double.value;
512 } else {
513 result.error = tmp_double.error;
514 }
515 return result;
516}
diff --git a/lib/perfdata.h b/lib/perfdata.h
new file mode 100644
index 00000000..74583ee5
--- /dev/null
+++ b/lib/perfdata.h
@@ -0,0 +1,203 @@
1#pragma once
2
3#include "../config.h"
4
5#include <inttypes.h>
6#include <stdbool.h>
7
8// Enum for the specific type of a perfdata_value
9typedef enum pd_value_type {
10 PD_TYPE_NONE = 0,
11 PD_TYPE_INT,
12 PD_TYPE_UINT,
13 PD_TYPE_DOUBLE
14} pd_value_type;
15
16typedef struct {
17 enum pd_value_type type;
18 union {
19 long long pd_int;
20 unsigned long long pd_uint;
21 double pd_double;
22 };
23} mp_perfdata_value;
24
25#define MP_OUTSIDE false
26#define MP_INSIDE true
27
28/*
29 * New range type with generic numerical values
30 */
31typedef struct mp_range_struct {
32 mp_perfdata_value start;
33 bool start_infinity; /* false (default) or true */
34
35 mp_perfdata_value end;
36 bool end_infinity;
37
38 bool alert_on_inside_range; /* OUTSIDE (default) or INSIDE */
39} mp_range;
40
41/*
42 * Old range type with floating point values
43 */
44typedef struct range_struct {
45 double start;
46 bool start_infinity;
47 double end;
48 int end_infinity;
49 int alert_on; /* OUTSIDE (default) or INSIDE */
50 char *text; /* original unparsed text input */
51} range;
52
53/*
54 * Perfdata type for storing perfdata output
55 */
56typedef struct perfdata_struct {
57 char *label;
58 char *uom;
59 mp_perfdata_value value;
60
61 bool warn_present;
62 mp_range warn;
63
64 bool crit_present;
65 mp_range crit;
66
67 bool min_present;
68 mp_perfdata_value min;
69
70 bool max_present;
71 mp_perfdata_value max;
72} mp_perfdata;
73
74/*
75 * List of mp_perfdata values
76 */
77typedef struct pd_list_struct {
78 mp_perfdata data;
79 struct pd_list_struct *next;
80} pd_list;
81
82/*
83 * ============
84 * Initializers
85 * ============
86 */
87/*
88 * Initialize mp_perfdata value. Always use this to generate a new one
89 */
90mp_perfdata perfdata_init(void);
91
92/*
93 * Initialize pd_list value. Always use this to generate a new one
94 */
95pd_list *pd_list_init(void);
96
97/*
98 * Initialize a new mp_range value, with unset values (start and end are infinite
99 */
100mp_range mp_range_init(void);
101
102/*
103 * Worker functions
104 */
105
106mp_range mp_range_set_start(mp_range, mp_perfdata_value);
107mp_range mp_range_set_end(mp_range, mp_perfdata_value);
108
109/*
110 * Parsing a range from a string
111 */
112
113typedef enum {
114 MP_PARSING_SUCCES = 0,
115 MP_PARSING_FAILURE,
116 MP_RANGE_PARSING_FAILURE,
117 MP_RANGE_PARSING_UNDERFLOW,
118 MP_RANGE_PARSING_OVERFLOW,
119 MP_RANGE_PARSING_INVALID_CHAR,
120} mp_range_parser_error;
121
122typedef struct mp_range_parsed {
123 mp_range_parser_error error;
124 mp_range range;
125} mp_range_parsed;
126
127mp_range_parsed mp_parse_range_string(const char * /*input*/);
128
129/*
130 * Appends a mp_perfdata value to a pd_list
131 */
132void pd_list_append(pd_list[1], mp_perfdata);
133
134#define mp_set_pd_value(P, V) \
135 _Generic((V), \
136 float: mp_set_pd_value_float, \
137 double: mp_set_pd_value_double, \
138 int: mp_set_pd_value_int, \
139 unsigned int: mp_set_pd_value_u_int, \
140 long: mp_set_pd_value_long, \
141 unsigned long: mp_set_pd_value_u_long, \
142 long long: mp_set_pd_value_long_long, \
143 unsigned long long: mp_set_pd_value_u_long_long)(P, V)
144
145mp_perfdata mp_set_pd_value_float(mp_perfdata, float);
146mp_perfdata mp_set_pd_value_double(mp_perfdata, double);
147mp_perfdata mp_set_pd_value_int(mp_perfdata, int);
148mp_perfdata mp_set_pd_value_u_int(mp_perfdata, unsigned int);
149mp_perfdata mp_set_pd_value_long(mp_perfdata, long);
150mp_perfdata mp_set_pd_value_u_long(mp_perfdata, unsigned long);
151mp_perfdata mp_set_pd_value_long_long(mp_perfdata, long long);
152mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
153
154#define mp_create_pd_value(V) \
155 _Generic((V), \
156 float: mp_create_pd_value_float, \
157 double: mp_create_pd_value_double, \
158 int: mp_create_pd_value_int, \
159 unsigned int: mp_create_pd_value_u_int, \
160 long: mp_create_pd_value_long, \
161 unsigned long: mp_create_pd_value_u_long, \
162 long long: mp_create_pd_value_long_long, \
163 unsigned long long: mp_create_pd_value_u_long_long)(V)
164
165mp_perfdata_value mp_create_pd_value_float(float);
166mp_perfdata_value mp_create_pd_value_double(double);
167mp_perfdata_value mp_create_pd_value_int(int);
168mp_perfdata_value mp_create_pd_value_u_int(unsigned int);
169mp_perfdata_value mp_create_pd_value_long(long);
170mp_perfdata_value mp_create_pd_value_u_long(unsigned long);
171mp_perfdata_value mp_create_pd_value_long_long(long long);
172mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long);
173
174/*
175 * Free the memory used by a pd_list
176 */
177void pd_list_free(pd_list[1]);
178
179int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value);
180
181// =================
182// String formatters
183// =================
184/*
185 * Generate string from mp_perfdata value
186 */
187char *pd_to_string(mp_perfdata);
188
189/*
190 * Generate string from perfdata_value value
191 */
192char *pd_value_to_string(mp_perfdata_value);
193
194/*
195 * Generate string from pd_list value for the final output
196 */
197char *pd_list_to_string(pd_list);
198
199/*
200 * Generate string from a mp_range value
201 */
202char *mp_range_to_string(mp_range);
203char *fmt_range(range);
diff --git a/lib/states.h b/lib/states.h
new file mode 100644
index 00000000..4a170caa
--- /dev/null
+++ b/lib/states.h
@@ -0,0 +1,71 @@
1#ifndef _MP_STATES_
2#define _MP_STATES_
3
4#include "../config.h"
5#include <sys/param.h>
6
7typedef enum state_enum {
8 STATE_OK,
9 STATE_WARNING,
10 STATE_CRITICAL,
11 STATE_UNKNOWN,
12 STATE_DEPENDENT
13} mp_state_enum;
14
15/* **************************************************************************
16 * max_state(STATE_x, STATE_y)
17 * compares STATE_x to STATE_y and returns result based on the following
18 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
19 *
20 * Note that numerically the above does not hold
21 ****************************************************************************/
22
23static inline mp_state_enum max_state(mp_state_enum a, mp_state_enum b) {
24 if (a == STATE_CRITICAL || b == STATE_CRITICAL) {
25 return STATE_CRITICAL;
26 }
27 if (a == STATE_WARNING || b == STATE_WARNING) {
28 return STATE_WARNING;
29 }
30 if (a == STATE_OK || b == STATE_OK) {
31 return STATE_OK;
32 }
33 if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) {
34 return STATE_UNKNOWN;
35 }
36 if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) {
37 return STATE_DEPENDENT;
38 }
39 return MAX(a, b);
40}
41
42/* **************************************************************************
43 * max_state_alt(STATE_x, STATE_y)
44 * compares STATE_x to STATE_y and returns result based on the following
45 * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL
46 *
47 * The main difference between max_state_alt and max_state it that it doesn't
48 * allow setting a default to UNKNOWN. It will instead prioritixe any valid
49 * non-OK state.
50 ****************************************************************************/
51
52static inline mp_state_enum max_state_alt(mp_state_enum a, mp_state_enum b) {
53 if (a == STATE_CRITICAL || b == STATE_CRITICAL) {
54 return STATE_CRITICAL;
55 }
56 if (a == STATE_WARNING || b == STATE_WARNING) {
57 return STATE_WARNING;
58 }
59 if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) {
60 return STATE_UNKNOWN;
61 }
62 if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) {
63 return STATE_DEPENDENT;
64 }
65 if (a == STATE_OK || b == STATE_OK) {
66 return STATE_OK;
67 }
68 return MAX(a, b);
69}
70
71#endif
diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am
index 31d79df6..9be94f6d 100644
--- a/lib/tests/Makefile.am
+++ b/lib/tests/Makefile.am
@@ -8,9 +8,9 @@ check_PROGRAMS = @EXTRA_TEST@
8AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 8AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
9 -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins 9 -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
10 10
11EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 11EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output
12 12
13np_test_scripts = test_base64.t test_cmd.t test_disk.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t 13np_test_scripts = test_base64.t test_cmd.t test_disk.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t test_generic_output.t
14np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini 14np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini
15EXTRA_DIST = $(np_test_scripts) $(np_test_files) var 15EXTRA_DIST = $(np_test_scripts) $(np_test_files) var
16 16
@@ -29,7 +29,7 @@ AM_CFLAGS = -g -I$(top_srcdir)/lib -I$(top_srcdir)/gl $(tap_cflags)
29AM_LDFLAGS = $(tap_ldflags) -ltap 29AM_LDFLAGS = $(tap_ldflags) -ltap
30LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO) 30LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO)
31 31
32SOURCES = test_utils.c test_disk.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c 32SOURCES = test_utils.c test_disk.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c test_generic_output.c
33 33
34test: ${noinst_PROGRAMS} 34test: ${noinst_PROGRAMS}
35 perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS) 35 perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS)
diff --git a/lib/tests/test_base64.c b/lib/tests/test_base64.c
index 05dd7943..94cb5aa9 100644
--- a/lib/tests/test_base64.c
+++ b/lib/tests/test_base64.c
@@ -1,29 +1,27 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "gl/base64.h" 20#include "gl/base64.h"
21#include "tap.h" 21#include "tap.h"
22 22
23int 23int main(int argc, char **argv) {
24main (int argc, char **argv) 24#if 0 /* The current base64 function doesn't work on 8bit data */
25{
26#if 0 /* The current base64 function doesn't work on 8bit data */
27 char random[1024] = { 25 char random[1024] = {
28 0x8b,0xb0,0xc4,0xe2,0xfc,0x22,0x9f,0x0d,0x85,0xe7,0x2c,0xaa,0x39,0xa1,0x46,0x88, 26 0x8b,0xb0,0xc4,0xe2,0xfc,0x22,0x9f,0x0d,0x85,0xe7,0x2c,0xaa,0x39,0xa1,0x46,0x88,
29 0x50,0xe6,0x34,0x37,0x0b,0x45,0x4b,0xb8,0xb2,0x86,0x7a,0x3e,0x7f,0x0c,0x40,0x18, 27 0x50,0xe6,0x34,0x37,0x0b,0x45,0x4b,0xb8,0xb2,0x86,0x7a,0x3e,0x7f,0x0c,0x40,0x18,
@@ -182,168 +180,124 @@ main (int argc, char **argv)
182#endif 180#endif
183 181
184 char random[1024] = { 182 char random[1024] = {
185 0x0b,0x30,0x44,0x62,0x7c,0x22,0x1f,0x0d,0x05,0x67,0x2c,0x2a,0x39,0x21,0x46,0x08, 183 0x0b, 0x30, 0x44, 0x62, 0x7c, 0x22, 0x1f, 0x0d, 0x05, 0x67, 0x2c, 0x2a, 0x39, 0x21, 0x46, 0x08, 0x50, 0x66, 0x34, 0x37, 0x0b, 0x45,
186 0x50,0x66,0x34,0x37,0x0b,0x45,0x4b,0x38,0x32,0x06,0x7a,0x3e,0x7f,0x0c,0x40,0x18, 184 0x4b, 0x38, 0x32, 0x06, 0x7a, 0x3e, 0x7f, 0x0c, 0x40, 0x18, 0x6b, 0x2d, 0x60, 0x4c, 0x60, 0x0c, 0x23, 0x43, 0x3b, 0x3e, 0x1b, 0x16,
187 0x6b,0x2d,0x60,0x4c,0x60,0x0c,0x23,0x43,0x3b,0x3e,0x1b,0x16,0x04,0x46,0x58,0x3f, 185 0x04, 0x46, 0x58, 0x3f, 0x40, 0x6a, 0x11, 0x05, 0x63, 0x71, 0x14, 0x35, 0x47, 0x79, 0x13, 0x6f, 0x6b, 0x27, 0x18, 0x5b, 0x48, 0x27,
188 0x40,0x6a,0x11,0x05,0x63,0x71,0x14,0x35,0x47,0x79,0x13,0x6f,0x6b,0x27,0x18,0x5b, 186 0x3e, 0x6f, 0x15, 0x33, 0x4f, 0x3e, 0x5e, 0x51, 0x73, 0x68, 0x25, 0x0f, 0x06, 0x5b, 0x7c, 0x72, 0x75, 0x3e, 0x3f, 0x1b, 0x5c, 0x6d,
189 0x48,0x27,0x3e,0x6f,0x15,0x33,0x4f,0x3e,0x5e,0x51,0x73,0x68,0x25,0x0f,0x06,0x5b, 187 0x6a, 0x39, 0x7c, 0x63, 0x63, 0x60, 0x6c, 0x7a, 0x33, 0x76, 0x52, 0x13, 0x25, 0x33, 0x7d, 0x65, 0x23, 0x27, 0x11, 0x06, 0x06, 0x47,
190 0x7c,0x72,0x75,0x3e,0x3f,0x1b,0x5c,0x6d,0x6a,0x39,0x7c,0x63,0x63,0x60,0x6c,0x7a, 188 0x71, 0x1e, 0x14, 0x74, 0x63, 0x70, 0x2d, 0x15, 0x27, 0x18, 0x51, 0x06, 0x05, 0x33, 0x11, 0x2c, 0x6b, 0x00, 0x2d, 0x77, 0x20, 0x48,
191 0x33,0x76,0x52,0x13,0x25,0x33,0x7d,0x65,0x23,0x27,0x11,0x06,0x06,0x47,0x71,0x1e, 189 0x0d, 0x73, 0x51, 0x45, 0x25, 0x7f, 0x7f, 0x35, 0x26, 0x2e, 0x26, 0x53, 0x24, 0x68, 0x1e, 0x0e, 0x58, 0x3a, 0x59, 0x50, 0x56, 0x37,
192 0x14,0x74,0x63,0x70,0x2d,0x15,0x27,0x18,0x51,0x06,0x05,0x33,0x11,0x2c,0x6b,0x00, 190 0x5f, 0x66, 0x01, 0x4c, 0x5a, 0x64, 0x32, 0x50, 0x7b, 0x6a, 0x20, 0x72, 0x2b, 0x1d, 0x7e, 0x43, 0x7b, 0x61, 0x42, 0x0b, 0x61, 0x73,
193 0x2d,0x77,0x20,0x48,0x0d,0x73,0x51,0x45,0x25,0x7f,0x7f,0x35,0x26,0x2e,0x26,0x53, 191 0x24, 0x79, 0x3a, 0x6b, 0x4a, 0x79, 0x6e, 0x09, 0x0f, 0x27, 0x2d, 0x0c, 0x5e, 0x32, 0x4b, 0x0d, 0x79, 0x46, 0x39, 0x21, 0x0a, 0x26,
194 0x24,0x68,0x1e,0x0e,0x58,0x3a,0x59,0x50,0x56,0x37,0x5f,0x66,0x01,0x4c,0x5a,0x64, 192 0x5f, 0x3a, 0x00, 0x26, 0x3f, 0x13, 0x2e, 0x7e, 0x50, 0x2b, 0x67, 0x46, 0x72, 0x3f, 0x3b, 0x01, 0x46, 0x1b, 0x0b, 0x35, 0x49, 0x39,
195 0x32,0x50,0x7b,0x6a,0x20,0x72,0x2b,0x1d,0x7e,0x43,0x7b,0x61,0x42,0x0b,0x61,0x73, 193 0x19, 0x70, 0x3d, 0x02, 0x41, 0x0e, 0x38, 0x05, 0x76, 0x65, 0x4f, 0x31, 0x6c, 0x5e, 0x17, 0x04, 0x15, 0x36, 0x26, 0x64, 0x34, 0x14,
196 0x24,0x79,0x3a,0x6b,0x4a,0x79,0x6e,0x09,0x0f,0x27,0x2d,0x0c,0x5e,0x32,0x4b,0x0d, 194 0x17, 0x7c, 0x0e, 0x0b, 0x5b, 0x55, 0x53, 0x6b, 0x00, 0x42, 0x41, 0x4f, 0x02, 0x5c, 0x13, 0x0a, 0x2c, 0x2c, 0x3e, 0x10, 0x14, 0x33,
197 0x79,0x46,0x39,0x21,0x0a,0x26,0x5f,0x3a,0x00,0x26,0x3f,0x13,0x2e,0x7e,0x50,0x2b, 195 0x45, 0x7c, 0x7a, 0x5a, 0x31, 0x61, 0x39, 0x08, 0x22, 0x6a, 0x1e, 0x0f, 0x6f, 0x1b, 0x6c, 0x13, 0x5e, 0x79, 0x20, 0x79, 0x50, 0x62,
198 0x67,0x46,0x72,0x3f,0x3b,0x01,0x46,0x1b,0x0b,0x35,0x49,0x39,0x19,0x70,0x3d,0x02, 196 0x06, 0x2c, 0x76, 0x17, 0x04, 0x2b, 0x2a, 0x75, 0x1f, 0x0c, 0x37, 0x4e, 0x0f, 0x7b, 0x2d, 0x34, 0x75, 0x60, 0x31, 0x74, 0x2e, 0x0a,
199 0x41,0x0e,0x38,0x05,0x76,0x65,0x4f,0x31,0x6c,0x5e,0x17,0x04,0x15,0x36,0x26,0x64, 197 0x4a, 0x11, 0x6c, 0x49, 0x25, 0x01, 0x3a, 0x3d, 0x22, 0x1e, 0x6d, 0x18, 0x51, 0x78, 0x2d, 0x62, 0x31, 0x4c, 0x50, 0x40, 0x17, 0x4b,
200 0x34,0x14,0x17,0x7c,0x0e,0x0b,0x5b,0x55,0x53,0x6b,0x00,0x42,0x41,0x4f,0x02,0x5c, 198 0x6f, 0x22, 0x00, 0x7f, 0x61, 0x2a, 0x34, 0x3e, 0x00, 0x5f, 0x2f, 0x5f, 0x2f, 0x14, 0x2a, 0x55, 0x27, 0x1f, 0x46, 0x1f, 0x12, 0x46,
201 0x13,0x0a,0x2c,0x2c,0x3e,0x10,0x14,0x33,0x45,0x7c,0x7a,0x5a,0x31,0x61,0x39,0x08, 199 0x5e, 0x1e, 0x0c, 0x7c, 0x38, 0x01, 0x61, 0x64, 0x76, 0x22, 0x6e, 0x08, 0x20, 0x38, 0x4f, 0x73, 0x72, 0x55, 0x12, 0x42, 0x19, 0x50,
202 0x22,0x6a,0x1e,0x0f,0x6f,0x1b,0x6c,0x13,0x5e,0x79,0x20,0x79,0x50,0x62,0x06,0x2c, 200 0x61, 0x43, 0x77, 0x7d, 0x41, 0x2e, 0x35, 0x4f, 0x3d, 0x31, 0x28, 0x58, 0x67, 0x1b, 0x03, 0x51, 0x20, 0x32, 0x1c, 0x08, 0x6e, 0x37,
203 0x76,0x17,0x04,0x2b,0x2a,0x75,0x1f,0x0c,0x37,0x4e,0x0f,0x7b,0x2d,0x34,0x75,0x60, 201 0x75, 0x37, 0x44, 0x4f, 0x68, 0x19, 0x07, 0x64, 0x14, 0x28, 0x25, 0x2b, 0x69, 0x35, 0x18, 0x27, 0x26, 0x14, 0x13, 0x70, 0x42, 0x19,
204 0x31,0x74,0x2e,0x0a,0x4a,0x11,0x6c,0x49,0x25,0x01,0x3a,0x3d,0x22,0x1e,0x6d,0x18, 202 0x12, 0x75, 0x3e, 0x02, 0x5d, 0x7c, 0x13, 0x1f, 0x16, 0x53, 0x3b, 0x74, 0x48, 0x3c, 0x5e, 0x39, 0x6c, 0x1c, 0x1c, 0x74, 0x39, 0x1f,
205 0x51,0x78,0x2d,0x62,0x31,0x4c,0x50,0x40,0x17,0x4b,0x6f,0x22,0x00,0x7f,0x61,0x2a, 203 0x00, 0x1b, 0x06, 0x0a, 0x68, 0x3b, 0x52, 0x4f, 0x1e, 0x6e, 0x3c, 0x35, 0x0c, 0x38, 0x0e, 0x0b, 0x3b, 0x1a, 0x76, 0x23, 0x29, 0x53,
206 0x34,0x3e,0x00,0x5f,0x2f,0x5f,0x2f,0x14,0x2a,0x55,0x27,0x1f,0x46,0x1f,0x12,0x46, 204 0x1e, 0x5f, 0x41, 0x0c, 0x4b, 0x0a, 0x65, 0x28, 0x78, 0x67, 0x48, 0x59, 0x26, 0x6d, 0x31, 0x76, 0x23, 0x70, 0x61, 0x64, 0x3b, 0x38,
207 0x5e,0x1e,0x0c,0x7c,0x38,0x01,0x61,0x64,0x76,0x22,0x6e,0x08,0x20,0x38,0x4f,0x73, 205 0x79, 0x66, 0x74, 0x53, 0x2c, 0x64, 0x64, 0x54, 0x03, 0x54, 0x65, 0x44, 0x4c, 0x18, 0x4f, 0x48, 0x20, 0x4f, 0x72, 0x10, 0x3f, 0x0c,
208 0x72,0x55,0x12,0x42,0x19,0x50,0x61,0x43,0x77,0x7d,0x41,0x2e,0x35,0x4f,0x3d,0x31, 206 0x52, 0x2d, 0x03, 0x14, 0x03, 0x51, 0x42, 0x10, 0x77, 0x6a, 0x34, 0x06, 0x32, 0x03, 0x72, 0x14, 0x7c, 0x08, 0x5d, 0x52, 0x1a, 0x62,
209 0x28,0x58,0x67,0x1b,0x03,0x51,0x20,0x32,0x1c,0x08,0x6e,0x37,0x75,0x37,0x44,0x4f, 207 0x7c, 0x3e, 0x30, 0x7e, 0x5f, 0x7f, 0x54, 0x0f, 0x44, 0x49, 0x5d, 0x5e, 0x10, 0x6a, 0x06, 0x2b, 0x06, 0x53, 0x10, 0x39, 0x37, 0x32,
210 0x68,0x19,0x07,0x64,0x14,0x28,0x25,0x2b,0x69,0x35,0x18,0x27,0x26,0x14,0x13,0x70, 208 0x4a, 0x4e, 0x3d, 0x2b, 0x65, 0x38, 0x39, 0x07, 0x72, 0x54, 0x64, 0x4d, 0x56, 0x6a, 0x03, 0x22, 0x70, 0x7b, 0x5f, 0x60, 0x0b, 0x2a,
211 0x42,0x19,0x12,0x75,0x3e,0x02,0x5d,0x7c,0x13,0x1f,0x16,0x53,0x3b,0x74,0x48,0x3c, 209 0x0b, 0x6b, 0x10, 0x64, 0x14, 0x05, 0x22, 0x00, 0x73, 0x40, 0x23, 0x5b, 0x51, 0x1f, 0x2b, 0x1a, 0x5d, 0x69, 0x7a, 0x46, 0x0c, 0x5f,
212 0x5e,0x39,0x6c,0x1c,0x1c,0x74,0x39,0x1f,0x00,0x1b,0x06,0x0a,0x68,0x3b,0x52,0x4f, 210 0x32, 0x4b, 0x4a, 0x28, 0x52, 0x79, 0x5b, 0x12, 0x42, 0x18, 0x00, 0x5d, 0x27, 0x31, 0x53, 0x3c, 0x4c, 0x36, 0x4e, 0x38, 0x3f, 0x72,
213 0x1e,0x6e,0x3c,0x35,0x0c,0x38,0x0e,0x0b,0x3b,0x1a,0x76,0x23,0x29,0x53,0x1e,0x5f, 211 0x03, 0x71, 0x02, 0x5b, 0x36, 0x59, 0x7f, 0x75, 0x6e, 0x08, 0x54, 0x0d, 0x34, 0x1c, 0x34, 0x57, 0x5d, 0x69, 0x48, 0x00, 0x3b, 0x05,
214 0x41,0x0c,0x4b,0x0a,0x65,0x28,0x78,0x67,0x48,0x59,0x26,0x6d,0x31,0x76,0x23,0x70, 212 0x07, 0x6e, 0x27, 0x65, 0x6e, 0x40, 0x3d, 0x3a, 0x4f, 0x72, 0x5d, 0x39, 0x16, 0x0f, 0x63, 0x12, 0x12, 0x15, 0x3a, 0x70, 0x0d, 0x57,
215 0x61,0x64,0x3b,0x38,0x79,0x66,0x74,0x53,0x2c,0x64,0x64,0x54,0x03,0x54,0x65,0x44, 213 0x18, 0x0d, 0x5e, 0x3d, 0x22, 0x68, 0x68, 0x7c, 0x6d, 0x4f, 0x0c, 0x7b, 0x09, 0x2d, 0x4a, 0x73, 0x20, 0x47, 0x07, 0x57, 0x75, 0x5d,
216 0x4c,0x18,0x4f,0x48,0x20,0x4f,0x72,0x10,0x3f,0x0c,0x52,0x2d,0x03,0x14,0x03,0x51, 214 0x53, 0x70, 0x34, 0x21, 0x40, 0x57, 0x51, 0x5e, 0x49, 0x44, 0x00, 0x54, 0x27, 0x04, 0x68, 0x7e, 0x59, 0x56, 0x58, 0x74, 0x14, 0x3c,
217 0x42,0x10,0x77,0x6a,0x34,0x06,0x32,0x03,0x72,0x14,0x7c,0x08,0x5d,0x52,0x1a,0x62, 215 0x16, 0x33, 0x41, 0x16, 0x4b, 0x2f, 0x49, 0x37, 0x0a, 0x54, 0x08, 0x08, 0x1f, 0x39, 0x67, 0x76, 0x28, 0x28, 0x07, 0x1d, 0x61, 0x47,
218 0x7c,0x3e,0x30,0x7e,0x5f,0x7f,0x54,0x0f,0x44,0x49,0x5d,0x5e,0x10,0x6a,0x06,0x2b, 216 0x51, 0x4d, 0x75, 0x26, 0x52, 0x47, 0x47, 0x0c, 0x57, 0x58, 0x74, 0x3e, 0x62, 0x6c, 0x58, 0x3a, 0x44, 0x1e, 0x16, 0x2e, 0x21, 0x1c,
219 0x06,0x53,0x10,0x39,0x37,0x32,0x4a,0x4e,0x3d,0x2b,0x65,0x38,0x39,0x07,0x72,0x54, 217 0x73, 0x45, 0x67, 0x74, 0x4f, 0x33, 0x66, 0x0e, 0x74, 0x66, 0x26, 0x1f, 0x2e, 0x38, 0x44, 0x40, 0x7e, 0x2a, 0x50, 0x52, 0x5e, 0x43,
220 0x64,0x4d,0x56,0x6a,0x03,0x22,0x70,0x7b,0x5f,0x60,0x0b,0x2a,0x0b,0x6b,0x10,0x64, 218 0x01, 0x7a, 0x38, 0x49, 0x3c, 0x55, 0x4d, 0x5a, 0x44, 0x08, 0x26, 0x59, 0x4d, 0x45, 0x0b, 0x48, 0x0a, 0x33, 0x5e, 0x4a, 0x4d, 0x75,
221 0x14,0x05,0x22,0x00,0x73,0x40,0x23,0x5b,0x51,0x1f,0x2b,0x1a,0x5d,0x69,0x7a,0x46, 219 0x16, 0x17, 0x63, 0x46, 0x01, 0x2a, 0x55, 0x7b, 0x0f, 0x02, 0x73, 0x6a, 0x4b, 0x7f, 0x75, 0x65, 0x3c, 0x4c, 0x33, 0x39, 0x6c, 0x74,
222 0x0c,0x5f,0x32,0x4b,0x4a,0x28,0x52,0x79,0x5b,0x12,0x42,0x18,0x00,0x5d,0x27,0x31, 220 0x05, 0x60, 0x0f, 0x7f, 0x2d, 0x41, 0x4d, 0x4d, 0x46, 0x71, 0x09, 0x6f, 0x4f, 0x60, 0x15, 0x0f, 0x46, 0x73, 0x63, 0x4c, 0x5e, 0x74,
223 0x53,0x3c,0x4c,0x36,0x4e,0x38,0x3f,0x72,0x03,0x71,0x02,0x5b,0x36,0x59,0x7f,0x75, 221 0x30, 0x0d, 0x28, 0x43, 0x08, 0x72, 0x32, 0x04, 0x2e, 0x31, 0x29, 0x27, 0x44, 0x6d, 0x13, 0x17, 0x48, 0x0f, 0x49, 0x52, 0x10, 0x13,
224 0x6e,0x08,0x54,0x0d,0x34,0x1c,0x34,0x57,0x5d,0x69,0x48,0x00,0x3b,0x05,0x07,0x6e, 222 0x7f, 0x17, 0x16, 0x62, 0x79, 0x35, 0x78, 0x3e, 0x01, 0x7c, 0x2e, 0x0f, 0x76, 0x3e, 0x5e, 0x53, 0x6c, 0x5b, 0x5f, 0x7c, 0x19, 0x41,
225 0x27,0x65,0x6e,0x40,0x3d,0x3a,0x4f,0x72,0x5d,0x39,0x16,0x0f,0x63,0x12,0x12,0x15, 223 0x02, 0x2f, 0x17, 0x64, 0x41, 0x75, 0x10, 0x04, 0x47, 0x7c, 0x3d, 0x4b, 0x52, 0x00, 0x10, 0x5d, 0x51, 0x4e, 0x7a, 0x27, 0x25, 0x55,
226 0x3a,0x70,0x0d,0x57,0x18,0x0d,0x5e,0x3d,0x22,0x68,0x68,0x7c,0x6d,0x4f,0x0c,0x7b, 224 0x40, 0x12, 0x35, 0x60, 0x05, 0x1b, 0x34, 0x2d, 0x04, 0x7a, 0x6a, 0x69, 0x02, 0x79, 0x03, 0x3a, 0x2f, 0x06, 0x0a, 0x79, 0x7b, 0x12,
227 0x09,0x2d,0x4a,0x73,0x20,0x47,0x07,0x57,0x75,0x5d,0x53,0x70,0x34,0x21,0x40,0x57, 225 0x5d, 0x7c, 0x52, 0x29, 0x47, 0x58, 0x12, 0x73, 0x3f, 0x27, 0x56, 0x05, 0x0c, 0x48, 0x32, 0x58, 0x6b, 0x57, 0x5c, 0x03, 0x64, 0x56,
228 0x51,0x5e,0x49,0x44,0x00,0x54,0x27,0x04,0x68,0x7e,0x59,0x56,0x58,0x74,0x14,0x3c, 226 0x11, 0x52, 0x7a, 0x30, 0x36, 0x29, 0x17, 0x3b, 0x68, 0x7a, 0x7c, 0x05, 0x6b, 0x6b, 0x13, 0x6a, 0x24, 0x5c, 0x68, 0x42, 0x18, 0x32,
229 0x16,0x33,0x41,0x16,0x4b,0x2f,0x49,0x37,0x0a,0x54,0x08,0x08,0x1f,0x39,0x67,0x76, 227 0x03, 0x73, 0x6e, 0x04, 0x21, 0x2e, 0x01, 0x04, 0x63, 0x7d, 0x44, 0x41, 0x12, 0x31, 0x0b, 0x15, 0x1f, 0x70, 0x00, 0x2e, 0x66, 0x14,
230 0x28,0x28,0x07,0x1d,0x61,0x47,0x51,0x4d,0x75,0x26,0x52,0x47,0x47,0x0c,0x57,0x58, 228 0x3c, 0x7f, 0x2b, 0x00, 0x1f, 0x0c, 0x28, 0x59, 0x0a, 0x16, 0x49, 0x5a, 0x5c, 0x64, 0x65, 0x4b, 0x11, 0x29, 0x15, 0x36, 0x5a, 0x65,
231 0x74,0x3e,0x62,0x6c,0x58,0x3a,0x44,0x1e,0x16,0x2e,0x21,0x1c,0x73,0x45,0x67,0x74, 229 0x19, 0x4f, 0x60, 0x23, 0x3a, 0x3a, 0x13, 0x25, 0x02, 0x78, 0x4c, 0x54};
232 0x4f,0x33,0x66,0x0e,0x74,0x66,0x26,0x1f,0x2e,0x38,0x44,0x40,0x7e,0x2a,0x50,0x52, 230 char b64_known[1369] = {
233 0x5e,0x43,0x01,0x7a,0x38,0x49,0x3c,0x55,0x4d,0x5a,0x44,0x08,0x26,0x59,0x4d,0x45, 231 0x43, 0x7a, 0x42, 0x45, 0x59, 0x6e, 0x77, 0x69, 0x48, 0x77, 0x30, 0x46, 0x5a, 0x79, 0x77, 0x71, 0x4f, 0x53, 0x46, 0x47, 0x43, 0x46,
234 0x0b,0x48,0x0a,0x33,0x5e,0x4a,0x4d,0x75,0x16,0x17,0x63,0x46,0x01,0x2a,0x55,0x7b, 232 0x42, 0x6d, 0x4e, 0x44, 0x63, 0x4c, 0x52, 0x55, 0x73, 0x34, 0x4d, 0x67, 0x5a, 0x36, 0x50, 0x6e, 0x38, 0x4d, 0x51, 0x42, 0x68, 0x72,
235 0x0f,0x02,0x73,0x6a,0x4b,0x7f,0x75,0x65,0x3c,0x4c,0x33,0x39,0x6c,0x74,0x05,0x60, 233 0x4c, 0x57, 0x42, 0x4d, 0x59, 0x41, 0x77, 0x6a, 0x51, 0x7a, 0x73, 0x2b, 0x47, 0x78, 0x59, 0x45, 0x52, 0x6c, 0x67, 0x2f, 0x51, 0x47,
236 0x0f,0x7f,0x2d,0x41,0x4d,0x4d,0x46,0x71,0x09,0x6f,0x4f,0x60,0x15,0x0f,0x46,0x73, 234 0x6f, 0x52, 0x42, 0x57, 0x4e, 0x78, 0x46, 0x44, 0x56, 0x48, 0x65, 0x52, 0x4e, 0x76, 0x61, 0x79, 0x63, 0x59, 0x57, 0x30, 0x67, 0x6e,
237 0x63,0x4c,0x5e,0x74,0x30,0x0d,0x28,0x43,0x08,0x72,0x32,0x04,0x2e,0x31,0x29,0x27, 235 0x50, 0x6d, 0x38, 0x56, 0x4d, 0x30, 0x38, 0x2b, 0x58, 0x6c, 0x46, 0x7a, 0x61, 0x43, 0x55, 0x50, 0x42, 0x6c, 0x74, 0x38, 0x63, 0x6e,
238 0x44,0x6d,0x13,0x17,0x48,0x0f,0x49,0x52,0x10,0x13,0x7f,0x17,0x16,0x62,0x79,0x35, 236 0x55, 0x2b, 0x50, 0x78, 0x74, 0x63, 0x62, 0x57, 0x6f, 0x35, 0x66, 0x47, 0x4e, 0x6a, 0x59, 0x47, 0x78, 0x36, 0x4d, 0x33, 0x5a, 0x53,
239 0x78,0x3e,0x01,0x7c,0x2e,0x0f,0x76,0x3e,0x5e,0x53,0x6c,0x5b,0x5f,0x7c,0x19,0x41, 237 0x45, 0x79, 0x55, 0x7a, 0x66, 0x57, 0x55, 0x6a, 0x4a, 0x78, 0x45, 0x47, 0x42, 0x6b, 0x64, 0x78, 0x48, 0x68, 0x52, 0x30, 0x59, 0x33,
240 0x02,0x2f,0x17,0x64,0x41,0x75,0x10,0x04,0x47,0x7c,0x3d,0x4b,0x52,0x00,0x10,0x5d, 238 0x41, 0x74, 0x46, 0x53, 0x63, 0x59, 0x55, 0x51, 0x59, 0x46, 0x4d, 0x78, 0x45, 0x73, 0x61, 0x77, 0x41, 0x74, 0x64, 0x79, 0x42, 0x49,
241 0x51,0x4e,0x7a,0x27,0x25,0x55,0x40,0x12,0x35,0x60,0x05,0x1b,0x34,0x2d,0x04,0x7a, 239 0x44, 0x58, 0x4e, 0x52, 0x52, 0x53, 0x56, 0x2f, 0x66, 0x7a, 0x55, 0x6d, 0x4c, 0x69, 0x5a, 0x54, 0x4a, 0x47, 0x67, 0x65, 0x44, 0x6c,
242 0x6a,0x69,0x02,0x79,0x03,0x3a,0x2f,0x06,0x0a,0x79,0x7b,0x12,0x5d,0x7c,0x52,0x29, 240 0x67, 0x36, 0x57, 0x56, 0x42, 0x57, 0x4e, 0x31, 0x39, 0x6d, 0x41, 0x55, 0x78, 0x61, 0x5a, 0x44, 0x4a, 0x51, 0x65, 0x32, 0x6f, 0x67,
243 0x47,0x58,0x12,0x73,0x3f,0x27,0x56,0x05,0x0c,0x48,0x32,0x58,0x6b,0x57,0x5c,0x03, 241 0x63, 0x69, 0x73, 0x64, 0x66, 0x6b, 0x4e, 0x37, 0x59, 0x55, 0x49, 0x4c, 0x59, 0x58, 0x4d, 0x6b, 0x65, 0x54, 0x70, 0x72, 0x53, 0x6e,
244 0x64,0x56,0x11,0x52,0x7a,0x30,0x36,0x29,0x17,0x3b,0x68,0x7a,0x7c,0x05,0x6b,0x6b, 242 0x6c, 0x75, 0x43, 0x51, 0x38, 0x6e, 0x4c, 0x51, 0x78, 0x65, 0x4d, 0x6b, 0x73, 0x4e, 0x65, 0x55, 0x59, 0x35, 0x49, 0x51, 0x6f, 0x6d,
245 0x13,0x6a,0x24,0x5c,0x68,0x42,0x18,0x32,0x03,0x73,0x6e,0x04,0x21,0x2e,0x01,0x04, 243 0x58, 0x7a, 0x6f, 0x41, 0x4a, 0x6a, 0x38, 0x54, 0x4c, 0x6e, 0x35, 0x51, 0x4b, 0x32, 0x64, 0x47, 0x63, 0x6a, 0x38, 0x37, 0x41, 0x55,
246 0x63,0x7d,0x44,0x41,0x12,0x31,0x0b,0x15,0x1f,0x70,0x00,0x2e,0x66,0x14,0x3c,0x7f, 244 0x59, 0x62, 0x43, 0x7a, 0x56, 0x4a, 0x4f, 0x52, 0x6c, 0x77, 0x50, 0x51, 0x4a, 0x42, 0x44, 0x6a, 0x67, 0x46, 0x64, 0x6d, 0x56, 0x50,
247 0x2b,0x00,0x1f,0x0c,0x28,0x59,0x0a,0x16,0x49,0x5a,0x5c,0x64,0x65,0x4b,0x11,0x29, 245 0x4d, 0x57, 0x78, 0x65, 0x46, 0x77, 0x51, 0x56, 0x4e, 0x69, 0x5a, 0x6b, 0x4e, 0x42, 0x51, 0x58, 0x66, 0x41, 0x34, 0x4c, 0x57, 0x31,
248 0x15,0x36,0x5a,0x65,0x19,0x4f,0x60,0x23,0x3a,0x3a,0x13,0x25,0x02,0x78,0x4c,0x54 246 0x56, 0x54, 0x61, 0x77, 0x42, 0x43, 0x51, 0x55, 0x38, 0x43, 0x58, 0x42, 0x4d, 0x4b, 0x4c, 0x43, 0x77, 0x2b, 0x45, 0x42, 0x51, 0x7a,
249 }; 247 0x52, 0x58, 0x78, 0x36, 0x57, 0x6a, 0x46, 0x68, 0x4f, 0x51, 0x67, 0x69, 0x61, 0x68, 0x34, 0x50, 0x62, 0x78, 0x74, 0x73, 0x45, 0x31,
250 char b64_known[1369] = { 248 0x35, 0x35, 0x49, 0x48, 0x6c, 0x51, 0x59, 0x67, 0x59, 0x73, 0x64, 0x68, 0x63, 0x45, 0x4b, 0x79, 0x70, 0x31, 0x48, 0x77, 0x77, 0x33,
251 0x43,0x7a,0x42,0x45,0x59,0x6e,0x77,0x69,0x48,0x77,0x30,0x46,0x5a,0x79,0x77,0x71, 249 0x54, 0x67, 0x39, 0x37, 0x4c, 0x54, 0x52, 0x31, 0x59, 0x44, 0x46, 0x30, 0x4c, 0x67, 0x70, 0x4b, 0x45, 0x57, 0x78, 0x4a, 0x4a, 0x51,
252 0x4f,0x53,0x46,0x47,0x43,0x46,0x42,0x6d,0x4e,0x44,0x63,0x4c,0x52,0x55,0x73,0x34, 250 0x45, 0x36, 0x50, 0x53, 0x49, 0x65, 0x62, 0x52, 0x68, 0x52, 0x65, 0x43, 0x31, 0x69, 0x4d, 0x55, 0x78, 0x51, 0x51, 0x42, 0x64, 0x4c,
253 0x4d,0x67,0x5a,0x36,0x50,0x6e,0x38,0x4d,0x51,0x42,0x68,0x72,0x4c,0x57,0x42,0x4d, 251 0x62, 0x79, 0x49, 0x41, 0x66, 0x32, 0x45, 0x71, 0x4e, 0x44, 0x34, 0x41, 0x58, 0x79, 0x39, 0x66, 0x4c, 0x78, 0x51, 0x71, 0x56, 0x53,
254 0x59,0x41,0x77,0x6a,0x51,0x7a,0x73,0x2b,0x47,0x78,0x59,0x45,0x52,0x6c,0x67,0x2f, 252 0x63, 0x66, 0x52, 0x68, 0x38, 0x53, 0x52, 0x6c, 0x34, 0x65, 0x44, 0x48, 0x77, 0x34, 0x41, 0x57, 0x46, 0x6b, 0x64, 0x69, 0x4a, 0x75,
255 0x51,0x47,0x6f,0x52,0x42,0x57,0x4e,0x78,0x46,0x44,0x56,0x48,0x65,0x52,0x4e,0x76, 253 0x43, 0x43, 0x41, 0x34, 0x54, 0x33, 0x4e, 0x79, 0x56, 0x52, 0x4a, 0x43, 0x47, 0x56, 0x42, 0x68, 0x51, 0x33, 0x64, 0x39, 0x51, 0x53,
256 0x61,0x79,0x63,0x59,0x57,0x30,0x67,0x6e,0x50,0x6d,0x38,0x56,0x4d,0x30,0x38,0x2b, 254 0x34, 0x31, 0x54, 0x7a, 0x30, 0x78, 0x4b, 0x46, 0x68, 0x6e, 0x47, 0x77, 0x4e, 0x52, 0x49, 0x44, 0x49, 0x63, 0x43, 0x47, 0x34, 0x33,
257 0x58,0x6c,0x46,0x7a,0x61,0x43,0x55,0x50,0x42,0x6c,0x74,0x38,0x63,0x6e,0x55,0x2b, 255 0x64, 0x54, 0x64, 0x45, 0x54, 0x32, 0x67, 0x5a, 0x42, 0x32, 0x51, 0x55, 0x4b, 0x43, 0x55, 0x72, 0x61, 0x54, 0x55, 0x59, 0x4a, 0x79,
258 0x50,0x78,0x74,0x63,0x62,0x57,0x6f,0x35,0x66,0x47,0x4e,0x6a,0x59,0x47,0x78,0x36, 256 0x59, 0x55, 0x45, 0x33, 0x42, 0x43, 0x47, 0x52, 0x4a, 0x31, 0x50, 0x67, 0x4a, 0x64, 0x66, 0x42, 0x4d, 0x66, 0x46, 0x6c, 0x4d, 0x37,
259 0x4d,0x33,0x5a,0x53,0x45,0x79,0x55,0x7a,0x66,0x57,0x55,0x6a,0x4a,0x78,0x45,0x47, 257 0x64, 0x45, 0x67, 0x38, 0x58, 0x6a, 0x6c, 0x73, 0x48, 0x42, 0x78, 0x30, 0x4f, 0x52, 0x38, 0x41, 0x47, 0x77, 0x59, 0x4b, 0x61, 0x44,
260 0x42,0x6b,0x64,0x78,0x48,0x68,0x52,0x30,0x59,0x33,0x41,0x74,0x46,0x53,0x63,0x59, 258 0x74, 0x53, 0x54, 0x78, 0x35, 0x75, 0x50, 0x44, 0x55, 0x4d, 0x4f, 0x41, 0x34, 0x4c, 0x4f, 0x78, 0x70, 0x32, 0x49, 0x79, 0x6c, 0x54,
261 0x55,0x51,0x59,0x46,0x4d,0x78,0x45,0x73,0x61,0x77,0x41,0x74,0x64,0x79,0x42,0x49, 259 0x48, 0x6c, 0x39, 0x42, 0x44, 0x45, 0x73, 0x4b, 0x5a, 0x53, 0x68, 0x34, 0x5a, 0x30, 0x68, 0x5a, 0x4a, 0x6d, 0x30, 0x78, 0x64, 0x69,
262 0x44,0x58,0x4e,0x52,0x52,0x53,0x56,0x2f,0x66,0x7a,0x55,0x6d,0x4c,0x69,0x5a,0x54, 260 0x4e, 0x77, 0x59, 0x57, 0x51, 0x37, 0x4f, 0x48, 0x6c, 0x6d, 0x64, 0x46, 0x4d, 0x73, 0x5a, 0x47, 0x52, 0x55, 0x41, 0x31, 0x52, 0x6c,
263 0x4a,0x47,0x67,0x65,0x44,0x6c,0x67,0x36,0x57,0x56,0x42,0x57,0x4e,0x31,0x39,0x6d, 261 0x52, 0x45, 0x77, 0x59, 0x54, 0x30, 0x67, 0x67, 0x54, 0x33, 0x49, 0x51, 0x50, 0x77, 0x78, 0x53, 0x4c, 0x51, 0x4d, 0x55, 0x41, 0x31,
264 0x41,0x55,0x78,0x61,0x5a,0x44,0x4a,0x51,0x65,0x32,0x6f,0x67,0x63,0x69,0x73,0x64, 262 0x46, 0x43, 0x45, 0x48, 0x64, 0x71, 0x4e, 0x41, 0x59, 0x79, 0x41, 0x33, 0x49, 0x55, 0x66, 0x41, 0x68, 0x64, 0x55, 0x68, 0x70, 0x69,
265 0x66,0x6b,0x4e,0x37,0x59,0x55,0x49,0x4c,0x59,0x58,0x4d,0x6b,0x65,0x54,0x70,0x72, 263 0x66, 0x44, 0x34, 0x77, 0x66, 0x6c, 0x39, 0x2f, 0x56, 0x41, 0x39, 0x45, 0x53, 0x56, 0x31, 0x65, 0x45, 0x47, 0x6f, 0x47, 0x4b, 0x77,
266 0x53,0x6e,0x6c,0x75,0x43,0x51,0x38,0x6e,0x4c,0x51,0x78,0x65,0x4d,0x6b,0x73,0x4e, 264 0x5a, 0x54, 0x45, 0x44, 0x6b, 0x33, 0x4d, 0x6b, 0x70, 0x4f, 0x50, 0x53, 0x74, 0x6c, 0x4f, 0x44, 0x6b, 0x48, 0x63, 0x6c, 0x52, 0x6b,
267 0x65,0x55,0x59,0x35,0x49,0x51,0x6f,0x6d,0x58,0x7a,0x6f,0x41,0x4a,0x6a,0x38,0x54, 265 0x54, 0x56, 0x5a, 0x71, 0x41, 0x79, 0x4a, 0x77, 0x65, 0x31, 0x39, 0x67, 0x43, 0x79, 0x6f, 0x4c, 0x61, 0x78, 0x42, 0x6b, 0x46, 0x41,
268 0x4c,0x6e,0x35,0x51,0x4b,0x32,0x64,0x47,0x63,0x6a,0x38,0x37,0x41,0x55,0x59,0x62, 266 0x55, 0x69, 0x41, 0x48, 0x4e, 0x41, 0x49, 0x31, 0x74, 0x52, 0x48, 0x79, 0x73, 0x61, 0x58, 0x57, 0x6c, 0x36, 0x52, 0x67, 0x78, 0x66,
269 0x43,0x7a,0x56,0x4a,0x4f,0x52,0x6c,0x77,0x50,0x51,0x4a,0x42,0x44,0x6a,0x67,0x46, 267 0x4d, 0x6b, 0x74, 0x4b, 0x4b, 0x46, 0x4a, 0x35, 0x57, 0x78, 0x4a, 0x43, 0x47, 0x41, 0x42, 0x64, 0x4a, 0x7a, 0x46, 0x54, 0x50, 0x45,
270 0x64,0x6d,0x56,0x50,0x4d,0x57,0x78,0x65,0x46,0x77,0x51,0x56,0x4e,0x69,0x5a,0x6b, 268 0x77, 0x32, 0x54, 0x6a, 0x67, 0x2f, 0x63, 0x67, 0x4e, 0x78, 0x41, 0x6c, 0x73, 0x32, 0x57, 0x58, 0x39, 0x31, 0x62, 0x67, 0x68, 0x55,
271 0x4e,0x42,0x51,0x58,0x66,0x41,0x34,0x4c,0x57,0x31,0x56,0x54,0x61,0x77,0x42,0x43, 269 0x44, 0x54, 0x51, 0x63, 0x4e, 0x46, 0x64, 0x64, 0x61, 0x55, 0x67, 0x41, 0x4f, 0x77, 0x55, 0x48, 0x62, 0x69, 0x64, 0x6c, 0x62, 0x6b,
272 0x51,0x55,0x38,0x43,0x58,0x42,0x4d,0x4b,0x4c,0x43,0x77,0x2b,0x45,0x42,0x51,0x7a, 270 0x41, 0x39, 0x4f, 0x6b, 0x39, 0x79, 0x58, 0x54, 0x6b, 0x57, 0x44, 0x32, 0x4d, 0x53, 0x45, 0x68, 0x55, 0x36, 0x63, 0x41, 0x31, 0x58,
273 0x52,0x58,0x78,0x36,0x57,0x6a,0x46,0x68,0x4f,0x51,0x67,0x69,0x61,0x68,0x34,0x50, 271 0x47, 0x41, 0x31, 0x65, 0x50, 0x53, 0x4a, 0x6f, 0x61, 0x48, 0x78, 0x74, 0x54, 0x77, 0x78, 0x37, 0x43, 0x53, 0x31, 0x4b, 0x63, 0x79,
274 0x62,0x78,0x74,0x73,0x45,0x31,0x35,0x35,0x49,0x48,0x6c,0x51,0x59,0x67,0x59,0x73, 272 0x42, 0x48, 0x42, 0x31, 0x64, 0x31, 0x58, 0x56, 0x4e, 0x77, 0x4e, 0x43, 0x46, 0x41, 0x56, 0x31, 0x46, 0x65, 0x53, 0x55, 0x51, 0x41,
275 0x64,0x68,0x63,0x45,0x4b,0x79,0x70,0x31,0x48,0x77,0x77,0x33,0x54,0x67,0x39,0x37, 273 0x56, 0x43, 0x63, 0x45, 0x61, 0x48, 0x35, 0x5a, 0x56, 0x6c, 0x68, 0x30, 0x46, 0x44, 0x77, 0x57, 0x4d, 0x30, 0x45, 0x57, 0x53, 0x79,
276 0x4c,0x54,0x52,0x31,0x59,0x44,0x46,0x30,0x4c,0x67,0x70,0x4b,0x45,0x57,0x78,0x4a, 274 0x39, 0x4a, 0x4e, 0x77, 0x70, 0x55, 0x43, 0x41, 0x67, 0x66, 0x4f, 0x57, 0x64, 0x32, 0x4b, 0x43, 0x67, 0x48, 0x48, 0x57, 0x46, 0x48,
277 0x4a,0x51,0x45,0x36,0x50,0x53,0x49,0x65,0x62,0x52,0x68,0x52,0x65,0x43,0x31,0x69, 275 0x55, 0x55, 0x31, 0x31, 0x4a, 0x6c, 0x4a, 0x48, 0x52, 0x77, 0x78, 0x58, 0x57, 0x48, 0x51, 0x2b, 0x59, 0x6d, 0x78, 0x59, 0x4f, 0x6b,
278 0x4d,0x55,0x78,0x51,0x51,0x42,0x64,0x4c,0x62,0x79,0x49,0x41,0x66,0x32,0x45,0x71, 276 0x51, 0x65, 0x46, 0x69, 0x34, 0x68, 0x48, 0x48, 0x4e, 0x46, 0x5a, 0x33, 0x52, 0x50, 0x4d, 0x32, 0x59, 0x4f, 0x64, 0x47, 0x59, 0x6d,
279 0x4e,0x44,0x34,0x41,0x58,0x79,0x39,0x66,0x4c,0x78,0x51,0x71,0x56,0x53,0x63,0x66, 277 0x48, 0x79, 0x34, 0x34, 0x52, 0x45, 0x42, 0x2b, 0x4b, 0x6c, 0x42, 0x53, 0x58, 0x6b, 0x4d, 0x42, 0x65, 0x6a, 0x68, 0x4a, 0x50, 0x46,
280 0x52,0x68,0x38,0x53,0x52,0x6c,0x34,0x65,0x44,0x48,0x77,0x34,0x41,0x57,0x46,0x6b, 278 0x56, 0x4e, 0x57, 0x6b, 0x51, 0x49, 0x4a, 0x6c, 0x6c, 0x4e, 0x52, 0x51, 0x74, 0x49, 0x43, 0x6a, 0x4e, 0x65, 0x53, 0x6b, 0x31, 0x31,
281 0x64,0x69,0x4a,0x75,0x43,0x43,0x41,0x34,0x54,0x33,0x4e,0x79,0x56,0x52,0x4a,0x43, 279 0x46, 0x68, 0x64, 0x6a, 0x52, 0x67, 0x45, 0x71, 0x56, 0x58, 0x73, 0x50, 0x41, 0x6e, 0x4e, 0x71, 0x53, 0x33, 0x39, 0x31, 0x5a, 0x54,
282 0x47,0x56,0x42,0x68,0x51,0x33,0x64,0x39,0x51,0x53,0x34,0x31,0x54,0x7a,0x30,0x78, 280 0x78, 0x4d, 0x4d, 0x7a, 0x6c, 0x73, 0x64, 0x41, 0x56, 0x67, 0x44, 0x33, 0x38, 0x74, 0x51, 0x55, 0x31, 0x4e, 0x52, 0x6e, 0x45, 0x4a,
283 0x4b,0x46,0x68,0x6e,0x47,0x77,0x4e,0x52,0x49,0x44,0x49,0x63,0x43,0x47,0x34,0x33, 281 0x62, 0x30, 0x39, 0x67, 0x46, 0x51, 0x39, 0x47, 0x63, 0x32, 0x4e, 0x4d, 0x58, 0x6e, 0x51, 0x77, 0x44, 0x53, 0x68, 0x44, 0x43, 0x48,
284 0x64,0x54,0x64,0x45,0x54,0x32,0x67,0x5a,0x42,0x32,0x51,0x55,0x4b,0x43,0x55,0x72, 282 0x49, 0x79, 0x42, 0x43, 0x34, 0x78, 0x4b, 0x53, 0x64, 0x45, 0x62, 0x52, 0x4d, 0x58, 0x53, 0x41, 0x39, 0x4a, 0x55, 0x68, 0x41, 0x54,
285 0x61,0x54,0x55,0x59,0x4a,0x79,0x59,0x55,0x45,0x33,0x42,0x43,0x47,0x52,0x4a,0x31, 283 0x66, 0x78, 0x63, 0x57, 0x59, 0x6e, 0x6b, 0x31, 0x65, 0x44, 0x34, 0x42, 0x66, 0x43, 0x34, 0x50, 0x64, 0x6a, 0x35, 0x65, 0x55, 0x32,
286 0x50,0x67,0x4a,0x64,0x66,0x42,0x4d,0x66,0x46,0x6c,0x4d,0x37,0x64,0x45,0x67,0x38, 284 0x78, 0x62, 0x58, 0x33, 0x77, 0x5a, 0x51, 0x51, 0x49, 0x76, 0x46, 0x32, 0x52, 0x42, 0x64, 0x52, 0x41, 0x45, 0x52, 0x33, 0x77, 0x39,
287 0x58,0x6a,0x6c,0x73,0x48,0x42,0x78,0x30,0x4f,0x52,0x38,0x41,0x47,0x77,0x59,0x4b, 285 0x53, 0x31, 0x49, 0x41, 0x45, 0x46, 0x31, 0x52, 0x54, 0x6e, 0x6f, 0x6e, 0x4a, 0x56, 0x56, 0x41, 0x45, 0x6a, 0x56, 0x67, 0x42, 0x52,
288 0x61,0x44,0x74,0x53,0x54,0x78,0x35,0x75,0x50,0x44,0x55,0x4d,0x4f,0x41,0x34,0x4c, 286 0x73, 0x30, 0x4c, 0x51, 0x52, 0x36, 0x61, 0x6d, 0x6b, 0x43, 0x65, 0x51, 0x4d, 0x36, 0x4c, 0x77, 0x59, 0x4b, 0x65, 0x58, 0x73, 0x53,
289 0x4f,0x78,0x70,0x32,0x49,0x79,0x6c,0x54,0x48,0x6c,0x39,0x42,0x44,0x45,0x73,0x4b, 287 0x58, 0x58, 0x78, 0x53, 0x4b, 0x55, 0x64, 0x59, 0x45, 0x6e, 0x4d, 0x2f, 0x4a, 0x31, 0x59, 0x46, 0x44, 0x45, 0x67, 0x79, 0x57, 0x47,
290 0x5a,0x53,0x68,0x34,0x5a,0x30,0x68,0x5a,0x4a,0x6d,0x30,0x78,0x64,0x69,0x4e,0x77, 288 0x74, 0x58, 0x58, 0x41, 0x4e, 0x6b, 0x56, 0x68, 0x46, 0x53, 0x65, 0x6a, 0x41, 0x32, 0x4b, 0x52, 0x63, 0x37, 0x61, 0x48, 0x70, 0x38,
291 0x59,0x57,0x51,0x37,0x4f,0x48,0x6c,0x6d,0x64,0x46,0x4d,0x73,0x5a,0x47,0x52,0x55, 289 0x42, 0x57, 0x74, 0x72, 0x45, 0x32, 0x6f, 0x6b, 0x58, 0x47, 0x68, 0x43, 0x47, 0x44, 0x49, 0x44, 0x63, 0x32, 0x34, 0x45, 0x49, 0x53,
292 0x41,0x31,0x52,0x6c,0x52,0x45,0x77,0x59,0x54,0x30,0x67,0x67,0x54,0x33,0x49,0x51, 290 0x34, 0x42, 0x42, 0x47, 0x4e, 0x39, 0x52, 0x45, 0x45, 0x53, 0x4d, 0x51, 0x73, 0x56, 0x48, 0x33, 0x41, 0x41, 0x4c, 0x6d, 0x59, 0x55,
293 0x50,0x77,0x78,0x53,0x4c,0x51,0x4d,0x55,0x41,0x31,0x46,0x43,0x45,0x48,0x64,0x71, 291 0x50, 0x48, 0x38, 0x72, 0x41, 0x42, 0x38, 0x4d, 0x4b, 0x46, 0x6b, 0x4b, 0x46, 0x6b, 0x6c, 0x61, 0x58, 0x47, 0x52, 0x6c, 0x53, 0x78,
294 0x4e,0x41,0x59,0x79,0x41,0x33,0x49,0x55,0x66,0x41,0x68,0x64,0x55,0x68,0x70,0x69, 292 0x45, 0x70, 0x46, 0x54, 0x5a, 0x61, 0x5a, 0x52, 0x6c, 0x50, 0x59, 0x43, 0x4d, 0x36, 0x4f, 0x68, 0x4d, 0x6c, 0x41, 0x6e, 0x68, 0x4d,
295 0x66,0x44,0x34,0x77,0x66,0x6c,0x39,0x2f,0x56,0x41,0x39,0x45,0x53,0x56,0x31,0x65, 293 0x56, 0x41, 0x3d, 0x3d, 0x00};
296 0x45,0x47,0x6f,0x47,0x4b,0x77,0x5a,0x54,0x45,0x44,0x6b,0x33,0x4d,0x6b,0x70,0x4f,
297 0x50,0x53,0x74,0x6c,0x4f,0x44,0x6b,0x48,0x63,0x6c,0x52,0x6b,0x54,0x56,0x5a,0x71,
298 0x41,0x79,0x4a,0x77,0x65,0x31,0x39,0x67,0x43,0x79,0x6f,0x4c,0x61,0x78,0x42,0x6b,
299 0x46,0x41,0x55,0x69,0x41,0x48,0x4e,0x41,0x49,0x31,0x74,0x52,0x48,0x79,0x73,0x61,
300 0x58,0x57,0x6c,0x36,0x52,0x67,0x78,0x66,0x4d,0x6b,0x74,0x4b,0x4b,0x46,0x4a,0x35,
301 0x57,0x78,0x4a,0x43,0x47,0x41,0x42,0x64,0x4a,0x7a,0x46,0x54,0x50,0x45,0x77,0x32,
302 0x54,0x6a,0x67,0x2f,0x63,0x67,0x4e,0x78,0x41,0x6c,0x73,0x32,0x57,0x58,0x39,0x31,
303 0x62,0x67,0x68,0x55,0x44,0x54,0x51,0x63,0x4e,0x46,0x64,0x64,0x61,0x55,0x67,0x41,
304 0x4f,0x77,0x55,0x48,0x62,0x69,0x64,0x6c,0x62,0x6b,0x41,0x39,0x4f,0x6b,0x39,0x79,
305 0x58,0x54,0x6b,0x57,0x44,0x32,0x4d,0x53,0x45,0x68,0x55,0x36,0x63,0x41,0x31,0x58,
306 0x47,0x41,0x31,0x65,0x50,0x53,0x4a,0x6f,0x61,0x48,0x78,0x74,0x54,0x77,0x78,0x37,
307 0x43,0x53,0x31,0x4b,0x63,0x79,0x42,0x48,0x42,0x31,0x64,0x31,0x58,0x56,0x4e,0x77,
308 0x4e,0x43,0x46,0x41,0x56,0x31,0x46,0x65,0x53,0x55,0x51,0x41,0x56,0x43,0x63,0x45,
309 0x61,0x48,0x35,0x5a,0x56,0x6c,0x68,0x30,0x46,0x44,0x77,0x57,0x4d,0x30,0x45,0x57,
310 0x53,0x79,0x39,0x4a,0x4e,0x77,0x70,0x55,0x43,0x41,0x67,0x66,0x4f,0x57,0x64,0x32,
311 0x4b,0x43,0x67,0x48,0x48,0x57,0x46,0x48,0x55,0x55,0x31,0x31,0x4a,0x6c,0x4a,0x48,
312 0x52,0x77,0x78,0x58,0x57,0x48,0x51,0x2b,0x59,0x6d,0x78,0x59,0x4f,0x6b,0x51,0x65,
313 0x46,0x69,0x34,0x68,0x48,0x48,0x4e,0x46,0x5a,0x33,0x52,0x50,0x4d,0x32,0x59,0x4f,
314 0x64,0x47,0x59,0x6d,0x48,0x79,0x34,0x34,0x52,0x45,0x42,0x2b,0x4b,0x6c,0x42,0x53,
315 0x58,0x6b,0x4d,0x42,0x65,0x6a,0x68,0x4a,0x50,0x46,0x56,0x4e,0x57,0x6b,0x51,0x49,
316 0x4a,0x6c,0x6c,0x4e,0x52,0x51,0x74,0x49,0x43,0x6a,0x4e,0x65,0x53,0x6b,0x31,0x31,
317 0x46,0x68,0x64,0x6a,0x52,0x67,0x45,0x71,0x56,0x58,0x73,0x50,0x41,0x6e,0x4e,0x71,
318 0x53,0x33,0x39,0x31,0x5a,0x54,0x78,0x4d,0x4d,0x7a,0x6c,0x73,0x64,0x41,0x56,0x67,
319 0x44,0x33,0x38,0x74,0x51,0x55,0x31,0x4e,0x52,0x6e,0x45,0x4a,0x62,0x30,0x39,0x67,
320 0x46,0x51,0x39,0x47,0x63,0x32,0x4e,0x4d,0x58,0x6e,0x51,0x77,0x44,0x53,0x68,0x44,
321 0x43,0x48,0x49,0x79,0x42,0x43,0x34,0x78,0x4b,0x53,0x64,0x45,0x62,0x52,0x4d,0x58,
322 0x53,0x41,0x39,0x4a,0x55,0x68,0x41,0x54,0x66,0x78,0x63,0x57,0x59,0x6e,0x6b,0x31,
323 0x65,0x44,0x34,0x42,0x66,0x43,0x34,0x50,0x64,0x6a,0x35,0x65,0x55,0x32,0x78,0x62,
324 0x58,0x33,0x77,0x5a,0x51,0x51,0x49,0x76,0x46,0x32,0x52,0x42,0x64,0x52,0x41,0x45,
325 0x52,0x33,0x77,0x39,0x53,0x31,0x49,0x41,0x45,0x46,0x31,0x52,0x54,0x6e,0x6f,0x6e,
326 0x4a,0x56,0x56,0x41,0x45,0x6a,0x56,0x67,0x42,0x52,0x73,0x30,0x4c,0x51,0x52,0x36,
327 0x61,0x6d,0x6b,0x43,0x65,0x51,0x4d,0x36,0x4c,0x77,0x59,0x4b,0x65,0x58,0x73,0x53,
328 0x58,0x58,0x78,0x53,0x4b,0x55,0x64,0x59,0x45,0x6e,0x4d,0x2f,0x4a,0x31,0x59,0x46,
329 0x44,0x45,0x67,0x79,0x57,0x47,0x74,0x58,0x58,0x41,0x4e,0x6b,0x56,0x68,0x46,0x53,
330 0x65,0x6a,0x41,0x32,0x4b,0x52,0x63,0x37,0x61,0x48,0x70,0x38,0x42,0x57,0x74,0x72,
331 0x45,0x32,0x6f,0x6b,0x58,0x47,0x68,0x43,0x47,0x44,0x49,0x44,0x63,0x32,0x34,0x45,
332 0x49,0x53,0x34,0x42,0x42,0x47,0x4e,0x39,0x52,0x45,0x45,0x53,0x4d,0x51,0x73,0x56,
333 0x48,0x33,0x41,0x41,0x4c,0x6d,0x59,0x55,0x50,0x48,0x38,0x72,0x41,0x42,0x38,0x4d,
334 0x4b,0x46,0x6b,0x4b,0x46,0x6b,0x6c,0x61,0x58,0x47,0x52,0x6c,0x53,0x78,0x45,0x70,
335 0x46,0x54,0x5a,0x61,0x5a,0x52,0x6c,0x50,0x59,0x43,0x4d,0x36,0x4f,0x68,0x4d,0x6c,
336 0x41,0x6e,0x68,0x4d,0x56,0x41,0x3d,0x3d,0x00
337 };
338 char *b64_test; 294 char *b64_test;
339 295
340 plan_tests(1); 296 plan_tests(1);
341 297
342 base64_encode_alloc (random, 1024, &b64_test); 298 base64_encode_alloc(random, 1024, &b64_test);
343 299
344 ok(strcmp(b64_known, b64_test) == 0, 300 ok(strcmp(b64_known, b64_test) == 0, "Test matching a base64 encoded 1024 bytes random string");
345 "Test matching a base64 encoded 1024 bytes random string");
346 301
347 return exit_status(); 302 return exit_status();
348} 303}
349
diff --git a/lib/tests/test_cmd.c b/lib/tests/test_cmd.c
index 02ae11f5..c8867dfb 100644
--- a/lib/tests/test_cmd.c
+++ b/lib/tests/test_cmd.c
@@ -1,20 +1,20 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_cmd.h" 20#include "utils_cmd.h"
@@ -22,27 +22,23 @@
22#include "tap.h" 22#include "tap.h"
23 23
24#define COMMAND_LINE 1024 24#define COMMAND_LINE 1024
25#define UNSET 65530 25#define UNSET 65530
26 26
27char * 27char *get_command(char *const *line) {
28get_command (char *const *line)
29{
30 char *cmd; 28 char *cmd;
31 int i = 0; 29 int i = 0;
32 30
33 asprintf (&cmd, " %s", line[i++]); 31 asprintf(&cmd, " %s", line[i++]);
34 while (line[i] != NULL) { 32 while (line[i] != NULL) {
35 asprintf (&cmd, "%s %s", cmd, line[i]); 33 asprintf(&cmd, "%s %s", cmd, line[i]);
36 i++; 34 i++;
37 } 35 }
38 36
39 return cmd; 37 return cmd;
40} 38}
41 39
42int 40int main(int argc, char **argv) {
43main (int argc, char **argv) 41 char **command_line = malloc(sizeof(char *) * COMMAND_LINE);
44{
45 char **command_line = malloc (sizeof (char *) * COMMAND_LINE);
46 char *command = NULL; 42 char *command = NULL;
47 char *perl; 43 char *perl;
48 output chld_out, chld_err; 44 output chld_out, chld_err;
@@ -51,183 +47,154 @@ main (int argc, char **argv)
51 47
52 plan_tests(51); 48 plan_tests(51);
53 49
54 diag ("Running plain echo command, set one"); 50 diag("Running plain echo command, set one");
55 51
56 /* ensure everything is empty before we begin */ 52 /* ensure everything is empty before we begin */
57 memset (&chld_out, 0, sizeof (output)); 53 memset(&chld_out, 0, sizeof(output));
58 memset (&chld_err, 0, sizeof (output)); 54 memset(&chld_err, 0, sizeof(output));
59 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 55 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
60 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 56 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
61 ok (result == UNSET, "(initialised) Checking exit code is reset"); 57 ok(result == UNSET, "(initialised) Checking exit code is reset");
62 58
63 command_line[0] = strdup ("/bin/echo"); 59 command_line[0] = strdup("/bin/echo");
64 command_line[1] = strdup ("this"); 60 command_line[1] = strdup("this");
65 command_line[2] = strdup ("is"); 61 command_line[2] = strdup("is");
66 command_line[3] = strdup ("test"); 62 command_line[3] = strdup("test");
67 command_line[4] = strdup ("one"); 63 command_line[4] = strdup("one");
68 64
69 command = get_command (command_line); 65 command = get_command(command_line);
70 66
71 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 67 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
72 ok (chld_out.lines == 1, 68 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
73 "(array) Check for expected number of stdout lines"); 69 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
74 ok (chld_err.lines == 0, 70 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(array) Check for expected stdout output");
75 "(array) Check for expected number of stderr lines"); 71 ok(result == 0, "(array) Checking exit code");
76 ok (strcmp (chld_out.line[0], "this is test one") == 0,
77 "(array) Check for expected stdout output");
78 ok (result == 0, "(array) Checking exit code");
79 72
80 /* ensure everything is empty again */ 73 /* ensure everything is empty again */
81 memset (&chld_out, 0, sizeof (output)); 74 memset(&chld_out, 0, sizeof(output));
82 memset (&chld_err, 0, sizeof (output)); 75 memset(&chld_err, 0, sizeof(output));
83 result = UNSET; 76 result = UNSET;
84 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 77 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
85 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 78 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
86 ok (result == UNSET, "(initialised) Checking exit code is reset"); 79 ok(result == UNSET, "(initialised) Checking exit code is reset");
87 80
88 result = cmd_run (command, &chld_out, &chld_err, 0); 81 result = cmd_run(command, &chld_out, &chld_err, 0);
89 82
90 ok (chld_out.lines == 1, 83 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
91 "(string) Check for expected number of stdout lines"); 84 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
92 ok (chld_err.lines == 0, 85 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output");
93 "(string) Check for expected number of stderr lines"); 86 ok(result == 0, "(string) Checking exit code");
94 ok (strcmp (chld_out.line[0], "this is test one") == 0,
95 "(string) Check for expected stdout output");
96 ok (result == 0, "(string) Checking exit code");
97 87
98 diag ("Running plain echo command, set two"); 88 diag("Running plain echo command, set two");
99 89
100 /* ensure everything is empty again */ 90 /* ensure everything is empty again */
101 memset (&chld_out, 0, sizeof (output)); 91 memset(&chld_out, 0, sizeof(output));
102 memset (&chld_err, 0, sizeof (output)); 92 memset(&chld_err, 0, sizeof(output));
103 result = UNSET; 93 result = UNSET;
104 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 94 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
105 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 95 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
106 ok (result == UNSET, "(initialised) Checking exit code is reset"); 96 ok(result == UNSET, "(initialised) Checking exit code is reset");
107 97
108 command_line[0] = strdup ("/bin/echo"); 98 command_line[0] = strdup("/bin/echo");
109 command_line[1] = strdup ("this is test two"); 99 command_line[1] = strdup("this is test two");
110 command_line[2] = NULL; 100 command_line[2] = NULL;
111 command_line[3] = NULL; 101 command_line[3] = NULL;
112 command_line[4] = NULL; 102 command_line[4] = NULL;
113 103
114 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 104 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
115 ok (chld_out.lines == 1, 105 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
116 "(array) Check for expected number of stdout lines"); 106 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
117 ok (chld_err.lines == 0, 107 ok(strcmp(chld_out.line[0], "this is test two") == 0, "(array) Check for expected stdout output");
118 "(array) Check for expected number of stderr lines"); 108 ok(result == 0, "(array) Checking exit code");
119 ok (strcmp (chld_out.line[0], "this is test two") == 0,
120 "(array) Check for expected stdout output");
121 ok (result == 0, "(array) Checking exit code");
122 109
123 /* ensure everything is empty again */ 110 /* ensure everything is empty again */
124 memset (&chld_out, 0, sizeof (output)); 111 memset(&chld_out, 0, sizeof(output));
125 memset (&chld_err, 0, sizeof (output)); 112 memset(&chld_err, 0, sizeof(output));
126 result = UNSET; 113 result = UNSET;
127 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 114 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
128 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 115 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
129 ok (result == UNSET, "(initialised) Checking exit code is reset"); 116 ok(result == UNSET, "(initialised) Checking exit code is reset");
130
131 result = cmd_run (command, &chld_out, &chld_err, 0);
132 117
133 ok (chld_out.lines == 1, 118 result = cmd_run(command, &chld_out, &chld_err, 0);
134 "(string) Check for expected number of stdout lines");
135 ok (chld_err.lines == 0,
136 "(string) Check for expected number of stderr lines");
137 ok (strcmp (chld_out.line[0], "this is test one") == 0,
138 "(string) Check for expected stdout output");
139 ok (result == 0, "(string) Checking exit code");
140 119
120 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
121 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
122 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output");
123 ok(result == 0, "(string) Checking exit code");
141 124
142 /* ensure everything is empty again */ 125 /* ensure everything is empty again */
143 memset (&chld_out, 0, sizeof (output)); 126 memset(&chld_out, 0, sizeof(output));
144 memset (&chld_err, 0, sizeof (output)); 127 memset(&chld_err, 0, sizeof(output));
145 result = UNSET; 128 result = UNSET;
146 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 129 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
147 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 130 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
148 ok (result == UNSET, "(initialised) Checking exit code is reset"); 131 ok(result == UNSET, "(initialised) Checking exit code is reset");
149 132
150 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */ 133 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */
151 command_line[0] = strdup("/bin/echo"); 134 command_line[0] = strdup("/bin/echo");
152 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3"); 135 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3");
153 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated"); 136 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated");
154 137
155 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 138 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
156 ok (chld_out.lines == 3, 139 ok(chld_out.lines == 3, "(array) Check for expected number of stdout lines");
157 "(array) Check for expected number of stdout lines"); 140 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
158 ok (chld_err.lines == 0, 141 ok(strcmp(chld_out.line[0], "this is a test via echo") == 0, "(array) Check line 1 for expected stdout output");
159 "(array) Check for expected number of stderr lines"); 142 ok(strcmp(chld_out.line[1], "line two") == 0, "(array) Check line 2 for expected stdout output");
160 ok (strcmp (chld_out.line[0], "this is a test via echo") == 0, 143 ok(strcmp(chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0,
161 "(array) Check line 1 for expected stdout output"); 144 "(array) Check line 3 for expected stdout output");
162 ok (strcmp (chld_out.line[1], "line two") == 0, 145 ok(result == 0, "(array) Checking exit code");
163 "(array) Check line 2 for expected stdout output");
164 ok (strcmp (chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0,
165 "(array) Check line 3 for expected stdout output");
166 ok (result == 0, "(array) Checking exit code");
167
168
169 146
170 /* ensure everything is empty again */ 147 /* ensure everything is empty again */
171 memset (&chld_out, 0, sizeof (output)); 148 memset(&chld_out, 0, sizeof(output));
172 memset (&chld_err, 0, sizeof (output)); 149 memset(&chld_err, 0, sizeof(output));
173 result = UNSET; 150 result = UNSET;
174 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 151 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
175 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 152 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
176 ok (result == UNSET, "(initialised) Checking exit code is reset"); 153 ok(result == UNSET, "(initialised) Checking exit code is reset");
177 154
178 command = (char *)malloc(COMMAND_LINE); 155 command = (char *)malloc(COMMAND_LINE);
179 strcpy(command, "/bin/echo3456 non-existent command"); 156 strcpy(command, "/bin/echo3456 non-existent command");
180 result = cmd_run (command, &chld_out, &chld_err, 0); 157 result = cmd_run(command, &chld_out, &chld_err, 0);
181
182 ok (chld_out.lines == 0,
183 "Non existent command, so no output");
184 ok (chld_err.lines == 0,
185 "No stderr either");
186 ok (result == 3, "Get return code 3 (?) for non-existent command");
187 158
159 ok(chld_out.lines == 0, "Non existent command, so no output");
160 ok(chld_err.lines == 0, "No stderr either");
161 ok(result == 3, "Get return code 3 (?) for non-existent command");
188 162
189 /* ensure everything is empty again */ 163 /* ensure everything is empty again */
190 memset (&chld_out, 0, sizeof (output)); 164 memset(&chld_out, 0, sizeof(output));
191 memset (&chld_err, 0, sizeof (output)); 165 memset(&chld_err, 0, sizeof(output));
192 result = UNSET; 166 result = UNSET;
193 167
194 command = (char *)malloc(COMMAND_LINE); 168 command = (char *)malloc(COMMAND_LINE);
195 strcpy(command, "/bin/sh non-existent-file"); 169 strcpy(command, "/bin/sh non-existent-file");
196 result = cmd_run (command, &chld_out, &chld_err, 0); 170 result = cmd_run(command, &chld_out, &chld_err, 0);
197
198 ok (chld_out.lines == 0,
199 "/bin/sh returns no stdout when file is missing...");
200 ok (chld_err.lines == 1,
201 "...but does give an error line");
202 ok (strstr(chld_err.line[0],"non-existent-file") != NULL, "And missing filename is in error message");
203 ok (result != 0, "Get non-zero return code from /bin/sh");
204 171
172 ok(chld_out.lines == 0, "/bin/sh returns no stdout when file is missing...");
173 ok(chld_err.lines == 1, "...but does give an error line");
174 ok(strstr(chld_err.line[0], "non-existent-file") != NULL, "And missing filename is in error message");
175 ok(result != 0, "Get non-zero return code from /bin/sh");
205 176
206 /* ensure everything is empty again */ 177 /* ensure everything is empty again */
207 result = UNSET; 178 result = UNSET;
208 179
209 command = (char *)malloc(COMMAND_LINE); 180 command = (char *)malloc(COMMAND_LINE);
210 strcpy(command, "/bin/sh -c 'exit 7'"); 181 strcpy(command, "/bin/sh -c 'exit 7'");
211 result = cmd_run (command, NULL, NULL, 0); 182 result = cmd_run(command, NULL, NULL, 0);
212
213 ok (result == 7, "Get return code 7 from /bin/sh");
214 183
184 ok(result == 7, "Get return code 7 from /bin/sh");
215 185
216 /* ensure everything is empty again */ 186 /* ensure everything is empty again */
217 memset (&chld_out, 0, sizeof (output)); 187 memset(&chld_out, 0, sizeof(output));
218 memset (&chld_err, 0, sizeof (output)); 188 memset(&chld_err, 0, sizeof(output));
219 result = UNSET; 189 result = UNSET;
220 190
221 command = (char *)malloc(COMMAND_LINE); 191 command = (char *)malloc(COMMAND_LINE);
222 strcpy(command, "/bin/non-existent-command"); 192 strcpy(command, "/bin/non-existent-command");
223 result = cmd_run (command, &chld_out, &chld_err, 0); 193 result = cmd_run(command, &chld_out, &chld_err, 0);
224
225 ok (chld_out.lines == 0,
226 "/bin/non-existent-command returns no stdout...");
227 ok (chld_err.lines == 0,
228 "...and no stderr output either");
229 ok (result == 3, "Get return code 3 = UNKNOWN when command does not exist");
230 194
195 ok(chld_out.lines == 0, "/bin/non-existent-command returns no stdout...");
196 ok(chld_err.lines == 0, "...and no stderr output either");
197 ok(result == 3, "Get return code 3 = UNKNOWN when command does not exist");
231 198
232 return exit_status (); 199 return exit_status();
233} 200}
diff --git a/lib/tests/test_disk.c b/lib/tests/test_disk.c
index e283fe2e..c18db7a4 100644
--- a/lib/tests/test_disk.c
+++ b/lib/tests/test_disk.c
@@ -1,36 +1,31 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_disk.h" 20#include "utils_disk.h"
21#include "tap.h" 21#include "tap.h"
22#include "regex.h" 22#include "regex.h"
23 23
24void np_test_mount_entry_regex (struct mount_entry *dummy_mount_list, 24void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc);
25 char *regstr, int cflags, int expect,
26 char *desc);
27 25
28 26int main(int argc, char **argv) {
29int 27 struct name_list *exclude_filesystem = NULL;
30main (int argc, char **argv) 28 struct name_list *exclude_fstype = NULL;
31{
32 struct name_list *exclude_filesystem=NULL;
33 struct name_list *exclude_fstype=NULL;
34 struct name_list *dummy_mountlist = NULL; 29 struct name_list *dummy_mountlist = NULL;
35 struct name_list *temp_name; 30 struct name_list *temp_name;
36 struct parameter_list *paths = NULL; 31 struct parameter_list *paths = NULL;
@@ -44,19 +39,19 @@ main (int argc, char **argv)
44 39
45 plan_tests(33); 40 plan_tests(33);
46 41
47 ok( np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list"); 42 ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
48 np_add_name(&exclude_filesystem, "/var/log"); 43 np_add_name(&exclude_filesystem, "/var/log");
49 ok( np_find_name(exclude_filesystem, "/var/log") == true, "is in list now"); 44 ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
50 ok( np_find_name(exclude_filesystem, "/home") == false, "/home not in list"); 45 ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list");
51 np_add_name(&exclude_filesystem, "/home"); 46 np_add_name(&exclude_filesystem, "/home");
52 ok( np_find_name(exclude_filesystem, "/home") == true, "is in list now"); 47 ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
53 ok( np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list"); 48 ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
54 49
55 ok( np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list"); 50 ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
56 np_add_name(&exclude_fstype, "iso9660"); 51 np_add_name(&exclude_fstype, "iso9660");
57 ok( np_find_name(exclude_fstype, "iso9660") == true, "is in list now"); 52 ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
58 53
59 ok( np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables"); 54 ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables");
60 55
61 /* 56 /*
62 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) { 57 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) {
@@ -64,55 +59,35 @@ main (int argc, char **argv)
64 } 59 }
65 */ 60 */
66 61
67 me = (struct mount_entry *) malloc(sizeof *me); 62 me = (struct mount_entry *)malloc(sizeof *me);
68 me->me_devname = strdup("/dev/c0t0d0s0"); 63 me->me_devname = strdup("/dev/c0t0d0s0");
69 me->me_mountdir = strdup("/"); 64 me->me_mountdir = strdup("/");
70 *mtail = me; 65 *mtail = me;
71 mtail = &me->me_next; 66 mtail = &me->me_next;
72 67
73 me = (struct mount_entry *) malloc(sizeof *me); 68 me = (struct mount_entry *)malloc(sizeof *me);
74 me->me_devname = strdup("/dev/c1t0d1s0"); 69 me->me_devname = strdup("/dev/c1t0d1s0");
75 me->me_mountdir = strdup("/var"); 70 me->me_mountdir = strdup("/var");
76 *mtail = me; 71 *mtail = me;
77 mtail = &me->me_next; 72 mtail = &me->me_next;
78 73
79 me = (struct mount_entry *) malloc(sizeof *me); 74 me = (struct mount_entry *)malloc(sizeof *me);
80 me->me_devname = strdup("/dev/c2t0d0s0"); 75 me->me_devname = strdup("/dev/c2t0d0s0");
81 me->me_mountdir = strdup("/home"); 76 me->me_mountdir = strdup("/home");
82 *mtail = me; 77 *mtail = me;
83 mtail = &me->me_next; 78 mtail = &me->me_next;
84 79
85 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), 80 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
86 cflags, 3, strdup("a")); 81 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3, strdup("regex on dev names:"));
87 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), 82 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0, strdup("regex on non existent dev/path:"));
88 cflags, 3,strdup("regex on dev names:")); 83 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0, strdup("regi on non existent dev/path:"));
89 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), 84 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3, strdup("partial devname regex match:"));
90 cflags, 0, 85 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1, strdup("partial devname regex match:"));
91 strdup("regex on non existent dev/path:")); 86 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:"));
92 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), 87 np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1, strdup("partial pathname regex match:"));
93 cflags | REG_ICASE,0, 88 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:"));
94 strdup("regi on non existent dev/path:")); 89 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:"));
95 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), 90 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:"));
96 cflags, 3,
97 strdup("partial devname regex match:"));
98 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"),
99 cflags, 1,
100 strdup("partial devname regex match:"));
101 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"),
102 cflags | REG_ICASE, 1,
103 strdup("partial devname regi match:"));
104 np_test_mount_entry_regex(dummy_mount_list, strdup("home"),
105 cflags, 1,
106 strdup("partial pathname regex match:"));
107 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"),
108 cflags | REG_ICASE, 1,
109 strdup("partial pathname regi match:"));
110 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"),
111 cflags, 2,
112 strdup("grouped regex pathname match:"));
113 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"),
114 cflags | REG_ICASE, 2,
115 strdup("grouped regi pathname match:"));
116 91
117 np_add_parameter(&paths, "/home/groups"); 92 np_add_parameter(&paths, "/home/groups");
118 np_add_parameter(&paths, "/var"); 93 np_add_parameter(&paths, "/var");
@@ -124,20 +99,20 @@ main (int argc, char **argv)
124 for (p = paths; p; p = p->name_next) { 99 for (p = paths; p; p = p->name_next) {
125 struct mount_entry *temp_me; 100 struct mount_entry *temp_me;
126 temp_me = p->best_match; 101 temp_me = p->best_match;
127 if (! strcmp(p->name, "/home/groups")) { 102 if (!strcmp(p->name, "/home/groups")) {
128 ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home"); 103 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home");
129 } else if (! strcmp(p->name, "/var")) { 104 } else if (!strcmp(p->name, "/var")) {
130 ok( temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var"); 105 ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
131 } else if (! strcmp(p->name, "/tmp")) { 106 } else if (!strcmp(p->name, "/tmp")) {
132 ok( temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /"); 107 ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
133 } else if (! strcmp(p->name, "/home/tonvoon")) { 108 } else if (!strcmp(p->name, "/home/tonvoon")) {
134 ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home"); 109 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home");
135 } else if (! strcmp(p->name, "/dev/c2t0d0s0")) { 110 } else if (!strcmp(p->name, "/dev/c2t0d0s0")) {
136 ok( temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0"); 111 ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0");
137 } 112 }
138 } 113 }
139 114
140 paths = NULL; /* Bad boy - should free, but this is a test suite */ 115 paths = NULL; /* Bad boy - should free, but this is a test suite */
141 np_add_parameter(&paths, "/home/groups"); 116 np_add_parameter(&paths, "/home/groups");
142 np_add_parameter(&paths, "/var"); 117 np_add_parameter(&paths, "/var");
143 np_add_parameter(&paths, "/tmp"); 118 np_add_parameter(&paths, "/tmp");
@@ -146,31 +121,31 @@ main (int argc, char **argv)
146 121
147 np_set_best_match(paths, dummy_mount_list, true); 122 np_set_best_match(paths, dummy_mount_list, true);
148 for (p = paths; p; p = p->name_next) { 123 for (p = paths; p; p = p->name_next) {
149 if (! strcmp(p->name, "/home/groups")) { 124 if (!strcmp(p->name, "/home/groups")) {
150 ok( ! p->best_match , "/home/groups correctly not found"); 125 ok(!p->best_match, "/home/groups correctly not found");
151 } else if (! strcmp(p->name, "/var")) { 126 } else if (!strcmp(p->name, "/var")) {
152 ok( p->best_match, "/var found"); 127 ok(p->best_match, "/var found");
153 } else if (! strcmp(p->name, "/tmp")) { 128 } else if (!strcmp(p->name, "/tmp")) {
154 ok(! p->best_match, "/tmp correctly not found"); 129 ok(!p->best_match, "/tmp correctly not found");
155 } else if (! strcmp(p->name, "/home/tonvoon")) { 130 } else if (!strcmp(p->name, "/home/tonvoon")) {
156 ok(! p->best_match, "/home/tonvoon not found"); 131 ok(!p->best_match, "/home/tonvoon not found");
157 } else if (! strcmp(p->name, "/home")) { 132 } else if (!strcmp(p->name, "/home")) {
158 ok( p->best_match, "/home found"); 133 ok(p->best_match, "/home found");
159 } 134 }
160 } 135 }
161 136
162 /* test deleting first element in paths */ 137 /* test deleting first element in paths */
163 paths = np_del_parameter(paths, NULL); 138 paths = np_del_parameter(paths, NULL);
164 for (p = paths; p; p = p->name_next) { 139 for (p = paths; p; p = p->name_next) {
165 if (! strcmp(p->name, "/home/groups")) 140 if (!strcmp(p->name, "/home/groups"))
166 found = 1; 141 found = 1;
167 } 142 }
168 ok(found == 0, "first element successfully deleted"); 143 ok(found == 0, "first element successfully deleted");
169 found = 0; 144 found = 0;
170 145
171 p=paths; 146 p = paths;
172 while (p) { 147 while (p) {
173 if (! strcmp(p->name, "/tmp")) 148 if (!strcmp(p->name, "/tmp"))
174 p = np_del_parameter(p, prev); 149 p = np_del_parameter(p, prev);
175 else { 150 else {
176 prev = p; 151 prev = p;
@@ -179,7 +154,7 @@ main (int argc, char **argv)
179 } 154 }
180 155
181 for (p = paths; p; p = p->name_next) { 156 for (p = paths; p; p = p->name_next) {
182 if (! strcmp(p->name, "/tmp")) 157 if (!strcmp(p->name, "/tmp"))
183 found = 1; 158 found = 1;
184 if (p->name_next) 159 if (p->name_next)
185 prev = p; 160 prev = p;
@@ -190,7 +165,7 @@ main (int argc, char **argv)
190 165
191 p = np_del_parameter(last, prev); 166 p = np_del_parameter(last, prev);
192 for (p = paths; p; p = p->name_next) { 167 for (p = paths; p; p = p->name_next) {
193 if (! strcmp(p->name, "/home")) 168 if (!strcmp(p->name, "/home"))
194 found = 1; 169 found = 1;
195 last = p; 170 last = p;
196 count++; 171 count++;
@@ -198,27 +173,20 @@ main (int argc, char **argv)
198 ok(found == 0, "last (/home) element successfully deleted"); 173 ok(found == 0, "last (/home) element successfully deleted");
199 ok(count == 2, "two elements remaining"); 174 ok(count == 2, "two elements remaining");
200 175
201
202 return exit_status(); 176 return exit_status();
203} 177}
204 178
205 179void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) {
206void
207np_test_mount_entry_regex (struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc)
208{
209 int matches = 0; 180 int matches = 0;
210 regex_t re; 181 regex_t re;
211 struct mount_entry *me; 182 struct mount_entry *me;
212 if (regcomp(&re,regstr, cflags) == 0) { 183 if (regcomp(&re, regstr, cflags) == 0) {
213 for (me = dummy_mount_list; me; me= me->me_next) { 184 for (me = dummy_mount_list; me; me = me->me_next) {
214 if(np_regex_match_mount_entry(me,&re)) 185 if (np_regex_match_mount_entry(me, &re))
215 matches++; 186 matches++;
216 } 187 }
217 ok( matches == expect, 188 ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches);
218 "%s '%s' matched %i/3 entries. ok: %i/3",
219 desc, regstr, expect, matches);
220 189
221 } else 190 } else
222 ok ( false, "regex '%s' not compilable", regstr); 191 ok(false, "regex '%s' not compilable", regstr);
223} 192}
224
diff --git a/lib/tests/test_generic_output b/lib/tests/test_generic_output
new file mode 100755
index 00000000..51e299a0
--- /dev/null
+++ b/lib/tests/test_generic_output
Binary files differ
diff --git a/lib/tests/test_generic_output.c b/lib/tests/test_generic_output.c
new file mode 100644
index 00000000..e67aefc9
--- /dev/null
+++ b/lib/tests/test_generic_output.c
@@ -0,0 +1,315 @@
1#include "../lib/output.h"
2#include "../../tap/tap.h"
3#include "./states.h"
4
5#include <string.h>
6
7void test_one_subcheck(void);
8void test_two_subchecks(void);
9
10void test_perfdata_formatting(void);
11void test_perfdata_formatting2(void);
12
13void test_deep_check_hierarchy(void);
14void test_deep_check_hierarchy2(void);
15
16void test_default_states1(void);
17void test_default_states2(void);
18
19int main(void) {
20 plan_tests(19);
21
22 diag("Simple test with one subcheck");
23 test_one_subcheck();
24
25 diag("Test with two subchecks");
26 test_two_subchecks();
27
28 diag("Test for performance data formatting");
29 test_perfdata_formatting();
30
31 diag("Another test for performance data formatting");
32 test_perfdata_formatting2();
33
34 diag("Test for deeper hierarchies");
35 test_deep_check_hierarchy();
36
37 diag("Another test for deeper hierarchies");
38 test_deep_check_hierarchy2();
39
40 diag("Testing the default state logic");
41 test_default_states1();
42
43 diag("Testing the default state logic #2");
44 test_default_states2();
45
46 return exit_status();
47}
48
49void test_one_subcheck(void) {
50 mp_subcheck sc1 = mp_subcheck_init();
51
52 sc1.output = "foobar";
53 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
54
55 mp_check check = mp_check_init();
56 mp_add_subcheck_to_check(&check, sc1);
57
58 ok(mp_compute_check_state(check) == STATE_WARNING, "Main state should be warning");
59
60 char *output = mp_fmt_output(check);
61
62 // diag("Formatted output");
63 // diag(output);
64
65 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
66 "\t\\_[WARNING] - foobar\n";
67
68 // diag("Expected output");
69 // diag(expected);
70
71 ok(strcmp(output, expected) == 0, "Simple output test");
72}
73
74void test_perfdata_formatting2(void) {
75 mp_perfdata pd1 = perfdata_init();
76 mp_perfdata pd2 = perfdata_init();
77
78 pd1.label = "foo";
79 pd2.label = "bar";
80
81 pd1 = mp_set_pd_value(pd1, 23);
82 pd2 = mp_set_pd_value(pd2, 1LL);
83
84 pd_list *tmp = pd_list_init();
85
86 pd_list_append(tmp, pd1);
87 pd_list_append(tmp, pd2);
88
89 char *result = pd_list_to_string(*tmp);
90
91 ok(strcmp(result, "foo=23;;; bar=1;;;") == 0, "Perfdata string formatting");
92}
93
94void test_perfdata_formatting(void) {
95 mp_perfdata pd1 = perfdata_init();
96
97 pd1.uom = "s";
98 pd1.label = "foo";
99
100 pd1 = mp_set_pd_value(pd1, 23);
101
102 char *pd_string = pd_to_string(pd1);
103
104 ok(strcmp(pd_string, "foo=23s;;;") == 0, "Perfdata string formatting");
105}
106
107void test_two_subchecks(void) {
108 mp_subcheck sc1 = mp_subcheck_init();
109
110 sc1.output = "foobar";
111 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
112
113 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state directly after setting it");
114
115 mp_perfdata pd1 = perfdata_init();
116
117 pd1 = mp_set_pd_value(pd1, 23);
118
119 pd1.uom = "s";
120 pd1.label = "foo";
121
122 mp_add_perfdata_to_subcheck(&sc1, pd1);
123
124 mp_subcheck sc2 = mp_subcheck_init();
125 sc2.output = "baz";
126 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
127
128 ok(mp_compute_subcheck_state(sc2) == STATE_OK, "Test subcheck 2 state after setting it");
129
130 mp_add_subcheck_to_subcheck(&sc1, sc2);
131
132 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state after adding a subcheck");
133
134 mp_check check = mp_check_init();
135 mp_add_subcheck_to_check(&check, sc1);
136
137 ok(mp_compute_check_state(check) == STATE_WARNING, "Test main check result");
138
139 char *output = mp_fmt_output(check);
140
141 // diag("Formatted output. Length: %u", strlen(output));
142 // diag(output);
143
144 ok(output != NULL, "Output should not be NULL");
145
146 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
147 "\t\\_[WARNING] - foobar\n"
148 "\t\t\\_[OK] - baz\n"
149 "|foo=23s;;; \n";
150
151 // diag("Expected output. Length: %u", strlen(expected));
152 // diag(expected);
153
154 ok(strcmp(output, expected) == 0, "Output is as expected");
155}
156
157void test_deep_check_hierarchy(void) {
158 // level 4
159 mp_subcheck sc4 = mp_subcheck_init();
160 sc4.output = "level4";
161 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
162
163 // level 3
164 mp_subcheck sc3 = mp_subcheck_init();
165 sc3.output = "level3";
166 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
167
168 // level 2
169 mp_subcheck sc2 = mp_subcheck_init();
170 sc2.output = "baz";
171 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
172
173 // level 1
174 mp_subcheck sc1 = mp_subcheck_init();
175
176 sc1.output = "foobar";
177 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
178
179 mp_perfdata pd1 = perfdata_init();
180
181 pd1.uom = "s";
182 pd1.label = "foo";
183 pd1 = mp_set_pd_value(pd1, 23);
184
185 mp_add_perfdata_to_subcheck(&sc1, pd1);
186
187 // main check
188 mp_check check = mp_check_init();
189
190 mp_add_subcheck_to_subcheck(&sc3, sc4);
191 mp_add_subcheck_to_subcheck(&sc2, sc3);
192 mp_add_subcheck_to_subcheck(&sc1, sc2);
193 mp_add_subcheck_to_check(&check, sc1);
194
195 char *output = mp_fmt_output(check);
196
197 size_t output_length = strlen(output);
198
199 // diag("Formatted output of length %i", output_length);
200 // diag(output);
201
202 ok(output != NULL, "Output should not be NULL");
203
204 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
205 "\t\\_[WARNING] - foobar\n"
206 "\t\t\\_[OK] - baz\n"
207 "\t\t\t\\_[OK] - level3\n"
208 "\t\t\t\t\\_[OK] - level4\n"
209 "|foo=23s;;; \n";
210
211 size_t expected_length = strlen(expected);
212
213 // diag("Expected output of length: %i", expected_length);
214 // diag(expected);
215
216 ok(output_length == expected_length, "Outputs are of equal length");
217 ok(strcmp(output, expected) == 0, "Output is as expected");
218}
219
220void test_deep_check_hierarchy2(void) {
221 // level 1
222 mp_subcheck sc1 = mp_subcheck_init();
223
224 sc1.output = "foobar";
225 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
226
227 mp_perfdata pd1 = perfdata_init();
228 pd1.uom = "s";
229 pd1.label = "foo";
230 pd1 = mp_set_pd_value(pd1, 23);
231
232 mp_add_perfdata_to_subcheck(&sc1, pd1);
233
234 // level 2
235 mp_subcheck sc2 = mp_subcheck_init();
236 sc2.output = "baz";
237 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
238
239 mp_perfdata pd2 = perfdata_init();
240 pd2.uom = "B";
241 pd2.label = "baz";
242 pd2 = mp_set_pd_value(pd2, 1024);
243 mp_add_perfdata_to_subcheck(&sc2, pd2);
244
245 // level 3
246 mp_subcheck sc3 = mp_subcheck_init();
247 sc3.output = "level3";
248 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
249
250 mp_perfdata pd3 = perfdata_init();
251 pd3.label = "floatMe";
252 pd3 = mp_set_pd_value(pd3, 1024.1024);
253 mp_add_perfdata_to_subcheck(&sc3, pd3);
254
255 // level 4
256 mp_subcheck sc4 = mp_subcheck_init();
257 sc4.output = "level4";
258 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
259
260 mp_check check = mp_check_init();
261
262 mp_add_subcheck_to_subcheck(&sc3, sc4);
263 mp_add_subcheck_to_subcheck(&sc2, sc3);
264 mp_add_subcheck_to_subcheck(&sc1, sc2);
265 mp_add_subcheck_to_check(&check, sc1);
266
267 char *output = mp_fmt_output(check);
268
269 // diag("Formatted output of length: %i", strlen(output));
270 // diag(output);
271
272 ok(output != NULL, "Output should not be NULL");
273
274 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
275 "\t\\_[WARNING] - foobar\n"
276 "\t\t\\_[OK] - baz\n"
277 "\t\t\t\\_[OK] - level3\n"
278 "\t\t\t\t\\_[OK] - level4\n"
279 "|foo=23s;;; baz=1024B;;; floatMe=1024.102400;;; \n";
280
281 // diag("Expected output of length: %i", strlen(expected));
282 // diag(expected);
283
284 ok(strcmp(output, expected) == 0, "Output is as expected");
285}
286
287void test_default_states1(void) {
288 mp_subcheck sc = mp_subcheck_init();
289
290 mp_state_enum state1 = mp_compute_subcheck_state(sc);
291 ok(state1 == STATE_UNKNOWN, "Default default state is Unknown");
292
293 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
294
295 mp_state_enum state2 = mp_compute_subcheck_state(sc);
296 ok(state2 == STATE_CRITICAL, "Default state is Critical");
297
298 sc = mp_set_subcheck_state(sc, STATE_OK);
299
300 mp_state_enum state3 = mp_compute_subcheck_state(sc);
301 ok(state3 == STATE_OK, "Default state is Critical");
302}
303
304void test_default_states2(void) {
305 mp_check check = mp_check_init();
306
307 mp_subcheck sc = mp_subcheck_init();
308 sc.output = "placeholder";
309 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
310
311 mp_add_subcheck_to_check(&check, sc);
312
313 mp_state_enum result_state = mp_compute_check_state(check);
314 ok(result_state == STATE_CRITICAL, "Derived state is the proper default state");
315}
diff --git a/lib/tests/test_generic_output.t b/lib/tests/test_generic_output.t
new file mode 100644
index 00000000..48c2ddf4
--- /dev/null
+++ b/lib/tests/test_generic_output.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_generic_output") {
4 plan skip_all => "./test_generic_output not compiled - please enable libtap library to test";
5}
6exec "./test_generic_output";
diff --git a/lib/tests/test_ini1.c b/lib/tests/test_ini1.c
index 6843bac2..246c1250 100644
--- a/lib/tests/test_ini1.c
+++ b/lib/tests/test_ini1.c
@@ -1,20 +1,20 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_base.h" 20#include "utils_base.h"
@@ -29,81 +29,93 @@ void my_free(char *string) {
29 } 29 }
30} 30}
31 31
32char* 32char *list2str(np_arg_list *optlst) {
33list2str(np_arg_list *optlst) 33 char *optstr = NULL;
34{
35 char *optstr=NULL;
36 np_arg_list *optltmp; 34 np_arg_list *optltmp;
37 35
38 /* Put everything as a space-separated string */ 36 /* Put everything as a space-separated string */
39 asprintf(&optstr, ""); 37 asprintf(&optstr, "");
40 while (optlst) { 38 while (optlst) {
41 asprintf(&optstr, "%s%s ", optstr, optlst->arg); 39 asprintf(&optstr, "%s%s ", optstr, optlst->arg);
42 optltmp=optlst; 40 optltmp = optlst;
43 optlst=optlst->next; 41 optlst = optlst->next;
44 free(optltmp); 42 free(optltmp);
45 } 43 }
46 /* Strip last whitespace */ 44 /* Strip last whitespace */
47 if (strlen(optstr)>1) optstr[strlen(optstr)-1]='\0'; 45 if (strlen(optstr) > 1)
46 optstr[strlen(optstr) - 1] = '\0';
48 47
49 return optstr; 48 return optstr;
50} 49}
51 50
52int 51int main(int argc, char **argv) {
53main (int argc, char **argv) 52 char *optstr = NULL;
54{
55 char *optstr=NULL;
56 53
57 plan_tests(12); 54 plan_tests(12);
58 55
59 optstr=list2str(np_get_defaults("section@./config-tiny.ini", "check_disk")); 56 optstr = list2str(np_get_defaults("section@./config-tiny.ini", "check_disk"));
60 ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "config-tiny.ini's section as expected"); 57 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "config-tiny.ini's section as expected");
61 my_free(optstr); 58 my_free(optstr);
62 59
63 optstr=list2str(np_get_defaults("@./config-tiny.ini", "section")); 60 optstr = list2str(np_get_defaults("@./config-tiny.ini", "section"));
64 ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "Used default section name, without specific"); 61 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "Used default section name, without specific");
65 my_free(optstr); 62 my_free(optstr);
66 63
67 optstr=list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); 64 optstr = list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk"));
68 ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); 65 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected");
69 my_free(optstr); 66 my_free(optstr);
70 67
71 optstr=list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk")); 68 optstr = list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk"));
72 ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name"); 69 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name");
73 my_free(optstr); 70 my_free(optstr);
74 71
75 optstr=list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk")); 72 optstr = list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk"));
76 ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's section2 with whitespace before section name"); 73 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section2 with whitespace before section name");
77 my_free(optstr); 74 my_free(optstr);
78 75
79 optstr=list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk")); 76 optstr = list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk"));
80 ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's section3 with whitespace after section name"); 77 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section3 with whitespace after section name");
81 my_free(optstr); 78 my_free(optstr);
82 79
83 optstr=list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); 80 optstr = list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk"));
84 ok( !strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected"); 81 ok(!strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected");
85 my_free(optstr); 82 my_free(optstr);
86 83
87 optstr=list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk")); 84 optstr = list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk"));
88 ok( !strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected"); 85 ok(!strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected");
89 my_free(optstr); 86 my_free(optstr);
90 87
91 optstr=list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk")); 88 optstr = list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk"));
92 ok( !strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments"); 89 ok(!strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments");
93 my_free(optstr); 90 my_free(optstr);
94 91
95 optstr=list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk")); 92 optstr = list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk"));
96 ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected"); 93 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected");
97 my_free(optstr); 94 my_free(optstr);
98 95
99 optstr=list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk")); 96 optstr = list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk"));
100 ok( !strcmp(optstr, "--foo=bar --bar=foo"), "plugin.ini's section_twice defined twice in the file"); 97 ok(!strcmp(optstr, "--foo=bar --bar=foo"), "plugin.ini's section_twice defined twice in the file");
101 my_free(optstr); 98 my_free(optstr);
102 99
103 optstr=list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp")); 100 optstr = list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp"));
104 ok( !strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --jail"), "Long options"); 101 ok(!strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar "
102 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
103 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
104 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
105 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
106 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
107 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --expect=Foo bar BAZ yadda yadda "
108 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
109 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo "
110 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
111 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
112 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
113 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
114 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
115 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo "
116 "bar BAZ yadda yadda yadda --jail"),
117 "Long options");
105 my_free(optstr); 118 my_free(optstr);
106 119
107 return exit_status(); 120 return exit_status();
108} 121}
109
diff --git a/lib/tests/test_ini3.c b/lib/tests/test_ini3.c
index 8a2a0414..2186e4bb 100644
--- a/lib/tests/test_ini3.c
+++ b/lib/tests/test_ini3.c
@@ -1,26 +1,24 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "parse_ini.h" 19#include "parse_ini.h"
20 20
21int 21int main(int argc, char **argv) {
22main (int argc, char **argv)
23{
24 22
25 /* 23 /*
26 * This is for testing arguments expected to die. 24 * This is for testing arguments expected to die.
@@ -30,4 +28,3 @@ main (int argc, char **argv)
30 28
31 return 0; 29 return 0;
32} 30}
33
diff --git a/lib/tests/test_opts1.c b/lib/tests/test_opts1.c
index 077c5b63..984183d3 100644
--- a/lib/tests/test_opts1.c
+++ b/lib/tests/test_opts1.c
@@ -1,19 +1,19 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16*****************************************************************************/ 16 *****************************************************************************/
17 17
18#include "common.h" 18#include "common.h"
19#include "utils_base.h" 19#include "utils_base.h"
@@ -40,23 +40,24 @@ void my_free(int *argc, char **newargv, char **argv) {
40#else 40#else
41void my_free(int *argc, char **newargv, char **argv) { 41void my_free(int *argc, char **newargv, char **argv) {
42 /* Free stuff (and print while we're at it) */ 42 /* Free stuff (and print while we're at it) */
43 int i, freeflag=1; 43 int i, freeflag = 1;
44 printf (" Arg(%i): ", *argc+1); 44 printf(" Arg(%i): ", *argc + 1);
45 printf ("'%s' ", newargv[0]); 45 printf("'%s' ", newargv[0]);
46 for (i=1; i<*argc; i++) { 46 for (i = 1; i < *argc; i++) {
47 printf ("'%s' ", newargv[i]); 47 printf("'%s' ", newargv[i]);
48 /* Stop freeing when we get to the start of the original array */ 48 /* Stop freeing when we get to the start of the original array */
49 if (freeflag) { 49 if (freeflag) {
50 if (newargv[i] == argv[1]) 50 if (newargv[i] == argv[1])
51 freeflag=0; 51 freeflag = 0;
52 else 52 else
53 free(newargv[i]); 53 free(newargv[i]);
54 } 54 }
55 } 55 }
56 printf ("\n"); 56 printf("\n");
57 /* Free only if it's a different array */ 57 /* Free only if it's a different array */
58 if (newargv != argv) free(newargv); 58 if (newargv != argv)
59 *argc=0; 59 free(newargv);
60 *argc = 0;
60} 61}
61#endif 62#endif
62 63
@@ -67,9 +68,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
67 printf(" Argument count doesn't match!\n"); 68 printf(" Argument count doesn't match!\n");
68 return 0; 69 return 0;
69 } 70 }
70 for (i=0; i<=i1; i++) { 71 for (i = 0; i <= i1; i++) {
71 if (a1[i]==NULL && a2[i]==NULL) continue; 72 if (a1[i] == NULL && a2[i] == NULL)
72 if (a1[i]==NULL || a2[i]==NULL) { 73 continue;
74 if (a1[i] == NULL || a2[i] == NULL) {
73 printf(" Argument # %i null in one array!\n", i); 75 printf(" Argument # %i null in one array!\n", i);
74 return 0; 76 return 0;
75 } 77 }
@@ -81,59 +83,58 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
81 return 1; 83 return 1;
82} 84}
83 85
84int 86int main(int argc, char **argv) {
85main (int argc, char **argv) 87 char **argv_new = NULL;
86{
87 char **argv_new=NULL;
88 int i, argc_test; 88 int i, argc_test;
89 89
90 plan_tests(5); 90 plan_tests(5);
91 91
92 { 92 {
93 char *argv_test[] = {"prog_name", (char *) NULL}; 93 char *argv_test[] = {"prog_name", (char *)NULL};
94 argc_test=1; 94 argc_test = 1;
95 char *argv_known[] = {"prog_name", (char *) NULL}; 95 char *argv_known[] = {"prog_name", (char *)NULL};
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 96 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
97 ok(array_diff(argc_test, argv_new, 1, argv_known), "No opts, returns correct argv/argc"); 97 ok(array_diff(argc_test, argv_new, 1, argv_known), "No opts, returns correct argv/argc");
98 my_free(&argc_test, argv_new, argv_test); 98 my_free(&argc_test, argv_new, argv_test);
99 } 99 }
100 100
101 { 101 {
102 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 102 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
103 argc_test=5; 103 argc_test = 5;
104 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 104 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 105 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
106 ok(array_diff(argc_test, argv_new, 5, argv_known), "No extra opts, verbatim copy of argv"); 106 ok(array_diff(argc_test, argv_new, 5, argv_known), "No extra opts, verbatim copy of argv");
107 my_free(&argc_test, argv_new, argv_test); 107 my_free(&argc_test, argv_new, argv_test);
108 } 108 }
109 109
110 { 110 {
111 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *) NULL}; 111 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *)NULL};
112 argc_test=2; 112 argc_test = 2;
113 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *) NULL}; 113 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *)NULL};
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 114 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
115 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section"); 115 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section");
116 my_free(&argc_test, argv_new, argv_test); 116 my_free(&argc_test, argv_new, argv_test);
117 } 117 }
118 118
119 { 119 {
120 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *) NULL}; 120 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *)NULL};
121 argc_test=4; 121 argc_test = 4;
122 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *) NULL}; 122 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *)NULL};
123 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 123 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
124 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice"); 124 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice");
125 my_free(&argc_test, argv_new, argv_test); 125 my_free(&argc_test, argv_new, argv_test);
126 } 126 }
127 127
128 { 128 {
129 char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini", "--arg2", (char *) NULL}; 129 char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini",
130 argc_test=6; 130 "--arg2", (char *)NULL};
131 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two", "--arg1=val1", "--arg2", (char *) NULL}; 131 argc_test = 6;
132 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 132 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two",
133 "--arg1=val1", "--arg2", (char *)NULL};
134 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
133 ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections"); 135 ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections");
134 my_free(&argc_test, argv_new, argv_test); 136 my_free(&argc_test, argv_new, argv_test);
135 } 137 }
136 138
137 return exit_status(); 139 return exit_status();
138} 140}
139
diff --git a/lib/tests/test_opts2.c b/lib/tests/test_opts2.c
index 780220ee..23496617 100644
--- a/lib/tests/test_opts2.c
+++ b/lib/tests/test_opts2.c
@@ -1,19 +1,19 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16*****************************************************************************/ 16 *****************************************************************************/
17 17
18#include "common.h" 18#include "common.h"
19#include "utils_base.h" 19#include "utils_base.h"
@@ -23,23 +23,24 @@
23 23
24void my_free(int *argc, char **newargv, char **argv) { 24void my_free(int *argc, char **newargv, char **argv) {
25 /* Free stuff (and print while we're at it) */ 25 /* Free stuff (and print while we're at it) */
26 int i, freeflag=1; 26 int i, freeflag = 1;
27 printf (" Arg(%i): ", *argc+1); 27 printf(" Arg(%i): ", *argc + 1);
28 printf ("'%s' ", newargv[0]); 28 printf("'%s' ", newargv[0]);
29 for (i=1; i<*argc; i++) { 29 for (i = 1; i < *argc; i++) {
30 printf ("'%s' ", newargv[i]); 30 printf("'%s' ", newargv[i]);
31 /* Stop freeing when we get to the start of the original array */ 31 /* Stop freeing when we get to the start of the original array */
32 if (freeflag) { 32 if (freeflag) {
33 if (newargv[i] == argv[1]) 33 if (newargv[i] == argv[1])
34 freeflag=0; 34 freeflag = 0;
35 else 35 else
36 free(newargv[i]); 36 free(newargv[i]);
37 } 37 }
38 } 38 }
39 printf ("\n"); 39 printf("\n");
40 /* Free only if it's a different array */ 40 /* Free only if it's a different array */
41 if (newargv != argv) free(newargv); 41 if (newargv != argv)
42 *argc=0; 42 free(newargv);
43 *argc = 0;
43} 44}
44 45
45int array_diff(int i1, char **a1, int i2, char **a2) { 46int array_diff(int i1, char **a1, int i2, char **a2) {
@@ -49,9 +50,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
49 printf(" Argument count doesn't match!\n"); 50 printf(" Argument count doesn't match!\n");
50 return 0; 51 return 0;
51 } 52 }
52 for (i=0; i<=i1; i++) { 53 for (i = 0; i <= i1; i++) {
53 if (a1[i]==NULL && a2[i]==NULL) continue; 54 if (a1[i] == NULL && a2[i] == NULL)
54 if (a1[i]==NULL || a2[i]==NULL) { 55 continue;
56 if (a1[i] == NULL || a2[i] == NULL) {
55 printf(" Argument # %i null in one array!\n", i); 57 printf(" Argument # %i null in one array!\n", i);
56 return 0; 58 return 0;
57 } 59 }
@@ -63,59 +65,77 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
63 return 1; 65 return 1;
64} 66}
65 67
66int 68int main(int argc, char **argv) {
67main (int argc, char **argv) 69 char **argv_new = NULL;
68{
69 char **argv_new=NULL;
70 int i, argc_test; 70 int i, argc_test;
71 71
72 plan_tests(5); 72 plan_tests(5);
73 73
74 { 74 {
75 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *) NULL}; 75 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *)NULL};
76 argc_test=5; 76 argc_test = 5;
77 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *) NULL}; 77 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *)NULL};
78 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 78 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
79 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1"); 79 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1");
80 my_free(&argc_test, argv_new, argv_test); 80 my_free(&argc_test, argv_new, argv_test);
81 } 81 }
82 82
83 { 83 {
84 char *argv_test[] = {"prog_name", "--extra-opts", (char *) NULL}; 84 char *argv_test[] = {"prog_name", "--extra-opts", (char *)NULL};
85 argc_test=2; 85 argc_test = 2;
86 char *argv_known[] = {"prog_name", "--foo=bar", (char *) NULL}; 86 char *argv_known[] = {"prog_name", "--foo=bar", (char *)NULL};
87 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 87 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
88 ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2"); 88 ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2");
89 my_free(&argc_test, argv_new, argv_test); 89 my_free(&argc_test, argv_new, argv_test);
90 } 90 }
91 91
92 { 92 {
93 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *) NULL}; 93 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *)NULL};
94 argc_test=5; 94 argc_test = 5;
95 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *) NULL}; 95 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *)NULL};
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 96 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
97 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3"); 97 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3");
98 my_free(&argc_test, argv_new, argv_test); 98 my_free(&argc_test, argv_new, argv_test);
99 } 99 }
100 100
101 { 101 {
102 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *) NULL}; 102 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *)NULL};
103 argc_test=5; 103 argc_test = 5;
104 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *) NULL}; 104 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 105 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
106 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4"); 106 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4");
107 my_free(&argc_test, argv_new, argv_test); 107 my_free(&argc_test, argv_new, argv_test);
108 } 108 }
109 109
110 { 110 {
111 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *) NULL}; 111 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *)NULL};
112 argc_test=3; 112 argc_test = 3;
113 char *argv_known[] = {"check_tcp", "--timeout=10", "--escape", "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", "--jail", (char *) NULL}; 113 char *argv_known[] = {
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_tcp"); 114 "check_tcp",
115 "--timeout=10",
116 "--escape",
117 "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
118 "yadda Foo bar BAZ yadda "
119 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
120 "yadda Foo bar BAZ "
121 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
122 "yadda yadda Foo bar "
123 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda",
124 "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
125 "yadda Foo bar BAZ yadda "
126 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
127 "yadda Foo bar BAZ "
128 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
129 "yadda yadda Foo bar "
130 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
131 "yadda yadda yadda Foo "
132 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda",
133 "--jail",
134 (char *)NULL};
135 argv_new = np_extra_opts(&argc_test, argv_test, "check_tcp");
115 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test"); 136 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test");
116 my_free(&argc_test, argv_new, argv_test); 137 my_free(&argc_test, argv_new, argv_test);
117 } 138 }
118 139
119 return exit_status(); 140 return exit_status();
120} 141}
121
diff --git a/lib/tests/test_opts3.c b/lib/tests/test_opts3.c
index b64270da..cecea437 100644
--- a/lib/tests/test_opts3.c
+++ b/lib/tests/test_opts3.c
@@ -1,31 +1,28 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16*****************************************************************************/ 16 *****************************************************************************/
17 17
18#include "extra_opts.h" 18#include "extra_opts.h"
19 19
20int 20int main(int argc, char **argv) {
21main (int argc, char **argv)
22{
23 21
24 /* 22 /*
25 * This is for testing arguments expected to die. 23 * This is for testing arguments expected to die.
26 */ 24 */
27 argv=np_extra_opts(&argc, argv, argv[0]); 25 argv = np_extra_opts(&argc, argv, argv[0]);
28 26
29 return 0; 27 return 0;
30} 28}
31
diff --git a/lib/tests/test_tcp.c b/lib/tests/test_tcp.c
index 1954b0fb..1b3003e9 100644
--- a/lib/tests/test_tcp.c
+++ b/lib/tests/test_tcp.c
@@ -1,34 +1,32 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_tcp.h" 20#include "utils_tcp.h"
21#include "tap.h" 21#include "tap.h"
22 22
23int 23int main(void) {
24main(void)
25{
26 char **server_expect; 24 char **server_expect;
27 int server_expect_count = 3; 25 int server_expect_count = 3;
28 26
29 plan_tests(9); 27 plan_tests(9);
30 28
31 server_expect = malloc(sizeof(char*) * server_expect_count); 29 server_expect = malloc(sizeof(char *) * server_expect_count);
32 30
33 server_expect[0] = strdup("AA"); 31 server_expect[0] = strdup("AA");
34 server_expect[1] = strdup("bb"); 32 server_expect[1] = strdup("bb");
@@ -42,17 +40,13 @@ main(void)
42 "Test matching any string at the beginning (substring match)"); 40 "Test matching any string at the beginning (substring match)");
43 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, 41 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE,
44 "Test with strings not matching at the beginning"); 42 "Test with strings not matching at the beginning");
45 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, 43 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, "Test matching any string");
46 "Test matching any string"); 44 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY, "Test not matching any string");
47 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY,
48 "Test not matching any string");
49 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_SUCCESS, 45 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_SUCCESS,
50 "Test matching all strings"); 46 "Test matching all strings");
51 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 47 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, "Test not matching all strings");
52 "Test not matching all strings");
53 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 48 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY,
54 "Test not matching any string (testing all)"); 49 "Test not matching any string (testing all)");
55 50
56
57 return exit_status(); 51 return exit_status();
58} 52}
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c
index 01afacdc..c3150f00 100644
--- a/lib/tests/test_utils.c
+++ b/lib/tests/test_utils.c
@@ -1,20 +1,20 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
5* the Free Software Foundation, either version 3 of the License, or 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_base.h" 20#include "utils_base.h"
@@ -27,331 +27,323 @@
27 27
28#include "utils_base.c" 28#include "utils_base.c"
29 29
30int 30int main(int argc, char **argv) {
31main (int argc, char **argv)
32{
33 char state_path[1024]; 31 char state_path[1024];
34 range *range; 32 range *range;
35 double temp; 33 double temp;
36 thresholds *thresholds = NULL; 34 thresholds *thresholds = NULL;
37 int i, rc; 35 int i, rc;
38 char *temp_string; 36 char *temp_string;
39 state_key *temp_state_key = NULL; 37 state_key *temp_state_key = NULL;
40 state_data *temp_state_data; 38 state_data *temp_state_data;
41 time_t current_time; 39 time_t current_time;
42 40
43 plan_tests(185); 41 plan_tests(185);
44 42
45 ok( this_monitoring_plugin==NULL, "monitoring_plugin not initialised"); 43 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised");
46 44
47 np_init( "check_test", argc, argv ); 45 np_init("check_test", argc, argv);
48 46
49 ok( this_monitoring_plugin!=NULL, "monitoring_plugin now initialised"); 47 ok(this_monitoring_plugin != NULL, "monitoring_plugin now initialised");
50 ok( !strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised" ); 48 ok(!strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised");
51 49
52 ok( this_monitoring_plugin->argc==argc, "Argc set" ); 50 ok(this_monitoring_plugin->argc == argc, "Argc set");
53 ok( this_monitoring_plugin->argv==argv, "Argv set" ); 51 ok(this_monitoring_plugin->argv == argv, "Argv set");
54 52
55 np_set_args(0,0); 53 np_set_args(0, 0);
56 54
57 ok( this_monitoring_plugin->argc==0, "argc changed" ); 55 ok(this_monitoring_plugin->argc == 0, "argc changed");
58 ok( this_monitoring_plugin->argv==0, "argv changed" ); 56 ok(this_monitoring_plugin->argv == 0, "argv changed");
59 57
60 np_set_args(argc, argv); 58 np_set_args(argc, argv);
61 59
62 range = parse_range_string("6"); 60 range = parse_range_string("6");
63 ok( range != NULL, "'6' is valid range"); 61 ok(range != NULL, "'6' is valid range");
64 ok( range->start == 0, "Start correct"); 62 ok(range->start == 0, "Start correct");
65 ok( range->start_infinity == false, "Not using negative infinity"); 63 ok(range->start_infinity == false, "Not using negative infinity");
66 ok( range->end == 6, "End correct"); 64 ok(range->end == 6, "End correct");
67 ok( range->end_infinity == false, "Not using infinity"); 65 ok(range->end_infinity == false, "Not using infinity");
68 free(range); 66 free(range);
69 67
70 range = parse_range_string("1:12%%"); 68 range = parse_range_string("1:12%%");
71 ok( range != NULL, "'1:12%%' is valid - percentages are ignored"); 69 ok(range != NULL, "'1:12%%' is valid - percentages are ignored");
72 ok( range->start == 1, "Start correct"); 70 ok(range->start == 1, "Start correct");
73 ok( range->start_infinity == false, "Not using negative infinity"); 71 ok(range->start_infinity == false, "Not using negative infinity");
74 ok( range->end == 12, "End correct"); 72 ok(range->end == 12, "End correct");
75 ok( range->end_infinity == false, "Not using infinity"); 73 ok(range->end_infinity == false, "Not using infinity");
76 free(range); 74 free(range);
77 75
78 range = parse_range_string("-7:23"); 76 range = parse_range_string("-7:23");
79 ok( range != NULL, "'-7:23' is valid range"); 77 ok(range != NULL, "'-7:23' is valid range");
80 ok( range->start == -7, "Start correct"); 78 ok(range->start == -7, "Start correct");
81 ok( range->start_infinity == false, "Not using negative infinity"); 79 ok(range->start_infinity == false, "Not using negative infinity");
82 ok( range->end == 23, "End correct"); 80 ok(range->end == 23, "End correct");
83 ok( range->end_infinity == false, "Not using infinity"); 81 ok(range->end_infinity == false, "Not using infinity");
84 free(range); 82 free(range);
85 83
86 range = parse_range_string(":5.75"); 84 range = parse_range_string(":5.75");
87 ok( range != NULL, "':5.75' is valid range"); 85 ok(range != NULL, "':5.75' is valid range");
88 ok( range->start == 0, "Start correct"); 86 ok(range->start == 0, "Start correct");
89 ok( range->start_infinity == false, "Not using negative infinity"); 87 ok(range->start_infinity == false, "Not using negative infinity");
90 ok( range->end == 5.75, "End correct"); 88 ok(range->end == 5.75, "End correct");
91 ok( range->end_infinity == false, "Not using infinity"); 89 ok(range->end_infinity == false, "Not using infinity");
92 free(range); 90 free(range);
93 91
94 range = parse_range_string("~:-95.99"); 92 range = parse_range_string("~:-95.99");
95 ok( range != NULL, "~:-95.99' is valid range"); 93 ok(range != NULL, "~:-95.99' is valid range");
96 ok( range->start_infinity == true, "Using negative infinity"); 94 ok(range->start_infinity == true, "Using negative infinity");
97 ok( range->end == -95.99, "End correct (with rounding errors)"); 95 ok(range->end == -95.99, "End correct (with rounding errors)");
98 ok( range->end_infinity == false, "Not using infinity"); 96 ok(range->end_infinity == false, "Not using infinity");
99 free(range); 97 free(range);
100 98
101 range = parse_range_string("12345678901234567890:"); 99 range = parse_range_string("12345678901234567890:");
102 temp = atof("12345678901234567890"); /* Can't just use this because number too large */ 100 temp = atof("12345678901234567890"); /* Can't just use this because number too large */
103 ok( range != NULL, "'12345678901234567890:' is valid range"); 101 ok(range != NULL, "'12345678901234567890:' is valid range");
104 ok( range->start == temp, "Start correct"); 102 ok(range->start == temp, "Start correct");
105 ok( range->start_infinity == false, "Not using negative infinity"); 103 ok(range->start_infinity == false, "Not using negative infinity");
106 ok( range->end_infinity == true, "Using infinity"); 104 ok(range->end_infinity == true, "Using infinity");
107 /* Cannot do a "-1" on temp, as it appears to be same value */ 105 /* Cannot do a "-1" on temp, as it appears to be same value */
108 ok( check_range(temp/1.1, range) == true, "12345678901234567890/1.1 - alert"); 106 ok(check_range(temp / 1.1, range) == true, "12345678901234567890/1.1 - alert");
109 ok( check_range(temp, range) == false, "12345678901234567890 - no alert"); 107 ok(check_range(temp, range) == false, "12345678901234567890 - no alert");
110 ok( check_range(temp*2, range) == false, "12345678901234567890*2 - no alert"); 108 ok(check_range(temp * 2, range) == false, "12345678901234567890*2 - no alert");
111 free(range); 109 free(range);
112 110
113 range = parse_range_string("~:0"); 111 range = parse_range_string("~:0");
114 ok( range != NULL, "'~:0' is valid range"); 112 ok(range != NULL, "'~:0' is valid range");
115 ok( range->start_infinity == true, "Using negative infinity"); 113 ok(range->start_infinity == true, "Using negative infinity");
116 ok( range->end == 0, "End correct"); 114 ok(range->end == 0, "End correct");
117 ok( range->end_infinity == false, "Not using infinity"); 115 ok(range->end_infinity == false, "Not using infinity");
118 ok( range->alert_on == OUTSIDE, "Will alert on outside of this range"); 116 ok(range->alert_on == OUTSIDE, "Will alert on outside of this range");
119 ok( check_range(0.5, range) == true, "0.5 - alert"); 117 ok(check_range(0.5, range) == true, "0.5 - alert");
120 ok( check_range(-10, range) == false, "-10 - no alert"); 118 ok(check_range(-10, range) == false, "-10 - no alert");
121 ok( check_range(0, range) == false, "0 - no alert"); 119 ok(check_range(0, range) == false, "0 - no alert");
122 free(range); 120 free(range);
123 121
124 range = parse_range_string("@0:657.8210567"); 122 range = parse_range_string("@0:657.8210567");
125 ok( range != 0, "@0:657.8210567' is a valid range"); 123 ok(range != 0, "@0:657.8210567' is a valid range");
126 ok( range->start == 0, "Start correct"); 124 ok(range->start == 0, "Start correct");
127 ok( range->start_infinity == false, "Not using negative infinity"); 125 ok(range->start_infinity == false, "Not using negative infinity");
128 ok( range->end == 657.8210567, "End correct"); 126 ok(range->end == 657.8210567, "End correct");
129 ok( range->end_infinity == false, "Not using infinity"); 127 ok(range->end_infinity == false, "Not using infinity");
130 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 128 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
131 ok( check_range(32.88, range) == true, "32.88 - alert"); 129 ok(check_range(32.88, range) == true, "32.88 - alert");
132 ok( check_range(-2, range) == false, "-2 - no alert"); 130 ok(check_range(-2, range) == false, "-2 - no alert");
133 ok( check_range(657.8210567, range) == true, "657.8210567 - alert"); 131 ok(check_range(657.8210567, range) == true, "657.8210567 - alert");
134 ok( check_range(0, range) == true, "0 - alert"); 132 ok(check_range(0, range) == true, "0 - alert");
135 free(range); 133 free(range);
136 134
137 range = parse_range_string("@1:1"); 135 range = parse_range_string("@1:1");
138 ok( range != NULL, "'@1:1' is a valid range"); 136 ok(range != NULL, "'@1:1' is a valid range");
139 ok( range->start == 1, "Start correct"); 137 ok(range->start == 1, "Start correct");
140 ok( range->start_infinity == false, "Not using negative infinity"); 138 ok(range->start_infinity == false, "Not using negative infinity");
141 ok( range->end == 1, "End correct"); 139 ok(range->end == 1, "End correct");
142 ok( range->end_infinity == false, "Not using infinity"); 140 ok(range->end_infinity == false, "Not using infinity");
143 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 141 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
144 ok( check_range(0.5, range) == false, "0.5 - no alert"); 142 ok(check_range(0.5, range) == false, "0.5 - no alert");
145 ok( check_range(1, range) == true, "1 - alert"); 143 ok(check_range(1, range) == true, "1 - alert");
146 ok( check_range(5.2, range) == false, "5.2 - no alert"); 144 ok(check_range(5.2, range) == false, "5.2 - no alert");
147 free(range); 145 free(range);
148 146
149 range = parse_range_string("1:1"); 147 range = parse_range_string("1:1");
150 ok( range != NULL, "'1:1' is a valid range"); 148 ok(range != NULL, "'1:1' is a valid range");
151 ok( range->start == 1, "Start correct"); 149 ok(range->start == 1, "Start correct");
152 ok( range->start_infinity == false, "Not using negative infinity"); 150 ok(range->start_infinity == false, "Not using negative infinity");
153 ok( range->end == 1, "End correct"); 151 ok(range->end == 1, "End correct");
154 ok( range->end_infinity == false, "Not using infinity"); 152 ok(range->end_infinity == false, "Not using infinity");
155 ok( check_range(0.5, range) == true, "0.5 - alert"); 153 ok(check_range(0.5, range) == true, "0.5 - alert");
156 ok( check_range(1, range) == false, "1 - no alert"); 154 ok(check_range(1, range) == false, "1 - no alert");
157 ok( check_range(5.2, range) == true, "5.2 - alert"); 155 ok(check_range(5.2, range) == true, "5.2 - alert");
158 free(range); 156 free(range);
159 157
160 range = parse_range_string("2:1"); 158 range = parse_range_string("2:1");
161 ok( range == NULL, "'2:1' rejected"); 159 ok(range == NULL, "'2:1' rejected");
162 160
163 rc = _set_thresholds(&thresholds, NULL, NULL); 161 rc = _set_thresholds(&thresholds, NULL, NULL);
164 ok( rc == 0, "Thresholds (NULL, NULL) set"); 162 ok(rc == 0, "Thresholds (NULL, NULL) set");
165 ok( thresholds->warning == NULL, "Warning not set"); 163 ok(thresholds->warning == NULL, "Warning not set");
166 ok( thresholds->critical == NULL, "Critical not set"); 164 ok(thresholds->critical == NULL, "Critical not set");
167 165
168 rc = _set_thresholds(&thresholds, NULL, "80"); 166 rc = _set_thresholds(&thresholds, NULL, "80");
169 ok( rc == 0, "Thresholds (NULL, '80') set"); 167 ok(rc == 0, "Thresholds (NULL, '80') set");
170 ok( thresholds->warning == NULL, "Warning not set"); 168 ok(thresholds->warning == NULL, "Warning not set");
171 ok( thresholds->critical->end == 80, "Critical set correctly"); 169 ok(thresholds->critical->end == 80, "Critical set correctly");
172 170
173 rc = _set_thresholds(&thresholds, "5:33", NULL); 171 rc = _set_thresholds(&thresholds, "5:33", NULL);
174 ok( rc == 0, "Thresholds ('5:33', NULL) set"); 172 ok(rc == 0, "Thresholds ('5:33', NULL) set");
175 ok( thresholds->warning->start == 5, "Warning start set"); 173 ok(thresholds->warning->start == 5, "Warning start set");
176 ok( thresholds->warning->end == 33, "Warning end set"); 174 ok(thresholds->warning->end == 33, "Warning end set");
177 ok( thresholds->critical == NULL, "Critical not set"); 175 ok(thresholds->critical == NULL, "Critical not set");
178 176
179 rc = _set_thresholds(&thresholds, "30", "60"); 177 rc = _set_thresholds(&thresholds, "30", "60");
180 ok( rc == 0, "Thresholds ('30', '60') set"); 178 ok(rc == 0, "Thresholds ('30', '60') set");
181 ok( thresholds->warning->end == 30, "Warning set correctly"); 179 ok(thresholds->warning->end == 30, "Warning set correctly");
182 ok( thresholds->critical->end == 60, "Critical set correctly"); 180 ok(thresholds->critical->end == 60, "Critical set correctly");
183 ok( get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); 181 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok");
184 ok( get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); 182 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning");
185 ok( get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); 183 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical");
186 184
187 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); 185 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20");
188 ok( rc == 0, "Thresholds ('-30:20', '-10:-2') set"); 186 ok(rc == 0, "Thresholds ('-30:20', '-10:-2') set");
189 ok( thresholds->warning->start == -10, "Warning start set correctly"); 187 ok(thresholds->warning->start == -10, "Warning start set correctly");
190 ok( thresholds->warning->end == -2, "Warning end set correctly"); 188 ok(thresholds->warning->end == -2, "Warning end set correctly");
191 ok( thresholds->critical->start == -30, "Critical start set correctly"); 189 ok(thresholds->critical->start == -30, "Critical start set correctly");
192 ok( thresholds->critical->end == 20, "Critical end set correctly"); 190 ok(thresholds->critical->end == 20, "Critical end set correctly");
193 ok( get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical"); 191 ok(get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical");
194 ok( get_status(-29, thresholds) == STATE_WARNING, "-29 - warning"); 192 ok(get_status(-29, thresholds) == STATE_WARNING, "-29 - warning");
195 ok( get_status(-11, thresholds) == STATE_WARNING, "-11 - warning"); 193 ok(get_status(-11, thresholds) == STATE_WARNING, "-11 - warning");
196 ok( get_status(-10, thresholds) == STATE_OK, "-10 - ok"); 194 ok(get_status(-10, thresholds) == STATE_OK, "-10 - ok");
197 ok( get_status(-2, thresholds) == STATE_OK, "-2 - ok"); 195 ok(get_status(-2, thresholds) == STATE_OK, "-2 - ok");
198 ok( get_status(-1, thresholds) == STATE_WARNING, "-1 - warning"); 196 ok(get_status(-1, thresholds) == STATE_WARNING, "-1 - warning");
199 ok( get_status(19, thresholds) == STATE_WARNING, "19 - warning"); 197 ok(get_status(19, thresholds) == STATE_WARNING, "19 - warning");
200 ok( get_status(21, thresholds) == STATE_CRITICAL, "21 - critical"); 198 ok(get_status(21, thresholds) == STATE_CRITICAL, "21 - critical");
201 199
202 char *test; 200 char *test;
203 test = np_escaped_string("bob\\n"); 201 test = np_escaped_string("bob\\n");
204 ok( strcmp(test, "bob\n") == 0, "bob\\n ok"); 202 ok(strcmp(test, "bob\n") == 0, "bob\\n ok");
205 free(test); 203 free(test);
206 204
207 test = np_escaped_string("rhuba\\rb"); 205 test = np_escaped_string("rhuba\\rb");
208 ok( strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay"); 206 ok(strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay");
209 free(test); 207 free(test);
210 208
211 test = np_escaped_string("ba\\nge\\r"); 209 test = np_escaped_string("ba\\nge\\r");
212 ok( strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay"); 210 ok(strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay");
213 free(test); 211 free(test);
214 212
215 test = np_escaped_string("\\rabbi\\t"); 213 test = np_escaped_string("\\rabbi\\t");
216 ok( strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay"); 214 ok(strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay");
217 free(test); 215 free(test);
218 216
219 test = np_escaped_string("and\\\\or"); 217 test = np_escaped_string("and\\\\or");
220 ok( strcmp(test, "and\\or") == 0, "and\\\\or okay"); 218 ok(strcmp(test, "and\\or") == 0, "and\\\\or okay");
221 free(test); 219 free(test);
222 220
223 test = np_escaped_string("bo\\gus"); 221 test = np_escaped_string("bo\\gus");
224 ok( strcmp(test, "bogus") == 0, "bo\\gus okay"); 222 ok(strcmp(test, "bogus") == 0, "bo\\gus okay");
225 free(test); 223 free(test);
226 224
227 test = np_escaped_string("everything"); 225 test = np_escaped_string("everything");
228 ok( strcmp(test, "everything") == 0, "everything okay"); 226 ok(strcmp(test, "everything") == 0, "everything okay");
229 227
230 /* np_extract_ntpvar tests (23) */ 228 /* np_extract_ntpvar tests (23) */
231 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo"); 229 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo");
232 ok(test && !strcmp(test, "bar"), "1st test as expected"); 230 ok(test && !strcmp(test, "bar"), "1st test as expected");
233 free(test); 231 free(test);
234 232
235 test=np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar"); 233 test = np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar");
236 ok(test && !strcmp(test, "foo"), "2nd test as expected"); 234 ok(test && !strcmp(test, "foo"), "2nd test as expected");
237 free(test); 235 free(test);
238 236
239 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar"); 237 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar");
240 ok(test && !strcmp(test, "barfoo"), "3rd test as expected"); 238 ok(test && !strcmp(test, "barfoo"), "3rd test as expected");
241 free(test); 239 free(test);
242 240
243 test=np_extract_ntpvar("foo=bar\n", "foo"); 241 test = np_extract_ntpvar("foo=bar\n", "foo");
244 ok(test && !strcmp(test, "bar"), "Single test as expected"); 242 ok(test && !strcmp(test, "bar"), "Single test as expected");
245 free(test); 243 free(test);
246 244
247 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd"); 245 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd");
248 ok(!test, "Key not found 1"); 246 ok(!test, "Key not found 1");
249 247
250 test=np_extract_ntpvar("foo=bar\n", "abcd"); 248 test = np_extract_ntpvar("foo=bar\n", "abcd");
251 ok(!test, "Key not found 2"); 249 ok(!test, "Key not found 2");
252 250
253 test=np_extract_ntpvar("foo=bar=foobar", "foo"); 251 test = np_extract_ntpvar("foo=bar=foobar", "foo");
254 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1"); 252 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1");
255 free(test); 253 free(test);
256 254
257 test=np_extract_ntpvar("foo", "foo"); 255 test = np_extract_ntpvar("foo", "foo");
258 ok(!test, "Malformed string 1"); 256 ok(!test, "Malformed string 1");
259 257
260 test=np_extract_ntpvar("foo,", "foo"); 258 test = np_extract_ntpvar("foo,", "foo");
261 ok(!test, "Malformed string 2"); 259 ok(!test, "Malformed string 2");
262 260
263 test=np_extract_ntpvar("foo=", "foo"); 261 test = np_extract_ntpvar("foo=", "foo");
264 ok(!test, "Malformed string 3"); 262 ok(!test, "Malformed string 3");
265 263
266 test=np_extract_ntpvar("foo=,bar=foo", "foo"); 264 test = np_extract_ntpvar("foo=,bar=foo", "foo");
267 ok(!test, "Malformed string 4"); 265 ok(!test, "Malformed string 4");
268 266
269 test=np_extract_ntpvar(",foo", "foo"); 267 test = np_extract_ntpvar(",foo", "foo");
270 ok(!test, "Malformed string 5"); 268 ok(!test, "Malformed string 5");
271 269
272 test=np_extract_ntpvar("=foo", "foo"); 270 test = np_extract_ntpvar("=foo", "foo");
273 ok(!test, "Malformed string 6"); 271 ok(!test, "Malformed string 6");
274 272
275 test=np_extract_ntpvar("=foo,", "foo"); 273 test = np_extract_ntpvar("=foo,", "foo");
276 ok(!test, "Malformed string 7"); 274 ok(!test, "Malformed string 7");
277 275
278 test=np_extract_ntpvar(",,,", "foo"); 276 test = np_extract_ntpvar(",,,", "foo");
279 ok(!test, "Malformed string 8"); 277 ok(!test, "Malformed string 8");
280 278
281 test=np_extract_ntpvar("===", "foo"); 279 test = np_extract_ntpvar("===", "foo");
282 ok(!test, "Malformed string 9"); 280 ok(!test, "Malformed string 9");
283 281
284 test=np_extract_ntpvar(",=,=,", "foo"); 282 test = np_extract_ntpvar(",=,=,", "foo");
285 ok(!test, "Malformed string 10"); 283 ok(!test, "Malformed string 10");
286 284
287 test=np_extract_ntpvar("=,=,=", "foo"); 285 test = np_extract_ntpvar("=,=,=", "foo");
288 ok(!test, "Malformed string 11"); 286 ok(!test, "Malformed string 11");
289 287
290 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo"); 288 test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo");
291 ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1"); 289 ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1");
292 free(test); 290 free(test);
293 291
294 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar"); 292 test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar");
295 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2"); 293 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2");
296 free(test); 294 free(test);
297 295
298 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar"); 296 test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar");
299 ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3"); 297 ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3");
300 free(test); 298 free(test);
301 299
302 test=np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar"); 300 test = np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar");
303 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4"); 301 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4");
304 free(test); 302 free(test);
305 303
306 test=np_extract_ntpvar("", "foo"); 304 test = np_extract_ntpvar("", "foo");
307 ok(!test, "Empty string return NULL"); 305 ok(!test, "Empty string return NULL");
308 306
309
310 /* This is the result of running ./test_utils */ 307 /* This is the result of running ./test_utils */
311 temp_string = (char *) _np_state_generate_key(); 308 temp_string = (char *)_np_state_generate_key();
312 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters" ) || 309 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters") ||
313 diag( "You are probably running in wrong directory. Must run as ./test_utils" ); 310 diag("You are probably running in wrong directory. Must run as ./test_utils");
314
315 311
316 this_monitoring_plugin->argc=4; 312 this_monitoring_plugin->argc = 4;
317 this_monitoring_plugin->argv[0] = "./test_utils"; 313 this_monitoring_plugin->argv[0] = "./test_utils";
318 this_monitoring_plugin->argv[1] = "here"; 314 this_monitoring_plugin->argv[1] = "here";
319 this_monitoring_plugin->argv[2] = "--and"; 315 this_monitoring_plugin->argv[2] = "--and";
320 this_monitoring_plugin->argv[3] = "now"; 316 this_monitoring_plugin->argv[3] = "now";
321 temp_string = (char *) _np_state_generate_key(); 317 temp_string = (char *)_np_state_generate_key();
322 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv" ); 318 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv");
323 319
324 unsetenv("MP_STATE_PATH"); 320 unsetenv("MP_STATE_PATH");
325 temp_string = (char *) _np_state_calculate_location_prefix(); 321 temp_string = (char *)_np_state_calculate_location_prefix();
326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory" ); 322 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory");
327 323
328 setenv("MP_STATE_PATH", "", 1); 324 setenv("MP_STATE_PATH", "", 1);
329 temp_string = (char *) _np_state_calculate_location_prefix(); 325 temp_string = (char *)_np_state_calculate_location_prefix();
330 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string" ); 326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string");
331 327
332 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1); 328 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
333 temp_string = (char *) _np_state_calculate_location_prefix(); 329 temp_string = (char *)_np_state_calculate_location_prefix();
334 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory" ); 330 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory");
335
336 331
332 ok(temp_state_key == NULL, "temp_state_key initially empty");
337 333
338 ok(temp_state_key==NULL, "temp_state_key initially empty"); 334 this_monitoring_plugin->argc = 1;
339
340 this_monitoring_plugin->argc=1;
341 this_monitoring_plugin->argv[0] = "./test_utils"; 335 this_monitoring_plugin->argv[0] = "./test_utils";
342 np_enable_state(NULL, 51); 336 np_enable_state(NULL, 51);
343 temp_state_key = this_monitoring_plugin->state; 337 temp_state_key = this_monitoring_plugin->state;
344 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); 338 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
345 ok( !strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename" ); 339 ok(!strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename");
346
347 340
348 np_enable_state("allowedchars_in_keyname", 77); 341 np_enable_state("allowedchars_in_keyname", 77);
349 temp_state_key = this_monitoring_plugin->state; 342 temp_state_key = this_monitoring_plugin->state;
350 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid()); 343 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid());
351 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); 344 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
352 ok( !strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars" ); 345 ok(!strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars");
353 ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" ); 346 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
354
355 347
356 /* Don't do this test just yet. Will die */ 348 /* Don't do this test just yet. Will die */
357 /* 349 /*
@@ -363,73 +355,65 @@ main (int argc, char **argv)
363 np_enable_state("funnykeyname", 54); 355 np_enable_state("funnykeyname", 54);
364 temp_state_key = this_monitoring_plugin->state; 356 temp_state_key = this_monitoring_plugin->state;
365 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid()); 357 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid());
366 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); 358 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
367 ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" ); 359 ok(!strcmp(temp_state_key->name, "funnykeyname"), "Got key name");
368 360
369 361 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
370 362 ok(temp_state_key->data_version == 54, "Version set");
371 ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" );
372 ok( temp_state_key->data_version==54, "Version set" );
373 363
374 temp_state_data = np_state_read(); 364 temp_state_data = np_state_read();
375 ok( temp_state_data==NULL, "Got no state data as file does not exist" ); 365 ok(temp_state_data == NULL, "Got no state data as file does not exist");
376
377 366
378/* 367 /*
379 temp_fp = fopen("var/statefile", "r"); 368 temp_fp = fopen("var/statefile", "r");
380 if (temp_fp==NULL) 369 if (temp_fp==NULL)
381 printf("Error opening. errno=%d\n", errno); 370 printf("Error opening. errno=%d\n", errno);
382 printf("temp_fp=%s\n", temp_fp); 371 printf("temp_fp=%s\n", temp_fp);
383 ok( _np_state_read_file(temp_fp) == true, "Can read state file" ); 372 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
384 fclose(temp_fp); 373 fclose(temp_fp);
385*/ 374 */
386 375
387 temp_state_key->_filename="var/statefile"; 376 temp_state_key->_filename = "var/statefile";
388 temp_state_data = np_state_read(); 377 temp_state_data = np_state_read();
389 ok( this_monitoring_plugin->state->state_data!=NULL, "Got state data now" ) || diag("Are you running in right directory? Will get coredump next if not"); 378 ok(this_monitoring_plugin->state->state_data != NULL, "Got state data now") ||
390 ok( this_monitoring_plugin->state->state_data->time==1234567890, "Got time" ); 379 diag("Are you running in right directory? Will get coredump next if not");
391 ok( !strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected" ); 380 ok(this_monitoring_plugin->state->state_data->time == 1234567890, "Got time");
381 ok(!strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected");
392 382
393 temp_state_key->data_version=53; 383 temp_state_key->data_version = 53;
394 temp_state_data = np_state_read(); 384 temp_state_data = np_state_read();
395 ok( temp_state_data==NULL, "Older data version gives NULL" ); 385 ok(temp_state_data == NULL, "Older data version gives NULL");
396 temp_state_key->data_version=54; 386 temp_state_key->data_version = 54;
397 387
398 temp_state_key->_filename="var/nonexistent"; 388 temp_state_key->_filename = "var/nonexistent";
399 temp_state_data = np_state_read(); 389 temp_state_data = np_state_read();
400 ok( temp_state_data==NULL, "Missing file gives NULL" ); 390 ok(temp_state_data == NULL, "Missing file gives NULL");
401 ok( this_monitoring_plugin->state->state_data==NULL, "No state information" ); 391 ok(this_monitoring_plugin->state->state_data == NULL, "No state information");
402 392
403 temp_state_key->_filename="var/oldformat"; 393 temp_state_key->_filename = "var/oldformat";
404 temp_state_data = np_state_read(); 394 temp_state_data = np_state_read();
405 ok( temp_state_data==NULL, "Old file format gives NULL" ); 395 ok(temp_state_data == NULL, "Old file format gives NULL");
406 396
407 temp_state_key->_filename="var/baddate"; 397 temp_state_key->_filename = "var/baddate";
408 temp_state_data = np_state_read(); 398 temp_state_data = np_state_read();
409 ok( temp_state_data==NULL, "Bad date gives NULL" ); 399 ok(temp_state_data == NULL, "Bad date gives NULL");
410 400
411 temp_state_key->_filename="var/missingdataline"; 401 temp_state_key->_filename = "var/missingdataline";
412 temp_state_data = np_state_read(); 402 temp_state_data = np_state_read();
413 ok( temp_state_data==NULL, "Missing data line gives NULL" ); 403 ok(temp_state_data == NULL, "Missing data line gives NULL");
414
415
416
417 404
418 unlink("var/generated"); 405 unlink("var/generated");
419 temp_state_key->_filename="var/generated"; 406 temp_state_key->_filename = "var/generated";
420 current_time=1234567890; 407 current_time = 1234567890;
421 np_state_write_string(current_time, "String to read"); 408 np_state_write_string(current_time, "String to read");
422 ok(system("cmp var/generated var/statefile")==0, "Generated file same as expected"); 409 ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected");
423
424
425
426 410
427 unlink("var/generated_directory/statefile"); 411 unlink("var/generated_directory/statefile");
428 unlink("var/generated_directory"); 412 unlink("var/generated_directory");
429 temp_state_key->_filename="var/generated_directory/statefile"; 413 temp_state_key->_filename = "var/generated_directory/statefile";
430 current_time=1234567890; 414 current_time = 1234567890;
431 np_state_write_string(current_time, "String to read"); 415 np_state_write_string(current_time, "String to read");
432 ok(system("cmp var/generated_directory/statefile var/statefile")==0, "Have created directory"); 416 ok(system("cmp var/generated_directory/statefile var/statefile") == 0, "Have created directory");
433 417
434 /* This test to check cannot write to dir - can't automate yet */ 418 /* This test to check cannot write to dir - can't automate yet */
435 /* 419 /*
@@ -438,15 +422,13 @@ main (int argc, char **argv)
438 np_state_write_string(current_time, "String to read"); 422 np_state_write_string(current_time, "String to read");
439 */ 423 */
440 424
441 425 temp_state_key->_filename = "var/generated";
442 temp_state_key->_filename="var/generated";
443 time(&current_time); 426 time(&current_time);
444 np_state_write_string(0, "String to read"); 427 np_state_write_string(0, "String to read");
445 temp_state_data = np_state_read(); 428 temp_state_data = np_state_read();
446 /* Check time is set to current_time */ 429 /* Check time is set to current_time */
447 ok(system("cmp var/generated var/statefile > /dev/null")!=0, "Generated file should be different this time"); 430 ok(system("cmp var/generated var/statefile > /dev/null") != 0, "Generated file should be different this time");
448 ok(this_monitoring_plugin->state->state_data->time-current_time<=1, "Has time generated from current time"); 431 ok(this_monitoring_plugin->state->state_data->time - current_time <= 1, "Has time generated from current time");
449
450 432
451 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */ 433 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */
452 /* 434 /*
@@ -454,23 +436,16 @@ main (int argc, char **argv)
454 np_state_write_string(0, "Bad file"); 436 np_state_write_string(0, "Bad file");
455 */ 437 */
456 438
457
458 np_cleanup(); 439 np_cleanup();
459 440
460 ok(this_monitoring_plugin==NULL, "Free'd this_monitoring_plugin"); 441 ok(this_monitoring_plugin == NULL, "Free'd this_monitoring_plugin");
461 442
462 ok(mp_suid() == false, "Test aren't suid"); 443 ok(mp_suid() == false, "Test aren't suid");
463 444
464 /* base states with random case */ 445 /* base states with random case */
465 char *states[] = { 446 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL};
466 "Ok", 447
467 "wArnINg", 448 for (i = 0; states[i] != NULL; i++) {
468 "cRiTIcaL",
469 "UnKNoWN",
470 NULL
471 };
472
473 for (i=0; states[i]!=NULL; i++) {
474 /* out of the random case states, create the lower and upper versions + numeric string one */ 449 /* out of the random case states, create the lower and upper versions + numeric string one */
475 char *statelower = strdup(states[i]); 450 char *statelower = strdup(states[i]);
476 char *stateupper = strdup(states[i]); 451 char *stateupper = strdup(states[i]);
@@ -488,23 +463,23 @@ main (int argc, char **argv)
488 char testname[64] = "Translate state string: "; 463 char testname[64] = "Translate state string: ";
489 int tlen = strlen(testname); 464 int tlen = strlen(testname);
490 465
491 strcpy(testname+tlen, states[i]); 466 strcpy(testname + tlen, states[i]);
492 ok(i==mp_translate_state(states[i]), testname); 467 ok(i == mp_translate_state(states[i]), testname);
493 468
494 strcpy(testname+tlen, statelower); 469 strcpy(testname + tlen, statelower);
495 ok(i==mp_translate_state(statelower), testname); 470 ok(i == mp_translate_state(statelower), testname);
496 471
497 strcpy(testname+tlen, stateupper); 472 strcpy(testname + tlen, stateupper);
498 ok(i==mp_translate_state(stateupper), testname); 473 ok(i == mp_translate_state(stateupper), testname);
499 474
500 strcpy(testname+tlen, statenum); 475 strcpy(testname + tlen, statenum);
501 ok(i==mp_translate_state(statenum), testname); 476 ok(i == mp_translate_state(statenum), testname);
502 } 477 }
503 ok(ERROR==mp_translate_state("warningfewgw"), "Translate state string with garbage"); 478 ok(ERROR == mp_translate_state("warningfewgw"), "Translate state string with garbage");
504 ok(ERROR==mp_translate_state("00"), "Translate state string: bad numeric string 1"); 479 ok(ERROR == mp_translate_state("00"), "Translate state string: bad numeric string 1");
505 ok(ERROR==mp_translate_state("01"), "Translate state string: bad numeric string 2"); 480 ok(ERROR == mp_translate_state("01"), "Translate state string: bad numeric string 2");
506 ok(ERROR==mp_translate_state("10"), "Translate state string: bad numeric string 3"); 481 ok(ERROR == mp_translate_state("10"), "Translate state string: bad numeric string 3");
507 ok(ERROR==mp_translate_state(""), "Translate state string: empty string"); 482 ok(ERROR == mp_translate_state(""), "Translate state string: empty string");
508 483
509 return exit_status(); 484 return exit_status();
510} 485}
diff --git a/lib/thresholds.c b/lib/thresholds.c
new file mode 100644
index 00000000..ddefae37
--- /dev/null
+++ b/lib/thresholds.c
@@ -0,0 +1,59 @@
1#include "./thresholds.h"
2#include "./utils_base.h"
3#include "perfdata.h"
4
5#include <stddef.h>
6
7mp_thresholds mp_thresholds_init() {
8 mp_thresholds tmp = {
9 .critical = {},
10 .critical_is_set = false,
11 .warning = {},
12 .warning_is_set = false,
13 };
14 return tmp;
15}
16
17char *fmt_threshold_warning(const thresholds th) {
18 if (th.warning == NULL) {
19 return "";
20 }
21
22 return fmt_range(*th.warning);
23}
24
25char *fmt_threshold_critical(const thresholds th) {
26 if (th.critical == NULL) {
27 return "";
28 }
29 return fmt_range(*th.critical);
30}
31
32mp_perfdata mp_pd_set_thresholds(mp_perfdata perfdata, mp_thresholds threshold) {
33 if (threshold.critical_is_set) {
34 perfdata.crit = threshold.critical;
35 perfdata.crit_present = true;
36 }
37
38 if (threshold.warning_is_set) {
39 perfdata.warn = threshold.warning;
40 perfdata.warn_present = true;
41 }
42
43 return perfdata;
44}
45
46mp_state_enum mp_get_pd_status(mp_perfdata perfdata) {
47 if (perfdata.crit_present) {
48 if (mp_check_range(perfdata.value, perfdata.crit)) {
49 return STATE_CRITICAL;
50 }
51 }
52 if (perfdata.warn_present) {
53 if (mp_check_range(perfdata.value, perfdata.warn)) {
54 return STATE_CRITICAL;
55 }
56 }
57
58 return STATE_OK;
59}
diff --git a/lib/thresholds.h b/lib/thresholds.h
new file mode 100644
index 00000000..4e7defee
--- /dev/null
+++ b/lib/thresholds.h
@@ -0,0 +1,28 @@
1#pragma once
2
3#include "./perfdata.h"
4#include "states.h"
5
6/*
7 * Old threshold type using the old range type
8 */
9typedef struct thresholds_struct {
10 range *warning;
11 range *critical;
12} thresholds;
13
14typedef struct mp_thresholds_struct {
15 bool warning_is_set;
16 mp_range warning;
17 bool critical_is_set;
18 mp_range critical;
19} mp_thresholds;
20
21mp_thresholds mp_thresholds_init(void);
22
23mp_perfdata mp_pd_set_thresholds(mp_perfdata /* pd */, mp_thresholds /* th */);
24
25mp_state_enum mp_get_pd_status(mp_perfdata /* pd */);
26
27char *fmt_threshold_warning(thresholds th);
28char *fmt_threshold_critical(thresholds th);
diff --git a/lib/utils_base.c b/lib/utils_base.c
index f8592f41..ff9540c7 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -1,28 +1,28 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* utils_base.c 3 * utils_base.c
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006 Monitoring Plugins Development Team 6 * Copyright (c) 2006 - 2024 Monitoring Plugins Development Team
7* 7 *
8* Library of useful functions for plugins 8 * Library of useful functions for plugins
9* 9 *
10* 10 *
11* This program is free software: you can redistribute it and/or modify 11 * This program is free software: you can redistribute it and/or modify
12* it under the terms of the GNU General Public License as published by 12 * it under the terms of the GNU General Public License as published by
13* the Free Software Foundation, either version 3 of the License, or 13 * the Free Software Foundation, either version 3 of the License, or
14* (at your option) any later version. 14 * (at your option) any later version.
15* 15 *
16* This program is distributed in the hope that it will be useful, 16 * This program is distributed in the hope that it will be useful,
17* but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19* GNU General Public License for more details. 19 * GNU General Public License for more details.
20* 20 *
21* You should have received a copy of the GNU General Public License 21 * You should have received a copy of the GNU General Public License
22* along with this program. If not, see <http://www.gnu.org/licenses/>. 22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23* 23 *
24* 24 *
25*****************************************************************************/ 25 *****************************************************************************/
26 26
27#include "../plugins/common.h" 27#include "../plugins/common.h"
28#include <stdarg.h> 28#include <stdarg.h>
@@ -33,43 +33,49 @@
33#include <unistd.h> 33#include <unistd.h>
34#include <sys/types.h> 34#include <sys/types.h>
35 35
36#define np_free(ptr) { if(ptr) { free(ptr); ptr = NULL; } } 36#define np_free(ptr) \
37 { \
38 if (ptr) { \
39 free(ptr); \
40 ptr = NULL; \
41 } \
42 }
37 43
38monitoring_plugin *this_monitoring_plugin=NULL; 44monitoring_plugin *this_monitoring_plugin = NULL;
39 45
40int timeout_state = STATE_CRITICAL; 46int timeout_state = STATE_CRITICAL;
41unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; 47unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
42 48
43bool _np_state_read_file(FILE *); 49bool _np_state_read_file(FILE *);
44 50
45void np_init( char *plugin_name, int argc, char **argv ) { 51void np_init(char *plugin_name, int argc, char **argv) {
46 if (this_monitoring_plugin==NULL) { 52 if (this_monitoring_plugin == NULL) {
47 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin)); 53 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin));
48 if (this_monitoring_plugin==NULL) { 54 if (this_monitoring_plugin == NULL) {
49 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 55 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
50 strerror(errno));
51 } 56 }
52 this_monitoring_plugin->plugin_name = strdup(plugin_name); 57 this_monitoring_plugin->plugin_name = strdup(plugin_name);
53 if (this_monitoring_plugin->plugin_name==NULL) 58 if (this_monitoring_plugin->plugin_name == NULL) {
54 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 59 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
60 }
55 this_monitoring_plugin->argc = argc; 61 this_monitoring_plugin->argc = argc;
56 this_monitoring_plugin->argv = argv; 62 this_monitoring_plugin->argv = argv;
57 } 63 }
58} 64}
59 65
60void np_set_args( int argc, char **argv ) { 66void np_set_args(int argc, char **argv) {
61 if (this_monitoring_plugin==NULL) 67 if (this_monitoring_plugin == NULL) {
62 die(STATE_UNKNOWN, _("This requires np_init to be called")); 68 die(STATE_UNKNOWN, _("This requires np_init to be called"));
69 }
63 70
64 this_monitoring_plugin->argc = argc; 71 this_monitoring_plugin->argc = argc;
65 this_monitoring_plugin->argv = argv; 72 this_monitoring_plugin->argv = argv;
66} 73}
67 74
68 75void np_cleanup(void) {
69void np_cleanup() { 76 if (this_monitoring_plugin != NULL) {
70 if (this_monitoring_plugin!=NULL) { 77 if (this_monitoring_plugin->state != NULL) {
71 if(this_monitoring_plugin->state!=NULL) { 78 if (this_monitoring_plugin->state->state_data) {
72 if(this_monitoring_plugin->state->state_data) {
73 np_free(this_monitoring_plugin->state->state_data->data); 79 np_free(this_monitoring_plugin->state->state_data->data);
74 np_free(this_monitoring_plugin->state->state_data); 80 np_free(this_monitoring_plugin->state->state_data);
75 } 81 }
@@ -79,48 +85,43 @@ void np_cleanup() {
79 np_free(this_monitoring_plugin->plugin_name); 85 np_free(this_monitoring_plugin->plugin_name);
80 np_free(this_monitoring_plugin); 86 np_free(this_monitoring_plugin);
81 } 87 }
82 this_monitoring_plugin=NULL; 88 this_monitoring_plugin = NULL;
83} 89}
84 90
85/* Hidden function to get a pointer to this_monitoring_plugin for testing */ 91/* Hidden function to get a pointer to this_monitoring_plugin for testing */
86void _get_monitoring_plugin( monitoring_plugin **pointer ){ 92void _get_monitoring_plugin(monitoring_plugin **pointer) { *pointer = this_monitoring_plugin; }
87 *pointer = this_monitoring_plugin;
88}
89 93
90void 94void die(int result, const char *fmt, ...) {
91die (int result, const char *fmt, ...) 95 if (fmt != NULL) {
92{
93 if(fmt!=NULL) {
94 va_list ap; 96 va_list ap;
95 va_start (ap, fmt); 97 va_start(ap, fmt);
96 vprintf (fmt, ap); 98 vprintf(fmt, ap);
97 va_end (ap); 99 va_end(ap);
98 } 100 }
99 101
100 if(this_monitoring_plugin!=NULL) { 102 if (this_monitoring_plugin != NULL) {
101 np_cleanup(); 103 np_cleanup();
102 } 104 }
103 exit (result); 105 exit(result);
104} 106}
105 107
106void set_range_start (range *this, double value) { 108void set_range_start(range *this, double value) {
107 this->start = value; 109 this->start = value;
108 this->start_infinity = false; 110 this->start_infinity = false;
109} 111}
110 112
111void set_range_end (range *this, double value) { 113void set_range_end(range *this, double value) {
112 this->end = value; 114 this->end = value;
113 this->end_infinity = false; 115 this->end_infinity = false;
114} 116}
115 117
116range 118range *parse_range_string(char *str) {
117*parse_range_string (char *str) {
118 range *temp_range; 119 range *temp_range;
119 double start; 120 double start;
120 double end; 121 double end;
121 char *end_str; 122 char *end_str;
122 123
123 temp_range = (range *) calloc(1, sizeof(range)); 124 temp_range = (range *)calloc(1, sizeof(range));
124 125
125 /* Set defaults */ 126 /* Set defaults */
126 temp_range->start = 0; 127 temp_range->start = 0;
@@ -140,10 +141,10 @@ range
140 if (str[0] == '~') { 141 if (str[0] == '~') {
141 temp_range->start_infinity = true; 142 temp_range->start_infinity = true;
142 } else { 143 } else {
143 start = strtod(str, NULL); /* Will stop at the ':' */ 144 start = strtod(str, NULL); /* Will stop at the ':' */
144 set_range_start(temp_range, start); 145 set_range_start(temp_range, start);
145 } 146 }
146 end_str++; /* Move past the ':' */ 147 end_str++; /* Move past the ':' */
147 } else { 148 } else {
148 end_str = str; 149 end_str = str;
149 } 150 }
@@ -152,9 +153,7 @@ range
152 set_range_end(temp_range, end); 153 set_range_end(temp_range, end);
153 } 154 }
154 155
155 if (temp_range->start_infinity == true || 156 if (temp_range->start_infinity == true || temp_range->end_infinity == true || temp_range->start <= temp_range->end) {
156 temp_range->end_infinity == true ||
157 temp_range->start <= temp_range->end) {
158 return temp_range; 157 return temp_range;
159 } 158 }
160 free(temp_range); 159 free(temp_range);
@@ -162,14 +161,12 @@ range
162} 161}
163 162
164/* returns 0 if okay, otherwise 1 */ 163/* returns 0 if okay, otherwise 1 */
165int 164int _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) {
166_set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
167{
168 thresholds *temp_thresholds = NULL; 165 thresholds *temp_thresholds = NULL;
169 166
170 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) 167 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) {
171 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 168 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
172 strerror(errno)); 169 }
173 170
174 temp_thresholds->warning = NULL; 171 temp_thresholds->warning = NULL;
175 temp_thresholds->critical = NULL; 172 temp_thresholds->critical = NULL;
@@ -190,9 +187,7 @@ _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_st
190 return 0; 187 return 0;
191} 188}
192 189
193void 190void set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) {
194set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
195{
196 switch (_set_thresholds(my_thresholds, warn_string, critical_string)) { 191 switch (_set_thresholds(my_thresholds, warn_string, critical_string)) {
197 case 0: 192 case 0:
198 return; 193 return;
@@ -206,7 +201,7 @@ set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_str
206 201
207void print_thresholds(const char *threshold_name, thresholds *my_threshold) { 202void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
208 printf("%s - ", threshold_name); 203 printf("%s - ", threshold_name);
209 if (! my_threshold) { 204 if (!my_threshold) {
210 printf("Threshold not set"); 205 printf("Threshold not set");
211 } else { 206 } else {
212 if (my_threshold->warning) { 207 if (my_threshold->warning) {
@@ -223,9 +218,48 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
223 printf("\n"); 218 printf("\n");
224} 219}
225 220
221/* Returns true if alert should be raised based on the range, false otherwise */
222bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
223 bool is_inside = false;
224
225 if (my_range.end_infinity == false && my_range.start_infinity == false) {
226 // range: .........|---inside---|...........
227 // value
228 if ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0)) {
229 is_inside = true;
230 } else {
231 is_inside = false;
232 }
233 } else if (my_range.start_infinity == false && my_range.end_infinity == true) {
234 // range: .........|---inside---------
235 // value
236 if (cmp_perfdata_value(my_range.start, value) < 0) {
237 is_inside = true;
238 } else {
239 is_inside = false;
240 }
241 } else if (my_range.start_infinity == true && my_range.end_infinity == false) {
242 // range: -inside--------|....................
243 // value
244 if (cmp_perfdata_value(value, my_range.end) == -1) {
245 is_inside = true;
246 } else {
247 is_inside = false;
248 }
249 } else {
250 // range from -inf to inf, so always inside
251 is_inside = true;
252 }
253
254 if ((is_inside && my_range.alert_on_inside_range == INSIDE) || (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
255 return true;
256 }
257
258 return false;
259}
260
226/* Returns true if alert should be raised based on the range */ 261/* Returns true if alert should be raised based on the range */
227bool check_range(double value, range *my_range) 262bool check_range(double value, range *my_range) {
228{
229 bool no = false; 263 bool no = false;
230 bool yes = true; 264 bool yes = true;
231 265
@@ -237,30 +271,28 @@ bool check_range(double value, range *my_range)
237 if (my_range->end_infinity == false && my_range->start_infinity == false) { 271 if (my_range->end_infinity == false && my_range->start_infinity == false) {
238 if ((my_range->start <= value) && (value <= my_range->end)) { 272 if ((my_range->start <= value) && (value <= my_range->end)) {
239 return no; 273 return no;
240 } else {
241 return yes;
242 } 274 }
243 } else if (my_range->start_infinity == false && my_range->end_infinity == true) { 275 return yes;
276 }
277
278 if (my_range->start_infinity == false && my_range->end_infinity == true) {
244 if (my_range->start <= value) { 279 if (my_range->start <= value) {
245 return no; 280 return no;
246 } else {
247 return yes;
248 } 281 }
249 } else if (my_range->start_infinity == true && my_range->end_infinity == false) { 282 return yes;
283 }
284
285 if (my_range->start_infinity == true && my_range->end_infinity == false) {
250 if (value <= my_range->end) { 286 if (value <= my_range->end) {
251 return no; 287 return no;
252 } else {
253 return yes;
254 } 288 }
255 } else { 289 return yes;
256 return no;
257 } 290 }
291 return no;
258} 292}
259 293
260/* Returns status */ 294/* Returns status */
261int 295int get_status(double value, thresholds *my_thresholds) {
262get_status(double value, thresholds *my_thresholds)
263{
264 if (my_thresholds->critical != NULL) { 296 if (my_thresholds->critical != NULL) {
265 if (check_range(value, my_thresholds->critical) == true) { 297 if (check_range(value, my_thresholds->critical) == true) {
266 return STATE_CRITICAL; 298 return STATE_CRITICAL;
@@ -274,27 +306,28 @@ get_status(double value, thresholds *my_thresholds)
274 return STATE_OK; 306 return STATE_OK;
275} 307}
276 308
277char *np_escaped_string (const char *string) { 309char *np_escaped_string(const char *string) {
278 char *data; 310 char *data;
279 int i, j=0; 311 int i;
312 int j = 0;
280 data = strdup(string); 313 data = strdup(string);
281 for (i=0; data[i]; i++) { 314 for (i = 0; data[i]; i++) {
282 if (data[i] == '\\') { 315 if (data[i] == '\\') {
283 switch(data[++i]) { 316 switch (data[++i]) {
284 case 'n': 317 case 'n':
285 data[j++] = '\n'; 318 data[j++] = '\n';
286 break; 319 break;
287 case 'r': 320 case 'r':
288 data[j++] = '\r'; 321 data[j++] = '\r';
289 break; 322 break;
290 case 't': 323 case 't':
291 data[j++] = '\t'; 324 data[j++] = '\t';
292 break; 325 break;
293 case '\\': 326 case '\\':
294 data[j++] = '\\'; 327 data[j++] = '\\';
295 break; 328 break;
296 default: 329 default:
297 data[j++] = data[i]; 330 data[j++] = data[i];
298 } 331 }
299 } else { 332 } else {
300 data[j++] = data[i]; 333 data[j++] = data[i];
@@ -313,33 +346,41 @@ int np_check_if_root(void) { return (geteuid() == 0); }
313 * data strings. 346 * data strings.
314 */ 347 */
315char *np_extract_value(const char *varlist, const char *name, char sep) { 348char *np_extract_value(const char *varlist, const char *name, char sep) {
316 char *tmp=NULL, *value=NULL; 349 char *tmp = NULL;
350 char *value = NULL;
317 int i; 351 int i;
318 352
319 while (1) { 353 while (1) {
320 /* Strip any leading space */ 354 /* Strip any leading space */
321 for (; isspace(varlist[0]); varlist++); 355 for (; isspace(varlist[0]); varlist++)
356 ;
322 357
323 if (strncmp(name, varlist, strlen(name)) == 0) { 358 if (strncmp(name, varlist, strlen(name)) == 0) {
324 varlist += strlen(name); 359 varlist += strlen(name);
325 /* strip trailing spaces */ 360 /* strip trailing spaces */
326 for (; isspace(varlist[0]); varlist++); 361 for (; isspace(varlist[0]); varlist++)
362 ;
327 363
328 if (varlist[0] == '=') { 364 if (varlist[0] == '=') {
329 /* We matched the key, go past the = sign */ 365 /* We matched the key, go past the = sign */
330 varlist++; 366 varlist++;
331 /* strip leading spaces */ 367 /* strip leading spaces */
332 for (; isspace(varlist[0]); varlist++); 368 for (; isspace(varlist[0]); varlist++)
369 ;
333 370
334 if ((tmp = index(varlist, sep))) { 371 if ((tmp = index(varlist, sep))) {
335 /* Value is delimited by a comma */ 372 /* Value is delimited by a comma */
336 if (tmp-varlist == 0) continue; 373 if (tmp - varlist == 0) {
337 value = (char *)calloc(1, tmp-varlist+1); 374 continue;
338 strncpy(value, varlist, tmp-varlist); 375 }
339 value[tmp-varlist] = '\0'; 376 value = (char *)calloc(1, tmp - varlist + 1);
377 strncpy(value, varlist, tmp - varlist);
378 value[tmp - varlist] = '\0';
340 } else { 379 } else {
341 /* Value is delimited by a \0 */ 380 /* Value is delimited by a \0 */
342 if (strlen(varlist) == 0) continue; 381 if (strlen(varlist) == 0) {
382 continue;
383 }
343 value = (char *)calloc(1, strlen(varlist) + 1); 384 value = (char *)calloc(1, strlen(varlist) + 1);
344 strncpy(value, varlist, strlen(varlist)); 385 strncpy(value, varlist, strlen(varlist));
345 value[strlen(varlist)] = '\0'; 386 value[strlen(varlist)] = '\0';
@@ -357,14 +398,16 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
357 } 398 }
358 399
359 /* Clean-up trailing spaces/newlines */ 400 /* Clean-up trailing spaces/newlines */
360 if (value) for (i=strlen(value)-1; isspace(value[i]); i--) value[i] = '\0'; 401 if (value) {
402 for (i = strlen(value) - 1; isspace(value[i]); i--) {
403 value[i] = '\0';
404 }
405 }
361 406
362 return value; 407 return value;
363} 408}
364 409
365const char * 410const char *state_text(int result) {
366state_text (int result)
367{
368 switch (result) { 411 switch (result) {
369 case STATE_OK: 412 case STATE_OK:
370 return "OK"; 413 return "OK";
@@ -383,15 +426,19 @@ state_text (int result)
383 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 426 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
384 * return the corresponding STATE_ value or ERROR) 427 * return the corresponding STATE_ value or ERROR)
385 */ 428 */
386int mp_translate_state (char *state_text) { 429int mp_translate_state(char *state_text) {
387 if (!strcasecmp(state_text,"OK") || !strcmp(state_text,"0")) 430 if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) {
388 return STATE_OK; 431 return STATE_OK;
389 if (!strcasecmp(state_text,"WARNING") || !strcmp(state_text,"1")) 432 }
433 if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1")) {
390 return STATE_WARNING; 434 return STATE_WARNING;
391 if (!strcasecmp(state_text,"CRITICAL") || !strcmp(state_text,"2")) 435 }
436 if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2")) {
392 return STATE_CRITICAL; 437 return STATE_CRITICAL;
393 if (!strcasecmp(state_text,"UNKNOWN") || !strcmp(state_text,"3")) 438 }
439 if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3")) {
394 return STATE_UNKNOWN; 440 return STATE_UNKNOWN;
441 }
395 return ERROR; 442 return ERROR;
396} 443}
397 444
@@ -400,11 +447,11 @@ int mp_translate_state (char *state_text) {
400 * hopefully a unique key per service/plugin invocation. Use the extra-opts 447 * hopefully a unique key per service/plugin invocation. Use the extra-opts
401 * parse of argv, so that uniqueness in parameters are reflected there. 448 * parse of argv, so that uniqueness in parameters are reflected there.
402 */ 449 */
403char *_np_state_generate_key() { 450char *_np_state_generate_key(void) {
404 int i; 451 int i;
405 char **argv = this_monitoring_plugin->argv; 452 char **argv = this_monitoring_plugin->argv;
406 char keyname[41]; 453 char keyname[41];
407 char *p=NULL; 454 char *p = NULL;
408 455
409 unsigned char result[256]; 456 unsigned char result[256];
410 457
@@ -418,7 +465,7 @@ char *_np_state_generate_key() {
418 465
419 EVP_DigestInit(ctx, EVP_sha256()); 466 EVP_DigestInit(ctx, EVP_sha256());
420 467
421 for(i=0; i<this_monitoring_plugin->argc; i++) { 468 for (i = 0; i < this_monitoring_plugin->argc; i++) {
422 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i])); 469 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
423 } 470 }
424 471
@@ -427,28 +474,28 @@ char *_np_state_generate_key() {
427 474
428 struct sha256_ctx ctx; 475 struct sha256_ctx ctx;
429 476
430 for(i=0; i<this_monitoring_plugin->argc; i++) { 477 for (i = 0; i < this_monitoring_plugin->argc; i++) {
431 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx); 478 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
432 } 479 }
433 480
434 sha256_finish_ctx(&ctx, result); 481 sha256_finish_ctx(&ctx, result);
435#endif // FOUNDOPENSSL 482#endif // FOUNDOPENSSL
436 483
437 for (i=0; i<20; ++i) { 484 for (i = 0; i < 20; ++i) {
438 sprintf(&keyname[2*i], "%02x", result[i]); 485 sprintf(&keyname[2 * i], "%02x", result[i]);
439 } 486 }
440 487
441 keyname[40]='\0'; 488 keyname[40] = '\0';
442 489
443 p = strdup(keyname); 490 p = strdup(keyname);
444 if(p==NULL) { 491 if (p == NULL) {
445 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 492 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
446 } 493 }
447 return p; 494 return p;
448} 495}
449 496
450void _cleanup_state_data() { 497void _cleanup_state_data(void) {
451 if (this_monitoring_plugin->state->state_data!=NULL) { 498 if (this_monitoring_plugin->state->state_data != NULL) {
452 np_free(this_monitoring_plugin->state->state_data->data); 499 np_free(this_monitoring_plugin->state->state_data->data);
453 np_free(this_monitoring_plugin->state->state_data); 500 np_free(this_monitoring_plugin->state->state_data);
454 } 501 }
@@ -459,19 +506,21 @@ void _cleanup_state_data() {
459 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY 506 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
460 * statically compiled shared state directory 507 * statically compiled shared state directory
461 */ 508 */
462char* _np_state_calculate_location_prefix(){ 509char *_np_state_calculate_location_prefix(void) {
463 char *env_dir; 510 char *env_dir;
464 511
465 /* Do not allow passing MP_STATE_PATH in setuid plugins 512 /* Do not allow passing MP_STATE_PATH in setuid plugins
466 * for security reasons */ 513 * for security reasons */
467 if (!mp_suid()) { 514 if (!mp_suid()) {
468 env_dir = getenv("MP_STATE_PATH"); 515 env_dir = getenv("MP_STATE_PATH");
469 if(env_dir && env_dir[0] != '\0') 516 if (env_dir && env_dir[0] != '\0') {
470 return env_dir; 517 return env_dir;
518 }
471 /* This is the former ENV, for backward-compatibility */ 519 /* This is the former ENV, for backward-compatibility */
472 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY"); 520 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
473 if(env_dir && env_dir[0] != '\0') 521 if (env_dir && env_dir[0] != '\0') {
474 return env_dir; 522 return env_dir;
523 }
475 } 524 }
476 525
477 return NP_STATE_DIR_PREFIX; 526 return NP_STATE_DIR_PREFIX;
@@ -486,46 +535,47 @@ void np_enable_state(char *keyname, int expected_data_version) {
486 state_key *this_state = NULL; 535 state_key *this_state = NULL;
487 char *temp_filename = NULL; 536 char *temp_filename = NULL;
488 char *temp_keyname = NULL; 537 char *temp_keyname = NULL;
489 char *p=NULL; 538 char *p = NULL;
490 int ret; 539 int ret;
491 540
492 if(this_monitoring_plugin==NULL) 541 if (this_monitoring_plugin == NULL) {
493 die(STATE_UNKNOWN, _("This requires np_init to be called")); 542 die(STATE_UNKNOWN, _("This requires np_init to be called"));
543 }
494 544
495 this_state = (state_key *) calloc(1, sizeof(state_key)); 545 this_state = (state_key *)calloc(1, sizeof(state_key));
496 if(this_state==NULL) 546 if (this_state == NULL) {
497 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 547 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
498 strerror(errno)); 548 }
499 549
500 if(keyname==NULL) { 550 if (keyname == NULL) {
501 temp_keyname = _np_state_generate_key(); 551 temp_keyname = _np_state_generate_key();
502 } else { 552 } else {
503 temp_keyname = strdup(keyname); 553 temp_keyname = strdup(keyname);
504 if(temp_keyname==NULL) 554 if (temp_keyname == NULL) {
505 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 555 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
556 }
506 } 557 }
507 /* Die if invalid characters used for keyname */ 558 /* Die if invalid characters used for keyname */
508 p = temp_keyname; 559 p = temp_keyname;
509 while(*p!='\0') { 560 while (*p != '\0') {
510 if(! (isalnum(*p) || *p == '_')) { 561 if (!(isalnum(*p) || *p == '_')) {
511 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'")); 562 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
512 } 563 }
513 p++; 564 p++;
514 } 565 }
515 this_state->name=temp_keyname; 566 this_state->name = temp_keyname;
516 this_state->plugin_name=this_monitoring_plugin->plugin_name; 567 this_state->plugin_name = this_monitoring_plugin->plugin_name;
517 this_state->data_version=expected_data_version; 568 this_state->data_version = expected_data_version;
518 this_state->state_data=NULL; 569 this_state->state_data = NULL;
519 570
520 /* Calculate filename */ 571 /* Calculate filename */
521 ret = asprintf(&temp_filename, "%s/%lu/%s/%s", 572 ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
522 _np_state_calculate_location_prefix(), (unsigned long)geteuid(), 573 this_monitoring_plugin->plugin_name, this_state->name);
523 this_monitoring_plugin->plugin_name, this_state->name); 574 if (ret < 0) {
524 if (ret < 0) 575 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
525 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 576 }
526 strerror(errno));
527 577
528 this_state->_filename=temp_filename; 578 this_state->_filename = temp_filename;
529 579
530 this_monitoring_plugin->state = this_state; 580 this_monitoring_plugin->state = this_state;
531} 581}
@@ -537,24 +587,25 @@ void np_enable_state(char *keyname, int expected_data_version) {
537 * If numerically lower, then return as no previous state. die with UNKNOWN 587 * If numerically lower, then return as no previous state. die with UNKNOWN
538 * if exceptional error. 588 * if exceptional error.
539 */ 589 */
540state_data *np_state_read() { 590state_data *np_state_read(void) {
541 state_data *this_state_data=NULL; 591 state_data *this_state_data = NULL;
542 FILE *statefile; 592 FILE *statefile;
543 bool rc = false; 593 bool rc = false;
544 594
545 if(this_monitoring_plugin==NULL) 595 if (this_monitoring_plugin == NULL) {
546 die(STATE_UNKNOWN, _("This requires np_init to be called")); 596 die(STATE_UNKNOWN, _("This requires np_init to be called"));
597 }
547 598
548 /* Open file. If this fails, no previous state found */ 599 /* Open file. If this fails, no previous state found */
549 statefile = fopen( this_monitoring_plugin->state->_filename, "r" ); 600 statefile = fopen(this_monitoring_plugin->state->_filename, "r");
550 if(statefile!=NULL) { 601 if (statefile != NULL) {
551 602
552 this_state_data = (state_data *) calloc(1, sizeof(state_data)); 603 this_state_data = (state_data *)calloc(1, sizeof(state_data));
553 if(this_state_data==NULL) 604 if (this_state_data == NULL) {
554 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 605 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
555 strerror(errno)); 606 }
556 607
557 this_state_data->data=NULL; 608 this_state_data->data = NULL;
558 this_monitoring_plugin->state->state_data = this_state_data; 609 this_monitoring_plugin->state->state_data = this_state_data;
559 610
560 rc = _np_state_read_file(statefile); 611 rc = _np_state_read_file(statefile);
@@ -562,7 +613,7 @@ state_data *np_state_read() {
562 fclose(statefile); 613 fclose(statefile);
563 } 614 }
564 615
565 if(!rc) { 616 if (!rc) {
566 _cleanup_state_data(); 617 _cleanup_state_data();
567 } 618 }
568 619
@@ -577,60 +628,70 @@ bool _np_state_read_file(FILE *f) {
577 size_t pos; 628 size_t pos;
578 char *line; 629 char *line;
579 int i; 630 int i;
580 int failure=0; 631 int failure = 0;
581 time_t current_time, data_time; 632 time_t current_time, data_time;
582 enum { STATE_FILE_VERSION, STATE_DATA_VERSION, STATE_DATA_TIME, STATE_DATA_TEXT, STATE_DATA_END } expected=STATE_FILE_VERSION; 633 enum {
634 STATE_FILE_VERSION,
635 STATE_DATA_VERSION,
636 STATE_DATA_TIME,
637 STATE_DATA_TEXT,
638 STATE_DATA_END
639 } expected = STATE_FILE_VERSION;
583 640
584 time(&current_time); 641 time(&current_time);
585 642
586 /* Note: This introduces a limit of 1024 bytes in the string data */ 643 /* Note: This introduces a limit of 1024 bytes in the string data */
587 line = (char *) calloc(1, 1024); 644 line = (char *)calloc(1, 1024);
588 if(line==NULL) 645 if (line == NULL) {
589 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 646 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
590 strerror(errno)); 647 }
591 648
592 while(!failure && (fgets(line,1024,f))!=NULL){ 649 while (!failure && (fgets(line, 1024, f)) != NULL) {
593 pos=strlen(line); 650 pos = strlen(line);
594 if(line[pos-1]=='\n') { 651 if (line[pos - 1] == '\n') {
595 line[pos-1]='\0'; 652 line[pos - 1] = '\0';
596 } 653 }
597 654
598 if(line[0] == '#') continue; 655 if (line[0] == '#') {
656 continue;
657 }
599 658
600 switch(expected) { 659 switch (expected) {
601 case STATE_FILE_VERSION: 660 case STATE_FILE_VERSION:
602 i=atoi(line); 661 i = atoi(line);
603 if(i!=NP_STATE_FORMAT_VERSION) 662 if (i != NP_STATE_FORMAT_VERSION) {
604 failure++; 663 failure++;
605 else 664 } else {
606 expected=STATE_DATA_VERSION; 665 expected = STATE_DATA_VERSION;
607 break; 666 }
608 case STATE_DATA_VERSION: 667 break;
609 i=atoi(line); 668 case STATE_DATA_VERSION:
610 if(i != this_monitoring_plugin->state->data_version) 669 i = atoi(line);
611 failure++; 670 if (i != this_monitoring_plugin->state->data_version) {
612 else 671 failure++;
613 expected=STATE_DATA_TIME; 672 } else {
614 break; 673 expected = STATE_DATA_TIME;
615 case STATE_DATA_TIME: 674 }
616 /* If time > now, error */ 675 break;
617 data_time=strtoul(line,NULL,10); 676 case STATE_DATA_TIME:
618 if(data_time > current_time) 677 /* If time > now, error */
619 failure++; 678 data_time = strtoul(line, NULL, 10);
620 else { 679 if (data_time > current_time) {
621 this_monitoring_plugin->state->state_data->time = data_time; 680 failure++;
622 expected=STATE_DATA_TEXT; 681 } else {
623 } 682 this_monitoring_plugin->state->state_data->time = data_time;
624 break; 683 expected = STATE_DATA_TEXT;
625 case STATE_DATA_TEXT: 684 }
626 this_monitoring_plugin->state->state_data->data = strdup(line); 685 break;
627 if(this_monitoring_plugin->state->state_data->data==NULL) 686 case STATE_DATA_TEXT:
628 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 687 this_monitoring_plugin->state->state_data->data = strdup(line);
629 expected=STATE_DATA_END; 688 if (this_monitoring_plugin->state->state_data->data == NULL) {
630 status=true; 689 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
631 break; 690 }
632 case STATE_DATA_END: 691 expected = STATE_DATA_END;
633 ; 692 status = true;
693 break;
694 case STATE_DATA_END:;
634 } 695 }
635 } 696 }
636 697
@@ -647,77 +708,78 @@ bool _np_state_read_file(FILE *f) {
647 */ 708 */
648void np_state_write_string(time_t data_time, char *data_string) { 709void np_state_write_string(time_t data_time, char *data_string) {
649 FILE *fp; 710 FILE *fp;
650 char *temp_file=NULL; 711 char *temp_file = NULL;
651 int fd=0, result=0; 712 int fd = 0, result = 0;
652 time_t current_time; 713 time_t current_time;
653 char *directories=NULL; 714 char *directories = NULL;
654 char *p=NULL; 715 char *p = NULL;
655 716
656 if(data_time==0) 717 if (data_time == 0) {
657 time(&current_time); 718 time(&current_time);
658 else 719 } else {
659 current_time=data_time; 720 current_time = data_time;
721 }
660 722
661 /* If file doesn't currently exist, create directories */ 723 /* If file doesn't currently exist, create directories */
662 if(access(this_monitoring_plugin->state->_filename,F_OK)!=0) { 724 if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) {
663 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename); 725 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
664 if(result < 0) 726 if (result < 0) {
665 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 727 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
666 strerror(errno)); 728 }
667 729
668 for(p=directories+1; *p; p++) { 730 for (p = directories + 1; *p; p++) {
669 if(*p=='/') { 731 if (*p == '/') {
670 *p='\0'; 732 *p = '\0';
671 if((access(directories,F_OK)!=0) && (mkdir(directories, S_IRWXU)!=0)) { 733 if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) {
672 /* Can't free this! Otherwise error message is wrong! */ 734 /* Can't free this! Otherwise error message is wrong! */
673 /* np_free(directories); */ 735 /* np_free(directories); */
674 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories); 736 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
675 } 737 }
676 *p='/'; 738 *p = '/';
677 } 739 }
678 } 740 }
679 np_free(directories); 741 np_free(directories);
680 } 742 }
681 743
682 result = asprintf(&temp_file,"%s.XXXXXX",this_monitoring_plugin->state->_filename); 744 result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename);
683 if(result < 0) 745 if (result < 0) {
684 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 746 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
685 strerror(errno)); 747 }
686 748
687 if((fd=mkstemp(temp_file))==-1) { 749 if ((fd = mkstemp(temp_file)) == -1) {
688 np_free(temp_file); 750 np_free(temp_file);
689 die(STATE_UNKNOWN, _("Cannot create temporary filename")); 751 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
690 } 752 }
691 753
692 fp=(FILE *)fdopen(fd,"w"); 754 fp = (FILE *)fdopen(fd, "w");
693 if(fp==NULL) { 755 if (fp == NULL) {
694 close(fd); 756 close(fd);
695 unlink(temp_file); 757 unlink(temp_file);
696 np_free(temp_file); 758 np_free(temp_file);
697 die(STATE_UNKNOWN, _("Unable to open temporary state file")); 759 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
698 } 760 }
699 761
700 fprintf(fp,"# NP State file\n"); 762 fprintf(fp, "# NP State file\n");
701 fprintf(fp,"%d\n",NP_STATE_FORMAT_VERSION); 763 fprintf(fp, "%d\n", NP_STATE_FORMAT_VERSION);
702 fprintf(fp,"%d\n",this_monitoring_plugin->state->data_version); 764 fprintf(fp, "%d\n", this_monitoring_plugin->state->data_version);
703 fprintf(fp,"%lu\n",current_time); 765 fprintf(fp, "%lu\n", current_time);
704 fprintf(fp,"%s\n",data_string); 766 fprintf(fp, "%s\n", data_string);
705 767
706 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP); 768 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
707 769
708 fflush(fp); 770 fflush(fp);
709 771
710 result=fclose(fp); 772 result = fclose(fp);
711 773
712 fsync(fd); 774 fsync(fd);
713 775
714 if(result!=0) { 776 if (result != 0) {
715 unlink(temp_file); 777 unlink(temp_file);
716 np_free(temp_file); 778 np_free(temp_file);
717 die(STATE_UNKNOWN, _("Error writing temp file")); 779 die(STATE_UNKNOWN, _("Error writing temp file"));
718 } 780 }
719 781
720 if(rename(temp_file, this_monitoring_plugin->state->_filename)!=0) { 782 if (rename(temp_file, this_monitoring_plugin->state->_filename) != 0) {
721 unlink(temp_file); 783 unlink(temp_file);
722 np_free(temp_file); 784 np_free(temp_file);
723 die(STATE_UNKNOWN, _("Cannot rename state temp file")); 785 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 9d4dffed..123066f8 100644
--- a/lib/utils_base.h
+++ b/lib/utils_base.h
@@ -2,8 +2,15 @@
2#define _UTILS_BASE_ 2#define _UTILS_BASE_
3/* Header file for Monitoring Plugins utils_base.c */ 3/* Header file for Monitoring Plugins utils_base.c */
4 4
5#include "../config.h"
6#include <time.h>
7
8#include "./perfdata.h"
9#include "./thresholds.h"
10
11
5#ifndef USE_OPENSSL 12#ifndef USE_OPENSSL
6# include "sha256.h" 13# include "sha256.h"
7#endif 14#endif
8 15
9/* This file holds header information for thresholds - use this in preference to 16/* This file holds header information for thresholds - use this in preference to
@@ -19,49 +26,35 @@
19#define OUTSIDE 0 26#define OUTSIDE 0
20#define INSIDE 1 27#define INSIDE 1
21 28
22typedef struct range_struct {
23 double start;
24 bool start_infinity;
25 double end;
26 int end_infinity;
27 int alert_on; /* OUTSIDE (default) or INSIDE */
28 char* text; /* original unparsed text input */
29 } range;
30
31typedef struct thresholds_struct {
32 range *warning;
33 range *critical;
34 } thresholds;
35
36#define NP_STATE_FORMAT_VERSION 1 29#define NP_STATE_FORMAT_VERSION 1
37 30
38typedef struct state_data_struct { 31typedef struct state_data_struct {
39 time_t time; 32 time_t time;
40 void *data; 33 void *data;
41 int length; /* Of binary data */ 34 int length; /* Of binary data */
42 } state_data; 35} state_data;
43
44 36
45typedef struct state_key_struct { 37typedef struct state_key_struct {
46 char *name; 38 char *name;
47 char *plugin_name; 39 char *plugin_name;
48 int data_version; 40 int data_version;
49 char *_filename; 41 char *_filename;
50 state_data *state_data; 42 state_data *state_data;
51 } state_key; 43} state_key;
52 44
53typedef struct np_struct { 45typedef struct np_struct {
54 char *plugin_name; 46 char *plugin_name;
55 state_key *state; 47 state_key *state;
56 int argc; 48 int argc;
57 char **argv; 49 char **argv;
58 } monitoring_plugin; 50} monitoring_plugin;
59 51
60range *parse_range_string (char *); 52range *parse_range_string(char *);
61int _set_thresholds(thresholds **, char *, char *); 53int _set_thresholds(thresholds **, char *, char *);
62void set_thresholds(thresholds **, char *, char *); 54void set_thresholds(thresholds **, char *, char *);
63void print_thresholds(const char *, thresholds *); 55void print_thresholds(const char *, thresholds *);
64bool check_range(double, range *); 56bool check_range(double, range *);
57bool mp_check_range(mp_perfdata_value, mp_range);
65int get_status(double, thresholds *); 58int get_status(double, thresholds *);
66 59
67/* Handle timeouts */ 60/* Handle timeouts */
@@ -71,13 +64,13 @@ extern unsigned int timeout_interval;
71/* All possible characters in a threshold range */ 64/* All possible characters in a threshold range */
72#define NP_THRESHOLDS_CHARS "-0123456789.:@~" 65#define NP_THRESHOLDS_CHARS "-0123456789.:@~"
73 66
74char *np_escaped_string (const char *); 67char *np_escaped_string(const char *);
75 68
76void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); 69void die(int, const char *, ...) __attribute__((noreturn, format(printf, 2, 3)));
77 70
78/* Return codes for _set_thresholds */ 71/* Return codes for _set_thresholds */
79#define NP_RANGE_UNPARSEABLE 1 72#define NP_RANGE_UNPARSEABLE 1
80#define NP_WARN_WITHIN_CRIT 2 73#define NP_WARN_WITHIN_CRIT 2
81 74
82/* a simple check to see if we're running as root. 75/* a simple check to see if we're running as root.
83 * returns zero on failure, nonzero on success */ 76 * returns zero on failure, nonzero on success */
@@ -93,7 +86,7 @@ int np_check_if_root(void);
93 * This function can be used to parse NTP control packet data and performance 86 * This function can be used to parse NTP control packet data and performance
94 * data strings. 87 * data strings.
95 */ 88 */
96char *np_extract_value(const char*, const char*, char); 89char *np_extract_value(const char *, const char *, char);
97 90
98/* 91/*
99 * Same as np_extract_value with separator suitable for NTP control packet 92 * Same as np_extract_value with separator suitable for NTP control packet
@@ -105,15 +98,15 @@ char *np_extract_value(const char*, const char*, char);
105 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 98 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
106 * return the corresponding NP_STATE or ERROR) 99 * return the corresponding NP_STATE or ERROR)
107 */ 100 */
108int mp_translate_state (char *); 101int mp_translate_state(char *);
109 102
110void np_enable_state(char *, int); 103void np_enable_state(char *, int);
111state_data *np_state_read(); 104state_data *np_state_read(void);
112void np_state_write_string(time_t, char *); 105void np_state_write_string(time_t, char *);
113 106
114void np_init(char *, int argc, char **argv); 107void np_init(char *, int argc, char **argv);
115void np_set_args(int argc, char **argv); 108void np_set_args(int argc, char **argv);
116void np_cleanup(); 109void np_cleanup(void);
117const char *state_text (int); 110const char *state_text(int);
118 111
119#endif /* _UTILS_BASE_ */ 112#endif /* _UTILS_BASE_ */
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c
index 7957ec14..18350ac0 100644
--- a/lib/utils_cmd.c
+++ b/lib/utils_cmd.c
@@ -1,40 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring run command utilities 3 * Monitoring run command utilities
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2006 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description : 8 * Description :
9* 9 *
10* A simple interface to executing programs from other programs, using an 10 * A simple interface to executing programs from other programs, using an
11* optimized and safe popen()-like implementation. It is considered safe 11 * optimized and safe popen()-like implementation. It is considered safe
12* in that no shell needs to be spawned and the environment passed to the 12 * in that no shell needs to be spawned and the environment passed to the
13* execve()'d program is essentially empty. 13 * execve()'d program is essentially empty.
14* 14 *
15* The code in this file is a derivative of popen.c which in turn was taken 15 * The code in this file is a derivative of popen.c which in turn was taken
16* from "Advanced Programming for the Unix Environment" by W. Richard Stevens. 16 * from "Advanced Programming for the Unix Environment" by W. Richard Stevens.
17* 17 *
18* Care has been taken to make sure the functions are async-safe. The one 18 * Care has been taken to make sure the functions are async-safe. The one
19* function which isn't is cmd_init() which it doesn't make sense to 19 * function which isn't is cmd_init() which it doesn't make sense to
20* call twice anyway, so the api as a whole should be considered async-safe. 20 * call twice anyway, so the api as a whole should be considered async-safe.
21* 21 *
22* 22 *
23* This program is free software: you can redistribute it and/or modify 23 * This program is free software: you can redistribute it and/or modify
24* it under the terms of the GNU General Public License as published by 24 * it under the terms of the GNU General Public License as published by
25* the Free Software Foundation, either version 3 of the License, or 25 * the Free Software Foundation, either version 3 of the License, or
26* (at your option) any later version. 26 * (at your option) any later version.
27* 27 *
28* This program is distributed in the hope that it will be useful, 28 * This program is distributed in the hope that it will be useful,
29* but WITHOUT ANY WARRANTY; without even the implied warranty of 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31* GNU General Public License for more details. 31 * GNU General Public License for more details.
32* 32 *
33* You should have received a copy of the GNU General Public License 33 * You should have received a copy of the GNU General Public License
34* along with this program. If not, see <http://www.gnu.org/licenses/>. 34 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35* 35 *
36* 36 *
37*****************************************************************************/ 37 *****************************************************************************/
38 38
39#define NAGIOSPLUG_API_C 1 39#define NAGIOSPLUG_API_C 1
40 40
@@ -59,7 +59,7 @@ static pid_t *_cmd_pids = NULL;
59#include <fcntl.h> 59#include <fcntl.h>
60 60
61#ifdef HAVE_SYS_WAIT_H 61#ifdef HAVE_SYS_WAIT_H
62# include <sys/wait.h> 62# include <sys/wait.h>
63#endif 63#endif
64 64
65/* used in _cmd_open to pass the environment to commands */ 65/* used in _cmd_open to pass the environment to commands */
@@ -67,57 +67,48 @@ extern char **environ;
67 67
68/** macros **/ 68/** macros **/
69#ifndef WEXITSTATUS 69#ifndef WEXITSTATUS
70# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 70# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
71#endif 71#endif
72 72
73#ifndef WIFEXITED 73#ifndef WIFEXITED
74# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 74# define WIFEXITED(stat_val) (((stat_val)&255) == 0)
75#endif 75#endif
76 76
77/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 77/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
78#if defined(SIG_IGN) && !defined(SIG_ERR) 78#if defined(SIG_IGN) && !defined(SIG_ERR)
79# define SIG_ERR ((Sigfunc *)-1) 79# define SIG_ERR ((Sigfunc *)-1)
80#endif 80#endif
81 81
82/** prototypes **/ 82/** prototypes **/
83static int _cmd_open (char *const *, int *, int *) 83static int _cmd_open(char *const *, int *, int *) __attribute__((__nonnull__(1, 2, 3)));
84 __attribute__ ((__nonnull__ (1, 2, 3)));
85 84
86static int _cmd_fetch_output (int, output *, int) 85static int _cmd_fetch_output(int, output *, int) __attribute__((__nonnull__(2)));
87 __attribute__ ((__nonnull__ (2)));
88 86
89static int _cmd_close (int); 87static int _cmd_close(int);
90 88
91/* prototype imported from utils.h */ 89/* prototype imported from utils.h */
92extern void die (int, const char *, ...) 90extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
93 __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
94
95 91
96/* this function is NOT async-safe. It is exported so multithreaded 92/* this function is NOT async-safe. It is exported so multithreaded
97 * plugins (or other apps) can call it prior to running any commands 93 * plugins (or other apps) can call it prior to running any commands
98 * through this api and thus achieve async-safeness throughout the api */ 94 * through this api and thus achieve async-safeness throughout the api */
99void 95void cmd_init(void) {
100cmd_init (void)
101{
102 long maxfd = mp_open_max(); 96 long maxfd = mp_open_max();
103 97
104 /* if maxfd is unnaturally high, we force it to a lower value 98 /* if maxfd is unnaturally high, we force it to a lower value
105 * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause 99 * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause
106 * a segfault when following calloc is called ... ) */ 100 * a segfault when following calloc is called ... ) */
107 101
108 if ( maxfd > MAXFD_LIMIT ) { 102 if (maxfd > MAXFD_LIMIT) {
109 maxfd = MAXFD_LIMIT; 103 maxfd = MAXFD_LIMIT;
110 } 104 }
111 105
112 if (!_cmd_pids) 106 if (!_cmd_pids)
113 _cmd_pids = calloc (maxfd, sizeof (pid_t)); 107 _cmd_pids = calloc(maxfd, sizeof(pid_t));
114} 108}
115 109
116
117/* Start running a command, array style */ 110/* Start running a command, array style */
118static int 111static int _cmd_open(char *const *argv, int *pfd, int *pfderr) {
119_cmd_open (char *const *argv, int *pfd, int *pfderr)
120{
121 pid_t pid; 112 pid_t pid;
122#ifdef RLIMIT_CORE 113#ifdef RLIMIT_CORE
123 struct rlimit limit; 114 struct rlimit limit;
@@ -130,26 +121,26 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
130 121
131 setenv("LC_ALL", "C", 1); 122 setenv("LC_ALL", "C", 1);
132 123
133 if (pipe (pfd) < 0 || pipe (pfderr) < 0 || (pid = fork ()) < 0) 124 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0)
134 return -1; /* errno set by the failing function */ 125 return -1; /* errno set by the failing function */
135 126
136 /* child runs exceve() and _exit. */ 127 /* child runs exceve() and _exit. */
137 if (pid == 0) { 128 if (pid == 0) {
138#ifdef RLIMIT_CORE 129#ifdef RLIMIT_CORE
139 /* the program we execve shouldn't leave core files */ 130 /* the program we execve shouldn't leave core files */
140 getrlimit (RLIMIT_CORE, &limit); 131 getrlimit(RLIMIT_CORE, &limit);
141 limit.rlim_cur = 0; 132 limit.rlim_cur = 0;
142 setrlimit (RLIMIT_CORE, &limit); 133 setrlimit(RLIMIT_CORE, &limit);
143#endif 134#endif
144 close (pfd[0]); 135 close(pfd[0]);
145 if (pfd[1] != STDOUT_FILENO) { 136 if (pfd[1] != STDOUT_FILENO) {
146 dup2 (pfd[1], STDOUT_FILENO); 137 dup2(pfd[1], STDOUT_FILENO);
147 close (pfd[1]); 138 close(pfd[1]);
148 } 139 }
149 close (pfderr[0]); 140 close(pfderr[0]);
150 if (pfderr[1] != STDERR_FILENO) { 141 if (pfderr[1] != STDERR_FILENO) {
151 dup2 (pfderr[1], STDERR_FILENO); 142 dup2(pfderr[1], STDERR_FILENO);
152 close (pfderr[1]); 143 close(pfderr[1]);
153 } 144 }
154 145
155 /* close all descriptors in _cmd_pids[] 146 /* close all descriptors in _cmd_pids[]
@@ -158,16 +149,16 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
158 long maxfd = mp_open_max(); 149 long maxfd = mp_open_max();
159 for (i = 0; i < maxfd; i++) 150 for (i = 0; i < maxfd; i++)
160 if (_cmd_pids[i] > 0) 151 if (_cmd_pids[i] > 0)
161 close (i); 152 close(i);
162 153
163 execve (argv[0], argv, environ); 154 execve(argv[0], argv, environ);
164 _exit (STATE_UNKNOWN); 155 _exit(STATE_UNKNOWN);
165 } 156 }
166 157
167 /* parent picks up execution here */ 158 /* parent picks up execution here */
168 /* close children descriptors in our address space */ 159 /* close children descriptors in our address space */
169 close (pfd[1]); 160 close(pfd[1]);
170 close (pfderr[1]); 161 close(pfderr[1]);
171 162
172 /* tag our file's entry in the pid-list and return it */ 163 /* tag our file's entry in the pid-list and return it */
173 _cmd_pids[pfd[0]] = pid; 164 _cmd_pids[pfd[0]] = pid;
@@ -175,9 +166,7 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
175 return pfd[0]; 166 return pfd[0];
176} 167}
177 168
178static int 169static int _cmd_close(int fd) {
179_cmd_close (int fd)
180{
181 int status; 170 int status;
182 pid_t pid; 171 pid_t pid;
183 172
@@ -187,40 +176,37 @@ _cmd_close (int fd)
187 return -1; 176 return -1;
188 177
189 _cmd_pids[fd] = 0; 178 _cmd_pids[fd] = 0;
190 if (close (fd) == -1) 179 if (close(fd) == -1)
191 return -1; 180 return -1;
192 181
193 /* EINTR is ok (sort of), everything else is bad */ 182 /* EINTR is ok (sort of), everything else is bad */
194 while (waitpid (pid, &status, 0) < 0) 183 while (waitpid(pid, &status, 0) < 0)
195 if (errno != EINTR) 184 if (errno != EINTR)
196 return -1; 185 return -1;
197 186
198 /* return child's termination status */ 187 /* return child's termination status */
199 return (WIFEXITED (status)) ? WEXITSTATUS (status) : -1; 188 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
200} 189}
201 190
202 191static int _cmd_fetch_output(int fd, output *op, int flags) {
203static int
204_cmd_fetch_output (int fd, output * op, int flags)
205{
206 size_t len = 0, i = 0, lineno = 0; 192 size_t len = 0, i = 0, lineno = 0;
207 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ 193 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
208 char *buf = NULL; 194 char *buf = NULL;
209 int ret; 195 int ret;
210 char tmpbuf[4096]; 196 char tmpbuf[4096];
211 197
212 op->buf = NULL; 198 op->buf = NULL;
213 op->buflen = 0; 199 op->buflen = 0;
214 while ((ret = read (fd, tmpbuf, sizeof (tmpbuf))) > 0) { 200 while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) {
215 len = (size_t) ret; 201 len = (size_t)ret;
216 op->buf = realloc (op->buf, op->buflen + len + 1); 202 op->buf = realloc(op->buf, op->buflen + len + 1);
217 memcpy (op->buf + op->buflen, tmpbuf, len); 203 memcpy(op->buf + op->buflen, tmpbuf, len);
218 op->buflen += len; 204 op->buflen += len;
219 i++; 205 i++;
220 } 206 }
221 207
222 if (ret < 0) { 208 if (ret < 0) {
223 printf ("read() returned %d: %s\n", ret, strerror (errno)); 209 printf("read() returned %d: %s\n", ret, strerror(errno));
224 return ret; 210 return ret;
225 } 211 }
226 212
@@ -231,10 +217,9 @@ _cmd_fetch_output (int fd, output * op, int flags)
231 217
232 /* and some may want both */ 218 /* and some may want both */
233 if (flags & CMD_NO_ASSOC) { 219 if (flags & CMD_NO_ASSOC) {
234 buf = malloc (op->buflen); 220 buf = malloc(op->buflen);
235 memcpy (buf, op->buf, op->buflen); 221 memcpy(buf, op->buf, op->buflen);
236 } 222 } else
237 else
238 buf = op->buf; 223 buf = op->buf;
239 224
240 op->line = NULL; 225 op->line = NULL;
@@ -248,8 +233,8 @@ _cmd_fetch_output (int fd, output * op, int flags)
248 ary_size = op->buflen >> --rsf; 233 ary_size = op->buflen >> --rsf;
249 } while (!ary_size); 234 } while (!ary_size);
250 235
251 op->line = realloc (op->line, ary_size * sizeof (char *)); 236 op->line = realloc(op->line, ary_size * sizeof(char *));
252 op->lens = realloc (op->lens, ary_size * sizeof (size_t)); 237 op->lens = realloc(op->lens, ary_size * sizeof(size_t));
253 } 238 }
254 239
255 /* set the pointer to the string */ 240 /* set the pointer to the string */
@@ -261,7 +246,7 @@ _cmd_fetch_output (int fd, output * op, int flags)
261 buf[i] = '\0'; 246 buf[i] = '\0';
262 247
263 /* calculate the string length using pointer difference */ 248 /* calculate the string length using pointer difference */
264 op->lens[lineno] = (size_t) & buf[i] - (size_t) op->line[lineno]; 249 op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno];
265 250
266 lineno++; 251 lineno++;
267 i++; 252 i++;
@@ -270,10 +255,7 @@ _cmd_fetch_output (int fd, output * op, int flags)
270 return lineno; 255 return lineno;
271} 256}
272 257
273 258int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
274int
275cmd_run (const char *cmdstring, output * out, output * err, int flags)
276{
277 int i = 0, argc; 259 int i = 0, argc;
278 size_t cmdlen; 260 size_t cmdlen;
279 char **argv = NULL; 261 char **argv = NULL;
@@ -285,120 +267,114 @@ cmd_run (const char *cmdstring, output * out, output * err, int flags)
285 267
286 /* initialize the structs */ 268 /* initialize the structs */
287 if (out) 269 if (out)
288 memset (out, 0, sizeof (output)); 270 memset(out, 0, sizeof(output));
289 if (err) 271 if (err)
290 memset (err, 0, sizeof (output)); 272 memset(err, 0, sizeof(output));
291 273
292 /* make copy of command string so strtok() doesn't silently modify it */ 274 /* make copy of command string so strtok() doesn't silently modify it */
293 /* (the calling program may want to access it later) */ 275 /* (the calling program may want to access it later) */
294 cmdlen = strlen (cmdstring); 276 cmdlen = strlen(cmdstring);
295 if ((cmd = malloc (cmdlen + 1)) == NULL) 277 if ((cmd = malloc(cmdlen + 1)) == NULL)
296 return -1; 278 return -1;
297 memcpy (cmd, cmdstring, cmdlen); 279 memcpy(cmd, cmdstring, cmdlen);
298 cmd[cmdlen] = '\0'; 280 cmd[cmdlen] = '\0';
299 281
300 /* This is not a shell, so we don't handle "???" */ 282 /* This is not a shell, so we don't handle "???" */
301 if (strstr (cmdstring, "\"")) return -1; 283 if (strstr(cmdstring, "\""))
284 return -1;
302 285
303 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 286 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
304 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 287 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''"))
305 return -1; 288 return -1;
306 289
307 /* each arg must be whitespace-separated, so args can be a maximum 290 /* each arg must be whitespace-separated, so args can be a maximum
308 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 291 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
309 argc = (cmdlen >> 1) + 2; 292 argc = (cmdlen >> 1) + 2;
310 argv = calloc (sizeof (char *), argc); 293 argv = calloc((size_t)argc, sizeof(char *));
311 294
312 if (argv == NULL) { 295 if (argv == NULL) {
313 printf ("%s\n", _("Could not malloc argv array in popen()")); 296 printf("%s\n", _("Could not malloc argv array in popen()"));
314 return -1; 297 return -1;
315 } 298 }
316 299
317 /* get command arguments (stupidly, but fairly quickly) */ 300 /* get command arguments (stupidly, but fairly quickly) */
318 while (cmd) { 301 while (cmd) {
319 str = cmd; 302 str = cmd;
320 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 303 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
321 304
322 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 305 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
323 str++; 306 str++;
324 if (!strstr (str, "'")) 307 if (!strstr(str, "'"))
325 return -1; /* balanced? */ 308 return -1; /* balanced? */
326 cmd = 1 + strstr (str, "'"); 309 cmd = 1 + strstr(str, "'");
327 str[strcspn (str, "'")] = 0; 310 str[strcspn(str, "'")] = 0;
328 } 311 } else {
329 else { 312 if (strpbrk(str, " \t\r\n")) {
330 if (strpbrk (str, " \t\r\n")) { 313 cmd = 1 + strpbrk(str, " \t\r\n");
331 cmd = 1 + strpbrk (str, " \t\r\n"); 314 str[strcspn(str, " \t\r\n")] = 0;
332 str[strcspn (str, " \t\r\n")] = 0; 315 } else {
333 }
334 else {
335 cmd = NULL; 316 cmd = NULL;
336 } 317 }
337 } 318 }
338 319
339 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 320 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n"))
340 cmd = NULL; 321 cmd = NULL;
341 322
342 argv[i++] = str; 323 argv[i++] = str;
343 } 324 }
344 325
345 return cmd_run_array (argv, out, err, flags); 326 return cmd_run_array(argv, out, err, flags);
346} 327}
347 328
348int 329int cmd_run_array(char *const *argv, output *out, output *err, int flags) {
349cmd_run_array (char *const *argv, output * out, output * err, int flags)
350{
351 int fd, pfd_out[2], pfd_err[2]; 330 int fd, pfd_out[2], pfd_err[2];
352 331
353 /* initialize the structs */ 332 /* initialize the structs */
354 if (out) 333 if (out)
355 memset (out, 0, sizeof (output)); 334 memset(out, 0, sizeof(output));
356 if (err) 335 if (err)
357 memset (err, 0, sizeof (output)); 336 memset(err, 0, sizeof(output));
358 337
359 if ((fd = _cmd_open (argv, pfd_out, pfd_err)) == -1) 338 if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1)
360 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); 339 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]);
361 340
362 if (out) 341 if (out)
363 out->lines = _cmd_fetch_output (pfd_out[0], out, flags); 342 out->lines = _cmd_fetch_output(pfd_out[0], out, flags);
364 if (err) 343 if (err)
365 err->lines = _cmd_fetch_output (pfd_err[0], err, flags); 344 err->lines = _cmd_fetch_output(pfd_err[0], err, flags);
366 345
367 return _cmd_close (fd); 346 return _cmd_close(fd);
368} 347}
369 348
370int 349int cmd_file_read(char *filename, output *out, int flags) {
371cmd_file_read ( char *filename, output *out, int flags)
372{
373 int fd; 350 int fd;
374 if(out) 351 if (out)
375 memset (out, 0, sizeof(output)); 352 memset(out, 0, sizeof(output));
376 353
377 if ((fd = open(filename, O_RDONLY)) == -1) { 354 if ((fd = open(filename, O_RDONLY)) == -1) {
378 die( STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno) ); 355 die(STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno));
379 } 356 }
380 357
381 if(out) 358 if (out)
382 out->lines = _cmd_fetch_output (fd, out, flags); 359 out->lines = _cmd_fetch_output(fd, out, flags);
383 360
384 if (close(fd) == -1) 361 if (close(fd) == -1)
385 die( STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno) ); 362 die(STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno));
386 363
387 return 0; 364 return 0;
388} 365}
389 366
390void 367void timeout_alarm_handler(int signo) {
391timeout_alarm_handler (int signo)
392{
393 if (signo == SIGALRM) { 368 if (signo == SIGALRM) {
394 printf (_("%s - Plugin timed out after %d seconds\n"), 369 printf(_("%s - Plugin timed out after %d seconds\n"), state_text(timeout_state), timeout_interval);
395 state_text(timeout_state), timeout_interval);
396 370
397 long maxfd = mp_open_max(); 371 long maxfd = mp_open_max();
398 if(_cmd_pids) for(long int i = 0; i < maxfd; i++) { 372 if (_cmd_pids)
399 if(_cmd_pids[i] != 0) kill(_cmd_pids[i], SIGKILL); 373 for (long int i = 0; i < maxfd; i++) {
400 } 374 if (_cmd_pids[i] != 0)
375 kill(_cmd_pids[i], SIGKILL);
376 }
401 377
402 exit (timeout_state); 378 exit(timeout_state);
403 } 379 }
404} 380}
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h
index 061f5d4f..d00069c9 100644
--- a/lib/utils_cmd.h
+++ b/lib/utils_cmd.h
@@ -4,12 +4,10 @@
4/* 4/*
5 * Header file for Monitoring Plugins utils_cmd.c 5 * Header file for Monitoring Plugins utils_cmd.c
6 * 6 *
7 *
8 */ 7 */
9 8
10/** types **/ 9/** types **/
11struct output 10struct output {
12{
13 char *buf; /* output buffer */ 11 char *buf; /* output buffer */
14 size_t buflen; /* output buffer content length */ 12 size_t buflen; /* output buffer content length */
15 char **line; /* array of lines (points to buf) */ 13 char **line; /* array of lines (points to buf) */
@@ -20,20 +18,18 @@ struct output
20typedef struct output output; 18typedef struct output output;
21 19
22/** prototypes **/ 20/** prototypes **/
23int cmd_run (const char *, output *, output *, int); 21int cmd_run(const char *, output *, output *, int);
24int cmd_run_array (char *const *, output *, output *, int); 22int cmd_run_array(char *const *, output *, output *, int);
25int cmd_file_read (char *, output *, int); 23int cmd_file_read(char *, output *, int);
26 24
27/* only multi-threaded plugins need to bother with this */ 25/* only multi-threaded plugins need to bother with this */
28void cmd_init (void); 26void cmd_init(void);
29#define CMD_INIT cmd_init() 27#define CMD_INIT cmd_init()
30 28
31/* possible flags for cmd_run()'s fourth argument */ 29/* possible flags for cmd_run()'s fourth argument */
32#define CMD_NO_ARRAYS 0x01 /* don't populate arrays at all */ 30#define CMD_NO_ARRAYS 0x01 /* don't populate arrays at all */
33#define CMD_NO_ASSOC 0x02 /* output.line won't point to buf */ 31#define CMD_NO_ASSOC 0x02 /* output.line won't point to buf */
34
35
36void timeout_alarm_handler (int);
37 32
33void timeout_alarm_handler(int);
38 34
39#endif /* _UTILS_CMD_ */ 35#endif /* _UTILS_CMD_ */
diff --git a/lib/utils_disk.c b/lib/utils_disk.c
index 483be06d..2b761f5e 100644
--- a/lib/utils_disk.c
+++ b/lib/utils_disk.c
@@ -1,44 +1,42 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Library for check_disk 3 * Library for check_disk
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains utilities for check_disk. These are tested by libtap 10 * This file contains utilities for check_disk. These are tested by libtap
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29#include "common.h" 29#include "common.h"
30#include "utils_disk.h" 30#include "utils_disk.h"
31#include "gl/fsusage.h" 31#include "gl/fsusage.h"
32#include <string.h> 32#include <string.h>
33 33
34void 34void np_add_name(struct name_list **list, const char *name) {
35np_add_name (struct name_list **list, const char *name) 35 struct name_list *new_entry;
36{ 36 new_entry = (struct name_list *)malloc(sizeof *new_entry);
37 struct name_list *new_entry; 37 new_entry->name = (char *)name;
38 new_entry = (struct name_list *) malloc (sizeof *new_entry); 38 new_entry->next = *list;
39 new_entry->name = (char *) name; 39 *list = new_entry;
40 new_entry->next = *list;
41 *list = new_entry;
42} 40}
43 41
44/* @brief Initialises a new regex at the begin of list via regcomp(3) 42/* @brief Initialises a new regex at the begin of list via regcomp(3)
@@ -50,17 +48,14 @@ np_add_name (struct name_list **list, const char *name)
50 * @param regex the string containing the regex which should be inserted into the list 48 * @param regex the string containing the regex which should be inserted into the list
51 * @param clags the cflags parameter for regcomp(3) 49 * @param clags the cflags parameter for regcomp(3)
52 */ 50 */
53int 51int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
54np_add_regex (struct regex_list **list, const char *regex, int cflags) 52 struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
55{
56 struct regex_list *new_entry = (struct regex_list *) malloc (sizeof *new_entry);
57 53
58 if (new_entry == NULL) { 54 if (new_entry == NULL) {
59 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 55 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
60 strerror(errno));
61 } 56 }
62 57
63 int regcomp_result = regcomp(&new_entry->regex, regex, cflags); 58 int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
64 59
65 if (!regcomp_result) { 60 if (!regcomp_result) {
66 // regcomp succeeded 61 // regcomp succeeded
@@ -74,197 +69,187 @@ np_add_regex (struct regex_list **list, const char *regex, int cflags)
74 69
75 return regcomp_result; 70 return regcomp_result;
76 } 71 }
77
78} 72}
79 73
80/* Initialises a new parameter at the end of list */ 74/* Initialises a new parameter at the end of list */
81struct parameter_list * 75struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name) {
82np_add_parameter(struct parameter_list **list, const char *name) 76 struct parameter_list *current = *list;
83{ 77 struct parameter_list *new_path;
84 struct parameter_list *current = *list; 78 new_path = (struct parameter_list *)malloc(sizeof *new_path);
85 struct parameter_list *new_path; 79 new_path->name = (char *)malloc(strlen(name) + 1);
86 new_path = (struct parameter_list *) malloc (sizeof *new_path); 80 new_path->best_match = NULL;
87 new_path->name = (char *) malloc(strlen(name) + 1); 81 new_path->name_next = NULL;
88 new_path->best_match = NULL; 82 new_path->name_prev = NULL;
89 new_path->name_next = NULL; 83 new_path->freespace_bytes = NULL;
90 new_path->name_prev = NULL; 84 new_path->freespace_units = NULL;
91 new_path->freespace_bytes = NULL; 85 new_path->freespace_percent = NULL;
92 new_path->freespace_units = NULL; 86 new_path->usedspace_bytes = NULL;
93 new_path->freespace_percent = NULL; 87 new_path->usedspace_units = NULL;
94 new_path->usedspace_bytes = NULL; 88 new_path->usedspace_percent = NULL;
95 new_path->usedspace_units = NULL; 89 new_path->usedinodes_percent = NULL;
96 new_path->usedspace_percent = NULL; 90 new_path->freeinodes_percent = NULL;
97 new_path->usedinodes_percent = NULL; 91 new_path->group = NULL;
98 new_path->freeinodes_percent = NULL; 92 new_path->dfree_pct = -1;
99 new_path->group = NULL; 93 new_path->dused_pct = -1;
100 new_path->dfree_pct = -1; 94 new_path->total = 0;
101 new_path->dused_pct = -1; 95 new_path->available = 0;
102 new_path->total = 0; 96 new_path->available_to_root = 0;
103 new_path->available = 0; 97 new_path->used = 0;
104 new_path->available_to_root = 0; 98 new_path->dused_units = 0;
105 new_path->used = 0; 99 new_path->dfree_units = 0;
106 new_path->dused_units = 0; 100 new_path->dtotal_units = 0;
107 new_path->dfree_units = 0; 101 new_path->inodes_total = 0;
108 new_path->dtotal_units = 0; 102 new_path->inodes_free = 0;
109 new_path->inodes_total = 0; 103 new_path->inodes_free_to_root = 0;
110 new_path->inodes_free = 0; 104 new_path->inodes_used = 0;
111 new_path->inodes_free_to_root = 0; 105 new_path->dused_inodes_percent = 0;
112 new_path->inodes_used = 0; 106 new_path->dfree_inodes_percent = 0;
113 new_path->dused_inodes_percent = 0; 107
114 new_path->dfree_inodes_percent = 0; 108 strcpy(new_path->name, name);
115 109
116 strcpy(new_path->name, name); 110 if (current == NULL) {
117 111 *list = new_path;
118 if (current == NULL) { 112 new_path->name_prev = NULL;
119 *list = new_path; 113 } else {
120 new_path->name_prev = NULL; 114 while (current->name_next) {
121 } else { 115 current = current->name_next;
122 while (current->name_next) { 116 }
123 current = current->name_next; 117 current->name_next = new_path;
124 } 118 new_path->name_prev = current;
125 current->name_next = new_path; 119 }
126 new_path->name_prev = current; 120 return new_path;
127 }
128 return new_path;
129} 121}
130 122
131/* Delete a given parameter from list and return pointer to next element*/ 123/* Delete a given parameter from list and return pointer to next element*/
132struct parameter_list * 124struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev) {
133np_del_parameter(struct parameter_list *item, struct parameter_list *prev) 125 if (item == NULL) {
134{ 126 return NULL;
135 if (item == NULL) { 127 }
136 return NULL; 128 struct parameter_list *next;
137 } 129
138 struct parameter_list *next; 130 if (item->name_next)
139 131 next = item->name_next;
140 if (item->name_next) 132 else
141 next = item->name_next; 133 next = NULL;
142 else 134
143 next = NULL; 135 if (next)
144 136 next->name_prev = prev;
145 if (next)
146 next->name_prev = prev;
147
148 if (prev)
149 prev->name_next = next;
150
151 if (item->name) {
152 free(item->name);
153 }
154 free(item);
155
156 return next;
157}
158 137
138 if (prev)
139 prev->name_next = next;
140
141 if (item->name) {
142 free(item->name);
143 }
144 free(item);
145
146 return next;
147}
159 148
160/* returns a pointer to the struct found in the list */ 149/* returns a pointer to the struct found in the list */
161struct parameter_list * 150struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name) {
162np_find_parameter(struct parameter_list *list, const char *name) 151 struct parameter_list *temp_list;
163{ 152 for (temp_list = list; temp_list; temp_list = temp_list->name_next) {
164 struct parameter_list *temp_list; 153 if (!strcmp(temp_list->name, name))
165 for (temp_list = list; temp_list; temp_list = temp_list->name_next) { 154 return temp_list;
166 if (! strcmp(temp_list->name, name)) 155 }
167 return temp_list; 156
168 } 157 return NULL;
169
170 return NULL;
171} 158}
172 159
173void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) { 160void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) {
174 struct parameter_list *d; 161 struct parameter_list *d;
175 for (d = desired; d; d= d->name_next) { 162 for (d = desired; d; d = d->name_next) {
176 if (! d->best_match) { 163 if (!d->best_match) {
177 struct mount_entry *me; 164 struct mount_entry *me;
178 size_t name_len = strlen(d->name); 165 size_t name_len = strlen(d->name);
179 size_t best_match_len = 0; 166 size_t best_match_len = 0;
180 struct mount_entry *best_match = NULL; 167 struct mount_entry *best_match = NULL;
181 struct fs_usage fsp; 168 struct fs_usage fsp;
182 169
183 /* set best match if path name exactly matches a mounted device name */ 170 /* set best match if path name exactly matches a mounted device name */
184 for (me = mount_list; me; me = me->me_next) { 171 for (me = mount_list; me; me = me->me_next) {
185 if (strcmp(me->me_devname, d->name)==0) { 172 if (strcmp(me->me_devname, d->name) == 0) {
186 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) { 173 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
187 best_match = me; 174 best_match = me;
188 } 175 }
189 } 176 }
190 } 177 }
191 178
192 /* set best match by directory name if no match was found by devname */ 179 /* set best match by directory name if no match was found by devname */
193 if (! best_match) { 180 if (!best_match) {
194 for (me = mount_list; me; me = me->me_next) { 181 for (me = mount_list; me; me = me->me_next) {
195 size_t len = strlen (me->me_mountdir); 182 size_t len = strlen(me->me_mountdir);
196 if ((!exact && (best_match_len <= len && len <= name_len && 183 if ((!exact &&
197 (len == 1 || strncmp (me->me_mountdir, d->name, len) == 0))) 184 (best_match_len <= len && len <= name_len && (len == 1 || strncmp(me->me_mountdir, d->name, len) == 0))) ||
198 || (exact && strcmp(me->me_mountdir, d->name)==0)) 185 (exact && strcmp(me->me_mountdir, d->name) == 0)) {
199 { 186 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
200 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) { 187 best_match = me;
201 best_match = me; 188 best_match_len = len;
202 best_match_len = len; 189 }
203 } 190 }
204 } 191 }
205 } 192 }
206 } 193
207 194 if (best_match) {
208 if (best_match) { 195 d->best_match = best_match;
209 d->best_match = best_match; 196 } else {
210 } else { 197 d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
211 d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */ 198 }
212 } 199 }
213 } 200 }
214 }
215} 201}
216 202
217/* Returns true if name is in list */ 203/* Returns true if name is in list */
218bool np_find_name (struct name_list *list, const char *name) { 204bool np_find_name(struct name_list *list, const char *name) {
219 const struct name_list *n; 205 const struct name_list *n;
220 206
221 if (list == NULL || name == NULL) { 207 if (list == NULL || name == NULL) {
222 return false; 208 return false;
223 } 209 }
224 for (n = list; n; n = n->next) { 210 for (n = list; n; n = n->next) {
225 if (!strcmp(name, n->name)) { 211 if (!strcmp(name, n->name)) {
226 return true; 212 return true;
227 } 213 }
228 } 214 }
229 return false; 215 return false;
230} 216}
231 217
232/* Returns true if name is in list */ 218/* Returns true if name is in list */
233bool np_find_regmatch (struct regex_list *list, const char *name) { 219bool np_find_regmatch(struct regex_list *list, const char *name) {
234 int len; 220 int len;
235 regmatch_t m; 221 regmatch_t m;
236 222
237 if (name == NULL) { 223 if (name == NULL) {
238 return false; 224 return false;
239 } 225 }
240 226
241 len = strlen(name); 227 len = strlen(name);
242 228
243 for (; list; list = list->next) { 229 for (; list; list = list->next) {
244 /* Emulate a full match as if surrounded with ^( )$ 230 /* Emulate a full match as if surrounded with ^( )$
245 by checking whether the match spans the whole name */ 231 by checking whether the match spans the whole name */
246 if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) { 232 if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) {
247 return true; 233 return true;
248 } 234 }
249 } 235 }
250 236
251 return false; 237 return false;
252} 238}
253 239
254bool np_seen_name(struct name_list *list, const char *name) { 240bool np_seen_name(struct name_list *list, const char *name) {
255 const struct name_list *s; 241 const struct name_list *s;
256 for (s = list; s; s=s->next) { 242 for (s = list; s; s = s->next) {
257 if (!strcmp(s->name, name)) { 243 if (!strcmp(s->name, name)) {
258 return true; 244 return true;
259 } 245 }
260 } 246 }
261 return false; 247 return false;
262} 248}
263 249
264bool np_regex_match_mount_entry (struct mount_entry* me, regex_t* re) { 250bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
265 if (regexec(re, me->me_devname, (size_t) 0, NULL, 0) == 0 || 251 if (regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0 || regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0) {
266 regexec(re, me->me_mountdir, (size_t) 0, NULL, 0) == 0 ) { 252 return true;
267 return true; 253 }
268 }
269 return false; 254 return false;
270} 255}
diff --git a/lib/utils_disk.h b/lib/utils_disk.h
index 5b2caf23..c5e81dc1 100644
--- a/lib/utils_disk.h
+++ b/lib/utils_disk.h
@@ -4,49 +4,45 @@
4#include "utils_base.h" 4#include "utils_base.h"
5#include "regex.h" 5#include "regex.h"
6 6
7struct name_list 7struct name_list {
8{ 8 char *name;
9 char *name; 9 struct name_list *next;
10 struct name_list *next;
11}; 10};
12 11
13struct regex_list 12struct regex_list {
14{ 13 regex_t regex;
15 regex_t regex; 14 struct regex_list *next;
16 struct regex_list *next;
17}; 15};
18 16
19struct parameter_list 17struct parameter_list {
20{ 18 char *name;
21 char *name; 19 thresholds *freespace_bytes;
22 thresholds *freespace_bytes; 20 thresholds *freespace_units;
23 thresholds *freespace_units; 21 thresholds *freespace_percent;
24 thresholds *freespace_percent; 22 thresholds *usedspace_bytes;
25 thresholds *usedspace_bytes; 23 thresholds *usedspace_units;
26 thresholds *usedspace_units; 24 thresholds *usedspace_percent;
27 thresholds *usedspace_percent; 25 thresholds *usedinodes_percent;
28 thresholds *usedinodes_percent; 26 thresholds *freeinodes_percent;
29 thresholds *freeinodes_percent; 27 char *group;
30 char *group; 28 struct mount_entry *best_match;
31 struct mount_entry *best_match; 29 struct parameter_list *name_next;
32 struct parameter_list *name_next; 30 struct parameter_list *name_prev;
33 struct parameter_list *name_prev; 31 uintmax_t total, available, available_to_root, used, inodes_free, inodes_free_to_root, inodes_used, inodes_total;
34 uintmax_t total, available, available_to_root, used, 32 double dfree_pct, dused_pct;
35 inodes_free, inodes_free_to_root, inodes_used, inodes_total; 33 uint64_t dused_units, dfree_units, dtotal_units;
36 double dfree_pct, dused_pct; 34 double dused_inodes_percent, dfree_inodes_percent;
37 uint64_t dused_units, dfree_units, dtotal_units;
38 double dused_inodes_percent, dfree_inodes_percent;
39}; 35};
40 36
41void np_add_name (struct name_list **list, const char *name); 37void np_add_name(struct name_list **list, const char *name);
42bool np_find_name (struct name_list *list, const char *name); 38bool np_find_name(struct name_list *list, const char *name);
43bool np_seen_name (struct name_list *list, const char *name); 39bool np_seen_name(struct name_list *list, const char *name);
44int np_add_regex (struct regex_list **list, const char *regex, int cflags); 40int np_add_regex(struct regex_list **list, const char *regex, int cflags);
45bool np_find_regmatch (struct regex_list *list, const char *name); 41bool np_find_regmatch(struct regex_list *list, const char *name);
46struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name); 42struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name);
47struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name); 43struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name);
48struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev); 44struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev);
49 45
50int search_parameter_list (struct parameter_list *list, const char *name); 46int search_parameter_list(struct parameter_list *list, const char *name);
51void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact); 47void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact);
52bool np_regex_match_mount_entry (struct mount_entry* me, regex_t* re); 48bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re);
diff --git a/lib/utils_tcp.c b/lib/utils_tcp.c
index 23ee4a95..daae1d54 100644
--- a/lib/utils_tcp.c
+++ b/lib/utils_tcp.c
@@ -1,51 +1,46 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Library for check_tcp 3 * Library for check_tcp
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2013 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains utilities for check_tcp. These are tested by libtap 10 * This file contains utilities for check_tcp. These are tested by libtap
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29#include "common.h" 29#include "common.h"
30#include "utils_tcp.h" 30#include "utils_tcp.h"
31 31
32#define VERBOSE(message) \ 32#define VERBOSE(message) \
33 do { \ 33 do { \
34 if (flags & NP_MATCH_VERBOSE) \ 34 if (flags & NP_MATCH_VERBOSE) \
35 puts(message); \ 35 puts(message); \
36 } while (0) 36 } while (0)
37 37
38enum np_match_result 38enum np_match_result np_expect_match(char *status, char **server_expect, int expect_count, int flags) {
39np_expect_match(char *status, char **server_expect, int expect_count, int flags)
40{
41 int i, match = 0, partial = 0; 39 int i, match = 0, partial = 0;
42 40
43 for (i = 0; i < expect_count; i++) { 41 for (i = 0; i < expect_count; i++) {
44 if (flags & NP_MATCH_VERBOSE) 42 if (flags & NP_MATCH_VERBOSE)
45 printf("looking for [%s] %s [%s]\n", server_expect[i], 43 printf("looking for [%s] %s [%s]\n", server_expect[i], (flags & NP_MATCH_EXACT) ? "in beginning of" : "anywhere in", status);
46 (flags & NP_MATCH_EXACT) ?
47 "in beginning of" : "anywhere in",
48 status);
49 44
50 if (flags & NP_MATCH_EXACT) { 45 if (flags & NP_MATCH_EXACT) {
51 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) { 46 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) {
@@ -58,15 +53,14 @@ np_expect_match(char *status, char **server_expect, int expect_count, int flags)
58 continue; 53 continue;
59 } 54 }
60 } else if (strstr(status, server_expect[i]) != NULL) { 55 } else if (strstr(status, server_expect[i]) != NULL) {
61 VERBOSE("found it"); 56 VERBOSE("found it");
62 match++; 57 match++;
63 continue; 58 continue;
64 } 59 }
65 VERBOSE("couldn't find it"); 60 VERBOSE("couldn't find it");
66 } 61 }
67 62
68 if ((flags & NP_MATCH_ALL && match == expect_count) || 63 if ((flags & NP_MATCH_ALL && match == expect_count) || (!(flags & NP_MATCH_ALL) && match >= 1))
69 (!(flags & NP_MATCH_ALL) && match >= 1))
70 return NP_MATCH_SUCCESS; 64 return NP_MATCH_SUCCESS;
71 else if (partial > 0 || !(flags & NP_MATCH_EXACT)) 65 else if (partial > 0 || !(flags & NP_MATCH_EXACT))
72 return NP_MATCH_RETRY; 66 return NP_MATCH_RETRY;
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h
index 0328a9cf..d5999e9b 100644
--- a/lib/utils_tcp.h
+++ b/lib/utils_tcp.h
@@ -1,8 +1,8 @@
1/* Header file for utils_tcp */ 1/* Header file for utils_tcp */
2 2
3#define NP_MATCH_ALL 0x1 3#define NP_MATCH_ALL 0x1
4#define NP_MATCH_EXACT 0x2 4#define NP_MATCH_EXACT 0x2
5#define NP_MATCH_VERBOSE 0x4 5#define NP_MATCH_VERBOSE 0x4
6 6
7/* 7/*
8 * The NP_MATCH_RETRY state indicates that matching might succeed if 8 * The NP_MATCH_RETRY state indicates that matching might succeed if
@@ -16,7 +16,4 @@ enum np_match_result {
16 NP_MATCH_RETRY 16 NP_MATCH_RETRY
17}; 17};
18 18
19enum np_match_result np_expect_match(char *status, 19enum np_match_result np_expect_match(char *status, char **server_expect, int server_expect_count, int flags);
20 char **server_expect,
21 int server_expect_count,
22 int flags);
diff --git a/lib/vendor/cJSON/cJSON.c b/lib/vendor/cJSON/cJSON.c
new file mode 100644
index 00000000..12076e92
--- /dev/null
+++ b/lib/vendor/cJSON/cJSON.c
@@ -0,0 +1,3165 @@
1/*
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23/* cJSON */
24/* JSON parser in C. */
25
26/* disable warnings about old C89 functions in MSVC */
27#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
28#define _CRT_SECURE_NO_DEPRECATE
29#endif
30
31#ifdef __GNUC__
32#pragma GCC visibility push(default)
33#endif
34#if defined(_MSC_VER)
35#pragma warning (push)
36/* disable warning about single line comments in system headers */
37#pragma warning (disable : 4001)
38#endif
39
40#include "../../../config.h"
41#include <string.h>
42#include <stdio.h>
43#include <math.h>
44#include <stdlib.h>
45#include <limits.h>
46#include <ctype.h>
47#include <float.h>
48
49#ifdef ENABLE_LOCALES
50#include <locale.h>
51#endif
52
53#if defined(_MSC_VER)
54#pragma warning (pop)
55#endif
56#ifdef __GNUC__
57#pragma GCC visibility pop
58#endif
59
60#include "cJSON.h"
61
62/* define our own boolean type */
63#ifdef true
64#undef true
65#endif
66#define true ((cJSON_bool)1)
67
68#ifdef false
69#undef false
70#endif
71#define false ((cJSON_bool)0)
72
73/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
74#ifndef isinf
75#define isinf(d) (isnan((d - d)) && !isnan(d))
76#endif
77#ifndef isnan
78#define isnan(d) (d != d)
79#endif
80
81#ifndef NAN
82#ifdef _WIN32
83#define NAN sqrt(-1.0)
84#else
85#define NAN 0.0/0.0
86#endif
87#endif
88
89typedef struct {
90 const unsigned char *json;
91 size_t position;
92} error;
93static error global_error = { NULL, 0 };
94
95CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
96{
97 return (const char*) (global_error.json + global_error.position);
98}
99
100CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
101{
102 if (!cJSON_IsString(item))
103 {
104 return NULL;
105 }
106
107 return item->valuestring;
108}
109
110CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
111{
112 if (!cJSON_IsNumber(item))
113 {
114 return (double) NAN;
115 }
116
117 return item->valuedouble;
118}
119
120/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
121#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18)
122 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
123#endif
124
125CJSON_PUBLIC(const char*) cJSON_Version(void)
126{
127 static char version[15];
128 sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
129
130 return version;
131}
132
133/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
134static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
135{
136 if ((string1 == NULL) || (string2 == NULL))
137 {
138 return 1;
139 }
140
141 if (string1 == string2)
142 {
143 return 0;
144 }
145
146 for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
147 {
148 if (*string1 == '\0')
149 {
150 return 0;
151 }
152 }
153
154 return tolower(*string1) - tolower(*string2);
155}
156
157typedef struct internal_hooks
158{
159 void *(CJSON_CDECL *allocate)(size_t size);
160 void (CJSON_CDECL *deallocate)(void *pointer);
161 void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
162} internal_hooks;
163
164#if defined(_MSC_VER)
165/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
166static void * CJSON_CDECL internal_malloc(size_t size)
167{
168 return malloc(size);
169}
170static void CJSON_CDECL internal_free(void *pointer)
171{
172 free(pointer);
173}
174static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
175{
176 return realloc(pointer, size);
177}
178#else
179#define internal_malloc malloc
180#define internal_free free
181#define internal_realloc realloc
182#endif
183
184/* strlen of character literals resolved at compile time */
185#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
186
187static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
188
189static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
190{
191 size_t length = 0;
192 unsigned char *copy = NULL;
193
194 if (string == NULL)
195 {
196 return NULL;
197 }
198
199 length = strlen((const char*)string) + sizeof("");
200 copy = (unsigned char*)hooks->allocate(length);
201 if (copy == NULL)
202 {
203 return NULL;
204 }
205 memcpy(copy, string, length);
206
207 return copy;
208}
209
210CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
211{
212 if (hooks == NULL)
213 {
214 /* Reset hooks */
215 global_hooks.allocate = malloc;
216 global_hooks.deallocate = free;
217 global_hooks.reallocate = realloc;
218 return;
219 }
220
221 global_hooks.allocate = malloc;
222 if (hooks->malloc_fn != NULL)
223 {
224 global_hooks.allocate = hooks->malloc_fn;
225 }
226
227 global_hooks.deallocate = free;
228 if (hooks->free_fn != NULL)
229 {
230 global_hooks.deallocate = hooks->free_fn;
231 }
232
233 /* use realloc only if both free and malloc are used */
234 global_hooks.reallocate = NULL;
235 if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
236 {
237 global_hooks.reallocate = realloc;
238 }
239}
240
241/* Internal constructor. */
242static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
243{
244 cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
245 if (node)
246 {
247 memset(node, '\0', sizeof(cJSON));
248 }
249
250 return node;
251}
252
253/* Delete a cJSON structure. */
254CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
255{
256 cJSON *next = NULL;
257 while (item != NULL)
258 {
259 next = item->next;
260 if (!(item->type & cJSON_IsReference) && (item->child != NULL))
261 {
262 cJSON_Delete(item->child);
263 }
264 if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
265 {
266 global_hooks.deallocate(item->valuestring);
267 item->valuestring = NULL;
268 }
269 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
270 {
271 global_hooks.deallocate(item->string);
272 item->string = NULL;
273 }
274 global_hooks.deallocate(item);
275 item = next;
276 }
277}
278
279/* get the decimal point character of the current locale */
280static unsigned char get_decimal_point(void)
281{
282#ifdef ENABLE_LOCALES
283 struct lconv *lconv = localeconv();
284 return (unsigned char) lconv->decimal_point[0];
285#else
286 return '.';
287#endif
288}
289
290typedef struct
291{
292 const unsigned char *content;
293 size_t length;
294 size_t offset;
295 size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
296 internal_hooks hooks;
297} parse_buffer;
298
299/* check if the given size is left to read in a given parse buffer (starting with 1) */
300#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
301/* check if the buffer can be accessed at the given index (starting with 0) */
302#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
303#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
304/* get a pointer to the buffer at the position */
305#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
306
307/* Parse the input text to generate a number, and populate the result into item. */
308static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
309{
310 double number = 0;
311 unsigned char *after_end = NULL;
312 unsigned char number_c_string[64];
313 unsigned char decimal_point = get_decimal_point();
314 size_t i = 0;
315
316 if ((input_buffer == NULL) || (input_buffer->content == NULL))
317 {
318 return false;
319 }
320
321 /* copy the number into a temporary buffer and replace '.' with the decimal point
322 * of the current locale (for strtod)
323 * This also takes care of '\0' not necessarily being available for marking the end of the input */
324 for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
325 {
326 switch (buffer_at_offset(input_buffer)[i])
327 {
328 case '0':
329 case '1':
330 case '2':
331 case '3':
332 case '4':
333 case '5':
334 case '6':
335 case '7':
336 case '8':
337 case '9':
338 case '+':
339 case '-':
340 case 'e':
341 case 'E':
342 number_c_string[i] = buffer_at_offset(input_buffer)[i];
343 break;
344
345 case '.':
346 number_c_string[i] = decimal_point;
347 break;
348
349 default:
350 goto loop_end;
351 }
352 }
353loop_end:
354 number_c_string[i] = '\0';
355
356 number = strtod((const char*)number_c_string, (char**)&after_end);
357 if (number_c_string == after_end)
358 {
359 return false; /* parse_error */
360 }
361
362 item->valuedouble = number;
363
364 /* use saturation in case of overflow */
365 if (number >= INT_MAX)
366 {
367 item->valueint = INT_MAX;
368 }
369 else if (number <= (double)INT_MIN)
370 {
371 item->valueint = INT_MIN;
372 }
373 else
374 {
375 item->valueint = (int)number;
376 }
377
378 item->type = cJSON_Number;
379
380 input_buffer->offset += (size_t)(after_end - number_c_string);
381 return true;
382}
383
384/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
385CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
386{
387 if (number >= INT_MAX)
388 {
389 object->valueint = INT_MAX;
390 }
391 else if (number <= (double)INT_MIN)
392 {
393 object->valueint = INT_MIN;
394 }
395 else
396 {
397 object->valueint = (int)number;
398 }
399
400 return object->valuedouble = number;
401}
402
403/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
404CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
405{
406 char *copy = NULL;
407 size_t v1_len;
408 size_t v2_len;
409 /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
410 if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference))
411 {
412 return NULL;
413 }
414 /* return NULL if the object is corrupted or valuestring is NULL */
415 if (object->valuestring == NULL || valuestring == NULL)
416 {
417 return NULL;
418 }
419
420 v1_len = strlen(valuestring);
421 v2_len = strlen(object->valuestring);
422
423 if (v1_len <= v2_len)
424 {
425 /* strcpy does not handle overlapping string: [X1, X2] [Y1, Y2] => X2 < Y1 or Y2 < X1 */
426 if (!( valuestring + v1_len < object->valuestring || object->valuestring + v2_len < valuestring ))
427 {
428 return NULL;
429 }
430 strcpy(object->valuestring, valuestring);
431 return object->valuestring;
432 }
433 copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
434 if (copy == NULL)
435 {
436 return NULL;
437 }
438 if (object->valuestring != NULL)
439 {
440 cJSON_free(object->valuestring);
441 }
442 object->valuestring = copy;
443
444 return copy;
445}
446
447typedef struct
448{
449 unsigned char *buffer;
450 size_t length;
451 size_t offset;
452 size_t depth; /* current nesting depth (for formatted printing) */
453 cJSON_bool noalloc;
454 cJSON_bool format; /* is this print a formatted print */
455 internal_hooks hooks;
456} printbuffer;
457
458/* realloc printbuffer if necessary to have at least "needed" bytes more */
459static unsigned char* ensure(printbuffer * const p, size_t needed)
460{
461 unsigned char *newbuffer = NULL;
462 size_t newsize = 0;
463
464 if ((p == NULL) || (p->buffer == NULL))
465 {
466 return NULL;
467 }
468
469 if ((p->length > 0) && (p->offset >= p->length))
470 {
471 /* make sure that offset is valid */
472 return NULL;
473 }
474
475 if (needed > INT_MAX)
476 {
477 /* sizes bigger than INT_MAX are currently not supported */
478 return NULL;
479 }
480
481 needed += p->offset + 1;
482 if (needed <= p->length)
483 {
484 return p->buffer + p->offset;
485 }
486
487 if (p->noalloc) {
488 return NULL;
489 }
490
491 /* calculate new buffer size */
492 if (needed > (INT_MAX / 2))
493 {
494 /* overflow of int, use INT_MAX if possible */
495 if (needed <= INT_MAX)
496 {
497 newsize = INT_MAX;
498 }
499 else
500 {
501 return NULL;
502 }
503 }
504 else
505 {
506 newsize = needed * 2;
507 }
508
509 if (p->hooks.reallocate != NULL)
510 {
511 /* reallocate with realloc if available */
512 newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
513 if (newbuffer == NULL)
514 {
515 p->hooks.deallocate(p->buffer);
516 p->length = 0;
517 p->buffer = NULL;
518
519 return NULL;
520 }
521 }
522 else
523 {
524 /* otherwise reallocate manually */
525 newbuffer = (unsigned char*)p->hooks.allocate(newsize);
526 if (!newbuffer)
527 {
528 p->hooks.deallocate(p->buffer);
529 p->length = 0;
530 p->buffer = NULL;
531
532 return NULL;
533 }
534
535 memcpy(newbuffer, p->buffer, p->offset + 1);
536 p->hooks.deallocate(p->buffer);
537 }
538 p->length = newsize;
539 p->buffer = newbuffer;
540
541 return newbuffer + p->offset;
542}
543
544/* calculate the new length of the string in a printbuffer and update the offset */
545static void update_offset(printbuffer * const buffer)
546{
547 const unsigned char *buffer_pointer = NULL;
548 if ((buffer == NULL) || (buffer->buffer == NULL))
549 {
550 return;
551 }
552 buffer_pointer = buffer->buffer + buffer->offset;
553
554 buffer->offset += strlen((const char*)buffer_pointer);
555}
556
557/* securely comparison of floating-point variables */
558static cJSON_bool compare_double(double a, double b)
559{
560 double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
561 return (fabs(a - b) <= maxVal * DBL_EPSILON);
562}
563
564/* Render the number nicely from the given item into a string. */
565static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
566{
567 unsigned char *output_pointer = NULL;
568 double d = item->valuedouble;
569 int length = 0;
570 size_t i = 0;
571 unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
572 unsigned char decimal_point = get_decimal_point();
573 double test = 0.0;
574
575 if (output_buffer == NULL)
576 {
577 return false;
578 }
579
580 /* This checks for NaN and Infinity */
581 if (isnan(d) || isinf(d))
582 {
583 length = sprintf((char*)number_buffer, "null");
584 }
585 else if(d == (double)item->valueint)
586 {
587 length = sprintf((char*)number_buffer, "%d", item->valueint);
588 }
589 else
590 {
591 /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
592 length = sprintf((char*)number_buffer, "%1.15g", d);
593
594 /* Check whether the original double can be recovered */
595 if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
596 {
597 /* If not, print with 17 decimal places of precision */
598 length = sprintf((char*)number_buffer, "%1.17g", d);
599 }
600 }
601
602 /* sprintf failed or buffer overrun occurred */
603 if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
604 {
605 return false;
606 }
607
608 /* reserve appropriate space in the output */
609 output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
610 if (output_pointer == NULL)
611 {
612 return false;
613 }
614
615 /* copy the printed number to the output and replace locale
616 * dependent decimal point with '.' */
617 for (i = 0; i < ((size_t)length); i++)
618 {
619 if (number_buffer[i] == decimal_point)
620 {
621 output_pointer[i] = '.';
622 continue;
623 }
624
625 output_pointer[i] = number_buffer[i];
626 }
627 output_pointer[i] = '\0';
628
629 output_buffer->offset += (size_t)length;
630
631 return true;
632}
633
634/* parse 4 digit hexadecimal number */
635static unsigned parse_hex4(const unsigned char * const input)
636{
637 unsigned int h = 0;
638 size_t i = 0;
639
640 for (i = 0; i < 4; i++)
641 {
642 /* parse digit */
643 if ((input[i] >= '0') && (input[i] <= '9'))
644 {
645 h += (unsigned int) input[i] - '0';
646 }
647 else if ((input[i] >= 'A') && (input[i] <= 'F'))
648 {
649 h += (unsigned int) 10 + input[i] - 'A';
650 }
651 else if ((input[i] >= 'a') && (input[i] <= 'f'))
652 {
653 h += (unsigned int) 10 + input[i] - 'a';
654 }
655 else /* invalid */
656 {
657 return 0;
658 }
659
660 if (i < 3)
661 {
662 /* shift left to make place for the next nibble */
663 h = h << 4;
664 }
665 }
666
667 return h;
668}
669
670/* converts a UTF-16 literal to UTF-8
671 * A literal can be one or two sequences of the form \uXXXX */
672static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
673{
674 long unsigned int codepoint = 0;
675 unsigned int first_code = 0;
676 const unsigned char *first_sequence = input_pointer;
677 unsigned char utf8_length = 0;
678 unsigned char utf8_position = 0;
679 unsigned char sequence_length = 0;
680 unsigned char first_byte_mark = 0;
681
682 if ((input_end - first_sequence) < 6)
683 {
684 /* input ends unexpectedly */
685 goto fail;
686 }
687
688 /* get the first utf16 sequence */
689 first_code = parse_hex4(first_sequence + 2);
690
691 /* check that the code is valid */
692 if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
693 {
694 goto fail;
695 }
696
697 /* UTF16 surrogate pair */
698 if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
699 {
700 const unsigned char *second_sequence = first_sequence + 6;
701 unsigned int second_code = 0;
702 sequence_length = 12; /* \uXXXX\uXXXX */
703
704 if ((input_end - second_sequence) < 6)
705 {
706 /* input ends unexpectedly */
707 goto fail;
708 }
709
710 if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
711 {
712 /* missing second half of the surrogate pair */
713 goto fail;
714 }
715
716 /* get the second utf16 sequence */
717 second_code = parse_hex4(second_sequence + 2);
718 /* check that the code is valid */
719 if ((second_code < 0xDC00) || (second_code > 0xDFFF))
720 {
721 /* invalid second half of the surrogate pair */
722 goto fail;
723 }
724
725
726 /* calculate the unicode codepoint from the surrogate pair */
727 codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
728 }
729 else
730 {
731 sequence_length = 6; /* \uXXXX */
732 codepoint = first_code;
733 }
734
735 /* encode as UTF-8
736 * takes at maximum 4 bytes to encode:
737 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
738 if (codepoint < 0x80)
739 {
740 /* normal ascii, encoding 0xxxxxxx */
741 utf8_length = 1;
742 }
743 else if (codepoint < 0x800)
744 {
745 /* two bytes, encoding 110xxxxx 10xxxxxx */
746 utf8_length = 2;
747 first_byte_mark = 0xC0; /* 11000000 */
748 }
749 else if (codepoint < 0x10000)
750 {
751 /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
752 utf8_length = 3;
753 first_byte_mark = 0xE0; /* 11100000 */
754 }
755 else if (codepoint <= 0x10FFFF)
756 {
757 /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
758 utf8_length = 4;
759 first_byte_mark = 0xF0; /* 11110000 */
760 }
761 else
762 {
763 /* invalid unicode codepoint */
764 goto fail;
765 }
766
767 /* encode as utf8 */
768 for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
769 {
770 /* 10xxxxxx */
771 (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
772 codepoint >>= 6;
773 }
774 /* encode first byte */
775 if (utf8_length > 1)
776 {
777 (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
778 }
779 else
780 {
781 (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
782 }
783
784 *output_pointer += utf8_length;
785
786 return sequence_length;
787
788fail:
789 return 0;
790}
791
792/* Parse the input text into an unescaped cinput, and populate item. */
793static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
794{
795 const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
796 const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
797 unsigned char *output_pointer = NULL;
798 unsigned char *output = NULL;
799
800 /* not a string */
801 if (buffer_at_offset(input_buffer)[0] != '\"')
802 {
803 goto fail;
804 }
805
806 {
807 /* calculate approximate size of the output (overestimate) */
808 size_t allocation_length = 0;
809 size_t skipped_bytes = 0;
810 while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
811 {
812 /* is escape sequence */
813 if (input_end[0] == '\\')
814 {
815 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
816 {
817 /* prevent buffer overflow when last input character is a backslash */
818 goto fail;
819 }
820 skipped_bytes++;
821 input_end++;
822 }
823 input_end++;
824 }
825 if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
826 {
827 goto fail; /* string ended unexpectedly */
828 }
829
830 /* This is at most how much we need for the output */
831 allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
832 output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
833 if (output == NULL)
834 {
835 goto fail; /* allocation failure */
836 }
837 }
838
839 output_pointer = output;
840 /* loop through the string literal */
841 while (input_pointer < input_end)
842 {
843 if (*input_pointer != '\\')
844 {
845 *output_pointer++ = *input_pointer++;
846 }
847 /* escape sequence */
848 else
849 {
850 unsigned char sequence_length = 2;
851 if ((input_end - input_pointer) < 1)
852 {
853 goto fail;
854 }
855
856 switch (input_pointer[1])
857 {
858 case 'b':
859 *output_pointer++ = '\b';
860 break;
861 case 'f':
862 *output_pointer++ = '\f';
863 break;
864 case 'n':
865 *output_pointer++ = '\n';
866 break;
867 case 'r':
868 *output_pointer++ = '\r';
869 break;
870 case 't':
871 *output_pointer++ = '\t';
872 break;
873 case '\"':
874 case '\\':
875 case '/':
876 *output_pointer++ = input_pointer[1];
877 break;
878
879 /* UTF-16 literal */
880 case 'u':
881 sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
882 if (sequence_length == 0)
883 {
884 /* failed to convert UTF16-literal to UTF-8 */
885 goto fail;
886 }
887 break;
888
889 default:
890 goto fail;
891 }
892 input_pointer += sequence_length;
893 }
894 }
895
896 /* zero terminate the output */
897 *output_pointer = '\0';
898
899 item->type = cJSON_String;
900 item->valuestring = (char*)output;
901
902 input_buffer->offset = (size_t) (input_end - input_buffer->content);
903 input_buffer->offset++;
904
905 return true;
906
907fail:
908 if (output != NULL)
909 {
910 input_buffer->hooks.deallocate(output);
911 output = NULL;
912 }
913
914 if (input_pointer != NULL)
915 {
916 input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
917 }
918
919 return false;
920}
921
922/* Render the cstring provided to an escaped version that can be printed. */
923static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
924{
925 const unsigned char *input_pointer = NULL;
926 unsigned char *output = NULL;
927 unsigned char *output_pointer = NULL;
928 size_t output_length = 0;
929 /* numbers of additional characters needed for escaping */
930 size_t escape_characters = 0;
931
932 if (output_buffer == NULL)
933 {
934 return false;
935 }
936
937 /* empty string */
938 if (input == NULL)
939 {
940 output = ensure(output_buffer, sizeof("\"\""));
941 if (output == NULL)
942 {
943 return false;
944 }
945 strcpy((char*)output, "\"\"");
946
947 return true;
948 }
949
950 /* set "flag" to 1 if something needs to be escaped */
951 for (input_pointer = input; *input_pointer; input_pointer++)
952 {
953 switch (*input_pointer)
954 {
955 case '\"':
956 case '\\':
957 case '\b':
958 case '\f':
959 case '\n':
960 case '\r':
961 case '\t':
962 /* one character escape sequence */
963 escape_characters++;
964 break;
965 default:
966 if (*input_pointer < 32)
967 {
968 /* UTF-16 escape sequence uXXXX */
969 escape_characters += 5;
970 }
971 break;
972 }
973 }
974 output_length = (size_t)(input_pointer - input) + escape_characters;
975
976 output = ensure(output_buffer, output_length + sizeof("\"\""));
977 if (output == NULL)
978 {
979 return false;
980 }
981
982 /* no characters have to be escaped */
983 if (escape_characters == 0)
984 {
985 output[0] = '\"';
986 memcpy(output + 1, input, output_length);
987 output[output_length + 1] = '\"';
988 output[output_length + 2] = '\0';
989
990 return true;
991 }
992
993 output[0] = '\"';
994 output_pointer = output + 1;
995 /* copy the string */
996 for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
997 {
998 if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
999 {
1000 /* normal character, copy */
1001 *output_pointer = *input_pointer;
1002 }
1003 else
1004 {
1005 /* character needs to be escaped */
1006 *output_pointer++ = '\\';
1007 switch (*input_pointer)
1008 {
1009 case '\\':
1010 *output_pointer = '\\';
1011 break;
1012 case '\"':
1013 *output_pointer = '\"';
1014 break;
1015 case '\b':
1016 *output_pointer = 'b';
1017 break;
1018 case '\f':
1019 *output_pointer = 'f';
1020 break;
1021 case '\n':
1022 *output_pointer = 'n';
1023 break;
1024 case '\r':
1025 *output_pointer = 'r';
1026 break;
1027 case '\t':
1028 *output_pointer = 't';
1029 break;
1030 default:
1031 /* escape and print as unicode codepoint */
1032 sprintf((char*)output_pointer, "u%04x", *input_pointer);
1033 output_pointer += 4;
1034 break;
1035 }
1036 }
1037 }
1038 output[output_length + 1] = '\"';
1039 output[output_length + 2] = '\0';
1040
1041 return true;
1042}
1043
1044/* Invoke print_string_ptr (which is useful) on an item. */
1045static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
1046{
1047 return print_string_ptr((unsigned char*)item->valuestring, p);
1048}
1049
1050/* Predeclare these prototypes. */
1051static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
1052static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
1053static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
1054static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
1055static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
1056static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
1057
1058/* Utility to jump whitespace and cr/lf */
1059static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
1060{
1061 if ((buffer == NULL) || (buffer->content == NULL))
1062 {
1063 return NULL;
1064 }
1065
1066 if (cannot_access_at_index(buffer, 0))
1067 {
1068 return buffer;
1069 }
1070
1071 while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
1072 {
1073 buffer->offset++;
1074 }
1075
1076 if (buffer->offset == buffer->length)
1077 {
1078 buffer->offset--;
1079 }
1080
1081 return buffer;
1082}
1083
1084/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
1085static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
1086{
1087 if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
1088 {
1089 return NULL;
1090 }
1091
1092 if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
1093 {
1094 buffer->offset += 3;
1095 }
1096
1097 return buffer;
1098}
1099
1100CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
1101{
1102 size_t buffer_length;
1103
1104 if (NULL == value)
1105 {
1106 return NULL;
1107 }
1108
1109 /* Adding null character size due to require_null_terminated. */
1110 buffer_length = strlen(value) + sizeof("");
1111
1112 return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
1113}
1114
1115/* Parse an object - create a new root, and populate. */
1116CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
1117{
1118 parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
1119 cJSON *item = NULL;
1120
1121 /* reset error position */
1122 global_error.json = NULL;
1123 global_error.position = 0;
1124
1125 if (value == NULL || 0 == buffer_length)
1126 {
1127 goto fail;
1128 }
1129
1130 buffer.content = (const unsigned char*)value;
1131 buffer.length = buffer_length;
1132 buffer.offset = 0;
1133 buffer.hooks = global_hooks;
1134
1135 item = cJSON_New_Item(&global_hooks);
1136 if (item == NULL) /* memory fail */
1137 {
1138 goto fail;
1139 }
1140
1141 if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
1142 {
1143 /* parse failure. ep is set. */
1144 goto fail;
1145 }
1146
1147 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
1148 if (require_null_terminated)
1149 {
1150 buffer_skip_whitespace(&buffer);
1151 if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
1152 {
1153 goto fail;
1154 }
1155 }
1156 if (return_parse_end)
1157 {
1158 *return_parse_end = (const char*)buffer_at_offset(&buffer);
1159 }
1160
1161 return item;
1162
1163fail:
1164 if (item != NULL)
1165 {
1166 cJSON_Delete(item);
1167 }
1168
1169 if (value != NULL)
1170 {
1171 error local_error;
1172 local_error.json = (const unsigned char*)value;
1173 local_error.position = 0;
1174
1175 if (buffer.offset < buffer.length)
1176 {
1177 local_error.position = buffer.offset;
1178 }
1179 else if (buffer.length > 0)
1180 {
1181 local_error.position = buffer.length - 1;
1182 }
1183
1184 if (return_parse_end != NULL)
1185 {
1186 *return_parse_end = (const char*)local_error.json + local_error.position;
1187 }
1188
1189 global_error = local_error;
1190 }
1191
1192 return NULL;
1193}
1194
1195/* Default options for cJSON_Parse */
1196CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
1197{
1198 return cJSON_ParseWithOpts(value, 0, 0);
1199}
1200
1201CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
1202{
1203 return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
1204}
1205
1206#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
1207
1208static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
1209{
1210 static const size_t default_buffer_size = 256;
1211 printbuffer buffer[1];
1212 unsigned char *printed = NULL;
1213
1214 memset(buffer, 0, sizeof(buffer));
1215
1216 /* create buffer */
1217 buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
1218 buffer->length = default_buffer_size;
1219 buffer->format = format;
1220 buffer->hooks = *hooks;
1221 if (buffer->buffer == NULL)
1222 {
1223 goto fail;
1224 }
1225
1226 /* print the value */
1227 if (!print_value(item, buffer))
1228 {
1229 goto fail;
1230 }
1231 update_offset(buffer);
1232
1233 /* check if reallocate is available */
1234 if (hooks->reallocate != NULL)
1235 {
1236 printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
1237 if (printed == NULL) {
1238 goto fail;
1239 }
1240 buffer->buffer = NULL;
1241 }
1242 else /* otherwise copy the JSON over to a new buffer */
1243 {
1244 printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
1245 if (printed == NULL)
1246 {
1247 goto fail;
1248 }
1249 memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
1250 printed[buffer->offset] = '\0'; /* just to be sure */
1251
1252 /* free the buffer */
1253 hooks->deallocate(buffer->buffer);
1254 buffer->buffer = NULL;
1255 }
1256
1257 return printed;
1258
1259fail:
1260 if (buffer->buffer != NULL)
1261 {
1262 hooks->deallocate(buffer->buffer);
1263 buffer->buffer = NULL;
1264 }
1265
1266 if (printed != NULL)
1267 {
1268 hooks->deallocate(printed);
1269 printed = NULL;
1270 }
1271
1272 return NULL;
1273}
1274
1275/* Render a cJSON item/entity/structure to text. */
1276CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
1277{
1278 return (char*)print(item, true, &global_hooks);
1279}
1280
1281CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
1282{
1283 return (char*)print(item, false, &global_hooks);
1284}
1285
1286CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
1287{
1288 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1289
1290 if (prebuffer < 0)
1291 {
1292 return NULL;
1293 }
1294
1295 p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
1296 if (!p.buffer)
1297 {
1298 return NULL;
1299 }
1300
1301 p.length = (size_t)prebuffer;
1302 p.offset = 0;
1303 p.noalloc = false;
1304 p.format = fmt;
1305 p.hooks = global_hooks;
1306
1307 if (!print_value(item, &p))
1308 {
1309 global_hooks.deallocate(p.buffer);
1310 p.buffer = NULL;
1311 return NULL;
1312 }
1313
1314 return (char*)p.buffer;
1315}
1316
1317CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
1318{
1319 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1320
1321 if ((length < 0) || (buffer == NULL))
1322 {
1323 return false;
1324 }
1325
1326 p.buffer = (unsigned char*)buffer;
1327 p.length = (size_t)length;
1328 p.offset = 0;
1329 p.noalloc = true;
1330 p.format = format;
1331 p.hooks = global_hooks;
1332
1333 return print_value(item, &p);
1334}
1335
1336/* Parser core - when encountering text, process appropriately. */
1337static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
1338{
1339 if ((input_buffer == NULL) || (input_buffer->content == NULL))
1340 {
1341 return false; /* no input */
1342 }
1343
1344 /* parse the different types of values */
1345 /* null */
1346 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
1347 {
1348 item->type = cJSON_NULL;
1349 input_buffer->offset += 4;
1350 return true;
1351 }
1352 /* false */
1353 if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
1354 {
1355 item->type = cJSON_False;
1356 input_buffer->offset += 5;
1357 return true;
1358 }
1359 /* true */
1360 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
1361 {
1362 item->type = cJSON_True;
1363 item->valueint = 1;
1364 input_buffer->offset += 4;
1365 return true;
1366 }
1367 /* string */
1368 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
1369 {
1370 return parse_string(item, input_buffer);
1371 }
1372 /* number */
1373 if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
1374 {
1375 return parse_number(item, input_buffer);
1376 }
1377 /* array */
1378 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
1379 {
1380 return parse_array(item, input_buffer);
1381 }
1382 /* object */
1383 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
1384 {
1385 return parse_object(item, input_buffer);
1386 }
1387
1388 return false;
1389}
1390
1391/* Render a value to text. */
1392static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
1393{
1394 unsigned char *output = NULL;
1395
1396 if ((item == NULL) || (output_buffer == NULL))
1397 {
1398 return false;
1399 }
1400
1401 switch ((item->type) & 0xFF)
1402 {
1403 case cJSON_NULL:
1404 output = ensure(output_buffer, 5);
1405 if (output == NULL)
1406 {
1407 return false;
1408 }
1409 strcpy((char*)output, "null");
1410 return true;
1411
1412 case cJSON_False:
1413 output = ensure(output_buffer, 6);
1414 if (output == NULL)
1415 {
1416 return false;
1417 }
1418 strcpy((char*)output, "false");
1419 return true;
1420
1421 case cJSON_True:
1422 output = ensure(output_buffer, 5);
1423 if (output == NULL)
1424 {
1425 return false;
1426 }
1427 strcpy((char*)output, "true");
1428 return true;
1429
1430 case cJSON_Number:
1431 return print_number(item, output_buffer);
1432
1433 case cJSON_Raw:
1434 {
1435 size_t raw_length = 0;
1436 if (item->valuestring == NULL)
1437 {
1438 return false;
1439 }
1440
1441 raw_length = strlen(item->valuestring) + sizeof("");
1442 output = ensure(output_buffer, raw_length);
1443 if (output == NULL)
1444 {
1445 return false;
1446 }
1447 memcpy(output, item->valuestring, raw_length);
1448 return true;
1449 }
1450
1451 case cJSON_String:
1452 return print_string(item, output_buffer);
1453
1454 case cJSON_Array:
1455 return print_array(item, output_buffer);
1456
1457 case cJSON_Object:
1458 return print_object(item, output_buffer);
1459
1460 default:
1461 return false;
1462 }
1463}
1464
1465/* Build an array from input text. */
1466static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
1467{
1468 cJSON *head = NULL; /* head of the linked list */
1469 cJSON *current_item = NULL;
1470
1471 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1472 {
1473 return false; /* to deeply nested */
1474 }
1475 input_buffer->depth++;
1476
1477 if (buffer_at_offset(input_buffer)[0] != '[')
1478 {
1479 /* not an array */
1480 goto fail;
1481 }
1482
1483 input_buffer->offset++;
1484 buffer_skip_whitespace(input_buffer);
1485 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
1486 {
1487 /* empty array */
1488 goto success;
1489 }
1490
1491 /* check if we skipped to the end of the buffer */
1492 if (cannot_access_at_index(input_buffer, 0))
1493 {
1494 input_buffer->offset--;
1495 goto fail;
1496 }
1497
1498 /* step back to character in front of the first element */
1499 input_buffer->offset--;
1500 /* loop through the comma separated array elements */
1501 do
1502 {
1503 /* allocate next item */
1504 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1505 if (new_item == NULL)
1506 {
1507 goto fail; /* allocation failure */
1508 }
1509
1510 /* attach next item to list */
1511 if (head == NULL)
1512 {
1513 /* start the linked list */
1514 current_item = head = new_item;
1515 }
1516 else
1517 {
1518 /* add to the end and advance */
1519 current_item->next = new_item;
1520 new_item->prev = current_item;
1521 current_item = new_item;
1522 }
1523
1524 /* parse next value */
1525 input_buffer->offset++;
1526 buffer_skip_whitespace(input_buffer);
1527 if (!parse_value(current_item, input_buffer))
1528 {
1529 goto fail; /* failed to parse value */
1530 }
1531 buffer_skip_whitespace(input_buffer);
1532 }
1533 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1534
1535 if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
1536 {
1537 goto fail; /* expected end of array */
1538 }
1539
1540success:
1541 input_buffer->depth--;
1542
1543 if (head != NULL) {
1544 head->prev = current_item;
1545 }
1546
1547 item->type = cJSON_Array;
1548 item->child = head;
1549
1550 input_buffer->offset++;
1551
1552 return true;
1553
1554fail:
1555 if (head != NULL)
1556 {
1557 cJSON_Delete(head);
1558 }
1559
1560 return false;
1561}
1562
1563/* Render an array to text */
1564static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
1565{
1566 unsigned char *output_pointer = NULL;
1567 size_t length = 0;
1568 cJSON *current_element = item->child;
1569
1570 if (output_buffer == NULL)
1571 {
1572 return false;
1573 }
1574
1575 /* Compose the output array. */
1576 /* opening square bracket */
1577 output_pointer = ensure(output_buffer, 1);
1578 if (output_pointer == NULL)
1579 {
1580 return false;
1581 }
1582
1583 *output_pointer = '[';
1584 output_buffer->offset++;
1585 output_buffer->depth++;
1586
1587 while (current_element != NULL)
1588 {
1589 if (!print_value(current_element, output_buffer))
1590 {
1591 return false;
1592 }
1593 update_offset(output_buffer);
1594 if (current_element->next)
1595 {
1596 length = (size_t) (output_buffer->format ? 2 : 1);
1597 output_pointer = ensure(output_buffer, length + 1);
1598 if (output_pointer == NULL)
1599 {
1600 return false;
1601 }
1602 *output_pointer++ = ',';
1603 if(output_buffer->format)
1604 {
1605 *output_pointer++ = ' ';
1606 }
1607 *output_pointer = '\0';
1608 output_buffer->offset += length;
1609 }
1610 current_element = current_element->next;
1611 }
1612
1613 output_pointer = ensure(output_buffer, 2);
1614 if (output_pointer == NULL)
1615 {
1616 return false;
1617 }
1618 *output_pointer++ = ']';
1619 *output_pointer = '\0';
1620 output_buffer->depth--;
1621
1622 return true;
1623}
1624
1625/* Build an object from the text. */
1626static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
1627{
1628 cJSON *head = NULL; /* linked list head */
1629 cJSON *current_item = NULL;
1630
1631 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1632 {
1633 return false; /* to deeply nested */
1634 }
1635 input_buffer->depth++;
1636
1637 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
1638 {
1639 goto fail; /* not an object */
1640 }
1641
1642 input_buffer->offset++;
1643 buffer_skip_whitespace(input_buffer);
1644 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
1645 {
1646 goto success; /* empty object */
1647 }
1648
1649 /* check if we skipped to the end of the buffer */
1650 if (cannot_access_at_index(input_buffer, 0))
1651 {
1652 input_buffer->offset--;
1653 goto fail;
1654 }
1655
1656 /* step back to character in front of the first element */
1657 input_buffer->offset--;
1658 /* loop through the comma separated array elements */
1659 do
1660 {
1661 /* allocate next item */
1662 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1663 if (new_item == NULL)
1664 {
1665 goto fail; /* allocation failure */
1666 }
1667
1668 /* attach next item to list */
1669 if (head == NULL)
1670 {
1671 /* start the linked list */
1672 current_item = head = new_item;
1673 }
1674 else
1675 {
1676 /* add to the end and advance */
1677 current_item->next = new_item;
1678 new_item->prev = current_item;
1679 current_item = new_item;
1680 }
1681
1682 if (cannot_access_at_index(input_buffer, 1))
1683 {
1684 goto fail; /* nothing comes after the comma */
1685 }
1686
1687 /* parse the name of the child */
1688 input_buffer->offset++;
1689 buffer_skip_whitespace(input_buffer);
1690 if (!parse_string(current_item, input_buffer))
1691 {
1692 goto fail; /* failed to parse name */
1693 }
1694 buffer_skip_whitespace(input_buffer);
1695
1696 /* swap valuestring and string, because we parsed the name */
1697 current_item->string = current_item->valuestring;
1698 current_item->valuestring = NULL;
1699
1700 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
1701 {
1702 goto fail; /* invalid object */
1703 }
1704
1705 /* parse the value */
1706 input_buffer->offset++;
1707 buffer_skip_whitespace(input_buffer);
1708 if (!parse_value(current_item, input_buffer))
1709 {
1710 goto fail; /* failed to parse value */
1711 }
1712 buffer_skip_whitespace(input_buffer);
1713 }
1714 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1715
1716 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
1717 {
1718 goto fail; /* expected end of object */
1719 }
1720
1721success:
1722 input_buffer->depth--;
1723
1724 if (head != NULL) {
1725 head->prev = current_item;
1726 }
1727
1728 item->type = cJSON_Object;
1729 item->child = head;
1730
1731 input_buffer->offset++;
1732 return true;
1733
1734fail:
1735 if (head != NULL)
1736 {
1737 cJSON_Delete(head);
1738 }
1739
1740 return false;
1741}
1742
1743/* Render an object to text. */
1744static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
1745{
1746 unsigned char *output_pointer = NULL;
1747 size_t length = 0;
1748 cJSON *current_item = item->child;
1749
1750 if (output_buffer == NULL)
1751 {
1752 return false;
1753 }
1754
1755 /* Compose the output: */
1756 length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
1757 output_pointer = ensure(output_buffer, length + 1);
1758 if (output_pointer == NULL)
1759 {
1760 return false;
1761 }
1762
1763 *output_pointer++ = '{';
1764 output_buffer->depth++;
1765 if (output_buffer->format)
1766 {
1767 *output_pointer++ = '\n';
1768 }
1769 output_buffer->offset += length;
1770
1771 while (current_item)
1772 {
1773 if (output_buffer->format)
1774 {
1775 size_t i;
1776 output_pointer = ensure(output_buffer, output_buffer->depth);
1777 if (output_pointer == NULL)
1778 {
1779 return false;
1780 }
1781 for (i = 0; i < output_buffer->depth; i++)
1782 {
1783 *output_pointer++ = '\t';
1784 }
1785 output_buffer->offset += output_buffer->depth;
1786 }
1787
1788 /* print key */
1789 if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
1790 {
1791 return false;
1792 }
1793 update_offset(output_buffer);
1794
1795 length = (size_t) (output_buffer->format ? 2 : 1);
1796 output_pointer = ensure(output_buffer, length);
1797 if (output_pointer == NULL)
1798 {
1799 return false;
1800 }
1801 *output_pointer++ = ':';
1802 if (output_buffer->format)
1803 {
1804 *output_pointer++ = '\t';
1805 }
1806 output_buffer->offset += length;
1807
1808 /* print value */
1809 if (!print_value(current_item, output_buffer))
1810 {
1811 return false;
1812 }
1813 update_offset(output_buffer);
1814
1815 /* print comma if not last */
1816 length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1817 output_pointer = ensure(output_buffer, length + 1);
1818 if (output_pointer == NULL)
1819 {
1820 return false;
1821 }
1822 if (current_item->next)
1823 {
1824 *output_pointer++ = ',';
1825 }
1826
1827 if (output_buffer->format)
1828 {
1829 *output_pointer++ = '\n';
1830 }
1831 *output_pointer = '\0';
1832 output_buffer->offset += length;
1833
1834 current_item = current_item->next;
1835 }
1836
1837 output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
1838 if (output_pointer == NULL)
1839 {
1840 return false;
1841 }
1842 if (output_buffer->format)
1843 {
1844 size_t i;
1845 for (i = 0; i < (output_buffer->depth - 1); i++)
1846 {
1847 *output_pointer++ = '\t';
1848 }
1849 }
1850 *output_pointer++ = '}';
1851 *output_pointer = '\0';
1852 output_buffer->depth--;
1853
1854 return true;
1855}
1856
1857/* Get Array size/item / object item. */
1858CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
1859{
1860 cJSON *child = NULL;
1861 size_t size = 0;
1862
1863 if (array == NULL)
1864 {
1865 return 0;
1866 }
1867
1868 child = array->child;
1869
1870 while(child != NULL)
1871 {
1872 size++;
1873 child = child->next;
1874 }
1875
1876 /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1877
1878 return (int)size;
1879}
1880
1881static cJSON* get_array_item(const cJSON *array, size_t index)
1882{
1883 cJSON *current_child = NULL;
1884
1885 if (array == NULL)
1886 {
1887 return NULL;
1888 }
1889
1890 current_child = array->child;
1891 while ((current_child != NULL) && (index > 0))
1892 {
1893 index--;
1894 current_child = current_child->next;
1895 }
1896
1897 return current_child;
1898}
1899
1900CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
1901{
1902 if (index < 0)
1903 {
1904 return NULL;
1905 }
1906
1907 return get_array_item(array, (size_t)index);
1908}
1909
1910static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
1911{
1912 cJSON *current_element = NULL;
1913
1914 if ((object == NULL) || (name == NULL))
1915 {
1916 return NULL;
1917 }
1918
1919 current_element = object->child;
1920 if (case_sensitive)
1921 {
1922 while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
1923 {
1924 current_element = current_element->next;
1925 }
1926 }
1927 else
1928 {
1929 while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
1930 {
1931 current_element = current_element->next;
1932 }
1933 }
1934
1935 if ((current_element == NULL) || (current_element->string == NULL)) {
1936 return NULL;
1937 }
1938
1939 return current_element;
1940}
1941
1942CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
1943{
1944 return get_object_item(object, string, false);
1945}
1946
1947CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
1948{
1949 return get_object_item(object, string, true);
1950}
1951
1952CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
1953{
1954 return cJSON_GetObjectItem(object, string) ? 1 : 0;
1955}
1956
1957/* Utility for array list handling. */
1958static void suffix_object(cJSON *prev, cJSON *item)
1959{
1960 prev->next = item;
1961 item->prev = prev;
1962}
1963
1964/* Utility for handling references. */
1965static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
1966{
1967 cJSON *reference = NULL;
1968 if (item == NULL)
1969 {
1970 return NULL;
1971 }
1972
1973 reference = cJSON_New_Item(hooks);
1974 if (reference == NULL)
1975 {
1976 return NULL;
1977 }
1978
1979 memcpy(reference, item, sizeof(cJSON));
1980 reference->string = NULL;
1981 reference->type |= cJSON_IsReference;
1982 reference->next = reference->prev = NULL;
1983 return reference;
1984}
1985
1986static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
1987{
1988 cJSON *child = NULL;
1989
1990 if ((item == NULL) || (array == NULL) || (array == item))
1991 {
1992 return false;
1993 }
1994
1995 child = array->child;
1996 /*
1997 * To find the last item in array quickly, we use prev in array
1998 */
1999 if (child == NULL)
2000 {
2001 /* list is empty, start new one */
2002 array->child = item;
2003 item->prev = item;
2004 item->next = NULL;
2005 }
2006 else
2007 {
2008 /* append to the end */
2009 if (child->prev)
2010 {
2011 suffix_object(child->prev, item);
2012 array->child->prev = item;
2013 }
2014 }
2015
2016 return true;
2017}
2018
2019/* Add item to array/object. */
2020CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
2021{
2022 return add_item_to_array(array, item);
2023}
2024
2025#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
2026 #pragma GCC diagnostic push
2027#endif
2028#ifdef __GNUC__
2029#pragma GCC diagnostic ignored "-Wcast-qual"
2030#endif
2031/* helper function to cast away const */
2032static void* cast_away_const(const void* string)
2033{
2034 return (void*)string;
2035}
2036#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
2037 #pragma GCC diagnostic pop
2038#endif
2039
2040
2041static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
2042{
2043 char *new_key = NULL;
2044 int new_type = cJSON_Invalid;
2045
2046 if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
2047 {
2048 return false;
2049 }
2050
2051 if (constant_key)
2052 {
2053 new_key = (char*)cast_away_const(string);
2054 new_type = item->type | cJSON_StringIsConst;
2055 }
2056 else
2057 {
2058 new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
2059 if (new_key == NULL)
2060 {
2061 return false;
2062 }
2063
2064 new_type = item->type & ~cJSON_StringIsConst;
2065 }
2066
2067 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
2068 {
2069 hooks->deallocate(item->string);
2070 }
2071
2072 item->string = new_key;
2073 item->type = new_type;
2074
2075 return add_item_to_array(object, item);
2076}
2077
2078CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
2079{
2080 return add_item_to_object(object, string, item, &global_hooks, false);
2081}
2082
2083/* Add an item to an object with constant string as key */
2084CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
2085{
2086 return add_item_to_object(object, string, item, &global_hooks, true);
2087}
2088
2089CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
2090{
2091 if (array == NULL)
2092 {
2093 return false;
2094 }
2095
2096 return add_item_to_array(array, create_reference(item, &global_hooks));
2097}
2098
2099CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
2100{
2101 if ((object == NULL) || (string == NULL))
2102 {
2103 return false;
2104 }
2105
2106 return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
2107}
2108
2109CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
2110{
2111 cJSON *null = cJSON_CreateNull();
2112 if (add_item_to_object(object, name, null, &global_hooks, false))
2113 {
2114 return null;
2115 }
2116
2117 cJSON_Delete(null);
2118 return NULL;
2119}
2120
2121CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
2122{
2123 cJSON *true_item = cJSON_CreateTrue();
2124 if (add_item_to_object(object, name, true_item, &global_hooks, false))
2125 {
2126 return true_item;
2127 }
2128
2129 cJSON_Delete(true_item);
2130 return NULL;
2131}
2132
2133CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
2134{
2135 cJSON *false_item = cJSON_CreateFalse();
2136 if (add_item_to_object(object, name, false_item, &global_hooks, false))
2137 {
2138 return false_item;
2139 }
2140
2141 cJSON_Delete(false_item);
2142 return NULL;
2143}
2144
2145CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
2146{
2147 cJSON *bool_item = cJSON_CreateBool(boolean);
2148 if (add_item_to_object(object, name, bool_item, &global_hooks, false))
2149 {
2150 return bool_item;
2151 }
2152
2153 cJSON_Delete(bool_item);
2154 return NULL;
2155}
2156
2157CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
2158{
2159 cJSON *number_item = cJSON_CreateNumber(number);
2160 if (add_item_to_object(object, name, number_item, &global_hooks, false))
2161 {
2162 return number_item;
2163 }
2164
2165 cJSON_Delete(number_item);
2166 return NULL;
2167}
2168
2169CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
2170{
2171 cJSON *string_item = cJSON_CreateString(string);
2172 if (add_item_to_object(object, name, string_item, &global_hooks, false))
2173 {
2174 return string_item;
2175 }
2176
2177 cJSON_Delete(string_item);
2178 return NULL;
2179}
2180
2181CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
2182{
2183 cJSON *raw_item = cJSON_CreateRaw(raw);
2184 if (add_item_to_object(object, name, raw_item, &global_hooks, false))
2185 {
2186 return raw_item;
2187 }
2188
2189 cJSON_Delete(raw_item);
2190 return NULL;
2191}
2192
2193CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
2194{
2195 cJSON *object_item = cJSON_CreateObject();
2196 if (add_item_to_object(object, name, object_item, &global_hooks, false))
2197 {
2198 return object_item;
2199 }
2200
2201 cJSON_Delete(object_item);
2202 return NULL;
2203}
2204
2205CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
2206{
2207 cJSON *array = cJSON_CreateArray();
2208 if (add_item_to_object(object, name, array, &global_hooks, false))
2209 {
2210 return array;
2211 }
2212
2213 cJSON_Delete(array);
2214 return NULL;
2215}
2216
2217CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
2218{
2219 if ((parent == NULL) || (item == NULL) || (item != parent->child && item->prev == NULL))
2220 {
2221 return NULL;
2222 }
2223
2224 if (item != parent->child)
2225 {
2226 /* not the first element */
2227 item->prev->next = item->next;
2228 }
2229 if (item->next != NULL)
2230 {
2231 /* not the last element */
2232 item->next->prev = item->prev;
2233 }
2234
2235 if (item == parent->child)
2236 {
2237 /* first element */
2238 parent->child = item->next;
2239 }
2240 else if (item->next == NULL)
2241 {
2242 /* last element */
2243 parent->child->prev = item->prev;
2244 }
2245
2246 /* make sure the detached item doesn't point anywhere anymore */
2247 item->prev = NULL;
2248 item->next = NULL;
2249
2250 return item;
2251}
2252
2253CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
2254{
2255 if (which < 0)
2256 {
2257 return NULL;
2258 }
2259
2260 return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
2261}
2262
2263CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
2264{
2265 cJSON_Delete(cJSON_DetachItemFromArray(array, which));
2266}
2267
2268CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
2269{
2270 cJSON *to_detach = cJSON_GetObjectItem(object, string);
2271
2272 return cJSON_DetachItemViaPointer(object, to_detach);
2273}
2274
2275CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
2276{
2277 cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
2278
2279 return cJSON_DetachItemViaPointer(object, to_detach);
2280}
2281
2282CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
2283{
2284 cJSON_Delete(cJSON_DetachItemFromObject(object, string));
2285}
2286
2287CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
2288{
2289 cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
2290}
2291
2292/* Replace array/object items with new ones. */
2293CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
2294{
2295 cJSON *after_inserted = NULL;
2296
2297 if (which < 0 || newitem == NULL)
2298 {
2299 return false;
2300 }
2301
2302 after_inserted = get_array_item(array, (size_t)which);
2303 if (after_inserted == NULL)
2304 {
2305 return add_item_to_array(array, newitem);
2306 }
2307
2308 if (after_inserted != array->child && after_inserted->prev == NULL) {
2309 /* return false if after_inserted is a corrupted array item */
2310 return false;
2311 }
2312
2313 newitem->next = after_inserted;
2314 newitem->prev = after_inserted->prev;
2315 after_inserted->prev = newitem;
2316 if (after_inserted == array->child)
2317 {
2318 array->child = newitem;
2319 }
2320 else
2321 {
2322 newitem->prev->next = newitem;
2323 }
2324 return true;
2325}
2326
2327CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
2328{
2329 if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL))
2330 {
2331 return false;
2332 }
2333
2334 if (replacement == item)
2335 {
2336 return true;
2337 }
2338
2339 replacement->next = item->next;
2340 replacement->prev = item->prev;
2341
2342 if (replacement->next != NULL)
2343 {
2344 replacement->next->prev = replacement;
2345 }
2346 if (parent->child == item)
2347 {
2348 if (parent->child->prev == parent->child)
2349 {
2350 replacement->prev = replacement;
2351 }
2352 parent->child = replacement;
2353 }
2354 else
2355 { /*
2356 * To find the last item in array quickly, we use prev in array.
2357 * We can't modify the last item's next pointer where this item was the parent's child
2358 */
2359 if (replacement->prev != NULL)
2360 {
2361 replacement->prev->next = replacement;
2362 }
2363 if (replacement->next == NULL)
2364 {
2365 parent->child->prev = replacement;
2366 }
2367 }
2368
2369 item->next = NULL;
2370 item->prev = NULL;
2371 cJSON_Delete(item);
2372
2373 return true;
2374}
2375
2376CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
2377{
2378 if (which < 0)
2379 {
2380 return false;
2381 }
2382
2383 return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
2384}
2385
2386static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
2387{
2388 if ((replacement == NULL) || (string == NULL))
2389 {
2390 return false;
2391 }
2392
2393 /* replace the name in the replacement */
2394 if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
2395 {
2396 cJSON_free(replacement->string);
2397 }
2398 replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2399 if (replacement->string == NULL)
2400 {
2401 return false;
2402 }
2403
2404 replacement->type &= ~cJSON_StringIsConst;
2405
2406 return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
2407}
2408
2409CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
2410{
2411 return replace_item_in_object(object, string, newitem, false);
2412}
2413
2414CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
2415{
2416 return replace_item_in_object(object, string, newitem, true);
2417}
2418
2419/* Create basic types: */
2420CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
2421{
2422 cJSON *item = cJSON_New_Item(&global_hooks);
2423 if(item)
2424 {
2425 item->type = cJSON_NULL;
2426 }
2427
2428 return item;
2429}
2430
2431CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
2432{
2433 cJSON *item = cJSON_New_Item(&global_hooks);
2434 if(item)
2435 {
2436 item->type = cJSON_True;
2437 }
2438
2439 return item;
2440}
2441
2442CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
2443{
2444 cJSON *item = cJSON_New_Item(&global_hooks);
2445 if(item)
2446 {
2447 item->type = cJSON_False;
2448 }
2449
2450 return item;
2451}
2452
2453CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
2454{
2455 cJSON *item = cJSON_New_Item(&global_hooks);
2456 if(item)
2457 {
2458 item->type = boolean ? cJSON_True : cJSON_False;
2459 }
2460
2461 return item;
2462}
2463
2464CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
2465{
2466 cJSON *item = cJSON_New_Item(&global_hooks);
2467 if(item)
2468 {
2469 item->type = cJSON_Number;
2470 item->valuedouble = num;
2471
2472 /* use saturation in case of overflow */
2473 if (num >= INT_MAX)
2474 {
2475 item->valueint = INT_MAX;
2476 }
2477 else if (num <= (double)INT_MIN)
2478 {
2479 item->valueint = INT_MIN;
2480 }
2481 else
2482 {
2483 item->valueint = (int)num;
2484 }
2485 }
2486
2487 return item;
2488}
2489
2490CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
2491{
2492 cJSON *item = cJSON_New_Item(&global_hooks);
2493 if(item)
2494 {
2495 item->type = cJSON_String;
2496 item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2497 if(!item->valuestring)
2498 {
2499 cJSON_Delete(item);
2500 return NULL;
2501 }
2502 }
2503
2504 return item;
2505}
2506
2507CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
2508{
2509 cJSON *item = cJSON_New_Item(&global_hooks);
2510 if (item != NULL)
2511 {
2512 item->type = cJSON_String | cJSON_IsReference;
2513 item->valuestring = (char*)cast_away_const(string);
2514 }
2515
2516 return item;
2517}
2518
2519CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
2520{
2521 cJSON *item = cJSON_New_Item(&global_hooks);
2522 if (item != NULL) {
2523 item->type = cJSON_Object | cJSON_IsReference;
2524 item->child = (cJSON*)cast_away_const(child);
2525 }
2526
2527 return item;
2528}
2529
2530CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
2531 cJSON *item = cJSON_New_Item(&global_hooks);
2532 if (item != NULL) {
2533 item->type = cJSON_Array | cJSON_IsReference;
2534 item->child = (cJSON*)cast_away_const(child);
2535 }
2536
2537 return item;
2538}
2539
2540CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
2541{
2542 cJSON *item = cJSON_New_Item(&global_hooks);
2543 if(item)
2544 {
2545 item->type = cJSON_Raw;
2546 item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
2547 if(!item->valuestring)
2548 {
2549 cJSON_Delete(item);
2550 return NULL;
2551 }
2552 }
2553
2554 return item;
2555}
2556
2557CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
2558{
2559 cJSON *item = cJSON_New_Item(&global_hooks);
2560 if(item)
2561 {
2562 item->type=cJSON_Array;
2563 }
2564
2565 return item;
2566}
2567
2568CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
2569{
2570 cJSON *item = cJSON_New_Item(&global_hooks);
2571 if (item)
2572 {
2573 item->type = cJSON_Object;
2574 }
2575
2576 return item;
2577}
2578
2579/* Create Arrays: */
2580CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
2581{
2582 size_t i = 0;
2583 cJSON *n = NULL;
2584 cJSON *p = NULL;
2585 cJSON *a = NULL;
2586
2587 if ((count < 0) || (numbers == NULL))
2588 {
2589 return NULL;
2590 }
2591
2592 a = cJSON_CreateArray();
2593
2594 for(i = 0; a && (i < (size_t)count); i++)
2595 {
2596 n = cJSON_CreateNumber(numbers[i]);
2597 if (!n)
2598 {
2599 cJSON_Delete(a);
2600 return NULL;
2601 }
2602 if(!i)
2603 {
2604 a->child = n;
2605 }
2606 else
2607 {
2608 suffix_object(p, n);
2609 }
2610 p = n;
2611 }
2612
2613 if (a && a->child) {
2614 a->child->prev = n;
2615 }
2616
2617 return a;
2618}
2619
2620CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
2621{
2622 size_t i = 0;
2623 cJSON *n = NULL;
2624 cJSON *p = NULL;
2625 cJSON *a = NULL;
2626
2627 if ((count < 0) || (numbers == NULL))
2628 {
2629 return NULL;
2630 }
2631
2632 a = cJSON_CreateArray();
2633
2634 for(i = 0; a && (i < (size_t)count); i++)
2635 {
2636 n = cJSON_CreateNumber((double)numbers[i]);
2637 if(!n)
2638 {
2639 cJSON_Delete(a);
2640 return NULL;
2641 }
2642 if(!i)
2643 {
2644 a->child = n;
2645 }
2646 else
2647 {
2648 suffix_object(p, n);
2649 }
2650 p = n;
2651 }
2652
2653 if (a && a->child) {
2654 a->child->prev = n;
2655 }
2656
2657 return a;
2658}
2659
2660CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
2661{
2662 size_t i = 0;
2663 cJSON *n = NULL;
2664 cJSON *p = NULL;
2665 cJSON *a = NULL;
2666
2667 if ((count < 0) || (numbers == NULL))
2668 {
2669 return NULL;
2670 }
2671
2672 a = cJSON_CreateArray();
2673
2674 for(i = 0; a && (i < (size_t)count); i++)
2675 {
2676 n = cJSON_CreateNumber(numbers[i]);
2677 if(!n)
2678 {
2679 cJSON_Delete(a);
2680 return NULL;
2681 }
2682 if(!i)
2683 {
2684 a->child = n;
2685 }
2686 else
2687 {
2688 suffix_object(p, n);
2689 }
2690 p = n;
2691 }
2692
2693 if (a && a->child) {
2694 a->child->prev = n;
2695 }
2696
2697 return a;
2698}
2699
2700CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
2701{
2702 size_t i = 0;
2703 cJSON *n = NULL;
2704 cJSON *p = NULL;
2705 cJSON *a = NULL;
2706
2707 if ((count < 0) || (strings == NULL))
2708 {
2709 return NULL;
2710 }
2711
2712 a = cJSON_CreateArray();
2713
2714 for (i = 0; a && (i < (size_t)count); i++)
2715 {
2716 n = cJSON_CreateString(strings[i]);
2717 if(!n)
2718 {
2719 cJSON_Delete(a);
2720 return NULL;
2721 }
2722 if(!i)
2723 {
2724 a->child = n;
2725 }
2726 else
2727 {
2728 suffix_object(p,n);
2729 }
2730 p = n;
2731 }
2732
2733 if (a && a->child) {
2734 a->child->prev = n;
2735 }
2736
2737 return a;
2738}
2739
2740/* Duplication */
2741cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse);
2742
2743CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
2744{
2745 return cJSON_Duplicate_rec(item, 0, recurse );
2746}
2747
2748cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse)
2749{
2750 cJSON *newitem = NULL;
2751 cJSON *child = NULL;
2752 cJSON *next = NULL;
2753 cJSON *newchild = NULL;
2754
2755 /* Bail on bad ptr */
2756 if (!item)
2757 {
2758 goto fail;
2759 }
2760 /* Create new item */
2761 newitem = cJSON_New_Item(&global_hooks);
2762 if (!newitem)
2763 {
2764 goto fail;
2765 }
2766 /* Copy over all vars */
2767 newitem->type = item->type & (~cJSON_IsReference);
2768 newitem->valueint = item->valueint;
2769 newitem->valuedouble = item->valuedouble;
2770 if (item->valuestring)
2771 {
2772 newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
2773 if (!newitem->valuestring)
2774 {
2775 goto fail;
2776 }
2777 }
2778 if (item->string)
2779 {
2780 newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
2781 if (!newitem->string)
2782 {
2783 goto fail;
2784 }
2785 }
2786 /* If non-recursive, then we're done! */
2787 if (!recurse)
2788 {
2789 return newitem;
2790 }
2791 /* Walk the ->next chain for the child. */
2792 child = item->child;
2793 while (child != NULL)
2794 {
2795 if(depth >= CJSON_CIRCULAR_LIMIT) {
2796 goto fail;
2797 }
2798 newchild = cJSON_Duplicate_rec(child, depth + 1, true); /* Duplicate (with recurse) each item in the ->next chain */
2799 if (!newchild)
2800 {
2801 goto fail;
2802 }
2803 if (next != NULL)
2804 {
2805 /* If newitem->child already set, then crosswire ->prev and ->next and move on */
2806 next->next = newchild;
2807 newchild->prev = next;
2808 next = newchild;
2809 }
2810 else
2811 {
2812 /* Set newitem->child and move to it */
2813 newitem->child = newchild;
2814 next = newchild;
2815 }
2816 child = child->next;
2817 }
2818 if (newitem && newitem->child)
2819 {
2820 newitem->child->prev = newchild;
2821 }
2822
2823 return newitem;
2824
2825fail:
2826 if (newitem != NULL)
2827 {
2828 cJSON_Delete(newitem);
2829 }
2830
2831 return NULL;
2832}
2833
2834static void skip_oneline_comment(char **input)
2835{
2836 *input += static_strlen("//");
2837
2838 for (; (*input)[0] != '\0'; ++(*input))
2839 {
2840 if ((*input)[0] == '\n') {
2841 *input += static_strlen("\n");
2842 return;
2843 }
2844 }
2845}
2846
2847static void skip_multiline_comment(char **input)
2848{
2849 *input += static_strlen("/*");
2850
2851 for (; (*input)[0] != '\0'; ++(*input))
2852 {
2853 if (((*input)[0] == '*') && ((*input)[1] == '/'))
2854 {
2855 *input += static_strlen("*/");
2856 return;
2857 }
2858 }
2859}
2860
2861static void minify_string(char **input, char **output) {
2862 (*output)[0] = (*input)[0];
2863 *input += static_strlen("\"");
2864 *output += static_strlen("\"");
2865
2866
2867 for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
2868 (*output)[0] = (*input)[0];
2869
2870 if ((*input)[0] == '\"') {
2871 (*output)[0] = '\"';
2872 *input += static_strlen("\"");
2873 *output += static_strlen("\"");
2874 return;
2875 } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
2876 (*output)[1] = (*input)[1];
2877 *input += static_strlen("\"");
2878 *output += static_strlen("\"");
2879 }
2880 }
2881}
2882
2883CJSON_PUBLIC(void) cJSON_Minify(char *json)
2884{
2885 char *into = json;
2886
2887 if (json == NULL)
2888 {
2889 return;
2890 }
2891
2892 while (json[0] != '\0')
2893 {
2894 switch (json[0])
2895 {
2896 case ' ':
2897 case '\t':
2898 case '\r':
2899 case '\n':
2900 json++;
2901 break;
2902
2903 case '/':
2904 if (json[1] == '/')
2905 {
2906 skip_oneline_comment(&json);
2907 }
2908 else if (json[1] == '*')
2909 {
2910 skip_multiline_comment(&json);
2911 } else {
2912 json++;
2913 }
2914 break;
2915
2916 case '\"':
2917 minify_string(&json, (char**)&into);
2918 break;
2919
2920 default:
2921 into[0] = json[0];
2922 json++;
2923 into++;
2924 }
2925 }
2926
2927 /* and null-terminate. */
2928 *into = '\0';
2929}
2930
2931CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
2932{
2933 if (item == NULL)
2934 {
2935 return false;
2936 }
2937
2938 return (item->type & 0xFF) == cJSON_Invalid;
2939}
2940
2941CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
2942{
2943 if (item == NULL)
2944 {
2945 return false;
2946 }
2947
2948 return (item->type & 0xFF) == cJSON_False;
2949}
2950
2951CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
2952{
2953 if (item == NULL)
2954 {
2955 return false;
2956 }
2957
2958 return (item->type & 0xff) == cJSON_True;
2959}
2960
2961
2962CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
2963{
2964 if (item == NULL)
2965 {
2966 return false;
2967 }
2968
2969 return (item->type & (cJSON_True | cJSON_False)) != 0;
2970}
2971CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
2972{
2973 if (item == NULL)
2974 {
2975 return false;
2976 }
2977
2978 return (item->type & 0xFF) == cJSON_NULL;
2979}
2980
2981CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
2982{
2983 if (item == NULL)
2984 {
2985 return false;
2986 }
2987
2988 return (item->type & 0xFF) == cJSON_Number;
2989}
2990
2991CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
2992{
2993 if (item == NULL)
2994 {
2995 return false;
2996 }
2997
2998 return (item->type & 0xFF) == cJSON_String;
2999}
3000
3001CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
3002{
3003 if (item == NULL)
3004 {
3005 return false;
3006 }
3007
3008 return (item->type & 0xFF) == cJSON_Array;
3009}
3010
3011CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
3012{
3013 if (item == NULL)
3014 {
3015 return false;
3016 }
3017
3018 return (item->type & 0xFF) == cJSON_Object;
3019}
3020
3021CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
3022{
3023 if (item == NULL)
3024 {
3025 return false;
3026 }
3027
3028 return (item->type & 0xFF) == cJSON_Raw;
3029}
3030
3031CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
3032{
3033 if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
3034 {
3035 return false;
3036 }
3037
3038 /* check if type is valid */
3039 switch (a->type & 0xFF)
3040 {
3041 case cJSON_False:
3042 case cJSON_True:
3043 case cJSON_NULL:
3044 case cJSON_Number:
3045 case cJSON_String:
3046 case cJSON_Raw:
3047 case cJSON_Array:
3048 case cJSON_Object:
3049 break;
3050
3051 default:
3052 return false;
3053 }
3054
3055 /* identical objects are equal */
3056 if (a == b)
3057 {
3058 return true;
3059 }
3060
3061 switch (a->type & 0xFF)
3062 {
3063 /* in these cases and equal type is enough */
3064 case cJSON_False:
3065 case cJSON_True:
3066 case cJSON_NULL:
3067 return true;
3068
3069 case cJSON_Number:
3070 if (compare_double(a->valuedouble, b->valuedouble))
3071 {
3072 return true;
3073 }
3074 return false;
3075
3076 case cJSON_String:
3077 case cJSON_Raw:
3078 if ((a->valuestring == NULL) || (b->valuestring == NULL))
3079 {
3080 return false;
3081 }
3082 if (strcmp(a->valuestring, b->valuestring) == 0)
3083 {
3084 return true;
3085 }
3086
3087 return false;
3088
3089 case cJSON_Array:
3090 {
3091 cJSON *a_element = a->child;
3092 cJSON *b_element = b->child;
3093
3094 for (; (a_element != NULL) && (b_element != NULL);)
3095 {
3096 if (!cJSON_Compare(a_element, b_element, case_sensitive))
3097 {
3098 return false;
3099 }
3100
3101 a_element = a_element->next;
3102 b_element = b_element->next;
3103 }
3104
3105 /* one of the arrays is longer than the other */
3106 if (a_element != b_element) {
3107 return false;
3108 }
3109
3110 return true;
3111 }
3112
3113 case cJSON_Object:
3114 {
3115 cJSON *a_element = NULL;
3116 cJSON *b_element = NULL;
3117 cJSON_ArrayForEach(a_element, a)
3118 {
3119 /* TODO This has O(n^2) runtime, which is horrible! */
3120 b_element = get_object_item(b, a_element->string, case_sensitive);
3121 if (b_element == NULL)
3122 {
3123 return false;
3124 }
3125
3126 if (!cJSON_Compare(a_element, b_element, case_sensitive))
3127 {
3128 return false;
3129 }
3130 }
3131
3132 /* doing this twice, once on a and b to prevent true comparison if a subset of b
3133 * TODO: Do this the proper way, this is just a fix for now */
3134 cJSON_ArrayForEach(b_element, b)
3135 {
3136 a_element = get_object_item(a, b_element->string, case_sensitive);
3137 if (a_element == NULL)
3138 {
3139 return false;
3140 }
3141
3142 if (!cJSON_Compare(b_element, a_element, case_sensitive))
3143 {
3144 return false;
3145 }
3146 }
3147
3148 return true;
3149 }
3150
3151 default:
3152 return false;
3153 }
3154}
3155
3156CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
3157{
3158 return global_hooks.allocate(size);
3159}
3160
3161CJSON_PUBLIC(void) cJSON_free(void *object)
3162{
3163 global_hooks.deallocate(object);
3164 object = NULL;
3165}
diff --git a/lib/vendor/cJSON/cJSON.h b/lib/vendor/cJSON/cJSON.h
new file mode 100644
index 00000000..37520bbc
--- /dev/null
+++ b/lib/vendor/cJSON/cJSON.h
@@ -0,0 +1,306 @@
1/*
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23#ifndef cJSON__h
24#define cJSON__h
25
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
32#define __WINDOWS__
33#endif
34
35#ifdef __WINDOWS__
36
37/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
38
39CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
40CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
41CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
42
43For *nix builds that support visibility attribute, you can define similar behavior by
44
45setting default visibility to hidden by adding
46-fvisibility=hidden (for gcc)
47or
48-xldscope=hidden (for sun cc)
49to CFLAGS
50
51then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
52
53*/
54
55#define CJSON_CDECL __cdecl
56#define CJSON_STDCALL __stdcall
57
58/* export symbols by default, this is necessary for copy pasting the C and header file */
59#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
60#define CJSON_EXPORT_SYMBOLS
61#endif
62
63#if defined(CJSON_HIDE_SYMBOLS)
64#define CJSON_PUBLIC(type) type CJSON_STDCALL
65#elif defined(CJSON_EXPORT_SYMBOLS)
66#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
67#elif defined(CJSON_IMPORT_SYMBOLS)
68#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
69#endif
70#else /* !__WINDOWS__ */
71#define CJSON_CDECL
72#define CJSON_STDCALL
73
74#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
75#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
76#else
77#define CJSON_PUBLIC(type) type
78#endif
79#endif
80
81/* project version */
82#define CJSON_VERSION_MAJOR 1
83#define CJSON_VERSION_MINOR 7
84#define CJSON_VERSION_PATCH 18
85
86#include <stddef.h>
87
88/* cJSON Types: */
89#define cJSON_Invalid (0)
90#define cJSON_False (1 << 0)
91#define cJSON_True (1 << 1)
92#define cJSON_NULL (1 << 2)
93#define cJSON_Number (1 << 3)
94#define cJSON_String (1 << 4)
95#define cJSON_Array (1 << 5)
96#define cJSON_Object (1 << 6)
97#define cJSON_Raw (1 << 7) /* raw json */
98
99#define cJSON_IsReference 256
100#define cJSON_StringIsConst 512
101
102/* The cJSON structure: */
103typedef struct cJSON
104{
105 /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
106 struct cJSON *next;
107 struct cJSON *prev;
108 /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
109 struct cJSON *child;
110
111 /* The type of the item, as above. */
112 int type;
113
114 /* The item's string, if type==cJSON_String and type == cJSON_Raw */
115 char *valuestring;
116 /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
117 int valueint;
118 /* The item's number, if type==cJSON_Number */
119 double valuedouble;
120
121 /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
122 char *string;
123} cJSON;
124
125typedef struct cJSON_Hooks
126{
127 /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
128 void *(CJSON_CDECL *malloc_fn)(size_t sz);
129 void (CJSON_CDECL *free_fn)(void *ptr);
130} cJSON_Hooks;
131
132typedef int cJSON_bool;
133
134/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
135 * This is to prevent stack overflows. */
136#ifndef CJSON_NESTING_LIMIT
137#define CJSON_NESTING_LIMIT 1000
138#endif
139
140/* Limits the length of circular references can be before cJSON rejects to parse them.
141 * This is to prevent stack overflows. */
142#ifndef CJSON_CIRCULAR_LIMIT
143#define CJSON_CIRCULAR_LIMIT 10000
144#endif
145
146/* returns the version of cJSON as a string */
147CJSON_PUBLIC(const char*) cJSON_Version(void);
148
149/* Supply malloc, realloc and free functions to cJSON */
150CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
151
152/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
153/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
154CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
155CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
156/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
157/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
158CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
159CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
160
161/* Render a cJSON entity to text for transfer/storage. */
162CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
163/* Render a cJSON entity to text for transfer/storage without any formatting. */
164CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
165/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
166CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
167/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
168/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
169CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
170/* Delete a cJSON entity and all subentities. */
171CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
172
173/* Returns the number of items in an array (or object). */
174CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
175/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
176CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
177/* Get item "string" from object. Case insensitive. */
178CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
179CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
180CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
181/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
182CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
183
184/* Check item type and return its value */
185CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
186CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
187
188/* These functions check the type of an item */
189CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
190CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
191CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
192CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
193CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
194CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
195CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
196CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
197CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
198CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
199
200/* These calls create a cJSON item of the appropriate type. */
201CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
202CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
203CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
204CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
205CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
206CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
207/* raw json */
208CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
209CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
210CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
211
212/* Create a string where valuestring references a string so
213 * it will not be freed by cJSON_Delete */
214CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
215/* Create an object/array that only references it's elements so
216 * they will not be freed by cJSON_Delete */
217CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
218CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
219
220/* These utilities create an Array of count items.
221 * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
222CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
223CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
224CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
225CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
226
227/* Append item to the specified array/object. */
228CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
229CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
230/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
231 * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
232 * writing to `item->string` */
233CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
234/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
235CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
236CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
237
238/* Remove/Detach items from Arrays/Objects. */
239CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
240CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
241CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
242CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
243CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
244CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
245CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
246
247/* Update array items. */
248CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
249CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
250CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
251CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
252CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
253
254/* Duplicate a cJSON item */
255CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
256/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
257 * need to be released. With recurse!=0, it will duplicate any children connected to the item.
258 * The item->next and ->prev pointers are always zero on return from Duplicate. */
259/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
260 * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
261CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
262
263/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
264 * The input pointer json cannot point to a read-only address area, such as a string constant,
265 * but should point to a readable and writable address area. */
266CJSON_PUBLIC(void) cJSON_Minify(char *json);
267
268/* Helper functions for creating and adding items to an object at the same time.
269 * They return the added item or NULL on failure. */
270CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
271CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
272CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
273CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
274CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
275CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
276CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
277CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
278CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
279
280/* When assigning an integer value, it needs to be propagated to valuedouble too. */
281#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
282/* helper for the cJSON_SetNumberValue macro */
283CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
284#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
285/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
286CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
287
288/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
289#define cJSON_SetBoolValue(object, boolValue) ( \
290 (object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
291 (object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
292 cJSON_Invalid\
293)
294
295/* Macro for iterating over an array or object */
296#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
297
298/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
299CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
300CJSON_PUBLIC(void) cJSON_free(void *object);
301
302#ifdef __cplusplus
303}
304#endif
305
306#endif