summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am19
-rw-r--r--lib/extra_opts.c172
-rw-r--r--lib/extra_opts.h1
-rw-r--r--lib/maxfd.c38
-rw-r--r--lib/maxfd.h6
-rw-r--r--lib/monitoringplug.h7
-rw-r--r--lib/output.c636
-rw-r--r--lib/output.h117
-rw-r--r--lib/parse_ini.c342
-rw-r--r--lib/parse_ini.h1
-rw-r--r--lib/perfdata.c649
-rw-r--r--lib/perfdata.h219
-rw-r--r--lib/states.h71
-rw-r--r--lib/tests/Makefile.am6
-rw-r--r--lib/tests/test_base64.c359
-rw-r--r--lib/tests/test_cmd.c282
-rw-r--r--lib/tests/test_disk.c224
-rwxr-xr-xlib/tests/test_disk.t6
-rwxr-xr-xlib/tests/test_generic_outputbin0 -> 143808 bytes
-rw-r--r--lib/tests/test_generic_output.c317
-rw-r--r--lib/tests/test_generic_output.t6
-rw-r--r--lib/tests/test_ini1.c132
-rw-r--r--lib/tests/test_ini3.c37
-rw-r--r--lib/tests/test_opts1.c128
-rw-r--r--lib/tests/test_opts2.c148
-rw-r--r--lib/tests/test_opts3.c37
-rw-r--r--lib/tests/test_tcp.c62
-rw-r--r--lib/tests/test_utils.c549
-rw-r--r--lib/thresholds.c71
-rw-r--r--lib/thresholds.h31
-rw-r--r--lib/utils_base.c643
-rw-r--r--lib/utils_base.h74
-rw-r--r--lib/utils_cmd.c398
-rw-r--r--lib/utils_cmd.h26
-rw-r--r--lib/utils_disk.c270
-rw-r--r--lib/utils_disk.h52
-rw-r--r--lib/utils_tcp.c101
-rw-r--r--lib/utils_tcp.h13
-rw-r--r--lib/vendor/cJSON/cJSON.c3165
-rw-r--r--lib/vendor/cJSON/cJSON.h306
40 files changed, 7192 insertions, 2529 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index dc3ee893..27a08278 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -4,11 +4,23 @@ SUBDIRS = . tests
4 4
5noinst_LIBRARIES = libmonitoringplug.a 5noinst_LIBRARIES = libmonitoringplug.a
6 6
7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 7AM_CPPFLAGS = \
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_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_tcp.h \
14 utils_cmd.h \
15 parse_ini.h \
16 extra_opts.h \
17 maxfd.h \
18 perfdata.h \
19 output.h \
20 thresholds.h \
21 states.h \
22 vendor/cJSON/cJSON.h \
23 monitoringplug.h
12 24
13if USE_PARSE_INI 25if USE_PARSE_INI
14libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c 26libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c
@@ -16,4 +28,3 @@ endif USE_PARSE_INI
16 28
17test test-debug: 29test test-debug:
18 cd tests && make $@ 30 cd tests && make $@
19
diff --git a/lib/extra_opts.c b/lib/extra_opts.c
index 771621d8..3fe69014 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,130 @@
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{ 30 if (!str) {
31 if (!str)
32 return false; 31 return false;
33 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2) 32 }
33
34 if (strspn(str, "-") == 1 || strspn(str, "-") == 2) {
34 return true; 35 return true;
35 else 36 }
36 return false; 37
38 return false;
37} 39}
38 40
39/* this is the externally visible function used by plugins */ 41/* this is the externally visible function used by plugins */
40char **np_extra_opts(int *argc, char **argv, const char *plugin_name){ 42char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
41 np_arg_list *extra_args=NULL, *ea1=NULL, *ea_tmp=NULL; 43 if (*argc < 2) {
42 char **argv_new=NULL;
43 char *argptr=NULL;
44 int i, j, optfound, argc_new, ea_num=*argc;
45
46 if(*argc<2) {
47 /* No arguments provided */ 44 /* No arguments provided */
48 return argv; 45 return argv;
49 } 46 }
50 47
51 for(i=1; i<*argc; i++){ 48 np_arg_list *extra_args = NULL;
52 argptr=NULL; 49 np_arg_list *ea1 = NULL;
53 optfound=0; 50 np_arg_list *ea_tmp = NULL;
51 char *argptr = NULL;
52 int optfound;
53 size_t ea_num = (size_t)*argc;
54
55 for (int i = 1; i < *argc; i++) {
56 argptr = NULL;
57 optfound = 0;
54 58
55 /* Do we have an extra-opts parameter? */ 59 /* Do we have an extra-opts parameter? */
56 if(strncmp(argv[i], "--extra-opts=", 13)==0){ 60 if (strncmp(argv[i], "--extra-opts=", 13) == 0) {
57 /* It is a single argument with value */ 61 /* It is a single argument with value */
58 argptr=argv[i]+13; 62 argptr = argv[i] + 13;
59 /* Delete the extra opts argument */ 63 /* Delete the extra opts argument */
60 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 64 for (int j = i; j < *argc; j++) {
65 argv[j] = argv[j + 1];
66 }
67
61 i--; 68 i--;
62 *argc-=1; 69 *argc -= 1;
63 }else if(strcmp(argv[i], "--extra-opts")==0){ 70 } else if (strcmp(argv[i], "--extra-opts") == 0) {
64 if((i+1<*argc)&&!is_option2(argv[i+1])){ 71 if ((i + 1 < *argc) && !is_option2(argv[i + 1])) {
65 /* It is a argument with separate value */ 72 /* It is a argument with separate value */
66 argptr=argv[i+1]; 73 argptr = argv[i + 1];
67 /* Delete the extra-opts argument/value */ 74 /* Delete the extra-opts argument/value */
68 for(j=i;j<*argc-1;j++) argv[j]=argv[j+2]; 75 for (int j = i; j < *argc - 1; j++) {
69 i-=2; 76 argv[j] = argv[j + 2];
70 *argc-=2; 77 }
78
79 i -= 2;
80 *argc -= 2;
71 ea_num--; 81 ea_num--;
72 }else{ 82 } else {
73 /* It has no value */ 83 /* It has no value */
74 optfound=1; 84 optfound = 1;
75 /* Delete the extra opts argument */ 85 /* Delete the extra opts argument */
76 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 86 for (int j = i; j < *argc; j++) {
87 argv[j] = argv[j + 1];
88 }
89
77 i--; 90 i--;
78 *argc-=1; 91 *argc -= 1;
79 } 92 }
80 } 93 }
81 94
82 /* If we found extra-opts, expand them and store them for later*/ 95 /* If we found extra-opts, expand them and store them for later*/
83 if(argptr||optfound){ 96 if (argptr || optfound) {
84 /* Process ini section, returning a linked list of arguments */ 97 /* Process ini section, returning a linked list of arguments */
85 ea1=np_get_defaults(argptr, plugin_name); 98 ea1 = np_get_defaults(argptr, plugin_name);
86 if(ea1==NULL) { 99 if (ea1 == NULL) {
87 /* no extra args (empty section)? */ 100 /* no extra args (empty section)? */
88 ea_num--; 101 ea_num--;
89 continue; 102 continue;
90 } 103 }
91 104
92 /* append the list to extra_args */ 105 /* append the list to extra_args */
93 if(extra_args==NULL){ 106 if (extra_args == NULL) {
94 extra_args=ea1; 107 extra_args = ea1;
95 while((ea1 = ea1->next)) ea_num++; 108 while ((ea1 = ea1->next)) {
96 }else{ 109 ea_num++;
97 ea_tmp=extra_args; 110 }
98 while(ea_tmp->next) { 111 } else {
99 ea_tmp=ea_tmp->next; 112 ea_tmp = extra_args;
113 while (ea_tmp->next) {
114 ea_tmp = ea_tmp->next;
115 }
116 ea_tmp->next = ea1;
117 while ((ea1 = ea1->next)) {
118 ea_num++;
100 } 119 }
101 ea_tmp->next=ea1;
102 while((ea1 = ea1->next)) ea_num++;
103 } 120 }
104 ea1=ea_tmp=NULL; 121 ea1 = ea_tmp = NULL;
105 } 122 }
106 } /* lather, rince, repeat */ 123 } /* lather, rince, repeat */
107 124
108 if(ea_num==*argc && extra_args==NULL){ 125 if (ea_num == (size_t)*argc && extra_args == NULL) {
109 /* No extra-opts */ 126 /* No extra-opts */
110 return argv; 127 return argv;
111 } 128 }
112 129
113 /* done processing arguments. now create a new argv array... */ 130 /* done processing arguments. now create a new argv array... */
114 argv_new=(char**)malloc((ea_num+1)*sizeof(char**)); 131 char **argv_new = (char **)malloc((ea_num + 1) * sizeof(char **));
115 if(argv_new==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); 132 if (argv_new == NULL) {
133 die(STATE_UNKNOWN, _("malloc() failed!\n"));
134 }
116 135
117 /* starting with program name */ 136 /* starting with program name */
118 argv_new[0]=argv[0]; 137 argv_new[0] = argv[0];
119 argc_new=1; 138 int argc_new = 1;
120 /* then parsed ini opts (frying them up in the same run) */ 139 /* then parsed ini opts (frying them up in the same run) */
121 while(extra_args){ 140 while (extra_args) {
122 argv_new[argc_new++]=extra_args->arg; 141 argv_new[argc_new++] = extra_args->arg;
123 ea1=extra_args; 142 ea1 = extra_args;
124 extra_args=extra_args->next; 143 extra_args = extra_args->next;
125 free(ea1); 144 free(ea1);
126 } 145 }
127 /* finally the rest of the argv array */ 146 /* finally the rest of the argv array */
128 for (i=1; i<*argc; i++) argv_new[argc_new++]=argv[i]; 147 for (int i = 1; i < *argc; i++) {
129 *argc=argc_new; 148 argv_new[argc_new++] = argv[i];
149 }
150 *argc = argc_new;
130 /* and terminate. */ 151 /* and terminate. */
131 argv_new[argc_new]=NULL; 152 argv_new[argc_new] = NULL;
132 153
133 return argv_new; 154 return argv_new;
134} 155}
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..a0f79949 100644
--- a/lib/maxfd.c
+++ b/lib/maxfd.c
@@ -1,7 +1,26 @@
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>
3 22
4long mp_open_max (void) { 23long mp_open_max(void) {
5 long maxfd = 0L; 24 long maxfd = 0L;
6 /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX. 25 /* 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 26 * If that fails and the macro isn't defined, we fall back to an educated
@@ -10,17 +29,18 @@ long mp_open_max (void) {
10 29
11#ifdef _SC_OPEN_MAX 30#ifdef _SC_OPEN_MAX
12 errno = 0; 31 errno = 0;
13 if ((maxfd = sysconf (_SC_OPEN_MAX)) < 0) { 32 if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
14 if (errno == 0) 33 if (errno == 0) {
15 maxfd = DEFAULT_MAXFD; /* it's indeterminate */ 34 maxfd = DEFAULT_MAXFD; /* it's indeterminate */
16 else 35 } else {
17 die (STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n")); 36 die(STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n"));
37 }
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..f283969f
--- /dev/null
+++ b/lib/output.c
@@ -0,0 +1,636 @@
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// == Global variables
15static mp_output_format output_format = MP_FORMAT_DEFAULT;
16static mp_output_detail_level level_of_detail = MP_DETAIL_ALL;
17
18// == Prototypes ==
19static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
20 unsigned int indentation);
21static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
22
23// == Implementation ==
24
25/*
26 * Generate output string for a mp_subcheck object
27 */
28static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
29 char *result = strdup("");
30 int added = 0;
31
32 if (check.perfdata != NULL) {
33 added = asprintf(&result, "%s", pd_list_to_string(*check.perfdata));
34 }
35
36 if (check.subchecks == NULL) {
37 // No subchecks, return here
38 return result;
39 }
40
41 mp_subcheck_list *subchecks = check.subchecks;
42
43 while (subchecks != NULL) {
44 if (added > 0) {
45 added = asprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck));
46 } else {
47 // TODO free previous result here?
48 added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
49 }
50
51 subchecks = subchecks->next;
52 }
53
54 return result;
55}
56
57/*
58 * Initialiser for a mp_check object. Always use this to get a new one!
59 * It sets useful defaults
60 */
61mp_check mp_check_init(void) {
62 mp_check check = {
63 .evaluation_function = &mp_eval_check_default,
64 };
65 return check;
66}
67
68/*
69 * Initialiser for a mp_subcheck object. Always use this to get a new one!
70 * It sets useful defaults
71 */
72mp_subcheck mp_subcheck_init(void) {
73 mp_subcheck tmp = {0};
74 tmp.default_state = STATE_UNKNOWN; // Default state is unknown
75 tmp.state_set_explicitly = false;
76 return tmp;
77}
78
79/*
80 * Add a subcheck to a (the one and only) check object
81 */
82int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck subcheck) {
83 assert(subcheck.output != NULL); // There must be output in a subcheck
84
85 mp_subcheck_list *tmp = NULL;
86
87 if (check->subchecks == NULL) {
88 check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
89 if (check->subchecks == NULL) {
90 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
91 }
92
93 check->subchecks->subcheck = subcheck;
94 check->subchecks->next = NULL;
95 } else {
96 // Search for the end
97 tmp = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
98 if (tmp == NULL) {
99 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
100 }
101
102 tmp->subcheck = subcheck;
103 tmp->next = check->subchecks;
104
105 check->subchecks = tmp;
106 }
107
108 return 0;
109}
110
111/*
112 * Add a mp_perfdata data point to a mp_subcheck object
113 */
114void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata perfData) {
115 if (check->perfdata == NULL) {
116 check->perfdata = pd_list_init();
117 }
118 pd_list_append(check->perfdata, perfData);
119}
120
121/*
122 * Add a mp_subcheck object to another one. The seconde mp_subcheck (argument) is the lower in the
123 * hierarchy
124 */
125int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) {
126 if (subcheck.output == NULL) {
127 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__,
128 "Sub check output is NULL");
129 }
130
131 mp_subcheck_list *tmp = NULL;
132
133 if (check->subchecks == NULL) {
134 check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
135 if (check->subchecks == NULL) {
136 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
137 }
138
139 tmp = check->subchecks;
140 } else {
141 // Search for the end
142 tmp = check->subchecks;
143
144 while (tmp->next != NULL) {
145 tmp = tmp->next;
146 }
147
148 tmp->next = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
149 if (tmp->next == NULL) {
150 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
151 }
152
153 tmp = tmp->next;
154 }
155
156 tmp->subcheck = subcheck;
157
158 return 0;
159}
160
161/*
162 * Add a manual summary to a mp_check object, effectively replacing
163 * the autogenerated one
164 */
165void mp_add_summary(mp_check check[static 1], char *summary) { check->summary = summary; }
166
167/*
168 * Generate the summary string of a mp_check object based on it's subchecks
169 */
170char *get_subcheck_summary(mp_check check) {
171 mp_subcheck_list *subchecks = check.subchecks;
172
173 unsigned int ok = 0;
174 unsigned int warning = 0;
175 unsigned int critical = 0;
176 unsigned int unknown = 0;
177 while (subchecks != NULL) {
178 switch (subchecks->subcheck.state) {
179 case STATE_OK:
180 ok++;
181 break;
182 case STATE_WARNING:
183 warning++;
184 break;
185 case STATE_CRITICAL:
186 critical++;
187 break;
188 case STATE_UNKNOWN:
189 unknown++;
190 break;
191 default:
192 die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary");
193 }
194 subchecks = subchecks->next;
195 }
196 char *result = NULL;
197 asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown);
198 return result;
199}
200
201mp_state_enum mp_compute_subcheck_state(const mp_subcheck subcheck) {
202 if (subcheck.evaluation_function == NULL) {
203 return mp_eval_subcheck_default(subcheck);
204 }
205 return subcheck.evaluation_function(subcheck);
206}
207
208/*
209 * Generate the result state of a mp_subcheck object based on its own state and its subchecks
210 * states
211 */
212mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck) {
213 if (subcheck.evaluation_function != NULL) {
214 return subcheck.evaluation_function(subcheck);
215 }
216
217 if (subcheck.state_set_explicitly) {
218 return subcheck.state;
219 }
220
221 mp_subcheck_list *scl = subcheck.subchecks;
222
223 if (scl == NULL) {
224 return subcheck.default_state;
225 }
226
227 mp_state_enum result = STATE_OK;
228
229 while (scl != NULL) {
230 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
231 scl = scl->next;
232 }
233
234 return result;
235}
236
237mp_state_enum mp_compute_check_state(const mp_check check) {
238 // just a safety check
239 if (check.evaluation_function == NULL) {
240 return mp_eval_check_default(check);
241 }
242 return check.evaluation_function(check);
243}
244
245/*
246 * Generate the result state of a mp_check object based on it's own state and it's subchecks states
247 */
248mp_state_enum mp_eval_check_default(const mp_check check) {
249 assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here
250
251 mp_subcheck_list *scl = check.subchecks;
252 mp_state_enum result = STATE_OK;
253
254 while (scl != NULL) {
255 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
256 scl = scl->next;
257 }
258
259 return result;
260}
261
262/*
263 * Generate output string for a mp_check object
264 * Non static to be available for testing functions
265 */
266char *mp_fmt_output(mp_check check) {
267 char *result = NULL;
268
269 switch (output_format) {
270 case MP_FORMAT_MULTI_LINE: {
271 if (check.summary == NULL) {
272 check.summary = get_subcheck_summary(check);
273 }
274
275 asprintf(&result, "[%s] - %s", state_text(mp_compute_check_state(check)), check.summary);
276
277 mp_subcheck_list *subchecks = check.subchecks;
278
279 while (subchecks != NULL) {
280 if (level_of_detail == MP_DETAIL_ALL ||
281 mp_compute_subcheck_state(subchecks->subcheck) != STATE_OK) {
282 asprintf(&result, "%s\n%s", result,
283 fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
284 }
285 subchecks = subchecks->next;
286 }
287
288 char *pd_string = NULL;
289 subchecks = check.subchecks;
290
291 while (subchecks != NULL) {
292 if (pd_string == NULL) {
293 asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
294 } else {
295 asprintf(&pd_string, "%s %s", pd_string,
296 fmt_subcheck_perfdata(subchecks->subcheck));
297 }
298
299 subchecks = subchecks->next;
300 }
301
302 if (pd_string != NULL && strlen(pd_string) > 0) {
303 asprintf(&result, "%s|%s", result, pd_string);
304 }
305
306 break;
307 }
308 case MP_FORMAT_TEST_JSON: {
309 cJSON *resultObject = cJSON_CreateObject();
310 if (resultObject == NULL) {
311 die(STATE_UNKNOWN, "cJSON_CreateObject failed");
312 }
313
314 cJSON *resultState = cJSON_CreateString(state_text(mp_compute_check_state(check)));
315 cJSON_AddItemToObject(resultObject, "state", resultState);
316
317 if (check.summary == NULL) {
318 check.summary = get_subcheck_summary(check);
319 }
320
321 cJSON *summary = cJSON_CreateString(check.summary);
322 cJSON_AddItemToObject(resultObject, "summary", summary);
323
324 if (check.subchecks != NULL) {
325 cJSON *subchecks = cJSON_CreateArray();
326
327 mp_subcheck_list *sc = check.subchecks;
328
329 while (sc != NULL) {
330 cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
331 cJSON_AddItemToArray(subchecks, sc_json);
332 sc = sc->next;
333 }
334
335 cJSON_AddItemToObject(resultObject, "checks", subchecks);
336 }
337
338 result = cJSON_PrintUnformatted(resultObject);
339 break;
340 }
341 default:
342 die(STATE_UNKNOWN, "Invalid format");
343 }
344
345 return result;
346}
347
348/*
349 * Helper function to properly indent the output lines when using multiline
350 * formats
351 */
352static char *generate_indentation_string(unsigned int indentation) {
353 char *result = calloc(indentation + 1, sizeof(char));
354
355 for (unsigned int i = 0; i < indentation; i++) {
356 result[i] = '\t';
357 }
358
359 return result;
360}
361
362/*
363 * Helper function to generate the output string of mp_subcheck
364 */
365static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
366 unsigned int indentation) {
367 char *result = NULL;
368 mp_subcheck_list *subchecks = NULL;
369
370 switch (output_format) {
371 case MP_FORMAT_MULTI_LINE: {
372 char *tmp_string = NULL;
373 if ((tmp_string = strchr(check.output, '\n')) != NULL) {
374 // This is a multiline string, put the correct indentation in before proceeding
375 char *intermediate_string = "";
376 bool have_residual_chars = false;
377
378 while (tmp_string != NULL) {
379 *tmp_string = '\0';
380 asprintf(&intermediate_string, "%s%s\n%s", intermediate_string, check.output,
381 generate_indentation_string(
382 indentation + 1)); // one more indentation to make it look better
383
384 if (*(tmp_string + 1) != '\0') {
385 check.output = tmp_string + 1;
386 have_residual_chars = true;
387 } else {
388 // Null after the \n, so this is the end
389 have_residual_chars = false;
390 break;
391 }
392
393 tmp_string = strchr(check.output, '\n');
394 }
395
396 // add the rest (if any)
397 if (have_residual_chars) {
398 char *tmp = check.output;
399 xasprintf(&check.output, "%s\n%s%s", intermediate_string,
400 generate_indentation_string(indentation + 1), tmp);
401 } else {
402 check.output = intermediate_string;
403 }
404 }
405 asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation),
406 state_text(mp_compute_subcheck_state(check)), check.output);
407
408 subchecks = check.subchecks;
409
410 while (subchecks != NULL) {
411 asprintf(&result, "%s\n%s", result,
412 fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
413 subchecks = subchecks->next;
414 }
415 return result;
416 }
417 default:
418 die(STATE_UNKNOWN, "Invalid format");
419 }
420}
421
422static inline cJSON *json_serialise_pd_value(mp_perfdata_value value) {
423 cJSON *result = cJSON_CreateObject();
424
425 switch (value.type) {
426 case PD_TYPE_DOUBLE:
427 cJSON_AddStringToObject(result, "type", "double");
428 break;
429 case PD_TYPE_INT:
430 cJSON_AddStringToObject(result, "type", "int");
431 break;
432 case PD_TYPE_UINT:
433 cJSON_AddStringToObject(result, "type", "uint");
434 break;
435 case PD_TYPE_NONE:
436 die(STATE_UNKNOWN, "Perfdata type was None in json_serialise_pd_value");
437 }
438 cJSON_AddStringToObject(result, "value", pd_value_to_string(value));
439
440 return result;
441}
442
443static inline cJSON *json_serialise_range(mp_range range) {
444 cJSON *result = cJSON_CreateObject();
445
446 if (range.alert_on_inside_range) {
447 cJSON_AddBoolToObject(result, "alert_on_inside", true);
448 } else {
449 cJSON_AddBoolToObject(result, "alert_on_inside", false);
450 }
451
452 if (range.end_infinity) {
453 cJSON_AddStringToObject(result, "end", "inf");
454 } else {
455 cJSON_AddItemToObject(result, "end", json_serialise_pd_value(range.end));
456 }
457
458 if (range.start_infinity) {
459 cJSON_AddStringToObject(result, "start", "inf");
460 } else {
461 cJSON_AddItemToObject(result, "start", json_serialise_pd_value(range.end));
462 }
463
464 return result;
465}
466
467static inline cJSON *json_serialise_pd(mp_perfdata pd_val) {
468 cJSON *result = cJSON_CreateObject();
469
470 // Label
471 cJSON_AddStringToObject(result, "label", pd_val.label);
472
473 // Value
474 cJSON_AddItemToObject(result, "value", json_serialise_pd_value(pd_val.value));
475
476 // Uom
477 cJSON_AddStringToObject(result, "uom", pd_val.uom);
478
479 // Warn/Crit
480 if (pd_val.warn_present) {
481 cJSON *warn = json_serialise_range(pd_val.warn);
482 cJSON_AddItemToObject(result, "warn", warn);
483 }
484 if (pd_val.crit_present) {
485 cJSON *crit = json_serialise_range(pd_val.crit);
486 cJSON_AddItemToObject(result, "crit", crit);
487 }
488
489 if (pd_val.min_present) {
490 cJSON_AddItemToObject(result, "min", json_serialise_pd_value(pd_val.min));
491 }
492 if (pd_val.max_present) {
493 cJSON_AddItemToObject(result, "max", json_serialise_pd_value(pd_val.max));
494 }
495
496 return result;
497}
498
499static inline cJSON *json_serialise_pd_list(pd_list *list) {
500 cJSON *result = cJSON_CreateArray();
501
502 do {
503 cJSON *pd_value = json_serialise_pd(list->data);
504 cJSON_AddItemToArray(result, pd_value);
505 list = list->next;
506 } while (list != NULL);
507
508 return result;
509}
510
511static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck) {
512 cJSON *result = cJSON_CreateObject();
513
514 // Human readable output
515 cJSON *output = cJSON_CreateString(subcheck.output);
516 cJSON_AddItemToObject(result, "output", output);
517
518 // Test state (aka Exit Code)
519 cJSON *state = cJSON_CreateString(state_text(mp_compute_subcheck_state(subcheck)));
520 cJSON_AddItemToObject(result, "state", state);
521
522 // Perfdata
523 if (subcheck.perfdata != NULL) {
524 cJSON *perfdata = json_serialise_pd_list(subcheck.perfdata);
525 cJSON_AddItemToObject(result, "perfdata", perfdata);
526 }
527
528 if (subcheck.subchecks != NULL) {
529 cJSON *subchecks = cJSON_CreateArray();
530
531 mp_subcheck_list *sc = subcheck.subchecks;
532
533 while (sc != NULL) {
534 cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
535 cJSON_AddItemToArray(subchecks, sc_json);
536 sc = sc->next;
537 }
538
539 cJSON_AddItemToObject(result, "checks", subchecks);
540 }
541
542 return result;
543}
544
545/*
546 * Wrapper function to print the output string of a mp_check object
547 * Use this in concrete plugins.
548 */
549void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); }
550
551/*
552 * Convenience function to print the output string of a mp_check object and exit
553 * the program with the resulting state.
554 * Intended to be used to exit a monitoring plugin.
555 */
556void mp_exit(mp_check check) {
557 mp_print_output(check);
558 if (output_format == MP_FORMAT_TEST_JSON) {
559 exit(0);
560 }
561
562 exit(mp_compute_check_state(check));
563}
564
565/*
566 * Function to set the result state of a mp_subcheck object explicitly.
567 * This will overwrite the default state AND states derived from it's subchecks
568 */
569mp_subcheck mp_set_subcheck_state(mp_subcheck check, mp_state_enum state) {
570 check.state = state;
571 check.state_set_explicitly = true;
572 return check;
573}
574
575/*
576 * Function to set the default result state of a mp_subcheck object. This state
577 * will be used if neither an explicit state is set (see *mp_set_subcheck_state*)
578 * nor does it include other subchecks
579 */
580mp_subcheck mp_set_subcheck_default_state(mp_subcheck check, mp_state_enum state) {
581 check.default_state = state;
582 return check;
583}
584
585char *mp_output_format_map[] = {
586 [MP_FORMAT_MULTI_LINE] = "multi-line",
587 [MP_FORMAT_TEST_JSON] = "mp-test-json",
588};
589
590/*
591 * Function to parse the output from a string
592 */
593parsed_output_format mp_parse_output_format(char *format_string) {
594 parsed_output_format result = {
595 .parsing_success = false,
596 .output_format = MP_FORMAT_DEFAULT,
597 };
598
599 for (mp_output_format i = 0; i < (sizeof(mp_output_format_map) / sizeof(char *)); i++) {
600 if (strcasecmp(mp_output_format_map[i], format_string) == 0) {
601 result.parsing_success = true;
602 result.output_format = i;
603 break;
604 }
605 }
606
607 return result;
608}
609
610void mp_set_format(mp_output_format format) { output_format = format; }
611
612mp_output_format mp_get_format(void) { return output_format; }
613
614void mp_set_level_of_detail(mp_output_detail_level level) { level_of_detail = level; }
615
616mp_output_detail_level mp_get_level_of_detail(void) { return level_of_detail; }
617
618mp_state_enum mp_eval_ok(mp_check overall) {
619 (void)overall;
620 return STATE_OK;
621}
622
623mp_state_enum mp_eval_warning(mp_check overall) {
624 (void)overall;
625 return STATE_WARNING;
626}
627
628mp_state_enum mp_eval_critical(mp_check overall) {
629 (void)overall;
630 return STATE_CRITICAL;
631}
632
633mp_state_enum mp_eval_unknown(mp_check overall) {
634 (void)overall;
635 return STATE_UNKNOWN;
636}
diff --git a/lib/output.h b/lib/output.h
new file mode 100644
index 00000000..c63c8e3f
--- /dev/null
+++ b/lib/output.h
@@ -0,0 +1,117 @@
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 mp_subcheck mp_subcheck;
11struct mp_subcheck {
12 mp_state_enum state; // OK, Warning, Critical ... set explicitly
13 mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly
14 bool state_set_explicitly; // was the state set explicitly (or should it be derived from
15 // subchecks)
16
17 char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP
18 // connection to..")
19 pd_list *perfdata; // Performance data for this check
20 struct subcheck_list *subchecks; // subchecks deeper in the hierarchy
21
22 // the evaluation_functions computes the state of subcheck
23 mp_state_enum (*evaluation_function)(mp_subcheck);
24};
25
26/*
27 * A list of subchecks, used in subchecks and the main check
28 */
29typedef struct subcheck_list {
30 mp_subcheck subcheck;
31 struct subcheck_list *next;
32} mp_subcheck_list;
33
34/*
35 * Possible output formats
36 */
37typedef enum output_format {
38 MP_FORMAT_MULTI_LINE,
39 MP_FORMAT_TEST_JSON,
40} mp_output_format;
41
42#define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE
43
44/*
45 * Format related functions
46 */
47void mp_set_format(mp_output_format format);
48mp_output_format mp_get_format(void);
49
50// Output detail level
51
52typedef enum output_detail_level {
53 MP_DETAIL_ALL,
54 MP_DETAIL_NON_OK_ONLY,
55} mp_output_detail_level;
56
57void mp_set_level_of_detail(mp_output_detail_level level);
58mp_output_detail_level mp_get_level_of_detail(void);
59
60/*
61 * The main state object of a plugin. Exists only ONCE per plugin.
62 * This is the "root" of a tree of singular checks.
63 * The final result is always derived from the children and the "worst" state
64 * in the first layer of subchecks
65 */
66typedef struct mp_check mp_check;
67struct mp_check {
68 char *summary; // Overall summary, if not set a summary will be automatically generated
69 mp_subcheck_list *subchecks;
70
71 // the evaluation_functions computes the state of check
72 mp_state_enum (*evaluation_function)(mp_check);
73};
74
75mp_check mp_check_init(void);
76mp_subcheck mp_subcheck_init(void);
77
78mp_subcheck mp_set_subcheck_state(mp_subcheck, mp_state_enum);
79mp_subcheck mp_set_subcheck_default_state(mp_subcheck, mp_state_enum);
80
81int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck);
82int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck);
83
84void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], mp_perfdata);
85
86void mp_add_summary(mp_check check[static 1], char *summary);
87
88mp_state_enum mp_compute_check_state(mp_check);
89mp_state_enum mp_compute_subcheck_state(mp_subcheck);
90
91mp_state_enum mp_eval_ok(mp_check overall);
92mp_state_enum mp_eval_warning(mp_check overall);
93mp_state_enum mp_eval_critical(mp_check overall);
94mp_state_enum mp_eval_unknown(mp_check overall);
95mp_state_enum mp_eval_check_default(mp_check check);
96mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck);
97
98typedef struct {
99 bool parsing_success;
100 mp_output_format output_format;
101} parsed_output_format;
102parsed_output_format mp_parse_output_format(char *format_string);
103
104// TODO free and stuff
105// void mp_cleanup_check(mp_check check[static 1]);
106
107char *mp_fmt_output(mp_check);
108
109void mp_print_output(mp_check);
110
111/*
112 * ==================
113 * Exit functionality
114 * ==================
115 */
116
117void mp_exit(mp_check) __attribute__((noreturn));
diff --git a/lib/parse_ini.c b/lib/parse_ini.c
index 09c0dc4f..db337622 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,37 +40,29 @@ 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",
44 "monitoring-plugins.ini", 44 "nagios-plugins.ini", NULL};
45 "plugins.ini",
46 "nagios-plugins.ini",
47 NULL
48};
49 45
50static char *default_ini_path_names[] = { 46static char *default_ini_path_names[] = {
51 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", 47 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini",
52 "/usr/local/etc/monitoring-plugins.ini", 48 "/usr/local/etc/monitoring-plugins.ini", "/etc/monitoring-plugins/monitoring-plugins.ini",
53 "/etc/monitoring-plugins/monitoring-plugins.ini",
54 "/etc/monitoring-plugins.ini", 49 "/etc/monitoring-plugins.ini",
55 /* deprecated path names (for backward compatibility): */ 50 /* deprecated path names (for backward compatibility): */
56 "/etc/nagios/plugins.ini", 51 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini",
57 "/usr/local/nagios/etc/plugins.ini", 52 "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini", "/etc/nagios-plugins.ini",
58 "/usr/local/etc/nagios/plugins.ini", 53 "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL};
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 54
66/* eat all characters from a FILE pointer until n is encountered */ 55/* 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)) 56#define GOBBLE_TO(f, c, n) \
57 do { \
58 (c) = fgetc((f)); \
59 } while ((c) != EOF && (c) != (n))
68 60
69/* internal function that returns the constructed defaults options */ 61/* internal function that returns the constructed defaults options */
70static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); 62static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts);
71 63
72/* internal function that converts a single line into options format */ 64/* internal function that converts a single line into options format */
73static int add_option(FILE *f, np_arg_list **optlst); 65static int add_option(FILE *filePointer, np_arg_list **optlst);
74 66
75/* internal functions to find default file */ 67/* internal functions to find default file */
76static char *default_file(void); 68static char *default_file(void);
@@ -81,10 +73,9 @@ static char *default_file_in_path(void);
81 * [stanza][@filename] 73 * [stanza][@filename]
82 * into its separate parts. 74 * into its separate parts.
83 */ 75 */
84static void 76static 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) 77 size_t locator_len = 0;
86{ 78 size_t stanza_len = 0;
87 size_t locator_len = 0, stanza_len = 0;
88 79
89 /* if locator is NULL we'll use default values */ 80 /* if locator is NULL we'll use default values */
90 if (locator != NULL) { 81 if (locator != NULL) {
@@ -96,63 +87,63 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
96 i->stanza = malloc(sizeof(char) * (stanza_len + 1)); 87 i->stanza = malloc(sizeof(char) * (stanza_len + 1));
97 strncpy(i->stanza, locator, stanza_len); 88 strncpy(i->stanza, locator, stanza_len);
98 i->stanza[stanza_len] = '\0'; 89 i->stanza[stanza_len] = '\0';
99 } else {/* otherwise we use the default stanza */ 90 } else { /* otherwise we use the default stanza */
100 i->stanza = strdup(def_stanza); 91 i->stanza = strdup(def_stanza);
101 } 92 }
102 93
103 if (i->stanza == NULL) 94 if (i->stanza == NULL) {
104 die(STATE_UNKNOWN, _("malloc() failed!\n")); 95 die(STATE_UNKNOWN, _("malloc() failed!\n"));
96 }
105 97
106 /* check whether there's an @file part */ 98 /* check whether there's an @file part */
107 if (stanza_len == locator_len) { 99 if (stanza_len == locator_len) {
108 i->file = default_file(); 100 i->file = default_file();
109 i->file_string_on_heap = false; 101 i->file_string_on_heap = false;
110 } else { 102 } else {
111 i->file = strdup(&(locator[stanza_len + 1])); 103 i->file = strdup(&(locator[stanza_len + 1]));
112 i->file_string_on_heap = true; 104 i->file_string_on_heap = true;
113 } 105 }
114 106
115 if (i->file == NULL || i->file[0] == '\0') 107 if (i->file == NULL || i->file[0] == '\0') {
116 die(STATE_UNKNOWN, 108 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n"));
117 _("Cannot find config file in any standard location.\n")); 109 }
118} 110}
119 111
120/* 112/*
121 * This is the externally visible function used by extra_opts. 113 * This is the externally visible function used by extra_opts.
122 */ 114 */
123np_arg_list * 115np_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;
127 np_arg_list *defaults = NULL;
128 np_ini_info i;
129 int is_suid_plugin = mp_suid(); 116 int is_suid_plugin = mp_suid();
130 117
131 if (is_suid_plugin && idpriv_temp_drop() == -1) 118 if (is_suid_plugin && idpriv_temp_drop() == -1) {
132 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), 119 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno));
133 strerror(errno)); 120 }
121
122 FILE *inifile = NULL;
123 np_ini_info ini_info;
124 parse_locator(locator, default_section, &ini_info);
125 inifile = strcmp(ini_info.file, "-") == 0 ? stdin : fopen(ini_info.file, "r");
134 126
135 parse_locator(locator, default_section, &i); 127 if (inifile == NULL) {
136 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); 128 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno));
129 }
137 130
138 if (inifile == NULL) 131 np_arg_list *defaults = NULL;
139 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), 132 if (!read_defaults(inifile, ini_info.stanza, &defaults)) {
140 strerror(errno)); 133 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), ini_info.stanza, ini_info.file);
141 if (!read_defaults(inifile, i.stanza, &defaults)) 134 }
142 die(STATE_UNKNOWN,
143 _("Invalid section '%s' in config file '%s'\n"), i.stanza,
144 i.file);
145 135
146 if (i.file_string_on_heap) { 136 if (ini_info.file_string_on_heap) {
147 free(i.file); 137 free(ini_info.file);
148 } 138 }
149 139
150 if (inifile != stdin) 140 if (inifile != stdin) {
151 fclose(inifile); 141 fclose(inifile);
152 free(i.stanza); 142 }
153 if (is_suid_plugin && idpriv_temp_restore() == -1) 143 free(ini_info.stanza);
154 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), 144 if (is_suid_plugin && idpriv_temp_restore() == -1) {
155 strerror(errno)); 145 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno));
146 }
156 147
157 return defaults; 148 return defaults;
158} 149}
@@ -164,52 +155,58 @@ np_get_defaults(const char *locator, const char *default_section)
164 * be extra careful about user-supplied input (i.e. avoiding possible 155 * be extra careful about user-supplied input (i.e. avoiding possible
165 * format string vulnerabilities, etc). 156 * format string vulnerabilities, etc).
166 */ 157 */
167static int 158static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts) {
168read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
169{
170 int c = 0;
171 bool status = false; 159 bool status = false;
172 size_t i, stanza_len; 160 enum {
173 enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate = NOSTANZA; 161 NOSTANZA,
162 WRONGSTANZA,
163 RIGHTSTANZA
164 } stanzastate = NOSTANZA;
174 165
175 stanza_len = strlen(stanza); 166 size_t stanza_len = strlen(stanza);
176 167
177 /* our little stanza-parsing state machine */ 168 /* our little stanza-parsing state machine */
178 while ((c = fgetc(f)) != EOF) { 169 int current_char = 0;
170 while ((current_char = fgetc(defaults_file)) != EOF) {
179 /* gobble up leading whitespace */ 171 /* gobble up leading whitespace */
180 if (isspace(c)) 172 if (isspace(current_char)) {
181 continue; 173 continue;
182 switch (c) { 174 }
175 switch (current_char) {
183 /* globble up comment lines */ 176 /* globble up comment lines */
184 case ';': 177 case ';':
185 case '#': 178 case '#':
186 GOBBLE_TO(f, c, '\n'); 179 GOBBLE_TO(defaults_file, current_char, '\n');
187 break; 180 break;
188 /* start of a stanza, check to see if it matches */ 181 /* start of a stanza, check to see if it matches */
189 case '[': 182 case '[': {
190 stanzastate = WRONGSTANZA; 183 stanzastate = WRONGSTANZA;
184 size_t i;
191 for (i = 0; i < stanza_len; i++) { 185 for (i = 0; i < stanza_len; i++) {
192 c = fgetc(f); 186 current_char = fgetc(defaults_file);
193 /* strip leading whitespace */ 187 /* strip leading whitespace */
194 if (i == 0) 188 if (i == 0) {
195 for (; isspace(c); c = fgetc(f)) 189 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
196 continue; 190 }
191 }
197 /* nope, read to the end of the line */ 192 /* nope, read to the end of the line */
198 if (c != stanza[i]) { 193 if (current_char != stanza[i]) {
199 GOBBLE_TO(f, c, '\n'); 194 GOBBLE_TO(defaults_file, current_char, '\n');
200 break; 195 break;
201 } 196 }
202 } 197 }
198
203 /* if it matched up to here and the next char is ']'... */ 199 /* if it matched up to here and the next char is ']'... */
204 if (i == stanza_len) { 200 if (i == stanza_len) {
205 c = fgetc(f); 201 current_char = fgetc(defaults_file);
206 /* strip trailing whitespace */ 202 /* strip trailing whitespace */
207 for (; isspace(c); c = fgetc(f)) 203 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
208 continue; 204 }
209 if (c == ']') 205 if (current_char == ']') {
210 stanzastate = RIGHTSTANZA; 206 stanzastate = RIGHTSTANZA;
207 }
211 } 208 }
212 break; 209 } break;
213 /* otherwise, we're in the body of a stanza or a parse error */ 210 /* otherwise, we're in the body of a stanza or a parse error */
214 default: 211 default:
215 switch (stanzastate) { 212 switch (stanzastate) {
@@ -217,18 +214,16 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
217 * we're dealing with a config error 214 * we're dealing with a config error
218 */ 215 */
219 case NOSTANZA: 216 case NOSTANZA:
220 die(STATE_UNKNOWN, "%s\n", 217 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
221 _("Config file error"));
222 /* we're in a stanza, but for a different plugin */ 218 /* we're in a stanza, but for a different plugin */
223 case WRONGSTANZA: 219 case WRONGSTANZA:
224 GOBBLE_TO(f, c, '\n'); 220 GOBBLE_TO(defaults_file, current_char, '\n');
225 break; 221 break;
226 /* okay, this is where we start taking the config */ 222 /* okay, this is where we start taking the config */
227 case RIGHTSTANZA: 223 case RIGHTSTANZA:
228 ungetc(c, f); 224 ungetc(current_char, defaults_file);
229 if (add_option(f, opts)) { 225 if (add_option(defaults_file, opts)) {
230 die(STATE_UNKNOWN, "%s\n", 226 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
231 _("Config file error"));
232 } 227 }
233 status = true; 228 status = true;
234 break; 229 break;
@@ -246,15 +241,12 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
246 * --option[=value] 241 * --option[=value]
247 * appending it to the linked list optbuf. 242 * appending it to the linked list optbuf.
248 */ 243 */
249static int 244static int add_option(FILE *filePointer, np_arg_list **optlst) {
250add_option(FILE *f, np_arg_list **optlst) 245 char *linebuf = NULL;
251{ 246 bool done_reading = false;
252 np_arg_list *opttmp = *optlst, *optnew; 247 const size_t read_sz = 8;
253 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; 248 size_t linebuf_sz = 0;
254 char *eqptr = NULL, *valptr = NULL, *valend = NULL; 249 size_t read_pos = 0;
255 short done_reading = 0, equals = 0, value = 0;
256 size_t cfg_len = 0, read_sz = 8, linebuf_sz = 0, read_pos = 0;
257 size_t opt_len = 0, val_len = 0;
258 250
259 /* read one line from the file */ 251 /* read one line from the file */
260 while (!done_reading) { 252 while (!done_reading) {
@@ -262,75 +254,101 @@ add_option(FILE *f, np_arg_list **optlst)
262 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) { 254 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) {
263 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz; 255 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz;
264 linebuf = realloc(linebuf, linebuf_sz); 256 linebuf = realloc(linebuf, linebuf_sz);
265 if (linebuf == NULL) 257 if (linebuf == NULL) {
266 die(STATE_UNKNOWN, _("malloc() failed!\n")); 258 die(STATE_UNKNOWN, _("malloc() failed!\n"));
259 }
267 } 260 }
268 if (fgets(&linebuf[read_pos], (int)read_sz, f) == NULL) 261
269 done_reading = 1; 262 if (fgets(&linebuf[read_pos], (int)read_sz, filePointer) == NULL) {
270 else { 263 done_reading = true;
264 } else {
271 read_pos = strlen(linebuf); 265 read_pos = strlen(linebuf);
272 if (linebuf[read_pos - 1] == '\n') { 266 if (linebuf[read_pos - 1] == '\n') {
273 linebuf[--read_pos] = '\0'; 267 linebuf[--read_pos] = '\0';
274 done_reading = 1; 268 done_reading = true;
275 } 269 }
276 } 270 }
277 } 271 }
278 lineend = &linebuf[read_pos]; 272
273 char *lineend = &linebuf[read_pos];
279 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */ 274 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */
280 275
281 /* skip leading whitespace */ 276 /* skip leading whitespace */
282 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) 277 char *optptr = NULL;
283 continue; 278 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) {
279 }
280
284 /* continue to '=' or EOL, watching for spaces that might precede it */ 281 /* continue to '=' or EOL, watching for spaces that might precede it */
282 char *eqptr = NULL;
283 char *optend = NULL;
285 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) { 284 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) {
286 if (isspace(*eqptr) && optend == NULL) 285 if (isspace(*eqptr) && optend == NULL) {
287 optend = eqptr; 286 optend = eqptr;
288 else 287 } else {
289 optend = NULL; 288 optend = NULL;
289 }
290 } 290 }
291 if (optend == NULL) 291
292 if (optend == NULL) {
292 optend = eqptr; 293 optend = eqptr;
294 }
295
293 --optend; 296 --optend;
297
294 /* ^[[:space:]]*=foo is a syntax error */ 298 /* ^[[:space:]]*=foo is a syntax error */
295 if (optptr == eqptr) 299 if (optptr == eqptr) {
296 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 300 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
301 }
302
297 /* continue from '=' to start of value or EOL */ 303 /* continue from '=' to start of value or EOL */
298 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); 304 char *valptr = NULL;
299 valptr++) 305 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++) {
300 continue; 306 }
307
301 /* continue to the end of value */ 308 /* continue to the end of value */
302 for (valend = valptr; valend < lineend; valend++) 309 char *valend = NULL;
303 continue; 310 for (valend = valptr; valend < lineend; valend++) {
311 }
312
304 --valend; 313 --valend;
314
305 /* finally trim off trailing spaces */ 315 /* finally trim off trailing spaces */
306 for (; isspace(*valend); valend--) 316 for (; isspace(*valend); valend--) {
307 continue; 317 }
318
308 /* calculate the length of "--foo" */ 319 /* calculate the length of "--foo" */
309 opt_len = (size_t)(1 + optend - optptr); 320 size_t opt_len = (size_t)(1 + optend - optptr);
310 /* 1-character params needs only one dash */ 321 /* 1-character params needs only one dash */
311 if (opt_len == 1) 322 size_t cfg_len = 0;
323 if (opt_len == 1) {
312 cfg_len = 1 + (opt_len); 324 cfg_len = 1 + (opt_len);
313 else 325 } else {
314 cfg_len = 2 + (opt_len); 326 cfg_len = 2 + (opt_len);
327 }
328
329 size_t val_len = 0;
330 bool equals = false;
331 bool value = false;
315 /* if valptr<lineend then we have to also allocate space for "=bar" */ 332 /* if valptr<lineend then we have to also allocate space for "=bar" */
316 if (valptr < lineend) { 333 if (valptr < lineend) {
317 equals = value = 1; 334 equals = value = true;
318 val_len = (size_t)(1 + valend - valptr); 335 val_len = (size_t)(1 + valend - valptr);
319 cfg_len += 1 + val_len; 336 cfg_len += 1 + val_len;
320 } 337 } else if (valptr == lineend) {
321 /* if valptr==valend then we have "=" but no "bar" */ 338 /* if valptr==valend then we have "=" but no "bar" */
322 else if (valptr == lineend) { 339 equals = true;
323 equals = 1;
324 cfg_len += 1; 340 cfg_len += 1;
325 } 341 }
342
326 /* a line with no equal sign isn't valid */ 343 /* a line with no equal sign isn't valid */
327 if (equals == 0) 344 if (!equals) {
328 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 345 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
346 }
329 347
330 /* okay, now we have all the info we need, so we create a new np_arg_list 348 /* okay, now we have all the info we need, so we create a new np_arg_list
331 * element and set the argument... 349 * element and set the argument...
332 */ 350 */
333 optnew = malloc(sizeof(np_arg_list)); 351 np_arg_list *optnew = malloc(sizeof(np_arg_list));
334 optnew->next = NULL; 352 optnew->next = NULL;
335 353
336 read_pos = 0; 354 read_pos = 0;
@@ -353,11 +371,13 @@ add_option(FILE *f, np_arg_list **optlst)
353 optnew->arg[read_pos] = '\0'; 371 optnew->arg[read_pos] = '\0';
354 372
355 /* ...and put that to the end of the list */ 373 /* ...and put that to the end of the list */
356 if (*optlst == NULL) 374 if (*optlst == NULL) {
357 *optlst = optnew; 375 *optlst = optnew;
358 else { 376 } else {
359 while (opttmp->next != NULL) 377 np_arg_list *opttmp = *optlst;
378 while (opttmp->next != NULL) {
360 opttmp = opttmp->next; 379 opttmp = opttmp->next;
380 }
361 opttmp->next = optnew; 381 opttmp->next = optnew;
362 } 382 }
363 383
@@ -365,13 +385,11 @@ add_option(FILE *f, np_arg_list **optlst)
365 return 0; 385 return 0;
366} 386}
367 387
368static char * 388static char *default_file(void) {
369default_file(void) 389 char *ini_file;
370{
371 char *ini_file;
372 390
373 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || 391 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL ||
374 (ini_file = default_file_in_path()) != NULL) { 392 (ini_file = default_file_in_path()) != NULL) {
375 return ini_file; 393 return ini_file;
376 } 394 }
377 395
@@ -383,22 +401,26 @@ default_file(void)
383 return NULL; 401 return NULL;
384} 402}
385 403
386static char * 404static char *default_file_in_path(void) {
387default_file_in_path(void) 405 char *config_path;
388{ 406 char **file;
389 char *config_path, **file; 407 char *dir;
390 char *dir, *ini_file, *tokens; 408 char *ini_file;
409 char *tokens;
391 410
392 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) 411 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) {
393 return NULL; 412 return NULL;
413 }
394 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */ 414 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */
395 415
396 if ((tokens = strdup(config_path)) == NULL) 416 if ((tokens = strdup(config_path)) == NULL) {
397 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 417 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
418 }
398 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) { 419 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) {
399 for (file = default_ini_file_names; *file != NULL; file++) { 420 for (file = default_ini_file_names; *file != NULL; file++) {
400 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) 421 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) {
401 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 422 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
423 }
402 if (access(ini_file, F_OK) == 0) { 424 if (access(ini_file, F_OK) == 0) {
403 free(tokens); 425 free(tokens);
404 return ini_file; 426 return ini_file;
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..2930a8bc
--- /dev/null
+++ b/lib/perfdata.c
@@ -0,0 +1,649 @@
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
37 if (strchr(pd.label, '\'') == NULL) {
38 asprintf(&result, "'%s'=", pd.label);
39 } else {
40 // we have a illegal single quote in the string
41 // replace it silently instead of complaining
42 for (char *ptr = pd.label; *ptr == '\0'; ptr++) {
43 if (*ptr == '\'') {
44 *ptr = '_';
45 }
46 }
47 }
48
49 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
50
51 if (pd.uom != NULL) {
52 asprintf(&result, "%s%s", result, pd.uom);
53 }
54
55 if (pd.warn_present) {
56 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn));
57 } else {
58 asprintf(&result, "%s;", result);
59 }
60
61 if (pd.crit_present) {
62 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit));
63 } else {
64 asprintf(&result, "%s;", result);
65 }
66 if (pd.min_present) {
67 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min));
68 } else {
69 asprintf(&result, "%s;", result);
70 }
71
72 if (pd.max_present) {
73 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max));
74 }
75
76 /*printf("pd_to_string: %s\n", result); */
77
78 return result;
79}
80
81char *pd_list_to_string(const pd_list pd) {
82 char *result = pd_to_string(pd.data);
83
84 for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) {
85 asprintf(&result, "%s %s", result, pd_to_string(elem->data));
86 }
87
88 return result;
89}
90
91mp_perfdata perfdata_init() {
92 mp_perfdata pd = {};
93 return pd;
94}
95
96pd_list *pd_list_init() {
97 pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list));
98 if (tmp == NULL) {
99 die(STATE_UNKNOWN, "calloc failed\n");
100 }
101 tmp->next = NULL;
102 return tmp;
103}
104
105mp_range mp_range_init() {
106 mp_range result = {
107 .alert_on_inside_range = OUTSIDE,
108 .start = {},
109 .start_infinity = true,
110 .end = {},
111 .end_infinity = true,
112 };
113
114 return result;
115}
116
117mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) {
118 input.start = perf_val;
119 input.start_infinity = false;
120 return input;
121}
122
123mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) {
124 input.end = perf_val;
125 input.end_infinity = false;
126 return input;
127}
128
129void pd_list_append(pd_list pdl[1], const mp_perfdata pd) {
130 assert(pdl != NULL);
131
132 if (pdl->data.value.type == PD_TYPE_NONE) {
133 // first entry is still empty
134 pdl->data = pd;
135 } else {
136 // find last element in the list
137 pd_list *curr = pdl;
138 pd_list *next = pdl->next;
139
140 while (next != NULL) {
141 curr = next;
142 next = next->next;
143 }
144
145 if (curr->data.value.type == PD_TYPE_NONE) {
146 // still empty
147 curr->data = pd;
148 } else {
149 // new a new one
150 curr->next = pd_list_init();
151 curr->next->data = pd;
152 }
153 }
154}
155
156void pd_list_free(pd_list pdl[1]) {
157 while (pdl != NULL) {
158 pd_list *old = pdl;
159 pdl = pdl->next;
160 free(old);
161 }
162}
163
164/*
165 * returns -1 if a < b, 0 if a == b, 1 if a > b
166 */
167int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) {
168 // Test if types are different
169 if (a.type == b.type) {
170
171 switch (a.type) {
172 case PD_TYPE_UINT:
173 if (a.pd_uint < b.pd_uint) {
174 return -1;
175 } else if (a.pd_uint == b.pd_uint) {
176 return 0;
177 } else {
178 return 1;
179 }
180 break;
181 case PD_TYPE_INT:
182 if (a.pd_int < b.pd_int) {
183 return -1;
184 } else if (a.pd_int == b.pd_int) {
185 return 0;
186 } else {
187 return 1;
188 }
189 break;
190 case PD_TYPE_DOUBLE:
191 if (a.pd_int < b.pd_int) {
192 return -1;
193 } else if (a.pd_int == b.pd_int) {
194 return 0;
195 } else {
196 return 1;
197 }
198 break;
199 default:
200 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
201 }
202 }
203
204 // Get dirty here
205 long double floating_a = 0;
206
207 switch (a.type) {
208 case PD_TYPE_UINT:
209 floating_a = a.pd_uint;
210 break;
211 case PD_TYPE_INT:
212 floating_a = a.pd_int;
213 break;
214 case PD_TYPE_DOUBLE:
215 floating_a = a.pd_double;
216 break;
217 default:
218 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
219 }
220
221 long double floating_b = 0;
222 switch (b.type) {
223 case PD_TYPE_UINT:
224 floating_b = b.pd_uint;
225 break;
226 case PD_TYPE_INT:
227 floating_b = b.pd_int;
228 break;
229 case PD_TYPE_DOUBLE:
230 floating_b = b.pd_double;
231 break;
232 default:
233 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
234 }
235
236 if (floating_a < floating_b) {
237 return -1;
238 }
239 if (floating_a == floating_b) {
240 return 0;
241 }
242 return 1;
243}
244
245char *mp_range_to_string(const mp_range input) {
246 char *result = "";
247 if (input.alert_on_inside_range == INSIDE) {
248 asprintf(&result, "@");
249 }
250
251 if (input.start_infinity) {
252 asprintf(&result, "%s~:", result);
253 } else {
254 asprintf(&result, "%s%s:", result, pd_value_to_string(input.start));
255 }
256
257 if (!input.end_infinity) {
258 asprintf(&result, "%s%s", result, pd_value_to_string(input.end));
259 }
260 return result;
261}
262
263mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) {
264 return mp_set_pd_value_double(pd, value);
265}
266
267mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
268 pd.value.pd_double = value;
269 pd.value.type = PD_TYPE_DOUBLE;
270 return pd;
271}
272
273mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) {
274 return mp_set_pd_value_long_long(pd, (long long)value);
275}
276
277mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) {
278 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
279}
280
281mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) {
282 return mp_set_pd_value_long_long(pd, (long long)value);
283}
284
285mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) {
286 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
287}
288
289mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) {
290 return mp_set_pd_value_long_long(pd, (long long)value);
291}
292
293mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
294 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
295}
296
297mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) {
298 pd.value.pd_int = value;
299 pd.value.type = PD_TYPE_INT;
300 return pd;
301}
302
303mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) {
304 pd.value.pd_uint = value;
305 pd.value.type = PD_TYPE_UINT;
306 return pd;
307}
308
309mp_perfdata_value mp_create_pd_value_double(double value) {
310 mp_perfdata_value res = {0};
311 res.type = PD_TYPE_DOUBLE;
312 res.pd_double = value;
313 return res;
314}
315
316mp_perfdata_value mp_create_pd_value_float(float value) {
317 return mp_create_pd_value_double((double)value);
318}
319
320mp_perfdata_value mp_create_pd_value_char(char value) {
321 return mp_create_pd_value_long_long((long long)value);
322}
323
324mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) {
325 return mp_create_pd_value_u_long_long((unsigned long long)value);
326}
327
328mp_perfdata_value mp_create_pd_value_int(int value) {
329 return mp_create_pd_value_long_long((long long)value);
330}
331
332mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) {
333 return mp_create_pd_value_u_long_long((unsigned long long)value);
334}
335
336mp_perfdata_value mp_create_pd_value_long(long value) {
337 return mp_create_pd_value_long_long((long long)value);
338}
339
340mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) {
341 return mp_create_pd_value_u_long_long((unsigned long long)value);
342}
343
344mp_perfdata_value mp_create_pd_value_long_long(long long value) {
345 mp_perfdata_value res = {0};
346 res.type = PD_TYPE_INT;
347 res.pd_int = value;
348 return res;
349}
350
351mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) {
352 mp_perfdata_value res = {0};
353 res.type = PD_TYPE_UINT;
354 res.pd_uint = value;
355 return res;
356}
357
358char *fmt_range(range foo) { return foo.text; }
359
360typedef struct integer_parser_wrapper {
361 int error;
362 mp_perfdata_value value;
363} integer_parser_wrapper;
364
365typedef struct double_parser_wrapper {
366 int error;
367 mp_perfdata_value value;
368} double_parser_wrapper;
369
370typedef struct perfdata_value_parser_wrapper {
371 int error;
372 mp_perfdata_value value;
373} perfdata_value_parser_wrapper;
374
375double_parser_wrapper parse_double(const char *input);
376integer_parser_wrapper parse_integer(const char *input);
377perfdata_value_parser_wrapper parse_pd_value(const char *input);
378
379mp_range_parsed mp_parse_range_string(const char *input) {
380 if (input == NULL) {
381 mp_range_parsed result = {
382 .error = MP_RANGE_PARSING_FAILURE,
383 };
384 return result;
385 }
386
387 if (strlen(input) == 0) {
388 mp_range_parsed result = {
389 .error = MP_RANGE_PARSING_FAILURE,
390 };
391 return result;
392 }
393
394 mp_range_parsed result = {
395 .range = mp_range_init(),
396 .error = MP_PARSING_SUCCES,
397 };
398
399 if (input[0] == '@') {
400 // found an '@' at beginning, so invert the range logic
401 result.range.alert_on_inside_range = INSIDE;
402
403 // advance the pointer one symbol
404 input++;
405 }
406
407 char *working_copy = strdup(input);
408 if (working_copy == NULL) {
409 // strdup error, probably
410 mp_range_parsed result = {
411 .error = MP_RANGE_PARSING_FAILURE,
412 };
413 return result;
414 }
415 input = working_copy;
416
417 char *separator = index(working_copy, ':');
418 if (separator != NULL) {
419 // Found a separator
420 // set the separator to 0, so we have two different strings
421 *separator = '\0';
422
423 if (input[0] == '~') {
424 // the beginning starts with '~', so it might be infinity
425 if (&input[1] != separator) {
426 // the next symbol after '~' is not the separator!
427 // so input is probably wrong
428 result.error = MP_RANGE_PARSING_FAILURE;
429 free(working_copy);
430 return result;
431 }
432
433 result.range.start_infinity = true;
434 } else {
435 // No '~' at the beginning, so this should be a number
436 result.range.start_infinity = false;
437 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
438
439 if (parsed_pd.error != MP_PARSING_SUCCES) {
440 result.error = parsed_pd.error;
441 free(working_copy);
442 return result;
443 }
444
445 result.range.start = parsed_pd.value;
446 result.range.start_infinity = false;
447 }
448 // got the first part now
449 // advance the pointer
450 input = separator + 1;
451 }
452
453 // End part or no separator
454 if (input[0] == '\0') {
455 // the end is infinite
456 result.range.end_infinity = true;
457 } else {
458 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
459
460 if (parsed_pd.error != MP_PARSING_SUCCES) {
461 result.error = parsed_pd.error;
462 return result;
463 }
464 result.range.end = parsed_pd.value;
465 result.range.end_infinity = false;
466 }
467 free(working_copy);
468 return result;
469}
470
471double_parser_wrapper parse_double(const char *input) {
472 double_parser_wrapper result = {
473 .error = MP_PARSING_SUCCES,
474 };
475
476 if (input == NULL) {
477 result.error = MP_PARSING_FAILURE;
478 return result;
479 }
480
481 char *endptr = NULL;
482 errno = 0;
483 double tmp = strtod(input, &endptr);
484
485 if (input == endptr) {
486 // man 3 strtod says, no conversion performed
487 result.error = MP_PARSING_FAILURE;
488 return result;
489 }
490
491 if (errno) {
492 // some other error
493 // TODO maybe differentiate a little bit
494 result.error = MP_PARSING_FAILURE;
495 return result;
496 }
497
498 result.value = mp_create_pd_value(tmp);
499 return result;
500}
501
502integer_parser_wrapper parse_integer(const char *input) {
503 integer_parser_wrapper result = {
504 .error = MP_PARSING_SUCCES,
505 };
506
507 if (input == NULL) {
508 result.error = MP_PARSING_FAILURE;
509 return result;
510 }
511
512 char *endptr = NULL;
513 errno = 0;
514 long long tmp = strtoll(input, &endptr, 0);
515
516 // validating *sigh*
517 if (*endptr != '\0') {
518 // something went wrong in strtoll
519 if (tmp == LLONG_MIN) {
520 // underflow
521 result.error = MP_RANGE_PARSING_UNDERFLOW;
522 return result;
523 }
524
525 if (tmp == LLONG_MAX) {
526 // overflow
527 result.error = MP_RANGE_PARSING_OVERFLOW;
528 return result;
529 }
530
531 // still wrong, but not sure why, probably invalid characters
532 if (errno == EINVAL) {
533 result.error = MP_RANGE_PARSING_INVALID_CHAR;
534 return result;
535 }
536
537 // some other error, do catch all here
538 result.error = MP_RANGE_PARSING_FAILURE;
539 return result;
540 }
541
542 // no error, should be fine
543 result.value = mp_create_pd_value(tmp);
544 return result;
545}
546
547perfdata_value_parser_wrapper parse_pd_value(const char *input) {
548 // try integer first
549 integer_parser_wrapper tmp_int = parse_integer(input);
550
551 if (tmp_int.error == MP_PARSING_SUCCES) {
552 perfdata_value_parser_wrapper result = {
553 .error = tmp_int.error,
554 .value = tmp_int.value,
555 };
556 return result;
557 }
558
559 double_parser_wrapper tmp_double = parse_double(input);
560 perfdata_value_parser_wrapper result = {};
561 if (tmp_double.error == MP_PARSING_SUCCES) {
562 result.error = tmp_double.error;
563 result.value = tmp_double.value;
564 } else {
565 result.error = tmp_double.error;
566 }
567 return result;
568}
569
570mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
571 perfdata.max = value;
572 perfdata.max_present = true;
573 return perfdata;
574}
575
576mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
577 perfdata.min = value;
578 perfdata.min_present = true;
579 return perfdata;
580}
581
582double mp_get_pd_value(mp_perfdata_value value) {
583 assert(value.type != PD_TYPE_NONE);
584 switch (value.type) {
585 case PD_TYPE_DOUBLE:
586 return value.pd_double;
587 case PD_TYPE_INT:
588 return (double)value.pd_int;
589 case PD_TYPE_UINT:
590 return (double)value.pd_uint;
591 default:
592 return 0; // just to make the compiler happy
593 }
594}
595
596mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
597 if (left.type == right.type) {
598 switch (left.type) {
599 case PD_TYPE_DOUBLE:
600 left.pd_double *= right.pd_double;
601 return left;
602 case PD_TYPE_INT:
603 left.pd_int *= right.pd_int;
604 return left;
605 case PD_TYPE_UINT:
606 left.pd_uint *= right.pd_uint;
607 return left;
608 default:
609 // what to here?
610 return left;
611 }
612 }
613
614 // Different types, oh boy, just do the lazy thing for now and switch to double
615 switch (left.type) {
616 case PD_TYPE_INT:
617 left.pd_double = (double)left.pd_int;
618 left.type = PD_TYPE_DOUBLE;
619 break;
620 case PD_TYPE_UINT:
621 left.pd_double = (double)left.pd_uint;
622 left.type = PD_TYPE_DOUBLE;
623 break;
624 }
625
626 switch (right.type) {
627 case PD_TYPE_INT:
628 right.pd_double = (double)right.pd_int;
629 right.type = PD_TYPE_DOUBLE;
630 break;
631 case PD_TYPE_UINT:
632 right.pd_double = (double)right.pd_uint;
633 right.type = PD_TYPE_DOUBLE;
634 break;
635 }
636
637 left.pd_double *= right.pd_double;
638 return left;
639}
640
641mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
642 if (!range.end_infinity) {
643 range.end = mp_pd_value_multiply(range.end, factor);
644 }
645 if (!range.start_infinity) {
646 range.start = mp_pd_value_multiply(range.start, factor);
647 }
648 return range;
649}
diff --git a/lib/perfdata.h b/lib/perfdata.h
new file mode 100644
index 00000000..e51ef5fd
--- /dev/null
+++ b/lib/perfdata.h
@@ -0,0 +1,219 @@
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 {
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 {
45 double start;
46 bool start_infinity;
47 double end;
48 bool 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 {
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 char: mp_create_pd_value_char, \
159 unsigned char: mp_create_pd_value_u_char, \
160 int: mp_create_pd_value_int, \
161 unsigned int: mp_create_pd_value_u_int, \
162 long: mp_create_pd_value_long, \
163 unsigned long: mp_create_pd_value_u_long, \
164 long long: mp_create_pd_value_long_long, \
165 unsigned long long: mp_create_pd_value_u_long_long)(V)
166
167mp_perfdata_value mp_create_pd_value_float(float);
168mp_perfdata_value mp_create_pd_value_double(double);
169mp_perfdata_value mp_create_pd_value_char(char);
170mp_perfdata_value mp_create_pd_value_u_char(unsigned char);
171mp_perfdata_value mp_create_pd_value_int(int);
172mp_perfdata_value mp_create_pd_value_u_int(unsigned int);
173mp_perfdata_value mp_create_pd_value_long(long);
174mp_perfdata_value mp_create_pd_value_u_long(unsigned long);
175mp_perfdata_value mp_create_pd_value_long_long(long long);
176mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long);
177
178mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value);
179mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value);
180
181double mp_get_pd_value(mp_perfdata_value value);
182
183/*
184 * Free the memory used by a pd_list
185 */
186void pd_list_free(pd_list[1]);
187
188int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value);
189
190// ================
191// Helper functions
192// ================
193
194mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right);
195mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor);
196
197// =================
198// String formatters
199// =================
200/*
201 * Generate string from mp_perfdata value
202 */
203char *pd_to_string(mp_perfdata);
204
205/*
206 * Generate string from perfdata_value value
207 */
208char *pd_value_to_string(mp_perfdata_value);
209
210/*
211 * Generate string from pd_list value for the final output
212 */
213char *pd_list_to_string(pd_list);
214
215/*
216 * Generate string from a mp_range value
217 */
218char *mp_range_to_string(mp_range);
219char *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..7798a72e 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_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_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_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..798244da 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,175 @@ 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,
186 0x50,0x66,0x34,0x37,0x0b,0x45,0x4b,0x38,0x32,0x06,0x7a,0x3e,0x7f,0x0c,0x40,0x18, 184 0x08, 0x50, 0x66, 0x34, 0x37, 0x0b, 0x45, 0x4b, 0x38, 0x32, 0x06, 0x7a, 0x3e, 0x7f, 0x0c,
187 0x6b,0x2d,0x60,0x4c,0x60,0x0c,0x23,0x43,0x3b,0x3e,0x1b,0x16,0x04,0x46,0x58,0x3f, 185 0x40, 0x18, 0x6b, 0x2d, 0x60, 0x4c, 0x60, 0x0c, 0x23, 0x43, 0x3b, 0x3e, 0x1b, 0x16, 0x04,
188 0x40,0x6a,0x11,0x05,0x63,0x71,0x14,0x35,0x47,0x79,0x13,0x6f,0x6b,0x27,0x18,0x5b, 186 0x46, 0x58, 0x3f, 0x40, 0x6a, 0x11, 0x05, 0x63, 0x71, 0x14, 0x35, 0x47, 0x79, 0x13, 0x6f,
189 0x48,0x27,0x3e,0x6f,0x15,0x33,0x4f,0x3e,0x5e,0x51,0x73,0x68,0x25,0x0f,0x06,0x5b, 187 0x6b, 0x27, 0x18, 0x5b, 0x48, 0x27, 0x3e, 0x6f, 0x15, 0x33, 0x4f, 0x3e, 0x5e, 0x51, 0x73,
190 0x7c,0x72,0x75,0x3e,0x3f,0x1b,0x5c,0x6d,0x6a,0x39,0x7c,0x63,0x63,0x60,0x6c,0x7a, 188 0x68, 0x25, 0x0f, 0x06, 0x5b, 0x7c, 0x72, 0x75, 0x3e, 0x3f, 0x1b, 0x5c, 0x6d, 0x6a, 0x39,
191 0x33,0x76,0x52,0x13,0x25,0x33,0x7d,0x65,0x23,0x27,0x11,0x06,0x06,0x47,0x71,0x1e, 189 0x7c, 0x63, 0x63, 0x60, 0x6c, 0x7a, 0x33, 0x76, 0x52, 0x13, 0x25, 0x33, 0x7d, 0x65, 0x23,
192 0x14,0x74,0x63,0x70,0x2d,0x15,0x27,0x18,0x51,0x06,0x05,0x33,0x11,0x2c,0x6b,0x00, 190 0x27, 0x11, 0x06, 0x06, 0x47, 0x71, 0x1e, 0x14, 0x74, 0x63, 0x70, 0x2d, 0x15, 0x27, 0x18,
193 0x2d,0x77,0x20,0x48,0x0d,0x73,0x51,0x45,0x25,0x7f,0x7f,0x35,0x26,0x2e,0x26,0x53, 191 0x51, 0x06, 0x05, 0x33, 0x11, 0x2c, 0x6b, 0x00, 0x2d, 0x77, 0x20, 0x48, 0x0d, 0x73, 0x51,
194 0x24,0x68,0x1e,0x0e,0x58,0x3a,0x59,0x50,0x56,0x37,0x5f,0x66,0x01,0x4c,0x5a,0x64, 192 0x45, 0x25, 0x7f, 0x7f, 0x35, 0x26, 0x2e, 0x26, 0x53, 0x24, 0x68, 0x1e, 0x0e, 0x58, 0x3a,
195 0x32,0x50,0x7b,0x6a,0x20,0x72,0x2b,0x1d,0x7e,0x43,0x7b,0x61,0x42,0x0b,0x61,0x73, 193 0x59, 0x50, 0x56, 0x37, 0x5f, 0x66, 0x01, 0x4c, 0x5a, 0x64, 0x32, 0x50, 0x7b, 0x6a, 0x20,
196 0x24,0x79,0x3a,0x6b,0x4a,0x79,0x6e,0x09,0x0f,0x27,0x2d,0x0c,0x5e,0x32,0x4b,0x0d, 194 0x72, 0x2b, 0x1d, 0x7e, 0x43, 0x7b, 0x61, 0x42, 0x0b, 0x61, 0x73, 0x24, 0x79, 0x3a, 0x6b,
197 0x79,0x46,0x39,0x21,0x0a,0x26,0x5f,0x3a,0x00,0x26,0x3f,0x13,0x2e,0x7e,0x50,0x2b, 195 0x4a, 0x79, 0x6e, 0x09, 0x0f, 0x27, 0x2d, 0x0c, 0x5e, 0x32, 0x4b, 0x0d, 0x79, 0x46, 0x39,
198 0x67,0x46,0x72,0x3f,0x3b,0x01,0x46,0x1b,0x0b,0x35,0x49,0x39,0x19,0x70,0x3d,0x02, 196 0x21, 0x0a, 0x26, 0x5f, 0x3a, 0x00, 0x26, 0x3f, 0x13, 0x2e, 0x7e, 0x50, 0x2b, 0x67, 0x46,
199 0x41,0x0e,0x38,0x05,0x76,0x65,0x4f,0x31,0x6c,0x5e,0x17,0x04,0x15,0x36,0x26,0x64, 197 0x72, 0x3f, 0x3b, 0x01, 0x46, 0x1b, 0x0b, 0x35, 0x49, 0x39, 0x19, 0x70, 0x3d, 0x02, 0x41,
200 0x34,0x14,0x17,0x7c,0x0e,0x0b,0x5b,0x55,0x53,0x6b,0x00,0x42,0x41,0x4f,0x02,0x5c, 198 0x0e, 0x38, 0x05, 0x76, 0x65, 0x4f, 0x31, 0x6c, 0x5e, 0x17, 0x04, 0x15, 0x36, 0x26, 0x64,
201 0x13,0x0a,0x2c,0x2c,0x3e,0x10,0x14,0x33,0x45,0x7c,0x7a,0x5a,0x31,0x61,0x39,0x08, 199 0x34, 0x14, 0x17, 0x7c, 0x0e, 0x0b, 0x5b, 0x55, 0x53, 0x6b, 0x00, 0x42, 0x41, 0x4f, 0x02,
202 0x22,0x6a,0x1e,0x0f,0x6f,0x1b,0x6c,0x13,0x5e,0x79,0x20,0x79,0x50,0x62,0x06,0x2c, 200 0x5c, 0x13, 0x0a, 0x2c, 0x2c, 0x3e, 0x10, 0x14, 0x33, 0x45, 0x7c, 0x7a, 0x5a, 0x31, 0x61,
203 0x76,0x17,0x04,0x2b,0x2a,0x75,0x1f,0x0c,0x37,0x4e,0x0f,0x7b,0x2d,0x34,0x75,0x60, 201 0x39, 0x08, 0x22, 0x6a, 0x1e, 0x0f, 0x6f, 0x1b, 0x6c, 0x13, 0x5e, 0x79, 0x20, 0x79, 0x50,
204 0x31,0x74,0x2e,0x0a,0x4a,0x11,0x6c,0x49,0x25,0x01,0x3a,0x3d,0x22,0x1e,0x6d,0x18, 202 0x62, 0x06, 0x2c, 0x76, 0x17, 0x04, 0x2b, 0x2a, 0x75, 0x1f, 0x0c, 0x37, 0x4e, 0x0f, 0x7b,
205 0x51,0x78,0x2d,0x62,0x31,0x4c,0x50,0x40,0x17,0x4b,0x6f,0x22,0x00,0x7f,0x61,0x2a, 203 0x2d, 0x34, 0x75, 0x60, 0x31, 0x74, 0x2e, 0x0a, 0x4a, 0x11, 0x6c, 0x49, 0x25, 0x01, 0x3a,
206 0x34,0x3e,0x00,0x5f,0x2f,0x5f,0x2f,0x14,0x2a,0x55,0x27,0x1f,0x46,0x1f,0x12,0x46, 204 0x3d, 0x22, 0x1e, 0x6d, 0x18, 0x51, 0x78, 0x2d, 0x62, 0x31, 0x4c, 0x50, 0x40, 0x17, 0x4b,
207 0x5e,0x1e,0x0c,0x7c,0x38,0x01,0x61,0x64,0x76,0x22,0x6e,0x08,0x20,0x38,0x4f,0x73, 205 0x6f, 0x22, 0x00, 0x7f, 0x61, 0x2a, 0x34, 0x3e, 0x00, 0x5f, 0x2f, 0x5f, 0x2f, 0x14, 0x2a,
208 0x72,0x55,0x12,0x42,0x19,0x50,0x61,0x43,0x77,0x7d,0x41,0x2e,0x35,0x4f,0x3d,0x31, 206 0x55, 0x27, 0x1f, 0x46, 0x1f, 0x12, 0x46, 0x5e, 0x1e, 0x0c, 0x7c, 0x38, 0x01, 0x61, 0x64,
209 0x28,0x58,0x67,0x1b,0x03,0x51,0x20,0x32,0x1c,0x08,0x6e,0x37,0x75,0x37,0x44,0x4f, 207 0x76, 0x22, 0x6e, 0x08, 0x20, 0x38, 0x4f, 0x73, 0x72, 0x55, 0x12, 0x42, 0x19, 0x50, 0x61,
210 0x68,0x19,0x07,0x64,0x14,0x28,0x25,0x2b,0x69,0x35,0x18,0x27,0x26,0x14,0x13,0x70, 208 0x43, 0x77, 0x7d, 0x41, 0x2e, 0x35, 0x4f, 0x3d, 0x31, 0x28, 0x58, 0x67, 0x1b, 0x03, 0x51,
211 0x42,0x19,0x12,0x75,0x3e,0x02,0x5d,0x7c,0x13,0x1f,0x16,0x53,0x3b,0x74,0x48,0x3c, 209 0x20, 0x32, 0x1c, 0x08, 0x6e, 0x37, 0x75, 0x37, 0x44, 0x4f, 0x68, 0x19, 0x07, 0x64, 0x14,
212 0x5e,0x39,0x6c,0x1c,0x1c,0x74,0x39,0x1f,0x00,0x1b,0x06,0x0a,0x68,0x3b,0x52,0x4f, 210 0x28, 0x25, 0x2b, 0x69, 0x35, 0x18, 0x27, 0x26, 0x14, 0x13, 0x70, 0x42, 0x19, 0x12, 0x75,
213 0x1e,0x6e,0x3c,0x35,0x0c,0x38,0x0e,0x0b,0x3b,0x1a,0x76,0x23,0x29,0x53,0x1e,0x5f, 211 0x3e, 0x02, 0x5d, 0x7c, 0x13, 0x1f, 0x16, 0x53, 0x3b, 0x74, 0x48, 0x3c, 0x5e, 0x39, 0x6c,
214 0x41,0x0c,0x4b,0x0a,0x65,0x28,0x78,0x67,0x48,0x59,0x26,0x6d,0x31,0x76,0x23,0x70, 212 0x1c, 0x1c, 0x74, 0x39, 0x1f, 0x00, 0x1b, 0x06, 0x0a, 0x68, 0x3b, 0x52, 0x4f, 0x1e, 0x6e,
215 0x61,0x64,0x3b,0x38,0x79,0x66,0x74,0x53,0x2c,0x64,0x64,0x54,0x03,0x54,0x65,0x44, 213 0x3c, 0x35, 0x0c, 0x38, 0x0e, 0x0b, 0x3b, 0x1a, 0x76, 0x23, 0x29, 0x53, 0x1e, 0x5f, 0x41,
216 0x4c,0x18,0x4f,0x48,0x20,0x4f,0x72,0x10,0x3f,0x0c,0x52,0x2d,0x03,0x14,0x03,0x51, 214 0x0c, 0x4b, 0x0a, 0x65, 0x28, 0x78, 0x67, 0x48, 0x59, 0x26, 0x6d, 0x31, 0x76, 0x23, 0x70,
217 0x42,0x10,0x77,0x6a,0x34,0x06,0x32,0x03,0x72,0x14,0x7c,0x08,0x5d,0x52,0x1a,0x62, 215 0x61, 0x64, 0x3b, 0x38, 0x79, 0x66, 0x74, 0x53, 0x2c, 0x64, 0x64, 0x54, 0x03, 0x54, 0x65,
218 0x7c,0x3e,0x30,0x7e,0x5f,0x7f,0x54,0x0f,0x44,0x49,0x5d,0x5e,0x10,0x6a,0x06,0x2b, 216 0x44, 0x4c, 0x18, 0x4f, 0x48, 0x20, 0x4f, 0x72, 0x10, 0x3f, 0x0c, 0x52, 0x2d, 0x03, 0x14,
219 0x06,0x53,0x10,0x39,0x37,0x32,0x4a,0x4e,0x3d,0x2b,0x65,0x38,0x39,0x07,0x72,0x54, 217 0x03, 0x51, 0x42, 0x10, 0x77, 0x6a, 0x34, 0x06, 0x32, 0x03, 0x72, 0x14, 0x7c, 0x08, 0x5d,
220 0x64,0x4d,0x56,0x6a,0x03,0x22,0x70,0x7b,0x5f,0x60,0x0b,0x2a,0x0b,0x6b,0x10,0x64, 218 0x52, 0x1a, 0x62, 0x7c, 0x3e, 0x30, 0x7e, 0x5f, 0x7f, 0x54, 0x0f, 0x44, 0x49, 0x5d, 0x5e,
221 0x14,0x05,0x22,0x00,0x73,0x40,0x23,0x5b,0x51,0x1f,0x2b,0x1a,0x5d,0x69,0x7a,0x46, 219 0x10, 0x6a, 0x06, 0x2b, 0x06, 0x53, 0x10, 0x39, 0x37, 0x32, 0x4a, 0x4e, 0x3d, 0x2b, 0x65,
222 0x0c,0x5f,0x32,0x4b,0x4a,0x28,0x52,0x79,0x5b,0x12,0x42,0x18,0x00,0x5d,0x27,0x31, 220 0x38, 0x39, 0x07, 0x72, 0x54, 0x64, 0x4d, 0x56, 0x6a, 0x03, 0x22, 0x70, 0x7b, 0x5f, 0x60,
223 0x53,0x3c,0x4c,0x36,0x4e,0x38,0x3f,0x72,0x03,0x71,0x02,0x5b,0x36,0x59,0x7f,0x75, 221 0x0b, 0x2a, 0x0b, 0x6b, 0x10, 0x64, 0x14, 0x05, 0x22, 0x00, 0x73, 0x40, 0x23, 0x5b, 0x51,
224 0x6e,0x08,0x54,0x0d,0x34,0x1c,0x34,0x57,0x5d,0x69,0x48,0x00,0x3b,0x05,0x07,0x6e, 222 0x1f, 0x2b, 0x1a, 0x5d, 0x69, 0x7a, 0x46, 0x0c, 0x5f, 0x32, 0x4b, 0x4a, 0x28, 0x52, 0x79,
225 0x27,0x65,0x6e,0x40,0x3d,0x3a,0x4f,0x72,0x5d,0x39,0x16,0x0f,0x63,0x12,0x12,0x15, 223 0x5b, 0x12, 0x42, 0x18, 0x00, 0x5d, 0x27, 0x31, 0x53, 0x3c, 0x4c, 0x36, 0x4e, 0x38, 0x3f,
226 0x3a,0x70,0x0d,0x57,0x18,0x0d,0x5e,0x3d,0x22,0x68,0x68,0x7c,0x6d,0x4f,0x0c,0x7b, 224 0x72, 0x03, 0x71, 0x02, 0x5b, 0x36, 0x59, 0x7f, 0x75, 0x6e, 0x08, 0x54, 0x0d, 0x34, 0x1c,
227 0x09,0x2d,0x4a,0x73,0x20,0x47,0x07,0x57,0x75,0x5d,0x53,0x70,0x34,0x21,0x40,0x57, 225 0x34, 0x57, 0x5d, 0x69, 0x48, 0x00, 0x3b, 0x05, 0x07, 0x6e, 0x27, 0x65, 0x6e, 0x40, 0x3d,
228 0x51,0x5e,0x49,0x44,0x00,0x54,0x27,0x04,0x68,0x7e,0x59,0x56,0x58,0x74,0x14,0x3c, 226 0x3a, 0x4f, 0x72, 0x5d, 0x39, 0x16, 0x0f, 0x63, 0x12, 0x12, 0x15, 0x3a, 0x70, 0x0d, 0x57,
229 0x16,0x33,0x41,0x16,0x4b,0x2f,0x49,0x37,0x0a,0x54,0x08,0x08,0x1f,0x39,0x67,0x76, 227 0x18, 0x0d, 0x5e, 0x3d, 0x22, 0x68, 0x68, 0x7c, 0x6d, 0x4f, 0x0c, 0x7b, 0x09, 0x2d, 0x4a,
230 0x28,0x28,0x07,0x1d,0x61,0x47,0x51,0x4d,0x75,0x26,0x52,0x47,0x47,0x0c,0x57,0x58, 228 0x73, 0x20, 0x47, 0x07, 0x57, 0x75, 0x5d, 0x53, 0x70, 0x34, 0x21, 0x40, 0x57, 0x51, 0x5e,
231 0x74,0x3e,0x62,0x6c,0x58,0x3a,0x44,0x1e,0x16,0x2e,0x21,0x1c,0x73,0x45,0x67,0x74, 229 0x49, 0x44, 0x00, 0x54, 0x27, 0x04, 0x68, 0x7e, 0x59, 0x56, 0x58, 0x74, 0x14, 0x3c, 0x16,
232 0x4f,0x33,0x66,0x0e,0x74,0x66,0x26,0x1f,0x2e,0x38,0x44,0x40,0x7e,0x2a,0x50,0x52, 230 0x33, 0x41, 0x16, 0x4b, 0x2f, 0x49, 0x37, 0x0a, 0x54, 0x08, 0x08, 0x1f, 0x39, 0x67, 0x76,
233 0x5e,0x43,0x01,0x7a,0x38,0x49,0x3c,0x55,0x4d,0x5a,0x44,0x08,0x26,0x59,0x4d,0x45, 231 0x28, 0x28, 0x07, 0x1d, 0x61, 0x47, 0x51, 0x4d, 0x75, 0x26, 0x52, 0x47, 0x47, 0x0c, 0x57,
234 0x0b,0x48,0x0a,0x33,0x5e,0x4a,0x4d,0x75,0x16,0x17,0x63,0x46,0x01,0x2a,0x55,0x7b, 232 0x58, 0x74, 0x3e, 0x62, 0x6c, 0x58, 0x3a, 0x44, 0x1e, 0x16, 0x2e, 0x21, 0x1c, 0x73, 0x45,
235 0x0f,0x02,0x73,0x6a,0x4b,0x7f,0x75,0x65,0x3c,0x4c,0x33,0x39,0x6c,0x74,0x05,0x60, 233 0x67, 0x74, 0x4f, 0x33, 0x66, 0x0e, 0x74, 0x66, 0x26, 0x1f, 0x2e, 0x38, 0x44, 0x40, 0x7e,
236 0x0f,0x7f,0x2d,0x41,0x4d,0x4d,0x46,0x71,0x09,0x6f,0x4f,0x60,0x15,0x0f,0x46,0x73, 234 0x2a, 0x50, 0x52, 0x5e, 0x43, 0x01, 0x7a, 0x38, 0x49, 0x3c, 0x55, 0x4d, 0x5a, 0x44, 0x08,
237 0x63,0x4c,0x5e,0x74,0x30,0x0d,0x28,0x43,0x08,0x72,0x32,0x04,0x2e,0x31,0x29,0x27, 235 0x26, 0x59, 0x4d, 0x45, 0x0b, 0x48, 0x0a, 0x33, 0x5e, 0x4a, 0x4d, 0x75, 0x16, 0x17, 0x63,
238 0x44,0x6d,0x13,0x17,0x48,0x0f,0x49,0x52,0x10,0x13,0x7f,0x17,0x16,0x62,0x79,0x35, 236 0x46, 0x01, 0x2a, 0x55, 0x7b, 0x0f, 0x02, 0x73, 0x6a, 0x4b, 0x7f, 0x75, 0x65, 0x3c, 0x4c,
239 0x78,0x3e,0x01,0x7c,0x2e,0x0f,0x76,0x3e,0x5e,0x53,0x6c,0x5b,0x5f,0x7c,0x19,0x41, 237 0x33, 0x39, 0x6c, 0x74, 0x05, 0x60, 0x0f, 0x7f, 0x2d, 0x41, 0x4d, 0x4d, 0x46, 0x71, 0x09,
240 0x02,0x2f,0x17,0x64,0x41,0x75,0x10,0x04,0x47,0x7c,0x3d,0x4b,0x52,0x00,0x10,0x5d, 238 0x6f, 0x4f, 0x60, 0x15, 0x0f, 0x46, 0x73, 0x63, 0x4c, 0x5e, 0x74, 0x30, 0x0d, 0x28, 0x43,
241 0x51,0x4e,0x7a,0x27,0x25,0x55,0x40,0x12,0x35,0x60,0x05,0x1b,0x34,0x2d,0x04,0x7a, 239 0x08, 0x72, 0x32, 0x04, 0x2e, 0x31, 0x29, 0x27, 0x44, 0x6d, 0x13, 0x17, 0x48, 0x0f, 0x49,
242 0x6a,0x69,0x02,0x79,0x03,0x3a,0x2f,0x06,0x0a,0x79,0x7b,0x12,0x5d,0x7c,0x52,0x29, 240 0x52, 0x10, 0x13, 0x7f, 0x17, 0x16, 0x62, 0x79, 0x35, 0x78, 0x3e, 0x01, 0x7c, 0x2e, 0x0f,
243 0x47,0x58,0x12,0x73,0x3f,0x27,0x56,0x05,0x0c,0x48,0x32,0x58,0x6b,0x57,0x5c,0x03, 241 0x76, 0x3e, 0x5e, 0x53, 0x6c, 0x5b, 0x5f, 0x7c, 0x19, 0x41, 0x02, 0x2f, 0x17, 0x64, 0x41,
244 0x64,0x56,0x11,0x52,0x7a,0x30,0x36,0x29,0x17,0x3b,0x68,0x7a,0x7c,0x05,0x6b,0x6b, 242 0x75, 0x10, 0x04, 0x47, 0x7c, 0x3d, 0x4b, 0x52, 0x00, 0x10, 0x5d, 0x51, 0x4e, 0x7a, 0x27,
245 0x13,0x6a,0x24,0x5c,0x68,0x42,0x18,0x32,0x03,0x73,0x6e,0x04,0x21,0x2e,0x01,0x04, 243 0x25, 0x55, 0x40, 0x12, 0x35, 0x60, 0x05, 0x1b, 0x34, 0x2d, 0x04, 0x7a, 0x6a, 0x69, 0x02,
246 0x63,0x7d,0x44,0x41,0x12,0x31,0x0b,0x15,0x1f,0x70,0x00,0x2e,0x66,0x14,0x3c,0x7f, 244 0x79, 0x03, 0x3a, 0x2f, 0x06, 0x0a, 0x79, 0x7b, 0x12, 0x5d, 0x7c, 0x52, 0x29, 0x47, 0x58,
247 0x2b,0x00,0x1f,0x0c,0x28,0x59,0x0a,0x16,0x49,0x5a,0x5c,0x64,0x65,0x4b,0x11,0x29, 245 0x12, 0x73, 0x3f, 0x27, 0x56, 0x05, 0x0c, 0x48, 0x32, 0x58, 0x6b, 0x57, 0x5c, 0x03, 0x64,
248 0x15,0x36,0x5a,0x65,0x19,0x4f,0x60,0x23,0x3a,0x3a,0x13,0x25,0x02,0x78,0x4c,0x54 246 0x56, 0x11, 0x52, 0x7a, 0x30, 0x36, 0x29, 0x17, 0x3b, 0x68, 0x7a, 0x7c, 0x05, 0x6b, 0x6b,
249 }; 247 0x13, 0x6a, 0x24, 0x5c, 0x68, 0x42, 0x18, 0x32, 0x03, 0x73, 0x6e, 0x04, 0x21, 0x2e, 0x01,
250 char b64_known[1369] = { 248 0x04, 0x63, 0x7d, 0x44, 0x41, 0x12, 0x31, 0x0b, 0x15, 0x1f, 0x70, 0x00, 0x2e, 0x66, 0x14,
251 0x43,0x7a,0x42,0x45,0x59,0x6e,0x77,0x69,0x48,0x77,0x30,0x46,0x5a,0x79,0x77,0x71, 249 0x3c, 0x7f, 0x2b, 0x00, 0x1f, 0x0c, 0x28, 0x59, 0x0a, 0x16, 0x49, 0x5a, 0x5c, 0x64, 0x65,
252 0x4f,0x53,0x46,0x47,0x43,0x46,0x42,0x6d,0x4e,0x44,0x63,0x4c,0x52,0x55,0x73,0x34, 250 0x4b, 0x11, 0x29, 0x15, 0x36, 0x5a, 0x65, 0x19, 0x4f, 0x60, 0x23, 0x3a, 0x3a, 0x13, 0x25,
253 0x4d,0x67,0x5a,0x36,0x50,0x6e,0x38,0x4d,0x51,0x42,0x68,0x72,0x4c,0x57,0x42,0x4d, 251 0x02, 0x78, 0x4c, 0x54};
254 0x59,0x41,0x77,0x6a,0x51,0x7a,0x73,0x2b,0x47,0x78,0x59,0x45,0x52,0x6c,0x67,0x2f, 252 char b64_known[1369] = {
255 0x51,0x47,0x6f,0x52,0x42,0x57,0x4e,0x78,0x46,0x44,0x56,0x48,0x65,0x52,0x4e,0x76, 253 0x43, 0x7a, 0x42, 0x45, 0x59, 0x6e, 0x77, 0x69, 0x48, 0x77, 0x30, 0x46, 0x5a, 0x79, 0x77,
256 0x61,0x79,0x63,0x59,0x57,0x30,0x67,0x6e,0x50,0x6d,0x38,0x56,0x4d,0x30,0x38,0x2b, 254 0x71, 0x4f, 0x53, 0x46, 0x47, 0x43, 0x46, 0x42, 0x6d, 0x4e, 0x44, 0x63, 0x4c, 0x52, 0x55,
257 0x58,0x6c,0x46,0x7a,0x61,0x43,0x55,0x50,0x42,0x6c,0x74,0x38,0x63,0x6e,0x55,0x2b, 255 0x73, 0x34, 0x4d, 0x67, 0x5a, 0x36, 0x50, 0x6e, 0x38, 0x4d, 0x51, 0x42, 0x68, 0x72, 0x4c,
258 0x50,0x78,0x74,0x63,0x62,0x57,0x6f,0x35,0x66,0x47,0x4e,0x6a,0x59,0x47,0x78,0x36, 256 0x57, 0x42, 0x4d, 0x59, 0x41, 0x77, 0x6a, 0x51, 0x7a, 0x73, 0x2b, 0x47, 0x78, 0x59, 0x45,
259 0x4d,0x33,0x5a,0x53,0x45,0x79,0x55,0x7a,0x66,0x57,0x55,0x6a,0x4a,0x78,0x45,0x47, 257 0x52, 0x6c, 0x67, 0x2f, 0x51, 0x47, 0x6f, 0x52, 0x42, 0x57, 0x4e, 0x78, 0x46, 0x44, 0x56,
260 0x42,0x6b,0x64,0x78,0x48,0x68,0x52,0x30,0x59,0x33,0x41,0x74,0x46,0x53,0x63,0x59, 258 0x48, 0x65, 0x52, 0x4e, 0x76, 0x61, 0x79, 0x63, 0x59, 0x57, 0x30, 0x67, 0x6e, 0x50, 0x6d,
261 0x55,0x51,0x59,0x46,0x4d,0x78,0x45,0x73,0x61,0x77,0x41,0x74,0x64,0x79,0x42,0x49, 259 0x38, 0x56, 0x4d, 0x30, 0x38, 0x2b, 0x58, 0x6c, 0x46, 0x7a, 0x61, 0x43, 0x55, 0x50, 0x42,
262 0x44,0x58,0x4e,0x52,0x52,0x53,0x56,0x2f,0x66,0x7a,0x55,0x6d,0x4c,0x69,0x5a,0x54, 260 0x6c, 0x74, 0x38, 0x63, 0x6e, 0x55, 0x2b, 0x50, 0x78, 0x74, 0x63, 0x62, 0x57, 0x6f, 0x35,
263 0x4a,0x47,0x67,0x65,0x44,0x6c,0x67,0x36,0x57,0x56,0x42,0x57,0x4e,0x31,0x39,0x6d, 261 0x66, 0x47, 0x4e, 0x6a, 0x59, 0x47, 0x78, 0x36, 0x4d, 0x33, 0x5a, 0x53, 0x45, 0x79, 0x55,
264 0x41,0x55,0x78,0x61,0x5a,0x44,0x4a,0x51,0x65,0x32,0x6f,0x67,0x63,0x69,0x73,0x64, 262 0x7a, 0x66, 0x57, 0x55, 0x6a, 0x4a, 0x78, 0x45, 0x47, 0x42, 0x6b, 0x64, 0x78, 0x48, 0x68,
265 0x66,0x6b,0x4e,0x37,0x59,0x55,0x49,0x4c,0x59,0x58,0x4d,0x6b,0x65,0x54,0x70,0x72, 263 0x52, 0x30, 0x59, 0x33, 0x41, 0x74, 0x46, 0x53, 0x63, 0x59, 0x55, 0x51, 0x59, 0x46, 0x4d,
266 0x53,0x6e,0x6c,0x75,0x43,0x51,0x38,0x6e,0x4c,0x51,0x78,0x65,0x4d,0x6b,0x73,0x4e, 264 0x78, 0x45, 0x73, 0x61, 0x77, 0x41, 0x74, 0x64, 0x79, 0x42, 0x49, 0x44, 0x58, 0x4e, 0x52,
267 0x65,0x55,0x59,0x35,0x49,0x51,0x6f,0x6d,0x58,0x7a,0x6f,0x41,0x4a,0x6a,0x38,0x54, 265 0x52, 0x53, 0x56, 0x2f, 0x66, 0x7a, 0x55, 0x6d, 0x4c, 0x69, 0x5a, 0x54, 0x4a, 0x47, 0x67,
268 0x4c,0x6e,0x35,0x51,0x4b,0x32,0x64,0x47,0x63,0x6a,0x38,0x37,0x41,0x55,0x59,0x62, 266 0x65, 0x44, 0x6c, 0x67, 0x36, 0x57, 0x56, 0x42, 0x57, 0x4e, 0x31, 0x39, 0x6d, 0x41, 0x55,
269 0x43,0x7a,0x56,0x4a,0x4f,0x52,0x6c,0x77,0x50,0x51,0x4a,0x42,0x44,0x6a,0x67,0x46, 267 0x78, 0x61, 0x5a, 0x44, 0x4a, 0x51, 0x65, 0x32, 0x6f, 0x67, 0x63, 0x69, 0x73, 0x64, 0x66,
270 0x64,0x6d,0x56,0x50,0x4d,0x57,0x78,0x65,0x46,0x77,0x51,0x56,0x4e,0x69,0x5a,0x6b, 268 0x6b, 0x4e, 0x37, 0x59, 0x55, 0x49, 0x4c, 0x59, 0x58, 0x4d, 0x6b, 0x65, 0x54, 0x70, 0x72,
271 0x4e,0x42,0x51,0x58,0x66,0x41,0x34,0x4c,0x57,0x31,0x56,0x54,0x61,0x77,0x42,0x43, 269 0x53, 0x6e, 0x6c, 0x75, 0x43, 0x51, 0x38, 0x6e, 0x4c, 0x51, 0x78, 0x65, 0x4d, 0x6b, 0x73,
272 0x51,0x55,0x38,0x43,0x58,0x42,0x4d,0x4b,0x4c,0x43,0x77,0x2b,0x45,0x42,0x51,0x7a, 270 0x4e, 0x65, 0x55, 0x59, 0x35, 0x49, 0x51, 0x6f, 0x6d, 0x58, 0x7a, 0x6f, 0x41, 0x4a, 0x6a,
273 0x52,0x58,0x78,0x36,0x57,0x6a,0x46,0x68,0x4f,0x51,0x67,0x69,0x61,0x68,0x34,0x50, 271 0x38, 0x54, 0x4c, 0x6e, 0x35, 0x51, 0x4b, 0x32, 0x64, 0x47, 0x63, 0x6a, 0x38, 0x37, 0x41,
274 0x62,0x78,0x74,0x73,0x45,0x31,0x35,0x35,0x49,0x48,0x6c,0x51,0x59,0x67,0x59,0x73, 272 0x55, 0x59, 0x62, 0x43, 0x7a, 0x56, 0x4a, 0x4f, 0x52, 0x6c, 0x77, 0x50, 0x51, 0x4a, 0x42,
275 0x64,0x68,0x63,0x45,0x4b,0x79,0x70,0x31,0x48,0x77,0x77,0x33,0x54,0x67,0x39,0x37, 273 0x44, 0x6a, 0x67, 0x46, 0x64, 0x6d, 0x56, 0x50, 0x4d, 0x57, 0x78, 0x65, 0x46, 0x77, 0x51,
276 0x4c,0x54,0x52,0x31,0x59,0x44,0x46,0x30,0x4c,0x67,0x70,0x4b,0x45,0x57,0x78,0x4a, 274 0x56, 0x4e, 0x69, 0x5a, 0x6b, 0x4e, 0x42, 0x51, 0x58, 0x66, 0x41, 0x34, 0x4c, 0x57, 0x31,
277 0x4a,0x51,0x45,0x36,0x50,0x53,0x49,0x65,0x62,0x52,0x68,0x52,0x65,0x43,0x31,0x69, 275 0x56, 0x54, 0x61, 0x77, 0x42, 0x43, 0x51, 0x55, 0x38, 0x43, 0x58, 0x42, 0x4d, 0x4b, 0x4c,
278 0x4d,0x55,0x78,0x51,0x51,0x42,0x64,0x4c,0x62,0x79,0x49,0x41,0x66,0x32,0x45,0x71, 276 0x43, 0x77, 0x2b, 0x45, 0x42, 0x51, 0x7a, 0x52, 0x58, 0x78, 0x36, 0x57, 0x6a, 0x46, 0x68,
279 0x4e,0x44,0x34,0x41,0x58,0x79,0x39,0x66,0x4c,0x78,0x51,0x71,0x56,0x53,0x63,0x66, 277 0x4f, 0x51, 0x67, 0x69, 0x61, 0x68, 0x34, 0x50, 0x62, 0x78, 0x74, 0x73, 0x45, 0x31, 0x35,
280 0x52,0x68,0x38,0x53,0x52,0x6c,0x34,0x65,0x44,0x48,0x77,0x34,0x41,0x57,0x46,0x6b, 278 0x35, 0x49, 0x48, 0x6c, 0x51, 0x59, 0x67, 0x59, 0x73, 0x64, 0x68, 0x63, 0x45, 0x4b, 0x79,
281 0x64,0x69,0x4a,0x75,0x43,0x43,0x41,0x34,0x54,0x33,0x4e,0x79,0x56,0x52,0x4a,0x43, 279 0x70, 0x31, 0x48, 0x77, 0x77, 0x33, 0x54, 0x67, 0x39, 0x37, 0x4c, 0x54, 0x52, 0x31, 0x59,
282 0x47,0x56,0x42,0x68,0x51,0x33,0x64,0x39,0x51,0x53,0x34,0x31,0x54,0x7a,0x30,0x78, 280 0x44, 0x46, 0x30, 0x4c, 0x67, 0x70, 0x4b, 0x45, 0x57, 0x78, 0x4a, 0x4a, 0x51, 0x45, 0x36,
283 0x4b,0x46,0x68,0x6e,0x47,0x77,0x4e,0x52,0x49,0x44,0x49,0x63,0x43,0x47,0x34,0x33, 281 0x50, 0x53, 0x49, 0x65, 0x62, 0x52, 0x68, 0x52, 0x65, 0x43, 0x31, 0x69, 0x4d, 0x55, 0x78,
284 0x64,0x54,0x64,0x45,0x54,0x32,0x67,0x5a,0x42,0x32,0x51,0x55,0x4b,0x43,0x55,0x72, 282 0x51, 0x51, 0x42, 0x64, 0x4c, 0x62, 0x79, 0x49, 0x41, 0x66, 0x32, 0x45, 0x71, 0x4e, 0x44,
285 0x61,0x54,0x55,0x59,0x4a,0x79,0x59,0x55,0x45,0x33,0x42,0x43,0x47,0x52,0x4a,0x31, 283 0x34, 0x41, 0x58, 0x79, 0x39, 0x66, 0x4c, 0x78, 0x51, 0x71, 0x56, 0x53, 0x63, 0x66, 0x52,
286 0x50,0x67,0x4a,0x64,0x66,0x42,0x4d,0x66,0x46,0x6c,0x4d,0x37,0x64,0x45,0x67,0x38, 284 0x68, 0x38, 0x53, 0x52, 0x6c, 0x34, 0x65, 0x44, 0x48, 0x77, 0x34, 0x41, 0x57, 0x46, 0x6b,
287 0x58,0x6a,0x6c,0x73,0x48,0x42,0x78,0x30,0x4f,0x52,0x38,0x41,0x47,0x77,0x59,0x4b, 285 0x64, 0x69, 0x4a, 0x75, 0x43, 0x43, 0x41, 0x34, 0x54, 0x33, 0x4e, 0x79, 0x56, 0x52, 0x4a,
288 0x61,0x44,0x74,0x53,0x54,0x78,0x35,0x75,0x50,0x44,0x55,0x4d,0x4f,0x41,0x34,0x4c, 286 0x43, 0x47, 0x56, 0x42, 0x68, 0x51, 0x33, 0x64, 0x39, 0x51, 0x53, 0x34, 0x31, 0x54, 0x7a,
289 0x4f,0x78,0x70,0x32,0x49,0x79,0x6c,0x54,0x48,0x6c,0x39,0x42,0x44,0x45,0x73,0x4b, 287 0x30, 0x78, 0x4b, 0x46, 0x68, 0x6e, 0x47, 0x77, 0x4e, 0x52, 0x49, 0x44, 0x49, 0x63, 0x43,
290 0x5a,0x53,0x68,0x34,0x5a,0x30,0x68,0x5a,0x4a,0x6d,0x30,0x78,0x64,0x69,0x4e,0x77, 288 0x47, 0x34, 0x33, 0x64, 0x54, 0x64, 0x45, 0x54, 0x32, 0x67, 0x5a, 0x42, 0x32, 0x51, 0x55,
291 0x59,0x57,0x51,0x37,0x4f,0x48,0x6c,0x6d,0x64,0x46,0x4d,0x73,0x5a,0x47,0x52,0x55, 289 0x4b, 0x43, 0x55, 0x72, 0x61, 0x54, 0x55, 0x59, 0x4a, 0x79, 0x59, 0x55, 0x45, 0x33, 0x42,
292 0x41,0x31,0x52,0x6c,0x52,0x45,0x77,0x59,0x54,0x30,0x67,0x67,0x54,0x33,0x49,0x51, 290 0x43, 0x47, 0x52, 0x4a, 0x31, 0x50, 0x67, 0x4a, 0x64, 0x66, 0x42, 0x4d, 0x66, 0x46, 0x6c,
293 0x50,0x77,0x78,0x53,0x4c,0x51,0x4d,0x55,0x41,0x31,0x46,0x43,0x45,0x48,0x64,0x71, 291 0x4d, 0x37, 0x64, 0x45, 0x67, 0x38, 0x58, 0x6a, 0x6c, 0x73, 0x48, 0x42, 0x78, 0x30, 0x4f,
294 0x4e,0x41,0x59,0x79,0x41,0x33,0x49,0x55,0x66,0x41,0x68,0x64,0x55,0x68,0x70,0x69, 292 0x52, 0x38, 0x41, 0x47, 0x77, 0x59, 0x4b, 0x61, 0x44, 0x74, 0x53, 0x54, 0x78, 0x35, 0x75,
295 0x66,0x44,0x34,0x77,0x66,0x6c,0x39,0x2f,0x56,0x41,0x39,0x45,0x53,0x56,0x31,0x65, 293 0x50, 0x44, 0x55, 0x4d, 0x4f, 0x41, 0x34, 0x4c, 0x4f, 0x78, 0x70, 0x32, 0x49, 0x79, 0x6c,
296 0x45,0x47,0x6f,0x47,0x4b,0x77,0x5a,0x54,0x45,0x44,0x6b,0x33,0x4d,0x6b,0x70,0x4f, 294 0x54, 0x48, 0x6c, 0x39, 0x42, 0x44, 0x45, 0x73, 0x4b, 0x5a, 0x53, 0x68, 0x34, 0x5a, 0x30,
297 0x50,0x53,0x74,0x6c,0x4f,0x44,0x6b,0x48,0x63,0x6c,0x52,0x6b,0x54,0x56,0x5a,0x71, 295 0x68, 0x5a, 0x4a, 0x6d, 0x30, 0x78, 0x64, 0x69, 0x4e, 0x77, 0x59, 0x57, 0x51, 0x37, 0x4f,
298 0x41,0x79,0x4a,0x77,0x65,0x31,0x39,0x67,0x43,0x79,0x6f,0x4c,0x61,0x78,0x42,0x6b, 296 0x48, 0x6c, 0x6d, 0x64, 0x46, 0x4d, 0x73, 0x5a, 0x47, 0x52, 0x55, 0x41, 0x31, 0x52, 0x6c,
299 0x46,0x41,0x55,0x69,0x41,0x48,0x4e,0x41,0x49,0x31,0x74,0x52,0x48,0x79,0x73,0x61, 297 0x52, 0x45, 0x77, 0x59, 0x54, 0x30, 0x67, 0x67, 0x54, 0x33, 0x49, 0x51, 0x50, 0x77, 0x78,
300 0x58,0x57,0x6c,0x36,0x52,0x67,0x78,0x66,0x4d,0x6b,0x74,0x4b,0x4b,0x46,0x4a,0x35, 298 0x53, 0x4c, 0x51, 0x4d, 0x55, 0x41, 0x31, 0x46, 0x43, 0x45, 0x48, 0x64, 0x71, 0x4e, 0x41,
301 0x57,0x78,0x4a,0x43,0x47,0x41,0x42,0x64,0x4a,0x7a,0x46,0x54,0x50,0x45,0x77,0x32, 299 0x59, 0x79, 0x41, 0x33, 0x49, 0x55, 0x66, 0x41, 0x68, 0x64, 0x55, 0x68, 0x70, 0x69, 0x66,
302 0x54,0x6a,0x67,0x2f,0x63,0x67,0x4e,0x78,0x41,0x6c,0x73,0x32,0x57,0x58,0x39,0x31, 300 0x44, 0x34, 0x77, 0x66, 0x6c, 0x39, 0x2f, 0x56, 0x41, 0x39, 0x45, 0x53, 0x56, 0x31, 0x65,
303 0x62,0x67,0x68,0x55,0x44,0x54,0x51,0x63,0x4e,0x46,0x64,0x64,0x61,0x55,0x67,0x41, 301 0x45, 0x47, 0x6f, 0x47, 0x4b, 0x77, 0x5a, 0x54, 0x45, 0x44, 0x6b, 0x33, 0x4d, 0x6b, 0x70,
304 0x4f,0x77,0x55,0x48,0x62,0x69,0x64,0x6c,0x62,0x6b,0x41,0x39,0x4f,0x6b,0x39,0x79, 302 0x4f, 0x50, 0x53, 0x74, 0x6c, 0x4f, 0x44, 0x6b, 0x48, 0x63, 0x6c, 0x52, 0x6b, 0x54, 0x56,
305 0x58,0x54,0x6b,0x57,0x44,0x32,0x4d,0x53,0x45,0x68,0x55,0x36,0x63,0x41,0x31,0x58, 303 0x5a, 0x71, 0x41, 0x79, 0x4a, 0x77, 0x65, 0x31, 0x39, 0x67, 0x43, 0x79, 0x6f, 0x4c, 0x61,
306 0x47,0x41,0x31,0x65,0x50,0x53,0x4a,0x6f,0x61,0x48,0x78,0x74,0x54,0x77,0x78,0x37, 304 0x78, 0x42, 0x6b, 0x46, 0x41, 0x55, 0x69, 0x41, 0x48, 0x4e, 0x41, 0x49, 0x31, 0x74, 0x52,
307 0x43,0x53,0x31,0x4b,0x63,0x79,0x42,0x48,0x42,0x31,0x64,0x31,0x58,0x56,0x4e,0x77, 305 0x48, 0x79, 0x73, 0x61, 0x58, 0x57, 0x6c, 0x36, 0x52, 0x67, 0x78, 0x66, 0x4d, 0x6b, 0x74,
308 0x4e,0x43,0x46,0x41,0x56,0x31,0x46,0x65,0x53,0x55,0x51,0x41,0x56,0x43,0x63,0x45, 306 0x4b, 0x4b, 0x46, 0x4a, 0x35, 0x57, 0x78, 0x4a, 0x43, 0x47, 0x41, 0x42, 0x64, 0x4a, 0x7a,
309 0x61,0x48,0x35,0x5a,0x56,0x6c,0x68,0x30,0x46,0x44,0x77,0x57,0x4d,0x30,0x45,0x57, 307 0x46, 0x54, 0x50, 0x45, 0x77, 0x32, 0x54, 0x6a, 0x67, 0x2f, 0x63, 0x67, 0x4e, 0x78, 0x41,
310 0x53,0x79,0x39,0x4a,0x4e,0x77,0x70,0x55,0x43,0x41,0x67,0x66,0x4f,0x57,0x64,0x32, 308 0x6c, 0x73, 0x32, 0x57, 0x58, 0x39, 0x31, 0x62, 0x67, 0x68, 0x55, 0x44, 0x54, 0x51, 0x63,
311 0x4b,0x43,0x67,0x48,0x48,0x57,0x46,0x48,0x55,0x55,0x31,0x31,0x4a,0x6c,0x4a,0x48, 309 0x4e, 0x46, 0x64, 0x64, 0x61, 0x55, 0x67, 0x41, 0x4f, 0x77, 0x55, 0x48, 0x62, 0x69, 0x64,
312 0x52,0x77,0x78,0x58,0x57,0x48,0x51,0x2b,0x59,0x6d,0x78,0x59,0x4f,0x6b,0x51,0x65, 310 0x6c, 0x62, 0x6b, 0x41, 0x39, 0x4f, 0x6b, 0x39, 0x79, 0x58, 0x54, 0x6b, 0x57, 0x44, 0x32,
313 0x46,0x69,0x34,0x68,0x48,0x48,0x4e,0x46,0x5a,0x33,0x52,0x50,0x4d,0x32,0x59,0x4f, 311 0x4d, 0x53, 0x45, 0x68, 0x55, 0x36, 0x63, 0x41, 0x31, 0x58, 0x47, 0x41, 0x31, 0x65, 0x50,
314 0x64,0x47,0x59,0x6d,0x48,0x79,0x34,0x34,0x52,0x45,0x42,0x2b,0x4b,0x6c,0x42,0x53, 312 0x53, 0x4a, 0x6f, 0x61, 0x48, 0x78, 0x74, 0x54, 0x77, 0x78, 0x37, 0x43, 0x53, 0x31, 0x4b,
315 0x58,0x6b,0x4d,0x42,0x65,0x6a,0x68,0x4a,0x50,0x46,0x56,0x4e,0x57,0x6b,0x51,0x49, 313 0x63, 0x79, 0x42, 0x48, 0x42, 0x31, 0x64, 0x31, 0x58, 0x56, 0x4e, 0x77, 0x4e, 0x43, 0x46,
316 0x4a,0x6c,0x6c,0x4e,0x52,0x51,0x74,0x49,0x43,0x6a,0x4e,0x65,0x53,0x6b,0x31,0x31, 314 0x41, 0x56, 0x31, 0x46, 0x65, 0x53, 0x55, 0x51, 0x41, 0x56, 0x43, 0x63, 0x45, 0x61, 0x48,
317 0x46,0x68,0x64,0x6a,0x52,0x67,0x45,0x71,0x56,0x58,0x73,0x50,0x41,0x6e,0x4e,0x71, 315 0x35, 0x5a, 0x56, 0x6c, 0x68, 0x30, 0x46, 0x44, 0x77, 0x57, 0x4d, 0x30, 0x45, 0x57, 0x53,
318 0x53,0x33,0x39,0x31,0x5a,0x54,0x78,0x4d,0x4d,0x7a,0x6c,0x73,0x64,0x41,0x56,0x67, 316 0x79, 0x39, 0x4a, 0x4e, 0x77, 0x70, 0x55, 0x43, 0x41, 0x67, 0x66, 0x4f, 0x57, 0x64, 0x32,
319 0x44,0x33,0x38,0x74,0x51,0x55,0x31,0x4e,0x52,0x6e,0x45,0x4a,0x62,0x30,0x39,0x67, 317 0x4b, 0x43, 0x67, 0x48, 0x48, 0x57, 0x46, 0x48, 0x55, 0x55, 0x31, 0x31, 0x4a, 0x6c, 0x4a,
320 0x46,0x51,0x39,0x47,0x63,0x32,0x4e,0x4d,0x58,0x6e,0x51,0x77,0x44,0x53,0x68,0x44, 318 0x48, 0x52, 0x77, 0x78, 0x58, 0x57, 0x48, 0x51, 0x2b, 0x59, 0x6d, 0x78, 0x59, 0x4f, 0x6b,
321 0x43,0x48,0x49,0x79,0x42,0x43,0x34,0x78,0x4b,0x53,0x64,0x45,0x62,0x52,0x4d,0x58, 319 0x51, 0x65, 0x46, 0x69, 0x34, 0x68, 0x48, 0x48, 0x4e, 0x46, 0x5a, 0x33, 0x52, 0x50, 0x4d,
322 0x53,0x41,0x39,0x4a,0x55,0x68,0x41,0x54,0x66,0x78,0x63,0x57,0x59,0x6e,0x6b,0x31, 320 0x32, 0x59, 0x4f, 0x64, 0x47, 0x59, 0x6d, 0x48, 0x79, 0x34, 0x34, 0x52, 0x45, 0x42, 0x2b,
323 0x65,0x44,0x34,0x42,0x66,0x43,0x34,0x50,0x64,0x6a,0x35,0x65,0x55,0x32,0x78,0x62, 321 0x4b, 0x6c, 0x42, 0x53, 0x58, 0x6b, 0x4d, 0x42, 0x65, 0x6a, 0x68, 0x4a, 0x50, 0x46, 0x56,
324 0x58,0x33,0x77,0x5a,0x51,0x51,0x49,0x76,0x46,0x32,0x52,0x42,0x64,0x52,0x41,0x45, 322 0x4e, 0x57, 0x6b, 0x51, 0x49, 0x4a, 0x6c, 0x6c, 0x4e, 0x52, 0x51, 0x74, 0x49, 0x43, 0x6a,
325 0x52,0x33,0x77,0x39,0x53,0x31,0x49,0x41,0x45,0x46,0x31,0x52,0x54,0x6e,0x6f,0x6e, 323 0x4e, 0x65, 0x53, 0x6b, 0x31, 0x31, 0x46, 0x68, 0x64, 0x6a, 0x52, 0x67, 0x45, 0x71, 0x56,
326 0x4a,0x56,0x56,0x41,0x45,0x6a,0x56,0x67,0x42,0x52,0x73,0x30,0x4c,0x51,0x52,0x36, 324 0x58, 0x73, 0x50, 0x41, 0x6e, 0x4e, 0x71, 0x53, 0x33, 0x39, 0x31, 0x5a, 0x54, 0x78, 0x4d,
327 0x61,0x6d,0x6b,0x43,0x65,0x51,0x4d,0x36,0x4c,0x77,0x59,0x4b,0x65,0x58,0x73,0x53, 325 0x4d, 0x7a, 0x6c, 0x73, 0x64, 0x41, 0x56, 0x67, 0x44, 0x33, 0x38, 0x74, 0x51, 0x55, 0x31,
328 0x58,0x58,0x78,0x53,0x4b,0x55,0x64,0x59,0x45,0x6e,0x4d,0x2f,0x4a,0x31,0x59,0x46, 326 0x4e, 0x52, 0x6e, 0x45, 0x4a, 0x62, 0x30, 0x39, 0x67, 0x46, 0x51, 0x39, 0x47, 0x63, 0x32,
329 0x44,0x45,0x67,0x79,0x57,0x47,0x74,0x58,0x58,0x41,0x4e,0x6b,0x56,0x68,0x46,0x53, 327 0x4e, 0x4d, 0x58, 0x6e, 0x51, 0x77, 0x44, 0x53, 0x68, 0x44, 0x43, 0x48, 0x49, 0x79, 0x42,
330 0x65,0x6a,0x41,0x32,0x4b,0x52,0x63,0x37,0x61,0x48,0x70,0x38,0x42,0x57,0x74,0x72, 328 0x43, 0x34, 0x78, 0x4b, 0x53, 0x64, 0x45, 0x62, 0x52, 0x4d, 0x58, 0x53, 0x41, 0x39, 0x4a,
331 0x45,0x32,0x6f,0x6b,0x58,0x47,0x68,0x43,0x47,0x44,0x49,0x44,0x63,0x32,0x34,0x45, 329 0x55, 0x68, 0x41, 0x54, 0x66, 0x78, 0x63, 0x57, 0x59, 0x6e, 0x6b, 0x31, 0x65, 0x44, 0x34,
332 0x49,0x53,0x34,0x42,0x42,0x47,0x4e,0x39,0x52,0x45,0x45,0x53,0x4d,0x51,0x73,0x56, 330 0x42, 0x66, 0x43, 0x34, 0x50, 0x64, 0x6a, 0x35, 0x65, 0x55, 0x32, 0x78, 0x62, 0x58, 0x33,
333 0x48,0x33,0x41,0x41,0x4c,0x6d,0x59,0x55,0x50,0x48,0x38,0x72,0x41,0x42,0x38,0x4d, 331 0x77, 0x5a, 0x51, 0x51, 0x49, 0x76, 0x46, 0x32, 0x52, 0x42, 0x64, 0x52, 0x41, 0x45, 0x52,
334 0x4b,0x46,0x6b,0x4b,0x46,0x6b,0x6c,0x61,0x58,0x47,0x52,0x6c,0x53,0x78,0x45,0x70, 332 0x33, 0x77, 0x39, 0x53, 0x31, 0x49, 0x41, 0x45, 0x46, 0x31, 0x52, 0x54, 0x6e, 0x6f, 0x6e,
335 0x46,0x54,0x5a,0x61,0x5a,0x52,0x6c,0x50,0x59,0x43,0x4d,0x36,0x4f,0x68,0x4d,0x6c, 333 0x4a, 0x56, 0x56, 0x41, 0x45, 0x6a, 0x56, 0x67, 0x42, 0x52, 0x73, 0x30, 0x4c, 0x51, 0x52,
336 0x41,0x6e,0x68,0x4d,0x56,0x41,0x3d,0x3d,0x00 334 0x36, 0x61, 0x6d, 0x6b, 0x43, 0x65, 0x51, 0x4d, 0x36, 0x4c, 0x77, 0x59, 0x4b, 0x65, 0x58,
337 }; 335 0x73, 0x53, 0x58, 0x58, 0x78, 0x53, 0x4b, 0x55, 0x64, 0x59, 0x45, 0x6e, 0x4d, 0x2f, 0x4a,
336 0x31, 0x59, 0x46, 0x44, 0x45, 0x67, 0x79, 0x57, 0x47, 0x74, 0x58, 0x58, 0x41, 0x4e, 0x6b,
337 0x56, 0x68, 0x46, 0x53, 0x65, 0x6a, 0x41, 0x32, 0x4b, 0x52, 0x63, 0x37, 0x61, 0x48, 0x70,
338 0x38, 0x42, 0x57, 0x74, 0x72, 0x45, 0x32, 0x6f, 0x6b, 0x58, 0x47, 0x68, 0x43, 0x47, 0x44,
339 0x49, 0x44, 0x63, 0x32, 0x34, 0x45, 0x49, 0x53, 0x34, 0x42, 0x42, 0x47, 0x4e, 0x39, 0x52,
340 0x45, 0x45, 0x53, 0x4d, 0x51, 0x73, 0x56, 0x48, 0x33, 0x41, 0x41, 0x4c, 0x6d, 0x59, 0x55,
341 0x50, 0x48, 0x38, 0x72, 0x41, 0x42, 0x38, 0x4d, 0x4b, 0x46, 0x6b, 0x4b, 0x46, 0x6b, 0x6c,
342 0x61, 0x58, 0x47, 0x52, 0x6c, 0x53, 0x78, 0x45, 0x70, 0x46, 0x54, 0x5a, 0x61, 0x5a, 0x52,
343 0x6c, 0x50, 0x59, 0x43, 0x4d, 0x36, 0x4f, 0x68, 0x4d, 0x6c, 0x41, 0x6e, 0x68, 0x4d, 0x56,
344 0x41, 0x3d, 0x3d, 0x00};
338 char *b64_test; 345 char *b64_test;
339 346
340 plan_tests(1); 347 plan_tests(1);
341 348
342 base64_encode_alloc (random, 1024, &b64_test); 349 base64_encode_alloc(random, 1024, &b64_test);
343 350
344 ok(strcmp(b64_known, b64_test) == 0, 351 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 352
347 return exit_status(); 353 return exit_status();
348} 354}
349
diff --git a/lib/tests/test_cmd.c b/lib/tests/test_cmd.c
index 02ae11f5..d51016cc 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,212 +22,186 @@
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)
44{
45 char **command_line = malloc (sizeof (char *) * COMMAND_LINE);
46 char *command = NULL;
47 char *perl;
48 output chld_out, chld_err;
49 int c;
50 int result = UNSET;
51
52 plan_tests(51); 41 plan_tests(51);
53 42
54 diag ("Running plain echo command, set one"); 43 diag("Running plain echo command, set one");
55 44
56 /* ensure everything is empty before we begin */ 45 /* ensure everything is empty before we begin */
57 memset (&chld_out, 0, sizeof (output)); 46
58 memset (&chld_err, 0, sizeof (output)); 47 output chld_out;
59 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 48 memset(&chld_out, 0, sizeof(output));
60 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 49 output chld_err;
61 ok (result == UNSET, "(initialised) Checking exit code is reset"); 50 memset(&chld_err, 0, sizeof(output));
62 51 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
63 command_line[0] = strdup ("/bin/echo"); 52 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
64 command_line[1] = strdup ("this"); 53 int result = UNSET;
65 command_line[2] = strdup ("is"); 54 ok(result == UNSET, "(initialised) Checking exit code is reset");
66 command_line[3] = strdup ("test"); 55
67 command_line[4] = strdup ("one"); 56 char **command_line = malloc(sizeof(char *) * COMMAND_LINE);
68 57 command_line[0] = strdup("/bin/echo");
69 command = get_command (command_line); 58 command_line[1] = strdup("this");
70 59 command_line[2] = strdup("is");
71 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 60 command_line[3] = strdup("test");
72 ok (chld_out.lines == 1, 61 command_line[4] = strdup("one");
73 "(array) Check for expected number of stdout lines"); 62
74 ok (chld_err.lines == 0, 63 char *command = get_command(command_line);
75 "(array) Check for expected number of stderr lines"); 64
76 ok (strcmp (chld_out.line[0], "this is test one") == 0, 65 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
77 "(array) Check for expected stdout output"); 66 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
78 ok (result == 0, "(array) Checking exit code"); 67 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
68 ok(strcmp(chld_out.line[0], "this is test one") == 0,
69 "(array) Check for expected stdout output");
70 ok(result == 0, "(array) Checking exit code");
79 71
80 /* ensure everything is empty again */ 72 /* ensure everything is empty again */
81 memset (&chld_out, 0, sizeof (output)); 73 memset(&chld_out, 0, sizeof(output));
82 memset (&chld_err, 0, sizeof (output)); 74 memset(&chld_err, 0, sizeof(output));
83 result = UNSET; 75 result = UNSET;
84 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 76 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
85 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 77 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
86 ok (result == UNSET, "(initialised) Checking exit code is reset"); 78 ok(result == UNSET, "(initialised) Checking exit code is reset");
87 79
88 result = cmd_run (command, &chld_out, &chld_err, 0); 80 result = cmd_run(command, &chld_out, &chld_err, 0);
89 81
90 ok (chld_out.lines == 1, 82 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
91 "(string) Check for expected number of stdout lines"); 83 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
92 ok (chld_err.lines == 0, 84 ok(strcmp(chld_out.line[0], "this is test one") == 0,
93 "(string) Check for expected number of stderr lines"); 85 "(string) Check for expected stdout output");
94 ok (strcmp (chld_out.line[0], "this is test one") == 0, 86 ok(result == 0, "(string) Checking exit code");
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,
118 "(array) Check for expected number of stderr lines"); 108 "(array) Check for expected stdout output");
119 ok (strcmp (chld_out.line[0], "this is test two") == 0, 109 ok(result == 0, "(array) Checking exit code");
120 "(array) Check for expected stdout output");
121 ok (result == 0, "(array) Checking exit code");
122 110
123 /* ensure everything is empty again */ 111 /* ensure everything is empty again */
124 memset (&chld_out, 0, sizeof (output)); 112 memset(&chld_out, 0, sizeof(output));
125 memset (&chld_err, 0, sizeof (output)); 113 memset(&chld_err, 0, sizeof(output));
126 result = UNSET; 114 result = UNSET;
127 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 115 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
128 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 116 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
129 ok (result == UNSET, "(initialised) Checking exit code is reset"); 117 ok(result == UNSET, "(initialised) Checking exit code is reset");
130
131 result = cmd_run (command, &chld_out, &chld_err, 0);
132 118
133 ok (chld_out.lines == 1, 119 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 120
121 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
122 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
123 ok(strcmp(chld_out.line[0], "this is test one") == 0,
124 "(string) Check for expected stdout output");
125 ok(result == 0, "(string) Checking exit code");
141 126
142 /* ensure everything is empty again */ 127 /* ensure everything is empty again */
143 memset (&chld_out, 0, sizeof (output)); 128 memset(&chld_out, 0, sizeof(output));
144 memset (&chld_err, 0, sizeof (output)); 129 memset(&chld_err, 0, sizeof(output));
145 result = UNSET; 130 result = UNSET;
146 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 131 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
147 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 132 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
148 ok (result == UNSET, "(initialised) Checking exit code is reset"); 133 ok(result == UNSET, "(initialised) Checking exit code is reset");
149 134
150 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */ 135 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line
136 * output */
151 command_line[0] = strdup("/bin/echo"); 137 command_line[0] = strdup("/bin/echo");
152 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3"); 138 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"); 139 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated");
154 140
155 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 141 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
156 ok (chld_out.lines == 3, 142 ok(chld_out.lines == 3, "(array) Check for expected number of stdout lines");
157 "(array) Check for expected number of stdout lines"); 143 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
158 ok (chld_err.lines == 0, 144 ok(strcmp(chld_out.line[0], "this is a test via echo") == 0,
159 "(array) Check for expected number of stderr lines"); 145 "(array) Check line 1 for expected stdout output");
160 ok (strcmp (chld_out.line[0], "this is a test via echo") == 0, 146 ok(strcmp(chld_out.line[1], "line two") == 0,
161 "(array) Check line 1 for expected stdout output"); 147 "(array) Check line 2 for expected stdout output");
162 ok (strcmp (chld_out.line[1], "line two") == 0, 148 ok(strcmp(chld_out.line[2],
163 "(array) Check line 2 for expected stdout output"); 149 "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0,
164 ok (strcmp (chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0, 150 "(array) Check line 3 for expected stdout output");
165 "(array) Check line 3 for expected stdout output"); 151 ok(result == 0, "(array) Checking exit code");
166 ok (result == 0, "(array) Checking exit code");
167
168
169 152
170 /* ensure everything is empty again */ 153 /* ensure everything is empty again */
171 memset (&chld_out, 0, sizeof (output)); 154 memset(&chld_out, 0, sizeof(output));
172 memset (&chld_err, 0, sizeof (output)); 155 memset(&chld_err, 0, sizeof(output));
173 result = UNSET; 156 result = UNSET;
174 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 157 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
175 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 158 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
176 ok (result == UNSET, "(initialised) Checking exit code is reset"); 159 ok(result == UNSET, "(initialised) Checking exit code is reset");
177 160
178 command = (char *)malloc(COMMAND_LINE); 161 command = (char *)malloc(COMMAND_LINE);
179 strcpy(command, "/bin/echo3456 non-existent command"); 162 strcpy(command, "/bin/echo3456 non-existent command");
180 result = cmd_run (command, &chld_out, &chld_err, 0); 163 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 164
165 ok(chld_out.lines == 0, "Non existent command, so no output");
166 ok(chld_err.lines == 0, "No stderr either");
167 ok(result == 3, "Get return code 3 (?) for non-existent command");
188 168
189 /* ensure everything is empty again */ 169 /* ensure everything is empty again */
190 memset (&chld_out, 0, sizeof (output)); 170 memset(&chld_out, 0, sizeof(output));
191 memset (&chld_err, 0, sizeof (output)); 171 memset(&chld_err, 0, sizeof(output));
192 result = UNSET; 172 result = UNSET;
193 173
194 command = (char *)malloc(COMMAND_LINE); 174 command = (char *)malloc(COMMAND_LINE);
195 strcpy(command, "/bin/sh non-existent-file"); 175 strcpy(command, "/bin/sh non-existent-file");
196 result = cmd_run (command, &chld_out, &chld_err, 0); 176 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 177
178 ok(chld_out.lines == 0, "/bin/sh returns no stdout when file is missing...");
179 ok(chld_err.lines == 1, "...but does give an error line");
180 ok(strstr(chld_err.line[0], "non-existent-file") != NULL,
181 "And missing filename is in error message");
182 ok(result != 0, "Get non-zero return code from /bin/sh");
205 183
206 /* ensure everything is empty again */ 184 /* ensure everything is empty again */
207 result = UNSET; 185 result = UNSET;
208 186
209 command = (char *)malloc(COMMAND_LINE); 187 command = (char *)malloc(COMMAND_LINE);
210 strcpy(command, "/bin/sh -c 'exit 7'"); 188 strcpy(command, "/bin/sh -c 'exit 7'");
211 result = cmd_run (command, NULL, NULL, 0); 189 result = cmd_run(command, NULL, NULL, 0);
212
213 ok (result == 7, "Get return code 7 from /bin/sh");
214 190
191 ok(result == 7, "Get return code 7 from /bin/sh");
215 192
216 /* ensure everything is empty again */ 193 /* ensure everything is empty again */
217 memset (&chld_out, 0, sizeof (output)); 194 memset(&chld_out, 0, sizeof(output));
218 memset (&chld_err, 0, sizeof (output)); 195 memset(&chld_err, 0, sizeof(output));
219 result = UNSET; 196 result = UNSET;
220 197
221 command = (char *)malloc(COMMAND_LINE); 198 command = (char *)malloc(COMMAND_LINE);
222 strcpy(command, "/bin/non-existent-command"); 199 strcpy(command, "/bin/non-existent-command");
223 result = cmd_run (command, &chld_out, &chld_err, 0); 200 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 201
202 ok(chld_out.lines == 0, "/bin/non-existent-command returns no stdout...");
203 ok(chld_err.lines == 0, "...and no stderr output either");
204 ok(result == 3, "Get return code 3 = UNKNOWN when command does not exist");
231 205
232 return exit_status (); 206 return exit_status();
233} 207}
diff --git a/lib/tests/test_disk.c b/lib/tests/test_disk.c
deleted file mode 100644
index e283fe2e..00000000
--- a/lib/tests/test_disk.c
+++ /dev/null
@@ -1,224 +0,0 @@
1/*****************************************************************************
2*
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
5* the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
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/>.
15*
16*
17*****************************************************************************/
18
19#include "common.h"
20#include "utils_disk.h"
21#include "tap.h"
22#include "regex.h"
23
24void np_test_mount_entry_regex (struct mount_entry *dummy_mount_list,
25 char *regstr, int cflags, int expect,
26 char *desc);
27
28
29int
30main (int argc, char **argv)
31{
32 struct name_list *exclude_filesystem=NULL;
33 struct name_list *exclude_fstype=NULL;
34 struct name_list *dummy_mountlist = NULL;
35 struct name_list *temp_name;
36 struct parameter_list *paths = NULL;
37 struct parameter_list *p, *prev = NULL, *last = NULL;
38
39 struct mount_entry *dummy_mount_list;
40 struct mount_entry *me;
41 struct mount_entry **mtail = &dummy_mount_list;
42 int cflags = REG_NOSUB | REG_EXTENDED;
43 int found = 0, count = 0;
44
45 plan_tests(33);
46
47 ok( np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
48 np_add_name(&exclude_filesystem, "/var/log");
49 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");
51 np_add_name(&exclude_filesystem, "/home");
52 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");
54
55 ok( np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
56 np_add_name(&exclude_fstype, "iso9660");
57 ok( np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
58
59 ok( np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables");
60
61 /*
62 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) {
63 printf("Name: %s\n", temp_name->name);
64 }
65 */
66
67 me = (struct mount_entry *) malloc(sizeof *me);
68 me->me_devname = strdup("/dev/c0t0d0s0");
69 me->me_mountdir = strdup("/");
70 *mtail = me;
71 mtail = &me->me_next;
72
73 me = (struct mount_entry *) malloc(sizeof *me);
74 me->me_devname = strdup("/dev/c1t0d1s0");
75 me->me_mountdir = strdup("/var");
76 *mtail = me;
77 mtail = &me->me_next;
78
79 me = (struct mount_entry *) malloc(sizeof *me);
80 me->me_devname = strdup("/dev/c2t0d0s0");
81 me->me_mountdir = strdup("/home");
82 *mtail = me;
83 mtail = &me->me_next;
84
85 np_test_mount_entry_regex(dummy_mount_list, strdup("/"),
86 cflags, 3, strdup("a"));
87 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"),
88 cflags, 3,strdup("regex on dev names:"));
89 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"),
90 cflags, 0,
91 strdup("regex on non existent dev/path:"));
92 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"),
93 cflags | REG_ICASE,0,
94 strdup("regi on non existent dev/path:"));
95 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"),
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
117 np_add_parameter(&paths, "/home/groups");
118 np_add_parameter(&paths, "/var");
119 np_add_parameter(&paths, "/tmp");
120 np_add_parameter(&paths, "/home/tonvoon");
121 np_add_parameter(&paths, "/dev/c2t0d0s0");
122
123 np_set_best_match(paths, dummy_mount_list, false);
124 for (p = paths; p; p = p->name_next) {
125 struct mount_entry *temp_me;
126 temp_me = p->best_match;
127 if (! strcmp(p->name, "/home/groups")) {
128 ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home");
129 } else if (! strcmp(p->name, "/var")) {
130 ok( temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
131 } else if (! strcmp(p->name, "/tmp")) {
132 ok( temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
133 } else if (! strcmp(p->name, "/home/tonvoon")) {
134 ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home");
135 } 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");
137 }
138 }
139
140 paths = NULL; /* Bad boy - should free, but this is a test suite */
141 np_add_parameter(&paths, "/home/groups");
142 np_add_parameter(&paths, "/var");
143 np_add_parameter(&paths, "/tmp");
144 np_add_parameter(&paths, "/home/tonvoon");
145 np_add_parameter(&paths, "/home");
146
147 np_set_best_match(paths, dummy_mount_list, true);
148 for (p = paths; p; p = p->name_next) {
149 if (! strcmp(p->name, "/home/groups")) {
150 ok( ! p->best_match , "/home/groups correctly not found");
151 } else if (! strcmp(p->name, "/var")) {
152 ok( p->best_match, "/var found");
153 } else if (! strcmp(p->name, "/tmp")) {
154 ok(! p->best_match, "/tmp correctly not found");
155 } else if (! strcmp(p->name, "/home/tonvoon")) {
156 ok(! p->best_match, "/home/tonvoon not found");
157 } else if (! strcmp(p->name, "/home")) {
158 ok( p->best_match, "/home found");
159 }
160 }
161
162 /* test deleting first element in paths */
163 paths = np_del_parameter(paths, NULL);
164 for (p = paths; p; p = p->name_next) {
165 if (! strcmp(p->name, "/home/groups"))
166 found = 1;
167 }
168 ok(found == 0, "first element successfully deleted");
169 found = 0;
170
171 p=paths;
172 while (p) {
173 if (! strcmp(p->name, "/tmp"))
174 p = np_del_parameter(p, prev);
175 else {
176 prev = p;
177 p = p->name_next;
178 }
179 }
180
181 for (p = paths; p; p = p->name_next) {
182 if (! strcmp(p->name, "/tmp"))
183 found = 1;
184 if (p->name_next)
185 prev = p;
186 else
187 last = p;
188 }
189 ok(found == 0, "/tmp element successfully deleted");
190
191 p = np_del_parameter(last, prev);
192 for (p = paths; p; p = p->name_next) {
193 if (! strcmp(p->name, "/home"))
194 found = 1;
195 last = p;
196 count++;
197 }
198 ok(found == 0, "last (/home) element successfully deleted");
199 ok(count == 2, "two elements remaining");
200
201
202 return exit_status();
203}
204
205
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;
210 regex_t re;
211 struct mount_entry *me;
212 if (regcomp(&re,regstr, cflags) == 0) {
213 for (me = dummy_mount_list; me; me= me->me_next) {
214 if(np_regex_match_mount_entry(me,&re))
215 matches++;
216 }
217 ok( matches == expect,
218 "%s '%s' matched %i/3 entries. ok: %i/3",
219 desc, regstr, expect, matches);
220
221 } else
222 ok ( false, "regex '%s' not compilable", regstr);
223}
224
diff --git a/lib/tests/test_disk.t b/lib/tests/test_disk.t
deleted file mode 100755
index da84dfdf..00000000
--- a/lib/tests/test_disk.t
+++ /dev/null
@@ -1,6 +0,0 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_disk") {
4 plan skip_all => "./test_disk not compiled - please enable libtap library to test";
5}
6exec "./test_disk";
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..e4a78bcd
--- /dev/null
+++ b/lib/tests/test_generic_output.c
@@ -0,0 +1,317 @@
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,
114 "Test subcheck state directly after setting it");
115
116 mp_perfdata pd1 = perfdata_init();
117
118 pd1 = mp_set_pd_value(pd1, 23);
119
120 pd1.uom = "s";
121 pd1.label = "foo";
122
123 mp_add_perfdata_to_subcheck(&sc1, pd1);
124
125 mp_subcheck sc2 = mp_subcheck_init();
126 sc2.output = "baz";
127 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
128
129 ok(mp_compute_subcheck_state(sc2) == STATE_OK, "Test subcheck 2 state after setting it");
130
131 mp_add_subcheck_to_subcheck(&sc1, sc2);
132
133 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING,
134 "Test subcheck state after adding a subcheck");
135
136 mp_check check = mp_check_init();
137 mp_add_subcheck_to_check(&check, sc1);
138
139 ok(mp_compute_check_state(check) == STATE_WARNING, "Test main check result");
140
141 char *output = mp_fmt_output(check);
142
143 // diag("Formatted output. Length: %u", strlen(output));
144 // diag(output);
145
146 ok(output != NULL, "Output should not be NULL");
147
148 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
149 "\t\\_[WARNING] - foobar\n"
150 "\t\t\\_[OK] - baz\n"
151 "|foo=23s;;; \n";
152
153 // diag("Expected output. Length: %u", strlen(expected));
154 // diag(expected);
155
156 ok(strcmp(output, expected) == 0, "Output is as expected");
157}
158
159void test_deep_check_hierarchy(void) {
160 // level 4
161 mp_subcheck sc4 = mp_subcheck_init();
162 sc4.output = "level4";
163 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
164
165 // level 3
166 mp_subcheck sc3 = mp_subcheck_init();
167 sc3.output = "level3";
168 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
169
170 // level 2
171 mp_subcheck sc2 = mp_subcheck_init();
172 sc2.output = "baz";
173 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
174
175 // level 1
176 mp_subcheck sc1 = mp_subcheck_init();
177
178 sc1.output = "foobar";
179 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
180
181 mp_perfdata pd1 = perfdata_init();
182
183 pd1.uom = "s";
184 pd1.label = "foo";
185 pd1 = mp_set_pd_value(pd1, 23);
186
187 mp_add_perfdata_to_subcheck(&sc1, pd1);
188
189 // main check
190 mp_check check = mp_check_init();
191
192 mp_add_subcheck_to_subcheck(&sc3, sc4);
193 mp_add_subcheck_to_subcheck(&sc2, sc3);
194 mp_add_subcheck_to_subcheck(&sc1, sc2);
195 mp_add_subcheck_to_check(&check, sc1);
196
197 char *output = mp_fmt_output(check);
198
199 size_t output_length = strlen(output);
200
201 // diag("Formatted output of length %i", output_length);
202 // diag(output);
203
204 ok(output != NULL, "Output should not be NULL");
205
206 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
207 "\t\\_[WARNING] - foobar\n"
208 "\t\t\\_[OK] - baz\n"
209 "\t\t\t\\_[OK] - level3\n"
210 "\t\t\t\t\\_[OK] - level4\n"
211 "|foo=23s;;; \n";
212
213 size_t expected_length = strlen(expected);
214
215 // diag("Expected output of length: %i", expected_length);
216 // diag(expected);
217
218 ok(output_length == expected_length, "Outputs are of equal length");
219 ok(strcmp(output, expected) == 0, "Output is as expected");
220}
221
222void test_deep_check_hierarchy2(void) {
223 // level 1
224 mp_subcheck sc1 = mp_subcheck_init();
225
226 sc1.output = "foobar";
227 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
228
229 mp_perfdata pd1 = perfdata_init();
230 pd1.uom = "s";
231 pd1.label = "foo";
232 pd1 = mp_set_pd_value(pd1, 23);
233
234 mp_add_perfdata_to_subcheck(&sc1, pd1);
235
236 // level 2
237 mp_subcheck sc2 = mp_subcheck_init();
238 sc2.output = "baz";
239 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
240
241 mp_perfdata pd2 = perfdata_init();
242 pd2.uom = "B";
243 pd2.label = "baz";
244 pd2 = mp_set_pd_value(pd2, 1024);
245 mp_add_perfdata_to_subcheck(&sc2, pd2);
246
247 // level 3
248 mp_subcheck sc3 = mp_subcheck_init();
249 sc3.output = "level3";
250 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
251
252 mp_perfdata pd3 = perfdata_init();
253 pd3.label = "floatMe";
254 pd3 = mp_set_pd_value(pd3, 1024.1024);
255 mp_add_perfdata_to_subcheck(&sc3, pd3);
256
257 // level 4
258 mp_subcheck sc4 = mp_subcheck_init();
259 sc4.output = "level4";
260 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
261
262 mp_check check = mp_check_init();
263
264 mp_add_subcheck_to_subcheck(&sc3, sc4);
265 mp_add_subcheck_to_subcheck(&sc2, sc3);
266 mp_add_subcheck_to_subcheck(&sc1, sc2);
267 mp_add_subcheck_to_check(&check, sc1);
268
269 char *output = mp_fmt_output(check);
270
271 // diag("Formatted output of length: %i", strlen(output));
272 // diag(output);
273
274 ok(output != NULL, "Output should not be NULL");
275
276 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
277 "\t\\_[WARNING] - foobar\n"
278 "\t\t\\_[OK] - baz\n"
279 "\t\t\t\\_[OK] - level3\n"
280 "\t\t\t\t\\_[OK] - level4\n"
281 "|foo=23s;;; baz=1024B;;; floatMe=1024.102400;;; \n";
282
283 // diag("Expected output of length: %i", strlen(expected));
284 // diag(expected);
285
286 ok(strcmp(output, expected) == 0, "Output is as expected");
287}
288
289void test_default_states1(void) {
290 mp_subcheck sc = mp_subcheck_init();
291
292 mp_state_enum state1 = mp_compute_subcheck_state(sc);
293 ok(state1 == STATE_UNKNOWN, "Default default state is Unknown");
294
295 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
296
297 mp_state_enum state2 = mp_compute_subcheck_state(sc);
298 ok(state2 == STATE_CRITICAL, "Default state is Critical");
299
300 sc = mp_set_subcheck_state(sc, STATE_OK);
301
302 mp_state_enum state3 = mp_compute_subcheck_state(sc);
303 ok(state3 == STATE_OK, "Default state is Critical");
304}
305
306void test_default_states2(void) {
307 mp_check check = mp_check_init();
308
309 mp_subcheck sc = mp_subcheck_init();
310 sc.output = "placeholder";
311 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
312
313 mp_add_subcheck_to_check(&check, sc);
314
315 mp_state_enum result_state = mp_compute_check_state(check);
316 ok(result_state == STATE_CRITICAL, "Derived state is the proper default state");
317}
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..de983764 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,109 @@ 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';
47 }
48 48
49 return optstr; 49 return optstr;
50} 50}
51 51
52int 52int main(int argc, char **argv) {
53main (int argc, char **argv)
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 char *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"),
58 "config-tiny.ini's section as expected");
61 my_free(optstr); 59 my_free(optstr);
62 60
63 optstr=list2str(np_get_defaults("@./config-tiny.ini", "section")); 61 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"); 62 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"),
63 "Used default section name, without specific");
65 my_free(optstr); 64 my_free(optstr);
66 65
67 optstr=list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); 66 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"); 67 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"),
68 "config-tiny.ini's Section Two as expected");
69 my_free(optstr); 69 my_free(optstr);
70 70
71 optstr=list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk")); 71 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"); 72 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name");
73 my_free(optstr); 73 my_free(optstr);
74 74
75 optstr=list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk")); 75 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"); 76 ok(!strcmp(optstr, "--this=that"),
77 "config-tiny.ini's section2 with whitespace before section name");
77 my_free(optstr); 78 my_free(optstr);
78 79
79 optstr=list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk")); 80 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"); 81 ok(!strcmp(optstr, "--this=that"),
82 "config-tiny.ini's section3 with whitespace after section name");
81 my_free(optstr); 83 my_free(optstr);
82 84
83 optstr=list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); 85 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"); 86 ok(!strcmp(optstr, "--username=operator --password=secret"),
87 "plugin.ini's check_mysql as expected");
85 my_free(optstr); 88 my_free(optstr);
86 89
87 optstr=list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk")); 90 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"); 91 ok(!strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected");
89 my_free(optstr); 92 my_free(optstr);
90 93
91 optstr=list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk")); 94 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"); 95 ok(!strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments");
93 my_free(optstr); 96 my_free(optstr);
94 97
95 optstr=list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk")); 98 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"); 99 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"),
100 "config-dos.ini's Section Two as expected");
97 my_free(optstr); 101 my_free(optstr);
98 102
99 optstr=list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk")); 103 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"); 104 ok(!strcmp(optstr, "--foo=bar --bar=foo"),
105 "plugin.ini's section_twice defined twice in the file");
101 my_free(optstr); 106 my_free(optstr);
102 107
103 optstr=list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp")); 108 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"); 109 ok(!strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
110 "yadda Foo bar BAZ yadda yadda yadda Foo bar "
111 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
112 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar "
113 "BAZ yadda yadda yadda Foo bar BAZ yadda "
114 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
115 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
116 "yadda yadda Foo bar BAZ yadda yadda "
117 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
118 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
119 "yadda --expect=Foo bar BAZ yadda yadda "
120 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
121 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
122 "yadda Foo bar BAZ yadda yadda yadda Foo "
123 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
124 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar "
125 "BAZ yadda yadda yadda Foo bar BAZ yadda "
126 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
127 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
128 "yadda yadda Foo bar BAZ yadda yadda "
129 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
130 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
131 "yadda Foo bar BAZ yadda yadda yadda Foo "
132 "bar BAZ yadda yadda yadda --jail"),
133 "Long options");
105 my_free(optstr); 134 my_free(optstr);
106 135
107 return exit_status(); 136 return exit_status();
108} 137}
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..fa95c4d4 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,36 +40,41 @@ 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 bool freeflag = true;
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
47 printf ("'%s' ", newargv[i]); 47 for (int i = 1; i < *argc; i++) {
48 printf("'%s' ", newargv[i]);
48 /* Stop freeing when we get to the start of the original array */ 49 /* Stop freeing when we get to the start of the original array */
49 if (freeflag) { 50 if (freeflag) {
50 if (newargv[i] == argv[1]) 51 if (newargv[i] == argv[1]) {
51 freeflag=0; 52 freeflag = false;
52 else 53 } else {
53 free(newargv[i]); 54 free(newargv[i]);
55 }
54 } 56 }
55 } 57 }
56 printf ("\n"); 58 printf("\n");
57 /* Free only if it's a different array */ 59 /* Free only if it's a different array */
58 if (newargv != argv) free(newargv); 60 if (newargv != argv) {
59 *argc=0; 61 free(newargv);
62 }
63 *argc = 0;
60} 64}
61#endif 65#endif
62 66
63int array_diff(int i1, char **a1, int i2, char **a2) { 67int array_diff(int i1, char **a1, int i2, char **a2) {
64 int i;
65
66 if (i1 != i2) { 68 if (i1 != i2) {
67 printf(" Argument count doesn't match!\n"); 69 printf(" Argument count doesn't match!\n");
68 return 0; 70 return 0;
69 } 71 }
70 for (i=0; i<=i1; i++) { 72
71 if (a1[i]==NULL && a2[i]==NULL) continue; 73 for (int i = 0; i <= i1; i++) {
72 if (a1[i]==NULL || a2[i]==NULL) { 74 if (a1[i] == NULL && a2[i] == NULL) {
75 continue;
76 }
77 if (a1[i] == NULL || a2[i] == NULL) {
73 printf(" Argument # %i null in one array!\n", i); 78 printf(" Argument # %i null in one array!\n", i);
74 return 0; 79 return 0;
75 } 80 }
@@ -81,59 +86,66 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
81 return 1; 86 return 1;
82} 87}
83 88
84int 89int main(int argc, char **argv) {
85main (int argc, char **argv)
86{
87 char **argv_new=NULL;
88 int i, argc_test;
89
90 plan_tests(5); 90 plan_tests(5);
91 91
92 char **argv_new = NULL;
93 int argc_test;
92 { 94 {
93 char *argv_test[] = {"prog_name", (char *) NULL}; 95 char *argv_test[] = {"prog_name", (char *)NULL};
94 argc_test=1; 96 argc_test = 1;
95 char *argv_known[] = {"prog_name", (char *) NULL}; 97 char *argv_known[] = {"prog_name", (char *)NULL};
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 98 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"); 99 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); 100 my_free(&argc_test, argv_new, argv_test);
99 } 101 }
100 102
101 { 103 {
102 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 104 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
103 argc_test=5; 105 argc_test = 5;
104 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 106 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 107 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"); 108 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); 109 my_free(&argc_test, argv_new, argv_test);
108 } 110 }
109 111
110 { 112 {
111 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *) NULL}; 113 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *)NULL};
112 argc_test=2; 114 argc_test = 2;
113 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *) NULL}; 115 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank",
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 116 (char *)NULL};
117 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"); 118 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); 119 my_free(&argc_test, argv_new, argv_test);
117 } 120 }
118 121
119 { 122 {
120 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *) NULL}; 123 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts",
121 argc_test=4; 124 "sect2@./config-opts.ini", (char *)NULL};
122 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *) NULL}; 125 argc_test = 4;
123 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 126 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that",
127 (char *)NULL};
128 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"); 129 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice");
125 my_free(&argc_test, argv_new, argv_test); 130 my_free(&argc_test, argv_new, argv_test);
126 } 131 }
127 132
128 { 133 {
129 char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini", "--arg2", (char *) NULL}; 134 char *argv_test[] = {"prog_name",
130 argc_test=6; 135 "--arg1=val1",
131 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two", "--arg1=val1", "--arg2", (char *) NULL}; 136 "--extra-opts=@./config-opts.ini",
132 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 137 "--extra-opts",
138 "sect1@./config-opts.ini",
139 "--arg2",
140 (char *)NULL};
141 argc_test = 6;
142 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!",
143 "--blank", "--one=two", "--arg1=val1",
144 "--arg2", (char *)NULL};
145 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"); 146 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); 147 my_free(&argc_test, argv_new, argv_test);
135 } 148 }
136 149
137 return exit_status(); 150 return exit_status();
138} 151}
139
diff --git a/lib/tests/test_opts2.c b/lib/tests/test_opts2.c
index 780220ee..3dd1b039 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,35 +23,40 @@
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 bool freeflag = true;
27 printf (" Arg(%i): ", *argc+1); 27
28 printf ("'%s' ", newargv[0]); 28 printf(" Arg(%i): ", *argc + 1);
29 for (i=1; i<*argc; i++) { 29 printf("'%s' ", newargv[0]);
30 printf ("'%s' ", newargv[i]); 30 for (int i = 1; i < *argc; i++) {
31 printf("'%s' ", newargv[i]);
31 /* Stop freeing when we get to the start of the original array */ 32 /* Stop freeing when we get to the start of the original array */
32 if (freeflag) { 33 if (freeflag) {
33 if (newargv[i] == argv[1]) 34 if (newargv[i] == argv[1]) {
34 freeflag=0; 35 freeflag = false;
35 else 36 } else {
36 free(newargv[i]); 37 free(newargv[i]);
38 }
37 } 39 }
38 } 40 }
39 printf ("\n"); 41 printf("\n");
40 /* Free only if it's a different array */ 42 /* Free only if it's a different array */
41 if (newargv != argv) free(newargv); 43 if (newargv != argv) {
42 *argc=0; 44 free(newargv);
45 }
46 *argc = 0;
43} 47}
44 48
45int array_diff(int i1, char **a1, int i2, char **a2) { 49int array_diff(int i1, char **a1, int i2, char **a2) {
46 int i;
47
48 if (i1 != i2) { 50 if (i1 != i2) {
49 printf(" Argument count doesn't match!\n"); 51 printf(" Argument count doesn't match!\n");
50 return 0; 52 return 0;
51 } 53 }
52 for (i=0; i<=i1; i++) { 54
53 if (a1[i]==NULL && a2[i]==NULL) continue; 55 for (int i = 0; i <= i1; i++) {
54 if (a1[i]==NULL || a2[i]==NULL) { 56 if (a1[i] == NULL && a2[i] == NULL) {
57 continue;
58 }
59 if (a1[i] == NULL || a2[i] == NULL) {
55 printf(" Argument # %i null in one array!\n", i); 60 printf(" Argument # %i null in one array!\n", i);
56 return 0; 61 return 0;
57 } 62 }
@@ -63,59 +68,86 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
63 return 1; 68 return 1;
64} 69}
65 70
66int 71int main(int argc, char **argv) {
67main (int argc, char **argv)
68{
69 char **argv_new=NULL;
70 int i, argc_test;
71
72 plan_tests(5); 72 plan_tests(5);
73 73
74 char **argv_new = NULL;
75 int argc_test;
74 { 76 {
75 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *) NULL}; 77 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *)NULL};
76 argc_test=5; 78 argc_test = 5;
77 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *) NULL}; 79 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *)NULL};
78 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 80 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"); 81 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1");
80 my_free(&argc_test, argv_new, argv_test); 82 my_free(&argc_test, argv_new, argv_test);
81 } 83 }
82 84
83 { 85 {
84 char *argv_test[] = {"prog_name", "--extra-opts", (char *) NULL}; 86 char *argv_test[] = {"prog_name", "--extra-opts", (char *)NULL};
85 argc_test=2; 87 argc_test = 2;
86 char *argv_known[] = {"prog_name", "--foo=bar", (char *) NULL}; 88 char *argv_known[] = {"prog_name", "--foo=bar", (char *)NULL};
87 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 89 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"); 90 ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2");
89 my_free(&argc_test, argv_new, argv_test); 91 my_free(&argc_test, argv_new, argv_test);
90 } 92 }
91 93
92 { 94 {
93 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *) NULL}; 95 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1",
94 argc_test=5; 96 "--arg3", "val2", (char *)NULL};
95 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *) NULL}; 97 argc_test = 5;
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 98 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *)NULL};
99 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"); 100 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3");
98 my_free(&argc_test, argv_new, argv_test); 101 my_free(&argc_test, argv_new, argv_test);
99 } 102 }
100 103
101 { 104 {
102 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *) NULL}; 105 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *)NULL};
103 argc_test=5; 106 argc_test = 5;
104 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *) NULL}; 107 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 108 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"); 109 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4");
107 my_free(&argc_test, argv_new, argv_test); 110 my_free(&argc_test, argv_new, argv_test);
108 } 111 }
109 112
110 { 113 {
111 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *) NULL}; 114 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines",
112 argc_test=3; 115 (char *)NULL};
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}; 116 argc_test = 3;
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_tcp"); 117 char *argv_known[] = {"check_tcp",
118 "--timeout=10",
119 "--escape",
120 "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda "
121 "Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
122 "yadda Foo bar BAZ yadda "
123 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
124 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
125 "yadda Foo bar BAZ "
126 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
127 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
128 "yadda yadda Foo bar "
129 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
130 "yadda yadda yadda Foo bar BAZ yadda yadda yadda",
131 "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
132 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
133 "yadda Foo bar BAZ yadda "
134 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
135 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
136 "yadda Foo bar BAZ "
137 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
138 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
139 "yadda yadda Foo bar "
140 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
141 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
142 "yadda yadda yadda Foo "
143 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
144 "yadda yadda yadda Foo bar BAZ yadda yadda yadda",
145 "--jail",
146 (char *)NULL};
147 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"); 148 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test");
116 my_free(&argc_test, argv_new, argv_test); 149 my_free(&argc_test, argv_new, argv_test);
117 } 150 }
118 151
119 return exit_status(); 152 return exit_status();
120} 153}
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..37c818c9 100644
--- a/lib/tests/test_tcp.c
+++ b/lib/tests/test_tcp.c
@@ -1,58 +1,60 @@
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;
27 int server_expect_count = 3;
28
29 plan_tests(9); 24 plan_tests(9);
30 25
31 server_expect = malloc(sizeof(char*) * server_expect_count); 26 char **server_expect;
27 const int server_expect_count = 3;
28 server_expect = malloc(sizeof(char *) * server_expect_count);
32 29
33 server_expect[0] = strdup("AA"); 30 server_expect[0] = strdup("AA");
34 server_expect[1] = strdup("bb"); 31 server_expect[1] = strdup("bb");
35 server_expect[2] = strdup("CC"); 32 server_expect[2] = strdup("CC");
36 33
37 ok(np_expect_match("AA bb CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_SUCCESS, 34 ok(np_expect_match("AA bb CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
35 NP_MATCH_SUCCESS,
38 "Test matching any string at the beginning (first expect string)"); 36 "Test matching any string at the beginning (first expect string)");
39 ok(np_expect_match("bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_SUCCESS, 37 ok(np_expect_match("bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
38 NP_MATCH_SUCCESS,
40 "Test matching any string at the beginning (second expect string)"); 39 "Test matching any string at the beginning (second expect string)");
41 ok(np_expect_match("b", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_RETRY, 40 ok(np_expect_match("b", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_RETRY,
42 "Test matching any string at the beginning (substring match)"); 41 "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, 42 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
43 NP_MATCH_FAILURE,
44 "Test with strings not matching at the beginning"); 44 "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, 45 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
46 NP_MATCH_FAILURE,
46 "Test matching any string"); 47 "Test matching any string");
47 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY, 48 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY,
48 "Test not matching any string"); 49 "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, 50 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) ==
51 NP_MATCH_SUCCESS,
50 "Test matching all strings"); 52 "Test matching all strings");
51 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 53 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) ==
54 NP_MATCH_RETRY,
52 "Test not matching all strings"); 55 "Test not matching all strings");
53 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 56 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)"); 57 "Test not matching any string (testing all)");
55 58
56
57 return exit_status(); 59 return exit_status();
58} 60}
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c
index 01afacdc..8040dec8 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,484 +27,315 @@
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) 31 plan_tests(155);
32{
33 char state_path[1024];
34 range *range;
35 double temp;
36 thresholds *thresholds = NULL;
37 int i, rc;
38 char *temp_string;
39 state_key *temp_state_key = NULL;
40 state_data *temp_state_data;
41 time_t current_time;
42
43 plan_tests(185);
44 32
45 ok( this_monitoring_plugin==NULL, "monitoring_plugin not initialised"); 33 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised");
46 34
47 np_init( "check_test", argc, argv ); 35 np_init("check_test", argc, argv);
48 36
49 ok( this_monitoring_plugin!=NULL, "monitoring_plugin now initialised"); 37 ok(this_monitoring_plugin != NULL, "monitoring_plugin now initialised");
50 ok( !strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised" ); 38 ok(!strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised");
51 39
52 ok( this_monitoring_plugin->argc==argc, "Argc set" ); 40 ok(this_monitoring_plugin->argc == argc, "Argc set");
53 ok( this_monitoring_plugin->argv==argv, "Argv set" ); 41 ok(this_monitoring_plugin->argv == argv, "Argv set");
54 42
55 np_set_args(0,0); 43 np_set_args(0, 0);
56 44
57 ok( this_monitoring_plugin->argc==0, "argc changed" ); 45 ok(this_monitoring_plugin->argc == 0, "argc changed");
58 ok( this_monitoring_plugin->argv==0, "argv changed" ); 46 ok(this_monitoring_plugin->argv == 0, "argv changed");
59 47
60 np_set_args(argc, argv); 48 np_set_args(argc, argv);
61 49
62 range = parse_range_string("6"); 50 range *range = parse_range_string("6");
63 ok( range != NULL, "'6' is valid range"); 51 ok(range != NULL, "'6' is valid range");
64 ok( range->start == 0, "Start correct"); 52 ok(range->start == 0, "Start correct");
65 ok( range->start_infinity == false, "Not using negative infinity"); 53 ok(range->start_infinity == false, "Not using negative infinity");
66 ok( range->end == 6, "End correct"); 54 ok(range->end == 6, "End correct");
67 ok( range->end_infinity == false, "Not using infinity"); 55 ok(range->end_infinity == false, "Not using infinity");
68 free(range); 56 free(range);
69 57
70 range = parse_range_string("1:12%%"); 58 range = parse_range_string("1:12%%");
71 ok( range != NULL, "'1:12%%' is valid - percentages are ignored"); 59 ok(range != NULL, "'1:12%%' is valid - percentages are ignored");
72 ok( range->start == 1, "Start correct"); 60 ok(range->start == 1, "Start correct");
73 ok( range->start_infinity == false, "Not using negative infinity"); 61 ok(range->start_infinity == false, "Not using negative infinity");
74 ok( range->end == 12, "End correct"); 62 ok(range->end == 12, "End correct");
75 ok( range->end_infinity == false, "Not using infinity"); 63 ok(range->end_infinity == false, "Not using infinity");
76 free(range); 64 free(range);
77 65
78 range = parse_range_string("-7:23"); 66 range = parse_range_string("-7:23");
79 ok( range != NULL, "'-7:23' is valid range"); 67 ok(range != NULL, "'-7:23' is valid range");
80 ok( range->start == -7, "Start correct"); 68 ok(range->start == -7, "Start correct");
81 ok( range->start_infinity == false, "Not using negative infinity"); 69 ok(range->start_infinity == false, "Not using negative infinity");
82 ok( range->end == 23, "End correct"); 70 ok(range->end == 23, "End correct");
83 ok( range->end_infinity == false, "Not using infinity"); 71 ok(range->end_infinity == false, "Not using infinity");
84 free(range); 72 free(range);
85 73
86 range = parse_range_string(":5.75"); 74 range = parse_range_string(":5.75");
87 ok( range != NULL, "':5.75' is valid range"); 75 ok(range != NULL, "':5.75' is valid range");
88 ok( range->start == 0, "Start correct"); 76 ok(range->start == 0, "Start correct");
89 ok( range->start_infinity == false, "Not using negative infinity"); 77 ok(range->start_infinity == false, "Not using negative infinity");
90 ok( range->end == 5.75, "End correct"); 78 ok(range->end == 5.75, "End correct");
91 ok( range->end_infinity == false, "Not using infinity"); 79 ok(range->end_infinity == false, "Not using infinity");
92 free(range); 80 free(range);
93 81
94 range = parse_range_string("~:-95.99"); 82 range = parse_range_string("~:-95.99");
95 ok( range != NULL, "~:-95.99' is valid range"); 83 ok(range != NULL, "~:-95.99' is valid range");
96 ok( range->start_infinity == true, "Using negative infinity"); 84 ok(range->start_infinity == true, "Using negative infinity");
97 ok( range->end == -95.99, "End correct (with rounding errors)"); 85 ok(range->end == -95.99, "End correct (with rounding errors)");
98 ok( range->end_infinity == false, "Not using infinity"); 86 ok(range->end_infinity == false, "Not using infinity");
99 free(range); 87 free(range);
100 88
101 range = parse_range_string("12345678901234567890:"); 89 range = parse_range_string("12345678901234567890:");
102 temp = atof("12345678901234567890"); /* Can't just use this because number too large */ 90 double temp = atof("12345678901234567890"); /* Can't just use this because number too large */
103 ok( range != NULL, "'12345678901234567890:' is valid range"); 91 ok(range != NULL, "'12345678901234567890:' is valid range");
104 ok( range->start == temp, "Start correct"); 92 ok(range->start == temp, "Start correct");
105 ok( range->start_infinity == false, "Not using negative infinity"); 93 ok(range->start_infinity == false, "Not using negative infinity");
106 ok( range->end_infinity == true, "Using infinity"); 94 ok(range->end_infinity == true, "Using infinity");
107 /* Cannot do a "-1" on temp, as it appears to be same value */ 95 /* 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"); 96 ok(check_range(temp / 1.1, range) == true, "12345678901234567890/1.1 - alert");
109 ok( check_range(temp, range) == false, "12345678901234567890 - no alert"); 97 ok(check_range(temp, range) == false, "12345678901234567890 - no alert");
110 ok( check_range(temp*2, range) == false, "12345678901234567890*2 - no alert"); 98 ok(check_range(temp * 2, range) == false, "12345678901234567890*2 - no alert");
111 free(range); 99 free(range);
112 100
113 range = parse_range_string("~:0"); 101 range = parse_range_string("~:0");
114 ok( range != NULL, "'~:0' is valid range"); 102 ok(range != NULL, "'~:0' is valid range");
115 ok( range->start_infinity == true, "Using negative infinity"); 103 ok(range->start_infinity == true, "Using negative infinity");
116 ok( range->end == 0, "End correct"); 104 ok(range->end == 0, "End correct");
117 ok( range->end_infinity == false, "Not using infinity"); 105 ok(range->end_infinity == false, "Not using infinity");
118 ok( range->alert_on == OUTSIDE, "Will alert on outside of this range"); 106 ok(range->alert_on == OUTSIDE, "Will alert on outside of this range");
119 ok( check_range(0.5, range) == true, "0.5 - alert"); 107 ok(check_range(0.5, range) == true, "0.5 - alert");
120 ok( check_range(-10, range) == false, "-10 - no alert"); 108 ok(check_range(-10, range) == false, "-10 - no alert");
121 ok( check_range(0, range) == false, "0 - no alert"); 109 ok(check_range(0, range) == false, "0 - no alert");
122 free(range); 110 free(range);
123 111
124 range = parse_range_string("@0:657.8210567"); 112 range = parse_range_string("@0:657.8210567");
125 ok( range != 0, "@0:657.8210567' is a valid range"); 113 ok(range != 0, "@0:657.8210567' is a valid range");
126 ok( range->start == 0, "Start correct"); 114 ok(range->start == 0, "Start correct");
127 ok( range->start_infinity == false, "Not using negative infinity"); 115 ok(range->start_infinity == false, "Not using negative infinity");
128 ok( range->end == 657.8210567, "End correct"); 116 ok(range->end == 657.8210567, "End correct");
129 ok( range->end_infinity == false, "Not using infinity"); 117 ok(range->end_infinity == false, "Not using infinity");
130 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 118 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
131 ok( check_range(32.88, range) == true, "32.88 - alert"); 119 ok(check_range(32.88, range) == true, "32.88 - alert");
132 ok( check_range(-2, range) == false, "-2 - no alert"); 120 ok(check_range(-2, range) == false, "-2 - no alert");
133 ok( check_range(657.8210567, range) == true, "657.8210567 - alert"); 121 ok(check_range(657.8210567, range) == true, "657.8210567 - alert");
134 ok( check_range(0, range) == true, "0 - alert"); 122 ok(check_range(0, range) == true, "0 - alert");
135 free(range); 123 free(range);
136 124
137 range = parse_range_string("@1:1"); 125 range = parse_range_string("@1:1");
138 ok( range != NULL, "'@1:1' is a valid range"); 126 ok(range != NULL, "'@1:1' is a valid range");
139 ok( range->start == 1, "Start correct"); 127 ok(range->start == 1, "Start correct");
140 ok( range->start_infinity == false, "Not using negative infinity"); 128 ok(range->start_infinity == false, "Not using negative infinity");
141 ok( range->end == 1, "End correct"); 129 ok(range->end == 1, "End correct");
142 ok( range->end_infinity == false, "Not using infinity"); 130 ok(range->end_infinity == false, "Not using infinity");
143 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 131 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
144 ok( check_range(0.5, range) == false, "0.5 - no alert"); 132 ok(check_range(0.5, range) == false, "0.5 - no alert");
145 ok( check_range(1, range) == true, "1 - alert"); 133 ok(check_range(1, range) == true, "1 - alert");
146 ok( check_range(5.2, range) == false, "5.2 - no alert"); 134 ok(check_range(5.2, range) == false, "5.2 - no alert");
147 free(range); 135 free(range);
148 136
149 range = parse_range_string("1:1"); 137 range = parse_range_string("1:1");
150 ok( range != NULL, "'1:1' is a valid range"); 138 ok(range != NULL, "'1:1' is a valid range");
151 ok( range->start == 1, "Start correct"); 139 ok(range->start == 1, "Start correct");
152 ok( range->start_infinity == false, "Not using negative infinity"); 140 ok(range->start_infinity == false, "Not using negative infinity");
153 ok( range->end == 1, "End correct"); 141 ok(range->end == 1, "End correct");
154 ok( range->end_infinity == false, "Not using infinity"); 142 ok(range->end_infinity == false, "Not using infinity");
155 ok( check_range(0.5, range) == true, "0.5 - alert"); 143 ok(check_range(0.5, range) == true, "0.5 - alert");
156 ok( check_range(1, range) == false, "1 - no alert"); 144 ok(check_range(1, range) == false, "1 - no alert");
157 ok( check_range(5.2, range) == true, "5.2 - alert"); 145 ok(check_range(5.2, range) == true, "5.2 - alert");
158 free(range); 146 free(range);
159 147
160 range = parse_range_string("2:1"); 148 range = parse_range_string("2:1");
161 ok( range == NULL, "'2:1' rejected"); 149 ok(range == NULL, "'2:1' rejected");
162 150
163 rc = _set_thresholds(&thresholds, NULL, NULL); 151 thresholds *thresholds = NULL;
164 ok( rc == 0, "Thresholds (NULL, NULL) set"); 152 int returnCode;
165 ok( thresholds->warning == NULL, "Warning not set"); 153 returnCode = _set_thresholds(&thresholds, NULL, NULL);
166 ok( thresholds->critical == NULL, "Critical not set"); 154 ok(returnCode == 0, "Thresholds (NULL, NULL) set");
167 155 ok(thresholds->warning == NULL, "Warning not set");
168 rc = _set_thresholds(&thresholds, NULL, "80"); 156 ok(thresholds->critical == NULL, "Critical not set");
169 ok( rc == 0, "Thresholds (NULL, '80') set"); 157
170 ok( thresholds->warning == NULL, "Warning not set"); 158 returnCode = _set_thresholds(&thresholds, NULL, "80");
171 ok( thresholds->critical->end == 80, "Critical set correctly"); 159 ok(returnCode == 0, "Thresholds (NULL, '80') set");
172 160 ok(thresholds->warning == NULL, "Warning not set");
173 rc = _set_thresholds(&thresholds, "5:33", NULL); 161 ok(thresholds->critical->end == 80, "Critical set correctly");
174 ok( rc == 0, "Thresholds ('5:33', NULL) set"); 162
175 ok( thresholds->warning->start == 5, "Warning start set"); 163 returnCode = _set_thresholds(&thresholds, "5:33", NULL);
176 ok( thresholds->warning->end == 33, "Warning end set"); 164 ok(returnCode == 0, "Thresholds ('5:33', NULL) set");
177 ok( thresholds->critical == NULL, "Critical not set"); 165 ok(thresholds->warning->start == 5, "Warning start set");
178 166 ok(thresholds->warning->end == 33, "Warning end set");
179 rc = _set_thresholds(&thresholds, "30", "60"); 167 ok(thresholds->critical == NULL, "Critical not set");
180 ok( rc == 0, "Thresholds ('30', '60') set"); 168
181 ok( thresholds->warning->end == 30, "Warning set correctly"); 169 returnCode = _set_thresholds(&thresholds, "30", "60");
182 ok( thresholds->critical->end == 60, "Critical set correctly"); 170 ok(returnCode == 0, "Thresholds ('30', '60') set");
183 ok( get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); 171 ok(thresholds->warning->end == 30, "Warning set correctly");
184 ok( get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); 172 ok(thresholds->critical->end == 60, "Critical set correctly");
185 ok( get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); 173 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok");
186 174 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning");
187 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); 175 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical");
188 ok( rc == 0, "Thresholds ('-30:20', '-10:-2') set"); 176
189 ok( thresholds->warning->start == -10, "Warning start set correctly"); 177 returnCode = _set_thresholds(&thresholds, "-10:-2", "-30:20");
190 ok( thresholds->warning->end == -2, "Warning end set correctly"); 178 ok(returnCode == 0, "Thresholds ('-30:20', '-10:-2') set");
191 ok( thresholds->critical->start == -30, "Critical start set correctly"); 179 ok(thresholds->warning->start == -10, "Warning start set correctly");
192 ok( thresholds->critical->end == 20, "Critical end set correctly"); 180 ok(thresholds->warning->end == -2, "Warning end set correctly");
193 ok( get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical"); 181 ok(thresholds->critical->start == -30, "Critical start set correctly");
194 ok( get_status(-29, thresholds) == STATE_WARNING, "-29 - warning"); 182 ok(thresholds->critical->end == 20, "Critical end set correctly");
195 ok( get_status(-11, thresholds) == STATE_WARNING, "-11 - warning"); 183 ok(get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical");
196 ok( get_status(-10, thresholds) == STATE_OK, "-10 - ok"); 184 ok(get_status(-29, thresholds) == STATE_WARNING, "-29 - warning");
197 ok( get_status(-2, thresholds) == STATE_OK, "-2 - ok"); 185 ok(get_status(-11, thresholds) == STATE_WARNING, "-11 - warning");
198 ok( get_status(-1, thresholds) == STATE_WARNING, "-1 - warning"); 186 ok(get_status(-10, thresholds) == STATE_OK, "-10 - ok");
199 ok( get_status(19, thresholds) == STATE_WARNING, "19 - warning"); 187 ok(get_status(-2, thresholds) == STATE_OK, "-2 - ok");
200 ok( get_status(21, thresholds) == STATE_CRITICAL, "21 - critical"); 188 ok(get_status(-1, thresholds) == STATE_WARNING, "-1 - warning");
189 ok(get_status(19, thresholds) == STATE_WARNING, "19 - warning");
190 ok(get_status(21, thresholds) == STATE_CRITICAL, "21 - critical");
201 191
202 char *test; 192 char *test;
203 test = np_escaped_string("bob\\n"); 193 test = np_escaped_string("bob\\n");
204 ok( strcmp(test, "bob\n") == 0, "bob\\n ok"); 194 ok(strcmp(test, "bob\n") == 0, "bob\\n ok");
205 free(test); 195 free(test);
206 196
207 test = np_escaped_string("rhuba\\rb"); 197 test = np_escaped_string("rhuba\\rb");
208 ok( strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay"); 198 ok(strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay");
209 free(test); 199 free(test);
210 200
211 test = np_escaped_string("ba\\nge\\r"); 201 test = np_escaped_string("ba\\nge\\r");
212 ok( strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay"); 202 ok(strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay");
213 free(test); 203 free(test);
214 204
215 test = np_escaped_string("\\rabbi\\t"); 205 test = np_escaped_string("\\rabbi\\t");
216 ok( strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay"); 206 ok(strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay");
217 free(test); 207 free(test);
218 208
219 test = np_escaped_string("and\\\\or"); 209 test = np_escaped_string("and\\\\or");
220 ok( strcmp(test, "and\\or") == 0, "and\\\\or okay"); 210 ok(strcmp(test, "and\\or") == 0, "and\\\\or okay");
221 free(test); 211 free(test);
222 212
223 test = np_escaped_string("bo\\gus"); 213 test = np_escaped_string("bo\\gus");
224 ok( strcmp(test, "bogus") == 0, "bo\\gus okay"); 214 ok(strcmp(test, "bogus") == 0, "bo\\gus okay");
225 free(test); 215 free(test);
226 216
227 test = np_escaped_string("everything"); 217 test = np_escaped_string("everything");
228 ok( strcmp(test, "everything") == 0, "everything okay"); 218 ok(strcmp(test, "everything") == 0, "everything okay");
229 219
230 /* np_extract_ntpvar tests (23) */ 220 /* np_extract_ntpvar tests (23) */
231 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo"); 221 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo");
232 ok(test && !strcmp(test, "bar"), "1st test as expected"); 222 ok(test && !strcmp(test, "bar"), "1st test as expected");
233 free(test); 223 free(test);
234 224
235 test=np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar"); 225 test = np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar");
236 ok(test && !strcmp(test, "foo"), "2nd test as expected"); 226 ok(test && !strcmp(test, "foo"), "2nd test as expected");
237 free(test); 227 free(test);
238 228
239 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar"); 229 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar");
240 ok(test && !strcmp(test, "barfoo"), "3rd test as expected"); 230 ok(test && !strcmp(test, "barfoo"), "3rd test as expected");
241 free(test); 231 free(test);
242 232
243 test=np_extract_ntpvar("foo=bar\n", "foo"); 233 test = np_extract_ntpvar("foo=bar\n", "foo");
244 ok(test && !strcmp(test, "bar"), "Single test as expected"); 234 ok(test && !strcmp(test, "bar"), "Single test as expected");
245 free(test); 235 free(test);
246 236
247 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd"); 237 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd");
248 ok(!test, "Key not found 1"); 238 ok(!test, "Key not found 1");
249 239
250 test=np_extract_ntpvar("foo=bar\n", "abcd"); 240 test = np_extract_ntpvar("foo=bar\n", "abcd");
251 ok(!test, "Key not found 2"); 241 ok(!test, "Key not found 2");
252 242
253 test=np_extract_ntpvar("foo=bar=foobar", "foo"); 243 test = np_extract_ntpvar("foo=bar=foobar", "foo");
254 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1"); 244 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1");
255 free(test); 245 free(test);
256 246
257 test=np_extract_ntpvar("foo", "foo"); 247 test = np_extract_ntpvar("foo", "foo");
258 ok(!test, "Malformed string 1"); 248 ok(!test, "Malformed string 1");
259 249
260 test=np_extract_ntpvar("foo,", "foo"); 250 test = np_extract_ntpvar("foo,", "foo");
261 ok(!test, "Malformed string 2"); 251 ok(!test, "Malformed string 2");
262 252
263 test=np_extract_ntpvar("foo=", "foo"); 253 test = np_extract_ntpvar("foo=", "foo");
264 ok(!test, "Malformed string 3"); 254 ok(!test, "Malformed string 3");
265 255
266 test=np_extract_ntpvar("foo=,bar=foo", "foo"); 256 test = np_extract_ntpvar("foo=,bar=foo", "foo");
267 ok(!test, "Malformed string 4"); 257 ok(!test, "Malformed string 4");
268 258
269 test=np_extract_ntpvar(",foo", "foo"); 259 test = np_extract_ntpvar(",foo", "foo");
270 ok(!test, "Malformed string 5"); 260 ok(!test, "Malformed string 5");
271 261
272 test=np_extract_ntpvar("=foo", "foo"); 262 test = np_extract_ntpvar("=foo", "foo");
273 ok(!test, "Malformed string 6"); 263 ok(!test, "Malformed string 6");
274 264
275 test=np_extract_ntpvar("=foo,", "foo"); 265 test = np_extract_ntpvar("=foo,", "foo");
276 ok(!test, "Malformed string 7"); 266 ok(!test, "Malformed string 7");
277 267
278 test=np_extract_ntpvar(",,,", "foo"); 268 test = np_extract_ntpvar(",,,", "foo");
279 ok(!test, "Malformed string 8"); 269 ok(!test, "Malformed string 8");
280 270
281 test=np_extract_ntpvar("===", "foo"); 271 test = np_extract_ntpvar("===", "foo");
282 ok(!test, "Malformed string 9"); 272 ok(!test, "Malformed string 9");
283 273
284 test=np_extract_ntpvar(",=,=,", "foo"); 274 test = np_extract_ntpvar(",=,=,", "foo");
285 ok(!test, "Malformed string 10"); 275 ok(!test, "Malformed string 10");
286 276
287 test=np_extract_ntpvar("=,=,=", "foo"); 277 test = np_extract_ntpvar("=,=,=", "foo");
288 ok(!test, "Malformed string 11"); 278 ok(!test, "Malformed string 11");
289 279
290 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo"); 280 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"); 281 ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1");
292 free(test); 282 free(test);
293 283
294 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar"); 284 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"); 285 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2");
296 free(test); 286 free(test);
297 287
298 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar"); 288 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"); 289 ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3");
300 free(test); 290 free(test);
301 291
302 test=np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar"); 292 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"); 293 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4");
304 free(test); 294 free(test);
305 295
306 test=np_extract_ntpvar("", "foo"); 296 test = np_extract_ntpvar("", "foo");
307 ok(!test, "Empty string return NULL"); 297 ok(!test, "Empty string return NULL");
308 298
309
310 /* This is the result of running ./test_utils */
311 temp_string = (char *) _np_state_generate_key();
312 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" );
314
315
316 this_monitoring_plugin->argc=4;
317 this_monitoring_plugin->argv[0] = "./test_utils";
318 this_monitoring_plugin->argv[1] = "here";
319 this_monitoring_plugin->argv[2] = "--and";
320 this_monitoring_plugin->argv[3] = "now";
321 temp_string = (char *) _np_state_generate_key();
322 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv" );
323
324 unsetenv("MP_STATE_PATH");
325 temp_string = (char *) _np_state_calculate_location_prefix();
326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory" );
327
328 setenv("MP_STATE_PATH", "", 1);
329 temp_string = (char *) _np_state_calculate_location_prefix();
330 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string" );
331
332 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
333 temp_string = (char *) _np_state_calculate_location_prefix();
334 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory" );
335
336
337
338 ok(temp_state_key==NULL, "temp_state_key initially empty");
339
340 this_monitoring_plugin->argc=1;
341 this_monitoring_plugin->argv[0] = "./test_utils";
342 np_enable_state(NULL, 51);
343 temp_state_key = this_monitoring_plugin->state;
344 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" );
345 ok( !strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename" );
346
347
348 np_enable_state("allowedchars_in_keyname", 77);
349 temp_state_key = this_monitoring_plugin->state;
350 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" );
352 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" );
354
355
356 /* Don't do this test just yet. Will die */
357 /*
358 np_enable_state("bad^chars$in@here", 77);
359 temp_state_key = this_monitoring_plugin->state;
360 ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced" );
361 */
362
363 np_enable_state("funnykeyname", 54);
364 temp_state_key = this_monitoring_plugin->state;
365 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" );
367 ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" );
368
369
370
371 ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" );
372 ok( temp_state_key->data_version==54, "Version set" );
373
374 temp_state_data = np_state_read();
375 ok( temp_state_data==NULL, "Got no state data as file does not exist" );
376
377
378/*
379 temp_fp = fopen("var/statefile", "r");
380 if (temp_fp==NULL)
381 printf("Error opening. errno=%d\n", errno);
382 printf("temp_fp=%s\n", temp_fp);
383 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
384 fclose(temp_fp);
385*/
386
387 temp_state_key->_filename="var/statefile";
388 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");
390 ok( this_monitoring_plugin->state->state_data->time==1234567890, "Got time" );
391 ok( !strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected" );
392
393 temp_state_key->data_version=53;
394 temp_state_data = np_state_read();
395 ok( temp_state_data==NULL, "Older data version gives NULL" );
396 temp_state_key->data_version=54;
397
398 temp_state_key->_filename="var/nonexistent";
399 temp_state_data = np_state_read();
400 ok( temp_state_data==NULL, "Missing file gives NULL" );
401 ok( this_monitoring_plugin->state->state_data==NULL, "No state information" );
402
403 temp_state_key->_filename="var/oldformat";
404 temp_state_data = np_state_read();
405 ok( temp_state_data==NULL, "Old file format gives NULL" );
406
407 temp_state_key->_filename="var/baddate";
408 temp_state_data = np_state_read();
409 ok( temp_state_data==NULL, "Bad date gives NULL" );
410
411 temp_state_key->_filename="var/missingdataline";
412 temp_state_data = np_state_read();
413 ok( temp_state_data==NULL, "Missing data line gives NULL" );
414
415
416
417
418 unlink("var/generated");
419 temp_state_key->_filename="var/generated";
420 current_time=1234567890;
421 np_state_write_string(current_time, "String to read");
422 ok(system("cmp var/generated var/statefile")==0, "Generated file same as expected");
423
424
425
426
427 unlink("var/generated_directory/statefile");
428 unlink("var/generated_directory");
429 temp_state_key->_filename="var/generated_directory/statefile";
430 current_time=1234567890;
431 np_state_write_string(current_time, "String to read");
432 ok(system("cmp var/generated_directory/statefile var/statefile")==0, "Have created directory");
433
434 /* This test to check cannot write to dir - can't automate yet */
435 /*
436 unlink("var/generated_bad_dir");
437 mkdir("var/generated_bad_dir", S_IRUSR);
438 np_state_write_string(current_time, "String to read");
439 */
440
441
442 temp_state_key->_filename="var/generated";
443 time(&current_time);
444 np_state_write_string(0, "String to read");
445 temp_state_data = np_state_read();
446 /* 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");
448 ok(this_monitoring_plugin->state->state_data->time-current_time<=1, "Has time generated from current time");
449
450
451 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */
452 /*
453 temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write";
454 np_state_write_string(0, "Bad file");
455 */
456
457
458 np_cleanup();
459
460 ok(this_monitoring_plugin==NULL, "Free'd this_monitoring_plugin");
461
462 ok(mp_suid() == false, "Test aren't suid"); 299 ok(mp_suid() == false, "Test aren't suid");
463 300
464 /* base states with random case */ 301 /* base states with random case */
465 char *states[] = { 302 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL};
466 "Ok", 303
467 "wArnINg", 304 for (int i = 0; states[i] != NULL; i++) {
468 "cRiTIcaL", 305 /* out of the random case states, create the lower and upper versions + numeric string one
469 "UnKNoWN", 306 */
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 */
475 char *statelower = strdup(states[i]); 307 char *statelower = strdup(states[i]);
476 char *stateupper = strdup(states[i]); 308 char *stateupper = strdup(states[i]);
477 char statenum[2]; 309 char statenum[2];
478 char *temp_ptr; 310 for (char *temp_ptr = statelower; *temp_ptr; temp_ptr++) {
479 for (temp_ptr = statelower; *temp_ptr; temp_ptr++) { 311 *temp_ptr = (char)tolower(*temp_ptr);
480 *temp_ptr = tolower(*temp_ptr);
481 } 312 }
482 for (temp_ptr = stateupper; *temp_ptr; temp_ptr++) { 313 for (char *temp_ptr = stateupper; *temp_ptr; temp_ptr++) {
483 *temp_ptr = toupper(*temp_ptr); 314 *temp_ptr = (char)toupper(*temp_ptr);
484 } 315 }
485 snprintf(statenum, 2, "%i", i); 316 snprintf(statenum, 2, "%i", i);
486 317
487 /* Base test names, we'll append the state string */ 318 /* Base test names, we'll append the state string */
488 char testname[64] = "Translate state string: "; 319 char testname[64] = "Translate state string: ";
489 int tlen = strlen(testname); 320 size_t tlen = strlen(testname);
490 321
491 strcpy(testname+tlen, states[i]); 322 strcpy(testname + tlen, states[i]);
492 ok(i==mp_translate_state(states[i]), testname); 323 ok(i == mp_translate_state(states[i]), testname);
493 324
494 strcpy(testname+tlen, statelower); 325 strcpy(testname + tlen, statelower);
495 ok(i==mp_translate_state(statelower), testname); 326 ok(i == mp_translate_state(statelower), testname);
496 327
497 strcpy(testname+tlen, stateupper); 328 strcpy(testname + tlen, stateupper);
498 ok(i==mp_translate_state(stateupper), testname); 329 ok(i == mp_translate_state(stateupper), testname);
499 330
500 strcpy(testname+tlen, statenum); 331 strcpy(testname + tlen, statenum);
501 ok(i==mp_translate_state(statenum), testname); 332 ok(i == mp_translate_state(statenum), testname);
502 } 333 }
503 ok(ERROR==mp_translate_state("warningfewgw"), "Translate state string with garbage"); 334 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"); 335 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"); 336 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"); 337 ok(ERROR == mp_translate_state("10"), "Translate state string: bad numeric string 3");
507 ok(ERROR==mp_translate_state(""), "Translate state string: empty string"); 338 ok(ERROR == mp_translate_state(""), "Translate state string: empty string");
508 339
509 return exit_status(); 340 return exit_status();
510} 341}
diff --git a/lib/thresholds.c b/lib/thresholds.c
new file mode 100644
index 00000000..de2b9315
--- /dev/null
+++ b/lib/thresholds.c
@@ -0,0 +1,71 @@
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_WARNING;
55 }
56 }
57
58 return STATE_OK;
59}
60
61mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn) {
62 thlds.warning = warn;
63 thlds.warning_is_set = true;
64 return thlds;
65}
66
67mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit) {
68 thlds.critical = crit;
69 thlds.critical_is_set = true;
70 return thlds;
71}
diff --git a/lib/thresholds.h b/lib/thresholds.h
new file mode 100644
index 00000000..f8647681
--- /dev/null
+++ b/lib/thresholds.h
@@ -0,0 +1,31 @@
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 {
10 range *warning;
11 range *critical;
12} thresholds;
13
14typedef 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
27mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn);
28mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit);
29
30char *fmt_threshold_warning(thresholds th);
31char *fmt_threshold_critical(thresholds th);
diff --git a/lib/utils_base.c b/lib/utils_base.c
index f8592f41..28e6dc47 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -1,30 +1,31 @@
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 "states.h"
28#include <stdarg.h> 29#include <stdarg.h>
29#include "utils_base.h" 30#include "utils_base.h"
30#include <ctype.h> 31#include <ctype.h>
@@ -33,94 +34,87 @@
33#include <unistd.h> 34#include <unistd.h>
34#include <sys/types.h> 35#include <sys/types.h>
35 36
36#define np_free(ptr) { if(ptr) { free(ptr); ptr = NULL; } } 37#define np_free(ptr) \
38 { \
39 if (ptr) { \
40 free(ptr); \
41 ptr = NULL; \
42 } \
43 }
37 44
38monitoring_plugin *this_monitoring_plugin=NULL; 45monitoring_plugin *this_monitoring_plugin = NULL;
39 46
40int timeout_state = STATE_CRITICAL; 47mp_state_enum timeout_state = STATE_CRITICAL;
41unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; 48unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
42 49
43bool _np_state_read_file(FILE *); 50bool _np_state_read_file(FILE *state_file);
44 51
45void np_init( char *plugin_name, int argc, char **argv ) { 52void np_init(char *plugin_name, int argc, char **argv) {
46 if (this_monitoring_plugin==NULL) { 53 if (this_monitoring_plugin == NULL) {
47 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin)); 54 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin));
48 if (this_monitoring_plugin==NULL) { 55 if (this_monitoring_plugin == NULL) {
49 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 56 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
50 strerror(errno));
51 } 57 }
52 this_monitoring_plugin->plugin_name = strdup(plugin_name); 58 this_monitoring_plugin->plugin_name = strdup(plugin_name);
53 if (this_monitoring_plugin->plugin_name==NULL) 59 if (this_monitoring_plugin->plugin_name == NULL) {
54 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 60 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
61 }
55 this_monitoring_plugin->argc = argc; 62 this_monitoring_plugin->argc = argc;
56 this_monitoring_plugin->argv = argv; 63 this_monitoring_plugin->argv = argv;
57 } 64 }
58} 65}
59 66
60void np_set_args( int argc, char **argv ) { 67void np_set_args(int argc, char **argv) {
61 if (this_monitoring_plugin==NULL) 68 if (this_monitoring_plugin == NULL) {
62 die(STATE_UNKNOWN, _("This requires np_init to be called")); 69 die(STATE_UNKNOWN, _("This requires np_init to be called"));
70 }
63 71
64 this_monitoring_plugin->argc = argc; 72 this_monitoring_plugin->argc = argc;
65 this_monitoring_plugin->argv = argv; 73 this_monitoring_plugin->argv = argv;
66} 74}
67 75
68 76void np_cleanup(void) {
69void np_cleanup() { 77 if (this_monitoring_plugin != NULL) {
70 if (this_monitoring_plugin!=NULL) {
71 if(this_monitoring_plugin->state!=NULL) {
72 if(this_monitoring_plugin->state->state_data) {
73 np_free(this_monitoring_plugin->state->state_data->data);
74 np_free(this_monitoring_plugin->state->state_data);
75 }
76 np_free(this_monitoring_plugin->state->name);
77 np_free(this_monitoring_plugin->state);
78 }
79 np_free(this_monitoring_plugin->plugin_name); 78 np_free(this_monitoring_plugin->plugin_name);
80 np_free(this_monitoring_plugin); 79 np_free(this_monitoring_plugin);
81 } 80 }
82 this_monitoring_plugin=NULL; 81 this_monitoring_plugin = NULL;
83} 82}
84 83
85/* Hidden function to get a pointer to this_monitoring_plugin for testing */ 84/* Hidden function to get a pointer to this_monitoring_plugin for testing */
86void _get_monitoring_plugin( monitoring_plugin **pointer ){ 85void _get_monitoring_plugin(monitoring_plugin **pointer) { *pointer = this_monitoring_plugin; }
87 *pointer = this_monitoring_plugin;
88}
89 86
90void 87void die(int result, const char *fmt, ...) {
91die (int result, const char *fmt, ...) 88 if (fmt != NULL) {
92{
93 if(fmt!=NULL) {
94 va_list ap; 89 va_list ap;
95 va_start (ap, fmt); 90 va_start(ap, fmt);
96 vprintf (fmt, ap); 91 vprintf(fmt, ap);
97 va_end (ap); 92 va_end(ap);
98 } 93 }
99 94
100 if(this_monitoring_plugin!=NULL) { 95 if (this_monitoring_plugin != NULL) {
101 np_cleanup(); 96 np_cleanup();
102 } 97 }
103 exit (result); 98 exit(result);
104} 99}
105 100
106void set_range_start (range *this, double value) { 101void set_range_start(range *this, double value) {
107 this->start = value; 102 this->start = value;
108 this->start_infinity = false; 103 this->start_infinity = false;
109} 104}
110 105
111void set_range_end (range *this, double value) { 106void set_range_end(range *this, double value) {
112 this->end = value; 107 this->end = value;
113 this->end_infinity = false; 108 this->end_infinity = false;
114} 109}
115 110
116range 111range *parse_range_string(char *str) {
117*parse_range_string (char *str) {
118 range *temp_range; 112 range *temp_range;
119 double start; 113 double start;
120 double end; 114 double end;
121 char *end_str; 115 char *end_str;
122 116
123 temp_range = (range *) calloc(1, sizeof(range)); 117 temp_range = (range *)calloc(1, sizeof(range));
124 118
125 /* Set defaults */ 119 /* Set defaults */
126 temp_range->start = 0; 120 temp_range->start = 0;
@@ -140,10 +134,10 @@ range
140 if (str[0] == '~') { 134 if (str[0] == '~') {
141 temp_range->start_infinity = true; 135 temp_range->start_infinity = true;
142 } else { 136 } else {
143 start = strtod(str, NULL); /* Will stop at the ':' */ 137 start = strtod(str, NULL); /* Will stop at the ':' */
144 set_range_start(temp_range, start); 138 set_range_start(temp_range, start);
145 } 139 }
146 end_str++; /* Move past the ':' */ 140 end_str++; /* Move past the ':' */
147 } else { 141 } else {
148 end_str = str; 142 end_str = str;
149 } 143 }
@@ -152,8 +146,7 @@ range
152 set_range_end(temp_range, end); 146 set_range_end(temp_range, end);
153 } 147 }
154 148
155 if (temp_range->start_infinity == true || 149 if (temp_range->start_infinity || temp_range->end_infinity ||
156 temp_range->end_infinity == true ||
157 temp_range->start <= temp_range->end) { 150 temp_range->start <= temp_range->end) {
158 return temp_range; 151 return temp_range;
159 } 152 }
@@ -162,14 +155,12 @@ range
162} 155}
163 156
164/* returns 0 if okay, otherwise 1 */ 157/* returns 0 if okay, otherwise 1 */
165int 158int _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; 159 thresholds *temp_thresholds = NULL;
169 160
170 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) 161 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) {
171 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 162 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
172 strerror(errno)); 163 }
173 164
174 temp_thresholds->warning = NULL; 165 temp_thresholds->warning = NULL;
175 temp_thresholds->critical = NULL; 166 temp_thresholds->critical = NULL;
@@ -190,9 +181,7 @@ _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_st
190 return 0; 181 return 0;
191} 182}
192 183
193void 184void 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)) { 185 switch (_set_thresholds(my_thresholds, warn_string, critical_string)) {
197 case 0: 186 case 0:
198 return; 187 return;
@@ -206,16 +195,18 @@ set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_str
206 195
207void print_thresholds(const char *threshold_name, thresholds *my_threshold) { 196void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
208 printf("%s - ", threshold_name); 197 printf("%s - ", threshold_name);
209 if (! my_threshold) { 198 if (!my_threshold) {
210 printf("Threshold not set"); 199 printf("Threshold not set");
211 } else { 200 } else {
212 if (my_threshold->warning) { 201 if (my_threshold->warning) {
213 printf("Warning: start=%g end=%g; ", my_threshold->warning->start, my_threshold->warning->end); 202 printf("Warning: start=%g end=%g; ", my_threshold->warning->start,
203 my_threshold->warning->end);
214 } else { 204 } else {
215 printf("Warning not set; "); 205 printf("Warning not set; ");
216 } 206 }
217 if (my_threshold->critical) { 207 if (my_threshold->critical) {
218 printf("Critical: start=%g end=%g", my_threshold->critical->start, my_threshold->critical->end); 208 printf("Critical: start=%g end=%g", my_threshold->critical->start,
209 my_threshold->critical->end);
219 } else { 210 } else {
220 printf("Critical not set"); 211 printf("Critical not set");
221 } 212 }
@@ -223,9 +214,38 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
223 printf("\n"); 214 printf("\n");
224} 215}
225 216
217/* Returns true if alert should be raised based on the range, false otherwise */
218bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
219 bool is_inside = false;
220
221 if (!my_range.end_infinity && !my_range.start_infinity) {
222 // range: .........|---inside---|...........
223 // value
224 is_inside = ((cmp_perfdata_value(value, my_range.start) >= 0) &&
225 (cmp_perfdata_value(value, my_range.end) <= 0));
226 } else if (!my_range.start_infinity && my_range.end_infinity) {
227 // range: .........|---inside---------
228 // value
229 is_inside = (cmp_perfdata_value(value, my_range.start) >= 0);
230 } else if (my_range.start_infinity && !my_range.end_infinity) {
231 // range: -inside--------|....................
232 // value
233 is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
234 } else {
235 // range from -inf to inf, so always inside
236 is_inside = true;
237 }
238
239 if ((is_inside && my_range.alert_on_inside_range == INSIDE) ||
240 (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
241 return true;
242 }
243
244 return false;
245}
246
226/* Returns true if alert should be raised based on the range */ 247/* Returns true if alert should be raised based on the range */
227bool check_range(double value, range *my_range) 248bool check_range(double value, range *my_range) {
228{
229 bool no = false; 249 bool no = false;
230 bool yes = true; 250 bool yes = true;
231 251
@@ -234,73 +254,71 @@ bool check_range(double value, range *my_range)
234 yes = false; 254 yes = false;
235 } 255 }
236 256
237 if (my_range->end_infinity == false && my_range->start_infinity == false) { 257 if (!my_range->end_infinity && !my_range->start_infinity) {
238 if ((my_range->start <= value) && (value <= my_range->end)) { 258 if ((my_range->start <= value) && (value <= my_range->end)) {
239 return no; 259 return no;
240 } else {
241 return yes;
242 } 260 }
243 } else if (my_range->start_infinity == false && my_range->end_infinity == true) { 261 return yes;
262 }
263
264 if (!my_range->start_infinity && my_range->end_infinity) {
244 if (my_range->start <= value) { 265 if (my_range->start <= value) {
245 return no; 266 return no;
246 } else {
247 return yes;
248 } 267 }
249 } else if (my_range->start_infinity == true && my_range->end_infinity == false) { 268 return yes;
269 }
270
271 if (my_range->start_infinity && !my_range->end_infinity) {
250 if (value <= my_range->end) { 272 if (value <= my_range->end) {
251 return no; 273 return no;
252 } else {
253 return yes;
254 } 274 }
255 } else { 275 return yes;
256 return no;
257 } 276 }
277 return no;
258} 278}
259 279
260/* Returns status */ 280/* Returns status */
261int 281mp_state_enum get_status(double value, thresholds *my_thresholds) {
262get_status(double value, thresholds *my_thresholds)
263{
264 if (my_thresholds->critical != NULL) { 282 if (my_thresholds->critical != NULL) {
265 if (check_range(value, my_thresholds->critical) == true) { 283 if (check_range(value, my_thresholds->critical)) {
266 return STATE_CRITICAL; 284 return STATE_CRITICAL;
267 } 285 }
268 } 286 }
269 if (my_thresholds->warning != NULL) { 287 if (my_thresholds->warning != NULL) {
270 if (check_range(value, my_thresholds->warning) == true) { 288 if (check_range(value, my_thresholds->warning)) {
271 return STATE_WARNING; 289 return STATE_WARNING;
272 } 290 }
273 } 291 }
274 return STATE_OK; 292 return STATE_OK;
275} 293}
276 294
277char *np_escaped_string (const char *string) { 295char *np_escaped_string(const char *string) {
278 char *data; 296 char *data;
279 int i, j=0; 297 int write_index = 0;
280 data = strdup(string); 298 data = strdup(string);
281 for (i=0; data[i]; i++) { 299 for (int i = 0; data[i]; i++) {
282 if (data[i] == '\\') { 300 if (data[i] == '\\') {
283 switch(data[++i]) { 301 switch (data[++i]) {
284 case 'n': 302 case 'n':
285 data[j++] = '\n'; 303 data[write_index++] = '\n';
286 break; 304 break;
287 case 'r': 305 case 'r':
288 data[j++] = '\r'; 306 data[write_index++] = '\r';
289 break; 307 break;
290 case 't': 308 case 't':
291 data[j++] = '\t'; 309 data[write_index++] = '\t';
292 break; 310 break;
293 case '\\': 311 case '\\':
294 data[j++] = '\\'; 312 data[write_index++] = '\\';
295 break; 313 break;
296 default: 314 default:
297 data[j++] = data[i]; 315 data[write_index++] = data[i];
298 } 316 }
299 } else { 317 } else {
300 data[j++] = data[i]; 318 data[write_index++] = data[i];
301 } 319 }
302 } 320 }
303 data[j] = '\0'; 321 data[write_index] = '\0';
304 return data; 322 return data;
305} 323}
306 324
@@ -313,33 +331,43 @@ int np_check_if_root(void) { return (geteuid() == 0); }
313 * data strings. 331 * data strings.
314 */ 332 */
315char *np_extract_value(const char *varlist, const char *name, char sep) { 333char *np_extract_value(const char *varlist, const char *name, char sep) {
316 char *tmp=NULL, *value=NULL; 334 char *tmp = NULL;
317 int i; 335 char *value = NULL;
318 336
319 while (1) { 337 while (true) {
320 /* Strip any leading space */ 338 /* Strip any leading space */
321 for (; isspace(varlist[0]); varlist++); 339 for (; isspace(varlist[0]); varlist++) {
340 ;
341 }
322 342
323 if (strncmp(name, varlist, strlen(name)) == 0) { 343 if (strncmp(name, varlist, strlen(name)) == 0) {
324 varlist += strlen(name); 344 varlist += strlen(name);
325 /* strip trailing spaces */ 345 /* strip trailing spaces */
326 for (; isspace(varlist[0]); varlist++); 346 for (; isspace(varlist[0]); varlist++) {
347 ;
348 }
327 349
328 if (varlist[0] == '=') { 350 if (varlist[0] == '=') {
329 /* We matched the key, go past the = sign */ 351 /* We matched the key, go past the = sign */
330 varlist++; 352 varlist++;
331 /* strip leading spaces */ 353 /* strip leading spaces */
332 for (; isspace(varlist[0]); varlist++); 354 for (; isspace(varlist[0]); varlist++) {
355 ;
356 }
333 357
334 if ((tmp = index(varlist, sep))) { 358 if ((tmp = index(varlist, sep))) {
335 /* Value is delimited by a comma */ 359 /* Value is delimited by a comma */
336 if (tmp-varlist == 0) continue; 360 if (tmp - varlist == 0) {
337 value = (char *)calloc(1, tmp-varlist+1); 361 continue;
338 strncpy(value, varlist, tmp-varlist); 362 }
339 value[tmp-varlist] = '\0'; 363 value = (char *)calloc(1, (unsigned long)(tmp - varlist + 1));
364 strncpy(value, varlist, (unsigned long)(tmp - varlist));
365 value[tmp - varlist] = '\0';
340 } else { 366 } else {
341 /* Value is delimited by a \0 */ 367 /* Value is delimited by a \0 */
342 if (strlen(varlist) == 0) continue; 368 if (strlen(varlist) == 0) {
369 continue;
370 }
343 value = (char *)calloc(1, strlen(varlist) + 1); 371 value = (char *)calloc(1, strlen(varlist) + 1);
344 strncpy(value, varlist, strlen(varlist)); 372 strncpy(value, varlist, strlen(varlist));
345 value[strlen(varlist)] = '\0'; 373 value[strlen(varlist)] = '\0';
@@ -357,14 +385,16 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
357 } 385 }
358 386
359 /* Clean-up trailing spaces/newlines */ 387 /* Clean-up trailing spaces/newlines */
360 if (value) for (i=strlen(value)-1; isspace(value[i]); i--) value[i] = '\0'; 388 if (value) {
389 for (unsigned long i = strlen(value) - 1; isspace(value[i]); i--) {
390 value[i] = '\0';
391 }
392 }
361 393
362 return value; 394 return value;
363} 395}
364 396
365const char * 397const char *state_text(mp_state_enum result) {
366state_text (int result)
367{
368 switch (result) { 398 switch (result) {
369 case STATE_OK: 399 case STATE_OK:
370 return "OK"; 400 return "OK";
@@ -383,345 +413,18 @@ state_text (int result)
383 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 413 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
384 * return the corresponding STATE_ value or ERROR) 414 * return the corresponding STATE_ value or ERROR)
385 */ 415 */
386int mp_translate_state (char *state_text) { 416int mp_translate_state(char *state_text) {
387 if (!strcasecmp(state_text,"OK") || !strcmp(state_text,"0")) 417 if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) {
388 return STATE_OK; 418 return STATE_OK;
389 if (!strcasecmp(state_text,"WARNING") || !strcmp(state_text,"1"))
390 return STATE_WARNING;
391 if (!strcasecmp(state_text,"CRITICAL") || !strcmp(state_text,"2"))
392 return STATE_CRITICAL;
393 if (!strcasecmp(state_text,"UNKNOWN") || !strcmp(state_text,"3"))
394 return STATE_UNKNOWN;
395 return ERROR;
396}
397
398/*
399 * Returns a string to use as a keyname, based on an md5 hash of argv, thus
400 * hopefully a unique key per service/plugin invocation. Use the extra-opts
401 * parse of argv, so that uniqueness in parameters are reflected there.
402 */
403char *_np_state_generate_key() {
404 int i;
405 char **argv = this_monitoring_plugin->argv;
406 char keyname[41];
407 char *p=NULL;
408
409 unsigned char result[256];
410
411#ifdef USE_OPENSSL
412 /*
413 * This code path is chosen if openssl is available (which should be the most common
414 * scenario). Alternatively, the gnulib implementation/
415 *
416 */
417 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
418
419 EVP_DigestInit(ctx, EVP_sha256());
420
421 for(i=0; i<this_monitoring_plugin->argc; i++) {
422 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
423 }
424
425 EVP_DigestFinal(ctx, result, NULL);
426#else
427
428 struct sha256_ctx ctx;
429
430 for(i=0; i<this_monitoring_plugin->argc; i++) {
431 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
432 }
433
434 sha256_finish_ctx(&ctx, result);
435#endif // FOUNDOPENSSL
436
437 for (i=0; i<20; ++i) {
438 sprintf(&keyname[2*i], "%02x", result[i]);
439 } 419 }
440 420 if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1")) {
441 keyname[40]='\0'; 421 return STATE_WARNING;
442
443 p = strdup(keyname);
444 if(p==NULL) {
445 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
446 }
447 return p;
448}
449
450void _cleanup_state_data() {
451 if (this_monitoring_plugin->state->state_data!=NULL) {
452 np_free(this_monitoring_plugin->state->state_data->data);
453 np_free(this_monitoring_plugin->state->state_data);
454 }
455}
456
457/*
458 * Internal function. Returns either:
459 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
460 * statically compiled shared state directory
461 */
462char* _np_state_calculate_location_prefix(){
463 char *env_dir;
464
465 /* Do not allow passing MP_STATE_PATH in setuid plugins
466 * for security reasons */
467 if (!mp_suid()) {
468 env_dir = getenv("MP_STATE_PATH");
469 if(env_dir && env_dir[0] != '\0')
470 return env_dir;
471 /* This is the former ENV, for backward-compatibility */
472 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
473 if(env_dir && env_dir[0] != '\0')
474 return env_dir;
475 }
476
477 return NP_STATE_DIR_PREFIX;
478}
479
480/*
481 * Initiatializer for state routines.
482 * Sets variables. Generates filename. Returns np_state_key. die with
483 * UNKNOWN if exception
484 */
485void np_enable_state(char *keyname, int expected_data_version) {
486 state_key *this_state = NULL;
487 char *temp_filename = NULL;
488 char *temp_keyname = NULL;
489 char *p=NULL;
490 int ret;
491
492 if(this_monitoring_plugin==NULL)
493 die(STATE_UNKNOWN, _("This requires np_init to be called"));
494
495 this_state = (state_key *) calloc(1, sizeof(state_key));
496 if(this_state==NULL)
497 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
498 strerror(errno));
499
500 if(keyname==NULL) {
501 temp_keyname = _np_state_generate_key();
502 } else {
503 temp_keyname = strdup(keyname);
504 if(temp_keyname==NULL)
505 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
506 }
507 /* Die if invalid characters used for keyname */
508 p = temp_keyname;
509 while(*p!='\0') {
510 if(! (isalnum(*p) || *p == '_')) {
511 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
512 }
513 p++;
514 }
515 this_state->name=temp_keyname;
516 this_state->plugin_name=this_monitoring_plugin->plugin_name;
517 this_state->data_version=expected_data_version;
518 this_state->state_data=NULL;
519
520 /* Calculate filename */
521 ret = asprintf(&temp_filename, "%s/%lu/%s/%s",
522 _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
523 this_monitoring_plugin->plugin_name, this_state->name);
524 if (ret < 0)
525 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
526 strerror(errno));
527
528 this_state->_filename=temp_filename;
529
530 this_monitoring_plugin->state = this_state;
531}
532
533/*
534 * Will return NULL if no data is available (first run). If key currently
535 * exists, read data. If state file format version is not expected, return
536 * as if no data. Get state data version number and compares to expected.
537 * If numerically lower, then return as no previous state. die with UNKNOWN
538 * if exceptional error.
539 */
540state_data *np_state_read() {
541 state_data *this_state_data=NULL;
542 FILE *statefile;
543 bool rc = false;
544
545 if(this_monitoring_plugin==NULL)
546 die(STATE_UNKNOWN, _("This requires np_init to be called"));
547
548 /* Open file. If this fails, no previous state found */
549 statefile = fopen( this_monitoring_plugin->state->_filename, "r" );
550 if(statefile!=NULL) {
551
552 this_state_data = (state_data *) calloc(1, sizeof(state_data));
553 if(this_state_data==NULL)
554 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
555 strerror(errno));
556
557 this_state_data->data=NULL;
558 this_monitoring_plugin->state->state_data = this_state_data;
559
560 rc = _np_state_read_file(statefile);
561
562 fclose(statefile);
563 }
564
565 if(!rc) {
566 _cleanup_state_data();
567 }
568
569 return this_monitoring_plugin->state->state_data;
570}
571
572/*
573 * Read the state file
574 */
575bool _np_state_read_file(FILE *f) {
576 bool status = false;
577 size_t pos;
578 char *line;
579 int i;
580 int failure=0;
581 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;
583
584 time(&current_time);
585
586 /* Note: This introduces a limit of 1024 bytes in the string data */
587 line = (char *) calloc(1, 1024);
588 if(line==NULL)
589 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
590 strerror(errno));
591
592 while(!failure && (fgets(line,1024,f))!=NULL){
593 pos=strlen(line);
594 if(line[pos-1]=='\n') {
595 line[pos-1]='\0';
596 }
597
598 if(line[0] == '#') continue;
599
600 switch(expected) {
601 case STATE_FILE_VERSION:
602 i=atoi(line);
603 if(i!=NP_STATE_FORMAT_VERSION)
604 failure++;
605 else
606 expected=STATE_DATA_VERSION;
607 break;
608 case STATE_DATA_VERSION:
609 i=atoi(line);
610 if(i != this_monitoring_plugin->state->data_version)
611 failure++;
612 else
613 expected=STATE_DATA_TIME;
614 break;
615 case STATE_DATA_TIME:
616 /* If time > now, error */
617 data_time=strtoul(line,NULL,10);
618 if(data_time > current_time)
619 failure++;
620 else {
621 this_monitoring_plugin->state->state_data->time = data_time;
622 expected=STATE_DATA_TEXT;
623 }
624 break;
625 case STATE_DATA_TEXT:
626 this_monitoring_plugin->state->state_data->data = strdup(line);
627 if(this_monitoring_plugin->state->state_data->data==NULL)
628 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
629 expected=STATE_DATA_END;
630 status=true;
631 break;
632 case STATE_DATA_END:
633 ;
634 }
635 }
636
637 np_free(line);
638 return status;
639}
640
641/*
642 * If time=NULL, use current time. Create state file, with state format
643 * version, default text. Writes version, time, and data. Avoid locking
644 * problems - use mv to write and then swap. Possible loss of state data if
645 * two things writing to same key at same time.
646 * Will die with UNKNOWN if errors
647 */
648void np_state_write_string(time_t data_time, char *data_string) {
649 FILE *fp;
650 char *temp_file=NULL;
651 int fd=0, result=0;
652 time_t current_time;
653 char *directories=NULL;
654 char *p=NULL;
655
656 if(data_time==0)
657 time(&current_time);
658 else
659 current_time=data_time;
660
661 /* If file doesn't currently exist, create directories */
662 if(access(this_monitoring_plugin->state->_filename,F_OK)!=0) {
663 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
664 if(result < 0)
665 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
666 strerror(errno));
667
668 for(p=directories+1; *p; p++) {
669 if(*p=='/') {
670 *p='\0';
671 if((access(directories,F_OK)!=0) && (mkdir(directories, S_IRWXU)!=0)) {
672 /* Can't free this! Otherwise error message is wrong! */
673 /* np_free(directories); */
674 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
675 }
676 *p='/';
677 }
678 }
679 np_free(directories);
680 }
681
682 result = asprintf(&temp_file,"%s.XXXXXX",this_monitoring_plugin->state->_filename);
683 if(result < 0)
684 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
685 strerror(errno));
686
687 if((fd=mkstemp(temp_file))==-1) {
688 np_free(temp_file);
689 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
690 }
691
692 fp=(FILE *)fdopen(fd,"w");
693 if(fp==NULL) {
694 close(fd);
695 unlink(temp_file);
696 np_free(temp_file);
697 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
698 } 422 }
699 423 if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2")) {
700 fprintf(fp,"# NP State file\n"); 424 return STATE_CRITICAL;
701 fprintf(fp,"%d\n",NP_STATE_FORMAT_VERSION);
702 fprintf(fp,"%d\n",this_monitoring_plugin->state->data_version);
703 fprintf(fp,"%lu\n",current_time);
704 fprintf(fp,"%s\n",data_string);
705
706 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
707
708 fflush(fp);
709
710 result=fclose(fp);
711
712 fsync(fd);
713
714 if(result!=0) {
715 unlink(temp_file);
716 np_free(temp_file);
717 die(STATE_UNKNOWN, _("Error writing temp file"));
718 } 425 }
719 426 if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3")) {
720 if(rename(temp_file, this_monitoring_plugin->state->_filename)!=0) { 427 return STATE_UNKNOWN;
721 unlink(temp_file);
722 np_free(temp_file);
723 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
724 } 428 }
725 429 return ERROR;
726 np_free(temp_file);
727} 430}
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 9d4dffed..27884bf0 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#include "states.h"
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,65 +26,34 @@
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
37
38typedef struct state_data_struct {
39 time_t time;
40 void *data;
41 int length; /* Of binary data */
42 } state_data;
43
44
45typedef struct state_key_struct {
46 char *name;
47 char *plugin_name;
48 int data_version;
49 char *_filename;
50 state_data *state_data;
51 } state_key;
52
53typedef struct np_struct { 29typedef struct np_struct {
54 char *plugin_name; 30 char *plugin_name;
55 state_key *state; 31 int argc;
56 int argc; 32 char **argv;
57 char **argv; 33} monitoring_plugin;
58 } monitoring_plugin;
59 34
60range *parse_range_string (char *); 35range *parse_range_string(char *);
61int _set_thresholds(thresholds **, char *, char *); 36int _set_thresholds(thresholds **, char *, char *);
62void set_thresholds(thresholds **, char *, char *); 37void set_thresholds(thresholds **, char *, char *);
63void print_thresholds(const char *, thresholds *); 38void print_thresholds(const char *, thresholds *);
64bool check_range(double, range *); 39bool check_range(double, range *);
65int get_status(double, thresholds *); 40bool mp_check_range(mp_perfdata_value, mp_range);
41mp_state_enum get_status(double, thresholds *);
66 42
67/* Handle timeouts */ 43/* Handle timeouts */
68extern int timeout_state; 44extern mp_state_enum timeout_state;
69extern unsigned int timeout_interval; 45extern unsigned int timeout_interval;
70 46
71/* All possible characters in a threshold range */ 47/* All possible characters in a threshold range */
72#define NP_THRESHOLDS_CHARS "-0123456789.:@~" 48#define NP_THRESHOLDS_CHARS "-0123456789.:@~"
73 49
74char *np_escaped_string (const char *); 50char *np_escaped_string(const char *);
75 51
76void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); 52void die(int, const char *, ...) __attribute__((noreturn, format(printf, 2, 3)));
77 53
78/* Return codes for _set_thresholds */ 54/* Return codes for _set_thresholds */
79#define NP_RANGE_UNPARSEABLE 1 55#define NP_RANGE_UNPARSEABLE 1
80#define NP_WARN_WITHIN_CRIT 2 56#define NP_WARN_WITHIN_CRIT 2
81 57
82/* a simple check to see if we're running as root. 58/* a simple check to see if we're running as root.
83 * returns zero on failure, nonzero on success */ 59 * returns zero on failure, nonzero on success */
@@ -93,7 +69,7 @@ int np_check_if_root(void);
93 * This function can be used to parse NTP control packet data and performance 69 * This function can be used to parse NTP control packet data and performance
94 * data strings. 70 * data strings.
95 */ 71 */
96char *np_extract_value(const char*, const char*, char); 72char *np_extract_value(const char *, const char *, char);
97 73
98/* 74/*
99 * Same as np_extract_value with separator suitable for NTP control packet 75 * Same as np_extract_value with separator suitable for NTP control packet
@@ -105,15 +81,11 @@ char *np_extract_value(const char*, const char*, char);
105 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 81 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
106 * return the corresponding NP_STATE or ERROR) 82 * return the corresponding NP_STATE or ERROR)
107 */ 83 */
108int mp_translate_state (char *); 84int mp_translate_state(char *);
109
110void np_enable_state(char *, int);
111state_data *np_state_read();
112void np_state_write_string(time_t, char *);
113 85
114void np_init(char *, int argc, char **argv); 86void np_init(char *, int argc, char **argv);
115void np_set_args(int argc, char **argv); 87void np_set_args(int argc, char **argv);
116void np_cleanup(); 88void np_cleanup(void);
117const char *state_text (int); 89const char *state_text(mp_state_enum);
118 90
119#endif /* _UTILS_BASE_ */ 91#endif /* _UTILS_BASE_ */
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c
index 7957ec14..35b83297 100644
--- a/lib/utils_cmd.c
+++ b/lib/utils_cmd.c
@@ -1,46 +1,45 @@
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
41/** includes **/ 41/** includes **/
42#include "common.h" 42#include "common.h"
43#include "utils.h"
44#include "utils_cmd.h" 43#include "utils_cmd.h"
45/* This variable must be global, since there's no way the caller 44/* This variable must be global, since there's no way the caller
46 * can forcibly slay a dead or ungainly running program otherwise. 45 * can forcibly slay a dead or ungainly running program otherwise.
@@ -59,115 +58,106 @@ static pid_t *_cmd_pids = NULL;
59#include <fcntl.h> 58#include <fcntl.h>
60 59
61#ifdef HAVE_SYS_WAIT_H 60#ifdef HAVE_SYS_WAIT_H
62# include <sys/wait.h> 61# include <sys/wait.h>
63#endif 62#endif
64 63
65/* used in _cmd_open to pass the environment to commands */
66extern char **environ;
67
68/** macros **/ 64/** macros **/
69#ifndef WEXITSTATUS 65#ifndef WEXITSTATUS
70# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 66# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
71#endif 67#endif
72 68
73#ifndef WIFEXITED 69#ifndef WIFEXITED
74# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 70# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
75#endif 71#endif
76 72
77/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 73/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
78#if defined(SIG_IGN) && !defined(SIG_ERR) 74#if defined(SIG_IGN) && !defined(SIG_ERR)
79# define SIG_ERR ((Sigfunc *)-1) 75# define SIG_ERR ((Sigfunc *)-1)
80#endif 76#endif
81 77
82/** prototypes **/ 78/** prototypes **/
83static int _cmd_open (char *const *, int *, int *) 79static int _cmd_open(char *const *argv, int *pfd, int *pfderr)
84 __attribute__ ((__nonnull__ (1, 2, 3))); 80 __attribute__((__nonnull__(1, 2, 3)));
85
86static int _cmd_fetch_output (int, output *, int)
87 __attribute__ ((__nonnull__ (2)));
88 81
89static int _cmd_close (int); 82static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) __attribute__((__nonnull__(2)));
90
91/* prototype imported from utils.h */
92extern void die (int, const char *, ...)
93 __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
94 83
84static int _cmd_close(int fileDescriptor);
95 85
96/* this function is NOT async-safe. It is exported so multithreaded 86/* this function is NOT async-safe. It is exported so multithreaded
97 * plugins (or other apps) can call it prior to running any commands 87 * plugins (or other apps) can call it prior to running any commands
98 * through this api and thus achieve async-safeness throughout the api */ 88 * through this api and thus achieve async-safeness throughout the api */
99void 89void cmd_init(void) {
100cmd_init (void)
101{
102 long maxfd = mp_open_max(); 90 long maxfd = mp_open_max();
103 91
104 /* if maxfd is unnaturally high, we force it to a lower value 92 /* 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 93 * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause
106 * a segfault when following calloc is called ... ) */ 94 * a segfault when following calloc is called ... ) */
107 95
108 if ( maxfd > MAXFD_LIMIT ) { 96 if (maxfd > MAXFD_LIMIT) {
109 maxfd = MAXFD_LIMIT; 97 maxfd = MAXFD_LIMIT;
110 } 98 }
111 99
112 if (!_cmd_pids) 100 if (!_cmd_pids) {
113 _cmd_pids = calloc (maxfd, sizeof (pid_t)); 101 _cmd_pids = calloc(maxfd, sizeof(pid_t));
102 }
114} 103}
115 104
116
117/* Start running a command, array style */ 105/* Start running a command, array style */
118static int 106static 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;
122#ifdef RLIMIT_CORE 107#ifdef RLIMIT_CORE
123 struct rlimit limit; 108 struct rlimit limit;
124#endif 109#endif
125 110
126 int i = 0; 111 int i = 0;
127 112
128 if (!_cmd_pids) 113 if (!_cmd_pids) {
129 CMD_INIT; 114 CMD_INIT;
115 }
130 116
131 setenv("LC_ALL", "C", 1); 117 setenv("LC_ALL", "C", 1);
132 118
133 if (pipe (pfd) < 0 || pipe (pfderr) < 0 || (pid = fork ()) < 0) 119 pid_t pid;
134 return -1; /* errno set by the failing function */ 120 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) {
121 return -1; /* errno set by the failing function */
122 }
135 123
136 /* child runs exceve() and _exit. */ 124 /* child runs exceve() and _exit. */
137 if (pid == 0) { 125 if (pid == 0) {
138#ifdef RLIMIT_CORE 126#ifdef RLIMIT_CORE
139 /* the program we execve shouldn't leave core files */ 127 /* the program we execve shouldn't leave core files */
140 getrlimit (RLIMIT_CORE, &limit); 128 getrlimit(RLIMIT_CORE, &limit);
141 limit.rlim_cur = 0; 129 limit.rlim_cur = 0;
142 setrlimit (RLIMIT_CORE, &limit); 130 setrlimit(RLIMIT_CORE, &limit);
143#endif 131#endif
144 close (pfd[0]); 132 close(pfd[0]);
145 if (pfd[1] != STDOUT_FILENO) { 133 if (pfd[1] != STDOUT_FILENO) {
146 dup2 (pfd[1], STDOUT_FILENO); 134 dup2(pfd[1], STDOUT_FILENO);
147 close (pfd[1]); 135 close(pfd[1]);
148 } 136 }
149 close (pfderr[0]); 137 close(pfderr[0]);
150 if (pfderr[1] != STDERR_FILENO) { 138 if (pfderr[1] != STDERR_FILENO) {
151 dup2 (pfderr[1], STDERR_FILENO); 139 dup2(pfderr[1], STDERR_FILENO);
152 close (pfderr[1]); 140 close(pfderr[1]);
153 } 141 }
154 142
155 /* close all descriptors in _cmd_pids[] 143 /* close all descriptors in _cmd_pids[]
156 * This is executed in a separate address space (pure child), 144 * This is executed in a separate address space (pure child),
157 * so we don't have to worry about async safety */ 145 * so we don't have to worry about async safety */
158 long maxfd = mp_open_max(); 146 long maxfd = mp_open_max();
159 for (i = 0; i < maxfd; i++) 147 for (i = 0; i < maxfd; i++) {
160 if (_cmd_pids[i] > 0) 148 if (_cmd_pids[i] > 0) {
161 close (i); 149 close(i);
150 }
151 }
162 152
163 execve (argv[0], argv, environ); 153 execve(argv[0], argv, environ);
164 _exit (STATE_UNKNOWN); 154 _exit(STATE_UNKNOWN);
165 } 155 }
166 156
167 /* parent picks up execution here */ 157 /* parent picks up execution here */
168 /* close children descriptors in our address space */ 158 /* close children descriptors in our address space */
169 close (pfd[1]); 159 close(pfd[1]);
170 close (pfderr[1]); 160 close(pfderr[1]);
171 161
172 /* tag our file's entry in the pid-list and return it */ 162 /* tag our file's entry in the pid-list and return it */
173 _cmd_pids[pfd[0]] = pid; 163 _cmd_pids[pfd[0]] = pid;
@@ -175,93 +165,94 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
175 return pfd[0]; 165 return pfd[0];
176} 166}
177 167
178static int 168static int _cmd_close(int fileDescriptor) {
179_cmd_close (int fd)
180{
181 int status;
182 pid_t pid; 169 pid_t pid;
183 170
184 /* make sure the provided fd was opened */ 171 /* make sure the provided fd was opened */
185 long maxfd = mp_open_max(); 172 long maxfd = mp_open_max();
186 if (fd < 0 || fd > maxfd || !_cmd_pids || (pid = _cmd_pids[fd]) == 0) 173 if (fileDescriptor < 0 || fileDescriptor > maxfd || !_cmd_pids ||
174 (pid = _cmd_pids[fileDescriptor]) == 0) {
187 return -1; 175 return -1;
176 }
188 177
189 _cmd_pids[fd] = 0; 178 _cmd_pids[fileDescriptor] = 0;
190 if (close (fd) == -1) 179 if (close(fileDescriptor) == -1) {
191 return -1; 180 return -1;
181 }
192 182
193 /* EINTR is ok (sort of), everything else is bad */ 183 /* EINTR is ok (sort of), everything else is bad */
194 while (waitpid (pid, &status, 0) < 0) 184 int status;
195 if (errno != EINTR) 185 while (waitpid(pid, &status, 0) < 0) {
186 if (errno != EINTR) {
196 return -1; 187 return -1;
188 }
189 }
197 190
198 /* return child's termination status */ 191 /* return child's termination status */
199 return (WIFEXITED (status)) ? WEXITSTATUS (status) : -1; 192 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
200} 193}
201 194
202 195static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) {
203static int
204_cmd_fetch_output (int fd, output * op, int flags)
205{
206 size_t len = 0, i = 0, lineno = 0;
207 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
208 char *buf = NULL;
209 int ret;
210 char tmpbuf[4096]; 196 char tmpbuf[4096];
211 197 cmd_output->buf = NULL;
212 op->buf = NULL; 198 cmd_output->buflen = 0;
213 op->buflen = 0; 199 ssize_t ret;
214 while ((ret = read (fd, tmpbuf, sizeof (tmpbuf))) > 0) { 200 while ((ret = read(fileDescriptor, tmpbuf, sizeof(tmpbuf))) > 0) {
215 len = (size_t) ret; 201 size_t len = (size_t)ret;
216 op->buf = realloc (op->buf, op->buflen + len + 1); 202 cmd_output->buf = realloc(cmd_output->buf, cmd_output->buflen + len + 1);
217 memcpy (op->buf + op->buflen, tmpbuf, len); 203 memcpy(cmd_output->buf + cmd_output->buflen, tmpbuf, len);
218 op->buflen += len; 204 cmd_output->buflen += len;
219 i++;
220 } 205 }
221 206
222 if (ret < 0) { 207 if (ret < 0) {
223 printf ("read() returned %d: %s\n", ret, strerror (errno)); 208 printf("read() returned %zd: %s\n", ret, strerror(errno));
224 return ret; 209 return ret;
225 } 210 }
226 211
227 /* some plugins may want to keep output unbroken, and some commands 212 /* some plugins may want to keep output unbroken, and some commands
228 * will yield no output, so return here for those */ 213 * will yield no output, so return here for those */
229 if (flags & CMD_NO_ARRAYS || !op->buf || !op->buflen) 214 if (flags & CMD_NO_ARRAYS || !cmd_output->buf || !cmd_output->buflen) {
230 return op->buflen; 215 return cmd_output->buflen;
216 }
231 217
232 /* and some may want both */ 218 /* and some may want both */
219 char *buf = NULL;
233 if (flags & CMD_NO_ASSOC) { 220 if (flags & CMD_NO_ASSOC) {
234 buf = malloc (op->buflen); 221 buf = malloc(cmd_output->buflen);
235 memcpy (buf, op->buf, op->buflen); 222 memcpy(buf, cmd_output->buf, cmd_output->buflen);
223 } else {
224 buf = cmd_output->buf;
236 } 225 }
237 else
238 buf = op->buf;
239 226
240 op->line = NULL; 227 cmd_output->line = NULL;
241 op->lens = NULL; 228 cmd_output->lens = NULL;
242 i = 0; 229 size_t i = 0;
243 while (i < op->buflen) { 230 size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
231 size_t rsf = 6;
232 size_t lineno = 0;
233 while (i < cmd_output->buflen) {
244 /* make sure we have enough memory */ 234 /* make sure we have enough memory */
245 if (lineno >= ary_size) { 235 if (lineno >= ary_size) {
246 /* ary_size must never be zero */ 236 /* ary_size must never be zero */
247 do { 237 do {
248 ary_size = op->buflen >> --rsf; 238 ary_size = cmd_output->buflen >> --rsf;
249 } while (!ary_size); 239 } while (!ary_size);
250 240
251 op->line = realloc (op->line, ary_size * sizeof (char *)); 241 cmd_output->line = realloc(cmd_output->line, ary_size * sizeof(char *));
252 op->lens = realloc (op->lens, ary_size * sizeof (size_t)); 242 cmd_output->lens = realloc(cmd_output->lens, ary_size * sizeof(size_t));
253 } 243 }
254 244
255 /* set the pointer to the string */ 245 /* set the pointer to the string */
256 op->line[lineno] = &buf[i]; 246 cmd_output->line[lineno] = &buf[i];
257 247
258 /* hop to next newline or end of buffer */ 248 /* hop to next newline or end of buffer */
259 while (buf[i] != '\n' && i < op->buflen) 249 while (buf[i] != '\n' && i < cmd_output->buflen) {
260 i++; 250 i++;
251 }
261 buf[i] = '\0'; 252 buf[i] = '\0';
262 253
263 /* calculate the string length using pointer difference */ 254 /* calculate the string length using pointer difference */
264 op->lens[lineno] = (size_t) & buf[i] - (size_t) op->line[lineno]; 255 cmd_output->lens[lineno] = (size_t)&buf[i] - (size_t)cmd_output->line[lineno];
265 256
266 lineno++; 257 lineno++;
267 i++; 258 i++;
@@ -270,135 +261,142 @@ _cmd_fetch_output (int fd, output * op, int flags)
270 return lineno; 261 return lineno;
271} 262}
272 263
273 264int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
274int 265 if (cmdstring == NULL) {
275cmd_run (const char *cmdstring, output * out, output * err, int flags)
276{
277 int i = 0, argc;
278 size_t cmdlen;
279 char **argv = NULL;
280 char *cmd = NULL;
281 char *str = NULL;
282
283 if (cmdstring == NULL)
284 return -1; 266 return -1;
267 }
285 268
286 /* initialize the structs */ 269 /* initialize the structs */
287 if (out) 270 if (out) {
288 memset (out, 0, sizeof (output)); 271 memset(out, 0, sizeof(output));
289 if (err) 272 }
290 memset (err, 0, sizeof (output)); 273 if (err) {
274 memset(err, 0, sizeof(output));
275 }
291 276
292 /* make copy of command string so strtok() doesn't silently modify it */ 277 /* make copy of command string so strtok() doesn't silently modify it */
293 /* (the calling program may want to access it later) */ 278 /* (the calling program may want to access it later) */
294 cmdlen = strlen (cmdstring); 279 size_t cmdlen = strlen(cmdstring);
295 if ((cmd = malloc (cmdlen + 1)) == NULL) 280 char *cmd = NULL;
281 if ((cmd = malloc(cmdlen + 1)) == NULL) {
296 return -1; 282 return -1;
297 memcpy (cmd, cmdstring, cmdlen); 283 }
284 memcpy(cmd, cmdstring, cmdlen);
298 cmd[cmdlen] = '\0'; 285 cmd[cmdlen] = '\0';
299 286
300 /* This is not a shell, so we don't handle "???" */ 287 /* This is not a shell, so we don't handle "???" */
301 if (strstr (cmdstring, "\"")) return -1; 288 if (strstr(cmdstring, "\"")) {
289 return -1;
290 }
302 291
303 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 292 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
304 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 293 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
305 return -1; 294 return -1;
295 }
306 296
307 /* each arg must be whitespace-separated, so args can be a maximum 297 /* 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 */ 298 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
309 argc = (cmdlen >> 1) + 2; 299 int argc = (cmdlen >> 1) + 2;
310 argv = calloc (sizeof (char *), argc); 300 char **argv = calloc((size_t)argc, sizeof(char *));
311 301
312 if (argv == NULL) { 302 if (argv == NULL) {
313 printf ("%s\n", _("Could not malloc argv array in popen()")); 303 printf("%s\n", _("Could not malloc argv array in popen()"));
314 return -1; 304 return -1;
315 } 305 }
316 306
317 /* get command arguments (stupidly, but fairly quickly) */ 307 /* get command arguments (stupidly, but fairly quickly) */
308 int i = 0;
318 while (cmd) { 309 while (cmd) {
319 str = cmd; 310 char *str = cmd;
320 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 311 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
321 312
322 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 313 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
323 str++; 314 str++;
324 if (!strstr (str, "'")) 315 if (!strstr(str, "'")) {
325 return -1; /* balanced? */ 316 return -1; /* balanced? */
326 cmd = 1 + strstr (str, "'");
327 str[strcspn (str, "'")] = 0;
328 }
329 else {
330 if (strpbrk (str, " \t\r\n")) {
331 cmd = 1 + strpbrk (str, " \t\r\n");
332 str[strcspn (str, " \t\r\n")] = 0;
333 } 317 }
334 else { 318 cmd = 1 + strstr(str, "'");
319 str[strcspn(str, "'")] = 0;
320 } else {
321 if (strpbrk(str, " \t\r\n")) {
322 cmd = 1 + strpbrk(str, " \t\r\n");
323 str[strcspn(str, " \t\r\n")] = 0;
324 } else {
335 cmd = NULL; 325 cmd = NULL;
336 } 326 }
337 } 327 }
338 328
339 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 329 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
340 cmd = NULL; 330 cmd = NULL;
331 }
341 332
342 argv[i++] = str; 333 argv[i++] = str;
343 } 334 }
344 335
345 return cmd_run_array (argv, out, err, flags); 336 return cmd_run_array(argv, out, err, flags);
346} 337}
347 338
348int 339int 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];
352
353 /* initialize the structs */ 340 /* initialize the structs */
354 if (out) 341 if (out) {
355 memset (out, 0, sizeof (output)); 342 memset(out, 0, sizeof(output));
356 if (err) 343 }
357 memset (err, 0, sizeof (output)); 344 if (err) {
345 memset(err, 0, sizeof(output));
346 }
358 347
359 if ((fd = _cmd_open (argv, pfd_out, pfd_err)) == -1) 348 int fd;
360 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); 349 int pfd_out[2];
350 int pfd_err[2];
351 if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1) {
352 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]);
353 }
361 354
362 if (out) 355 if (out) {
363 out->lines = _cmd_fetch_output (pfd_out[0], out, flags); 356 out->lines = _cmd_fetch_output(pfd_out[0], out, flags);
364 if (err) 357 }
365 err->lines = _cmd_fetch_output (pfd_err[0], err, flags); 358 if (err) {
359 err->lines = _cmd_fetch_output(pfd_err[0], err, flags);
360 }
366 361
367 return _cmd_close (fd); 362 return _cmd_close(fd);
368} 363}
369 364
370int 365int cmd_file_read(const char *filename, output *out, int flags) {
371cmd_file_read ( char *filename, output *out, int flags)
372{
373 int fd; 366 int fd;
374 if(out) 367 if (out) {
375 memset (out, 0, sizeof(output)); 368 memset(out, 0, sizeof(output));
369 }
376 370
377 if ((fd = open(filename, O_RDONLY)) == -1) { 371 if ((fd = open(filename, O_RDONLY)) == -1) {
378 die( STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno) ); 372 die(STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno));
379 } 373 }
380 374
381 if(out) 375 if (out) {
382 out->lines = _cmd_fetch_output (fd, out, flags); 376 out->lines = _cmd_fetch_output(fd, out, flags);
377 }
383 378
384 if (close(fd) == -1) 379 if (close(fd) == -1) {
385 die( STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno) ); 380 die(STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno));
381 }
386 382
387 return 0; 383 return 0;
388} 384}
389 385
390void 386void timeout_alarm_handler(int signo) {
391timeout_alarm_handler (int signo)
392{
393 if (signo == SIGALRM) { 387 if (signo == SIGALRM) {
394 printf (_("%s - Plugin timed out after %d seconds\n"), 388 printf(_("%s - Plugin timed out after %d seconds\n"), state_text(timeout_state),
395 state_text(timeout_state), timeout_interval); 389 timeout_interval);
396 390
397 long maxfd = mp_open_max(); 391 long maxfd = mp_open_max();
398 if(_cmd_pids) for(long int i = 0; i < maxfd; i++) { 392 if (_cmd_pids) {
399 if(_cmd_pids[i] != 0) kill(_cmd_pids[i], SIGKILL); 393 for (long int i = 0; i < maxfd; i++) {
394 if (_cmd_pids[i] != 0) {
395 kill(_cmd_pids[i], SIGKILL);
396 }
397 }
400 } 398 }
401 399
402 exit (timeout_state); 400 exit(timeout_state);
403 } 401 }
404} 402}
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h
index 061f5d4f..3672cdc9 100644
--- a/lib/utils_cmd.h
+++ b/lib/utils_cmd.h
@@ -4,36 +4,32 @@
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 */
8#include "../config.h"
9#include <stddef.h>
9 10
10/** types **/ 11/** types **/
11struct output 12typedef struct {
12{
13 char *buf; /* output buffer */ 13 char *buf; /* output buffer */
14 size_t buflen; /* output buffer content length */ 14 size_t buflen; /* output buffer content length */
15 char **line; /* array of lines (points to buf) */ 15 char **line; /* array of lines (points to buf) */
16 size_t *lens; /* string lengths */ 16 size_t *lens; /* string lengths */
17 size_t lines; /* lines of output */ 17 size_t lines; /* lines of output */
18}; 18} output;
19
20typedef 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(const 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
deleted file mode 100644
index 483be06d..00000000
--- a/lib/utils_disk.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/*****************************************************************************
2*
3* Library for check_disk
4*
5* License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team
7*
8* Description:
9*
10* This file contains utilities for check_disk. These are tested by libtap
11*
12*
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
15* the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version.
17*
18* This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details.
22*
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/>.
25*
26*
27*****************************************************************************/
28
29#include "common.h"
30#include "utils_disk.h"
31#include "gl/fsusage.h"
32#include <string.h>
33
34void
35np_add_name (struct name_list **list, const char *name)
36{
37 struct name_list *new_entry;
38 new_entry = (struct name_list *) malloc (sizeof *new_entry);
39 new_entry->name = (char *) name;
40 new_entry->next = *list;
41 *list = new_entry;
42}
43
44/* @brief Initialises a new regex at the begin of list via regcomp(3)
45 *
46 * @details if the regex fails to compile the error code of regcomp(3) is returned
47 * and list is not modified, otherwise list is modified to point to the new
48 * element
49 * @param list Pointer to a linked list of regex_list elements
50 * @param regex the string containing the regex which should be inserted into the list
51 * @param clags the cflags parameter for regcomp(3)
52 */
53int
54np_add_regex (struct regex_list **list, const char *regex, int cflags)
55{
56 struct regex_list *new_entry = (struct regex_list *) malloc (sizeof *new_entry);
57
58 if (new_entry == NULL) {
59 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
60 strerror(errno));
61 }
62
63 int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
64
65 if (!regcomp_result) {
66 // regcomp succeeded
67 new_entry->next = *list;
68 *list = new_entry;
69
70 return 0;
71 } else {
72 // regcomp failed
73 free(new_entry);
74
75 return regcomp_result;
76 }
77
78}
79
80/* Initialises a new parameter at the end of list */
81struct parameter_list *
82np_add_parameter(struct parameter_list **list, const char *name)
83{
84 struct parameter_list *current = *list;
85 struct parameter_list *new_path;
86 new_path = (struct parameter_list *) malloc (sizeof *new_path);
87 new_path->name = (char *) malloc(strlen(name) + 1);
88 new_path->best_match = NULL;
89 new_path->name_next = NULL;
90 new_path->name_prev = NULL;
91 new_path->freespace_bytes = NULL;
92 new_path->freespace_units = NULL;
93 new_path->freespace_percent = NULL;
94 new_path->usedspace_bytes = NULL;
95 new_path->usedspace_units = NULL;
96 new_path->usedspace_percent = NULL;
97 new_path->usedinodes_percent = NULL;
98 new_path->freeinodes_percent = NULL;
99 new_path->group = NULL;
100 new_path->dfree_pct = -1;
101 new_path->dused_pct = -1;
102 new_path->total = 0;
103 new_path->available = 0;
104 new_path->available_to_root = 0;
105 new_path->used = 0;
106 new_path->dused_units = 0;
107 new_path->dfree_units = 0;
108 new_path->dtotal_units = 0;
109 new_path->inodes_total = 0;
110 new_path->inodes_free = 0;
111 new_path->inodes_free_to_root = 0;
112 new_path->inodes_used = 0;
113 new_path->dused_inodes_percent = 0;
114 new_path->dfree_inodes_percent = 0;
115
116 strcpy(new_path->name, name);
117
118 if (current == NULL) {
119 *list = new_path;
120 new_path->name_prev = NULL;
121 } else {
122 while (current->name_next) {
123 current = current->name_next;
124 }
125 current->name_next = new_path;
126 new_path->name_prev = current;
127 }
128 return new_path;
129}
130
131/* Delete a given parameter from list and return pointer to next element*/
132struct parameter_list *
133np_del_parameter(struct parameter_list *item, struct parameter_list *prev)
134{
135 if (item == NULL) {
136 return NULL;
137 }
138 struct parameter_list *next;
139
140 if (item->name_next)
141 next = item->name_next;
142 else
143 next = NULL;
144
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
159
160/* returns a pointer to the struct found in the list */
161struct parameter_list *
162np_find_parameter(struct parameter_list *list, const char *name)
163{
164 struct parameter_list *temp_list;
165 for (temp_list = list; temp_list; temp_list = temp_list->name_next) {
166 if (! strcmp(temp_list->name, name))
167 return temp_list;
168 }
169
170 return NULL;
171}
172
173void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) {
174 struct parameter_list *d;
175 for (d = desired; d; d= d->name_next) {
176 if (! d->best_match) {
177 struct mount_entry *me;
178 size_t name_len = strlen(d->name);
179 size_t best_match_len = 0;
180 struct mount_entry *best_match = NULL;
181 struct fs_usage fsp;
182
183 /* set best match if path name exactly matches a mounted device name */
184 for (me = mount_list; me; me = me->me_next) {
185 if (strcmp(me->me_devname, d->name)==0) {
186 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
187 best_match = me;
188 }
189 }
190 }
191
192 /* set best match by directory name if no match was found by devname */
193 if (! best_match) {
194 for (me = mount_list; me; me = me->me_next) {
195 size_t len = strlen (me->me_mountdir);
196 if ((!exact && (best_match_len <= len && len <= name_len &&
197 (len == 1 || strncmp (me->me_mountdir, d->name, len) == 0)))
198 || (exact && strcmp(me->me_mountdir, d->name)==0))
199 {
200 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
201 best_match = me;
202 best_match_len = len;
203 }
204 }
205 }
206 }
207
208 if (best_match) {
209 d->best_match = best_match;
210 } else {
211 d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
212 }
213 }
214 }
215}
216
217/* Returns true if name is in list */
218bool np_find_name (struct name_list *list, const char *name) {
219 const struct name_list *n;
220
221 if (list == NULL || name == NULL) {
222 return false;
223 }
224 for (n = list; n; n = n->next) {
225 if (!strcmp(name, n->name)) {
226 return true;
227 }
228 }
229 return false;
230}
231
232/* Returns true if name is in list */
233bool np_find_regmatch (struct regex_list *list, const char *name) {
234 int len;
235 regmatch_t m;
236
237 if (name == NULL) {
238 return false;
239 }
240
241 len = strlen(name);
242
243 for (; list; list = list->next) {
244 /* Emulate a full match as if surrounded with ^( )$
245 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) {
247 return true;
248 }
249 }
250
251 return false;
252}
253
254bool np_seen_name(struct name_list *list, const char *name) {
255 const struct name_list *s;
256 for (s = list; s; s=s->next) {
257 if (!strcmp(s->name, name)) {
258 return true;
259 }
260 }
261 return false;
262}
263
264bool 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 ||
266 regexec(re, me->me_mountdir, (size_t) 0, NULL, 0) == 0 ) {
267 return true;
268 }
269 return false;
270}
diff --git a/lib/utils_disk.h b/lib/utils_disk.h
deleted file mode 100644
index 5b2caf23..00000000
--- a/lib/utils_disk.h
+++ /dev/null
@@ -1,52 +0,0 @@
1/* Header file for utils_disk */
2
3#include "mountlist.h"
4#include "utils_base.h"
5#include "regex.h"
6
7struct name_list
8{
9 char *name;
10 struct name_list *next;
11};
12
13struct regex_list
14{
15 regex_t regex;
16 struct regex_list *next;
17};
18
19struct parameter_list
20{
21 char *name;
22 thresholds *freespace_bytes;
23 thresholds *freespace_units;
24 thresholds *freespace_percent;
25 thresholds *usedspace_bytes;
26 thresholds *usedspace_units;
27 thresholds *usedspace_percent;
28 thresholds *usedinodes_percent;
29 thresholds *freeinodes_percent;
30 char *group;
31 struct mount_entry *best_match;
32 struct parameter_list *name_next;
33 struct parameter_list *name_prev;
34 uintmax_t total, available, available_to_root, used,
35 inodes_free, inodes_free_to_root, inodes_used, inodes_total;
36 double dfree_pct, dused_pct;
37 uint64_t dused_units, dfree_units, dtotal_units;
38 double dused_inodes_percent, dfree_inodes_percent;
39};
40
41void np_add_name (struct name_list **list, const char *name);
42bool np_find_name (struct name_list *list, const char *name);
43bool np_seen_name (struct name_list *list, const char *name);
44int np_add_regex (struct regex_list **list, const char *regex, int cflags);
45bool np_find_regmatch (struct regex_list *list, const char *name);
46struct 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);
48struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev);
49
50int 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);
52bool 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..a82d5a3f 100644
--- a/lib/utils_tcp.c
+++ b/lib/utils_tcp.c
@@ -1,75 +1,78 @@
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 "../config.h"
30#include "utils_tcp.h" 30#include "utils_tcp.h"
31#include <stdio.h>
32#include <string.h>
31 33
32#define VERBOSE(message) \ 34#define VERBOSE(message) \
33 do { \ 35 do { \
34 if (flags & NP_MATCH_VERBOSE) \ 36 if (flags & NP_MATCH_VERBOSE) \
35 puts(message); \ 37 puts(message); \
36 } while (0) 38 } while (0)
37 39
38enum np_match_result 40enum np_match_result np_expect_match(char *status, char **server_expect, int expect_count,
39np_expect_match(char *status, char **server_expect, int expect_count, int flags) 41 int flags) {
40{ 42 int match = 0;
41 int i, match = 0, partial = 0; 43 int partial = 0;
42 44 for (int i = 0; i < expect_count; i++) {
43 for (i = 0; i < expect_count; i++) { 45 if (flags & NP_MATCH_VERBOSE) {
44 if (flags & NP_MATCH_VERBOSE)
45 printf("looking for [%s] %s [%s]\n", server_expect[i], 46 printf("looking for [%s] %s [%s]\n", server_expect[i],
46 (flags & NP_MATCH_EXACT) ? 47 (flags & NP_MATCH_EXACT) ? "in beginning of" : "anywhere in", status);
47 "in beginning of" : "anywhere in", 48 }
48 status);
49 49
50 if (flags & NP_MATCH_EXACT) { 50 if (flags & NP_MATCH_EXACT) {
51 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) { 51 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) {
52 VERBOSE("found it"); 52 VERBOSE("found it");
53 match++; 53 match++;
54 continue; 54 continue;
55 } else if (strncmp(status, server_expect[i], strlen(status)) == 0) { 55 }
56
57 if (strncmp(status, server_expect[i], strlen(status)) == 0) {
56 VERBOSE("found a substring"); 58 VERBOSE("found a substring");
57 partial++; 59 partial++;
58 continue; 60 continue;
59 } 61 }
60 } else if (strstr(status, server_expect[i]) != NULL) { 62 } else if (strstr(status, server_expect[i]) != NULL) {
61 VERBOSE("found it"); 63 VERBOSE("found it");
62 match++; 64 match++;
63 continue; 65 continue;
64 } 66 }
65 VERBOSE("couldn't find it"); 67 VERBOSE("couldn't find it");
66 } 68 }
67 69
68 if ((flags & NP_MATCH_ALL && match == expect_count) || 70 if ((flags & NP_MATCH_ALL && match == expect_count) ||
69 (!(flags & NP_MATCH_ALL) && match >= 1)) 71 (!(flags & NP_MATCH_ALL) && match >= 1)) {
70 return NP_MATCH_SUCCESS; 72 return NP_MATCH_SUCCESS;
71 else if (partial > 0 || !(flags & NP_MATCH_EXACT)) 73 }
74 if (partial > 0 || !(flags & NP_MATCH_EXACT)) {
72 return NP_MATCH_RETRY; 75 return NP_MATCH_RETRY;
73 else 76 }
74 return NP_MATCH_FAILURE; 77 return NP_MATCH_FAILURE;
75} 78}
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h
index 0328a9cf..e5cdbb82 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
@@ -11,12 +11,11 @@
11 * server. 11 * server.
12 */ 12 */
13enum np_match_result { 13enum np_match_result {
14 NP_MATCH_NONE,
14 NP_MATCH_FAILURE, 15 NP_MATCH_FAILURE,
15 NP_MATCH_SUCCESS, 16 NP_MATCH_SUCCESS,
16 NP_MATCH_RETRY 17 NP_MATCH_RETRY
17}; 18};
18 19
19enum np_match_result np_expect_match(char *status, 20enum np_match_result np_expect_match(char *status, char **server_expect, int server_expect_count,
20 char **server_expect, 21 int flags);
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