diff options
Diffstat (limited to 'lib')
39 files changed, 7006 insertions, 1820 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index dc3ee893..e41201c4 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am | |||
@@ -7,8 +7,21 @@ noinst_LIBRARIES = libmonitoringplug.a | |||
7 | AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ | 7 | AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ |
8 | -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins | 8 | -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins |
9 | 9 | ||
10 | libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c | 10 | libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c |
11 | EXTRA_DIST = utils_base.h utils_disk.h utils_tcp.h utils_cmd.h parse_ini.h extra_opts.h maxfd.h | 11 | |
12 | EXTRA_DIST = utils_base.h \ | ||
13 | utils_disk.h \ | ||
14 | utils_tcp.h \ | ||
15 | utils_cmd.h \ | ||
16 | parse_ini.h \ | ||
17 | extra_opts.h \ | ||
18 | maxfd.h \ | ||
19 | perfdata.h \ | ||
20 | output.h \ | ||
21 | thresholds.h \ | ||
22 | states.h \ | ||
23 | vendor/cJSON/cJSON.h \ | ||
24 | monitoringplug.h | ||
12 | 25 | ||
13 | if USE_PARSE_INI | 26 | if USE_PARSE_INI |
14 | libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c | 27 | libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c |
@@ -16,4 +29,3 @@ endif USE_PARSE_INI | |||
16 | 29 | ||
17 | test test-debug: | 30 | test test-debug: |
18 | cd tests && make $@ | 31 | cd tests && make $@ |
19 | |||
diff --git a/lib/extra_opts.c b/lib/extra_opts.c index 771621d8..88787336 100644 --- a/lib/extra_opts.c +++ b/lib/extra_opts.c | |||
@@ -1,24 +1,24 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Monitoring Plugins extra_opts library | 3 | * Monitoring Plugins extra_opts library |
4 | * | 4 | * |
5 | * License: GPL | 5 | * License: GPL |
6 | * Copyright (c) 2007 Monitoring Plugins Development Team | 6 | * Copyright (c) 2007 - 2024 Monitoring Plugins Development Team |
7 | * | 7 | * |
8 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation, either version 3 of the License, or | 10 | * the Free Software Foundation, either version 3 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | * | 20 | * |
21 | *****************************************************************************/ | 21 | *****************************************************************************/ |
22 | 22 | ||
23 | #include "common.h" | 23 | #include "common.h" |
24 | #include "utils_base.h" | 24 | #include "utils_base.h" |
@@ -26,110 +26,115 @@ | |||
26 | #include "extra_opts.h" | 26 | #include "extra_opts.h" |
27 | 27 | ||
28 | /* FIXME: copied from utils.h; we should move a bunch of libs! */ | 28 | /* FIXME: copied from utils.h; we should move a bunch of libs! */ |
29 | bool is_option2 (char *str) | 29 | bool is_option2(char *str) { |
30 | { | ||
31 | if (!str) | 30 | if (!str) |
32 | return false; | 31 | return false; |
33 | else if (strspn (str, "-") == 1 || strspn (str, "-") == 2) | 32 | else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) |
34 | return true; | 33 | return true; |
35 | else | 34 | else |
36 | return false; | 35 | return false; |
37 | } | 36 | } |
38 | 37 | ||
39 | /* this is the externally visible function used by plugins */ | 38 | /* this is the externally visible function used by plugins */ |
40 | char **np_extra_opts(int *argc, char **argv, const char *plugin_name){ | 39 | char **np_extra_opts(int *argc, char **argv, const char *plugin_name) { |
41 | np_arg_list *extra_args=NULL, *ea1=NULL, *ea_tmp=NULL; | 40 | np_arg_list *extra_args = NULL, *ea1 = NULL, *ea_tmp = NULL; |
42 | char **argv_new=NULL; | 41 | char **argv_new = NULL; |
43 | char *argptr=NULL; | 42 | char *argptr = NULL; |
44 | int i, j, optfound, argc_new, ea_num=*argc; | 43 | int i, j, optfound, argc_new, ea_num = *argc; |
45 | 44 | ||
46 | if(*argc<2) { | 45 | if (*argc < 2) { |
47 | /* No arguments provided */ | 46 | /* No arguments provided */ |
48 | return argv; | 47 | return argv; |
49 | } | 48 | } |
50 | 49 | ||
51 | for(i=1; i<*argc; i++){ | 50 | for (i = 1; i < *argc; i++) { |
52 | argptr=NULL; | 51 | argptr = NULL; |
53 | optfound=0; | 52 | optfound = 0; |
54 | 53 | ||
55 | /* Do we have an extra-opts parameter? */ | 54 | /* Do we have an extra-opts parameter? */ |
56 | if(strncmp(argv[i], "--extra-opts=", 13)==0){ | 55 | if (strncmp(argv[i], "--extra-opts=", 13) == 0) { |
57 | /* It is a single argument with value */ | 56 | /* It is a single argument with value */ |
58 | argptr=argv[i]+13; | 57 | argptr = argv[i] + 13; |
59 | /* Delete the extra opts argument */ | 58 | /* Delete the extra opts argument */ |
60 | for(j=i;j<*argc;j++) argv[j]=argv[j+1]; | 59 | for (j = i; j < *argc; j++) |
60 | argv[j] = argv[j + 1]; | ||
61 | i--; | 61 | i--; |
62 | *argc-=1; | 62 | *argc -= 1; |
63 | }else if(strcmp(argv[i], "--extra-opts")==0){ | 63 | } else if (strcmp(argv[i], "--extra-opts") == 0) { |
64 | if((i+1<*argc)&&!is_option2(argv[i+1])){ | 64 | if ((i + 1 < *argc) && !is_option2(argv[i + 1])) { |
65 | /* It is a argument with separate value */ | 65 | /* It is a argument with separate value */ |
66 | argptr=argv[i+1]; | 66 | argptr = argv[i + 1]; |
67 | /* Delete the extra-opts argument/value */ | 67 | /* Delete the extra-opts argument/value */ |
68 | for(j=i;j<*argc-1;j++) argv[j]=argv[j+2]; | 68 | for (j = i; j < *argc - 1; j++) |
69 | i-=2; | 69 | argv[j] = argv[j + 2]; |
70 | *argc-=2; | 70 | i -= 2; |
71 | *argc -= 2; | ||
71 | ea_num--; | 72 | ea_num--; |
72 | }else{ | 73 | } else { |
73 | /* It has no value */ | 74 | /* It has no value */ |
74 | optfound=1; | 75 | optfound = 1; |
75 | /* Delete the extra opts argument */ | 76 | /* Delete the extra opts argument */ |
76 | for(j=i;j<*argc;j++) argv[j]=argv[j+1]; | 77 | for (j = i; j < *argc; j++) |
78 | argv[j] = argv[j + 1]; | ||
77 | i--; | 79 | i--; |
78 | *argc-=1; | 80 | *argc -= 1; |
79 | } | 81 | } |
80 | } | 82 | } |
81 | 83 | ||
82 | /* If we found extra-opts, expand them and store them for later*/ | 84 | /* If we found extra-opts, expand them and store them for later*/ |
83 | if(argptr||optfound){ | 85 | if (argptr || optfound) { |
84 | /* Process ini section, returning a linked list of arguments */ | 86 | /* Process ini section, returning a linked list of arguments */ |
85 | ea1=np_get_defaults(argptr, plugin_name); | 87 | ea1 = np_get_defaults(argptr, plugin_name); |
86 | if(ea1==NULL) { | 88 | if (ea1 == NULL) { |
87 | /* no extra args (empty section)? */ | 89 | /* no extra args (empty section)? */ |
88 | ea_num--; | 90 | ea_num--; |
89 | continue; | 91 | continue; |
90 | } | 92 | } |
91 | 93 | ||
92 | /* append the list to extra_args */ | 94 | /* append the list to extra_args */ |
93 | if(extra_args==NULL){ | 95 | if (extra_args == NULL) { |
94 | extra_args=ea1; | 96 | extra_args = ea1; |
95 | while((ea1 = ea1->next)) ea_num++; | 97 | while ((ea1 = ea1->next)) |
96 | }else{ | 98 | ea_num++; |
97 | ea_tmp=extra_args; | 99 | } else { |
98 | while(ea_tmp->next) { | 100 | ea_tmp = extra_args; |
99 | ea_tmp=ea_tmp->next; | 101 | while (ea_tmp->next) { |
102 | ea_tmp = ea_tmp->next; | ||
100 | } | 103 | } |
101 | ea_tmp->next=ea1; | 104 | ea_tmp->next = ea1; |
102 | while((ea1 = ea1->next)) ea_num++; | 105 | while ((ea1 = ea1->next)) |
106 | ea_num++; | ||
103 | } | 107 | } |
104 | ea1=ea_tmp=NULL; | 108 | ea1 = ea_tmp = NULL; |
105 | } | 109 | } |
106 | } /* lather, rince, repeat */ | 110 | } /* lather, rince, repeat */ |
107 | 111 | ||
108 | if(ea_num==*argc && extra_args==NULL){ | 112 | if (ea_num == *argc && extra_args == NULL) { |
109 | /* No extra-opts */ | 113 | /* No extra-opts */ |
110 | return argv; | 114 | return argv; |
111 | } | 115 | } |
112 | 116 | ||
113 | /* done processing arguments. now create a new argv array... */ | 117 | /* done processing arguments. now create a new argv array... */ |
114 | argv_new=(char**)malloc((ea_num+1)*sizeof(char**)); | 118 | argv_new = (char **)malloc((ea_num + 1) * sizeof(char **)); |
115 | if(argv_new==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); | 119 | if (argv_new == NULL) |
120 | die(STATE_UNKNOWN, _("malloc() failed!\n")); | ||
116 | 121 | ||
117 | /* starting with program name */ | 122 | /* starting with program name */ |
118 | argv_new[0]=argv[0]; | 123 | argv_new[0] = argv[0]; |
119 | argc_new=1; | 124 | argc_new = 1; |
120 | /* then parsed ini opts (frying them up in the same run) */ | 125 | /* then parsed ini opts (frying them up in the same run) */ |
121 | while(extra_args){ | 126 | while (extra_args) { |
122 | argv_new[argc_new++]=extra_args->arg; | 127 | argv_new[argc_new++] = extra_args->arg; |
123 | ea1=extra_args; | 128 | ea1 = extra_args; |
124 | extra_args=extra_args->next; | 129 | extra_args = extra_args->next; |
125 | free(ea1); | 130 | free(ea1); |
126 | } | 131 | } |
127 | /* finally the rest of the argv array */ | 132 | /* finally the rest of the argv array */ |
128 | for (i=1; i<*argc; i++) argv_new[argc_new++]=argv[i]; | 133 | for (i = 1; i < *argc; i++) |
129 | *argc=argc_new; | 134 | argv_new[argc_new++] = argv[i]; |
135 | *argc = argc_new; | ||
130 | /* and terminate. */ | 136 | /* and terminate. */ |
131 | argv_new[argc_new]=NULL; | 137 | argv_new[argc_new] = NULL; |
132 | 138 | ||
133 | return argv_new; | 139 | return argv_new; |
134 | } | 140 | } |
135 | |||
diff --git a/lib/extra_opts.h b/lib/extra_opts.h index 8ff14a16..3f64360f 100644 --- a/lib/extra_opts.h +++ b/lib/extra_opts.h | |||
@@ -20,4 +20,3 @@ | |||
20 | char **np_extra_opts(int *argc, char **argv, const char *plugin_name); | 20 | char **np_extra_opts(int *argc, char **argv, const char *plugin_name); |
21 | 21 | ||
22 | #endif /* _EXTRA_OPTS_H_ */ | 22 | #endif /* _EXTRA_OPTS_H_ */ |
23 | |||
diff --git a/lib/maxfd.c b/lib/maxfd.c index 529b3568..ca5b6e54 100644 --- a/lib/maxfd.c +++ b/lib/maxfd.c | |||
@@ -1,7 +1,27 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * License: GPL | ||
4 | * Copyright (c) 2024 Monitoring Plugins Development Team | ||
5 | * | ||
6 | * This program is free software: you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation, either version 3 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | * | ||
19 | *****************************************************************************/ | ||
20 | |||
1 | #include "./maxfd.h" | 21 | #include "./maxfd.h" |
2 | #include <errno.h> | 22 | #include <errno.h> |
3 | 23 | ||
4 | long mp_open_max (void) { | 24 | long mp_open_max(void) { |
5 | long maxfd = 0L; | 25 | long maxfd = 0L; |
6 | /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX. | 26 | /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX. |
7 | * If that fails and the macro isn't defined, we fall back to an educated | 27 | * If that fails and the macro isn't defined, we fall back to an educated |
@@ -10,17 +30,17 @@ long mp_open_max (void) { | |||
10 | 30 | ||
11 | #ifdef _SC_OPEN_MAX | 31 | #ifdef _SC_OPEN_MAX |
12 | errno = 0; | 32 | errno = 0; |
13 | if ((maxfd = sysconf (_SC_OPEN_MAX)) < 0) { | 33 | if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) { |
14 | if (errno == 0) | 34 | if (errno == 0) |
15 | maxfd = DEFAULT_MAXFD; /* it's indeterminate */ | 35 | maxfd = DEFAULT_MAXFD; /* it's indeterminate */ |
16 | else | 36 | else |
17 | die (STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n")); | 37 | die(STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n")); |
18 | } | 38 | } |
19 | #elif defined(OPEN_MAX) | 39 | #elif defined(OPEN_MAX) |
20 | return OPEN_MAX | 40 | return OPEN_MAX |
21 | #else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */ | 41 | #else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */ |
22 | return DEFAULT_MAXFD; | 42 | return DEFAULT_MAXFD; |
23 | #endif | 43 | #endif |
24 | 44 | ||
25 | return(maxfd); | 45 | return (maxfd); |
26 | } | 46 | } |
diff --git a/lib/maxfd.h b/lib/maxfd.h index 45218d0f..8fcd62d3 100644 --- a/lib/maxfd.h +++ b/lib/maxfd.h | |||
@@ -1,9 +1,9 @@ | |||
1 | #ifndef _MAXFD_ | 1 | #ifndef _MAXFD_ |
2 | #define _MAXFD_ | 2 | #define _MAXFD_ |
3 | 3 | ||
4 | #define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */ | 4 | #define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */ |
5 | #define MAXFD_LIMIT 8192 /* upper limit of open files */ | 5 | #define MAXFD_LIMIT 8192 /* upper limit of open files */ |
6 | 6 | ||
7 | long mp_open_max (void); | 7 | long mp_open_max(void); |
8 | 8 | ||
9 | #endif // _MAXFD_ | 9 | #endif // _MAXFD_ |
diff --git a/lib/monitoringplug.h b/lib/monitoringplug.h new file mode 100644 index 00000000..a555d736 --- /dev/null +++ b/lib/monitoringplug.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "./states.h" | ||
4 | #include "./utils_base.h" | ||
5 | #include "./thresholds.h" | ||
6 | #include "./maxfd.h" | ||
7 | #include "./output.h" | ||
diff --git a/lib/output.c b/lib/output.c new file mode 100644 index 00000000..17919afc --- /dev/null +++ b/lib/output.c | |||
@@ -0,0 +1,535 @@ | |||
1 | #include "./output.h" | ||
2 | #include "./utils_base.h" | ||
3 | #include "../plugins/utils.h" | ||
4 | |||
5 | #include <assert.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | #include <strings.h> | ||
9 | // #include <cjson/cJSON.h> | ||
10 | #include "./vendor/cJSON/cJSON.h" | ||
11 | #include "perfdata.h" | ||
12 | #include "states.h" | ||
13 | |||
14 | // == Prototypes == | ||
15 | static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation); | ||
16 | static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck); | ||
17 | |||
18 | // == Implementation == | ||
19 | |||
20 | /* | ||
21 | * Generate output string for a mp_subcheck object | ||
22 | */ | ||
23 | static inline char *fmt_subcheck_perfdata(mp_subcheck check) { | ||
24 | char *result = strdup(""); | ||
25 | int added = 0; | ||
26 | |||
27 | if (check.perfdata != NULL) { | ||
28 | added = asprintf(&result, "%s", pd_list_to_string(*check.perfdata)); | ||
29 | } | ||
30 | |||
31 | if (check.subchecks == NULL) { | ||
32 | // No subchecks, return here | ||
33 | return result; | ||
34 | } | ||
35 | |||
36 | mp_subcheck_list *subchecks = check.subchecks; | ||
37 | |||
38 | while (subchecks != NULL) { | ||
39 | if (added > 0) { | ||
40 | added = asprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck)); | ||
41 | } else { | ||
42 | // TODO free previous result here? | ||
43 | added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck)); | ||
44 | } | ||
45 | |||
46 | subchecks = subchecks->next; | ||
47 | } | ||
48 | |||
49 | return result; | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * Initialiser for a mp_check object. Always use this to get a new one! | ||
54 | * It sets useful defaults | ||
55 | */ | ||
56 | mp_check mp_check_init(void) { | ||
57 | mp_check check = {0}; | ||
58 | check.format = MP_FORMAT_DEFAULT; | ||
59 | return check; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Initialiser for a mp_subcheck object. Always use this to get a new one! | ||
64 | * It sets useful defaults | ||
65 | */ | ||
66 | mp_subcheck mp_subcheck_init(void) { | ||
67 | mp_subcheck tmp = {0}; | ||
68 | tmp.default_state = STATE_UNKNOWN; // Default state is unknown | ||
69 | tmp.state_set_explicitly = false; | ||
70 | return tmp; | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Add a subcheck to a (the one and only) check object | ||
75 | */ | ||
76 | int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck subcheck) { | ||
77 | assert(subcheck.output != NULL); // There must be output in a subcheck | ||
78 | |||
79 | mp_subcheck_list *tmp = NULL; | ||
80 | |||
81 | if (check->subchecks == NULL) { | ||
82 | check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list)); | ||
83 | if (check->subchecks == NULL) { | ||
84 | die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed"); | ||
85 | } | ||
86 | |||
87 | check->subchecks->subcheck = subcheck; | ||
88 | check->subchecks->next = NULL; | ||
89 | } else { | ||
90 | // Search for the end | ||
91 | tmp = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list)); | ||
92 | if (tmp == NULL) { | ||
93 | die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed"); | ||
94 | } | ||
95 | |||
96 | tmp->subcheck = subcheck; | ||
97 | tmp->next = check->subchecks; | ||
98 | |||
99 | check->subchecks = tmp; | ||
100 | } | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Add a mp_perfdata data point to a mp_subcheck object | ||
107 | */ | ||
108 | void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata perfData) { | ||
109 | if (check->perfdata == NULL) { | ||
110 | check->perfdata = pd_list_init(); | ||
111 | } | ||
112 | pd_list_append(check->perfdata, perfData); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Add a mp_subcheck object to another one. The seconde mp_subcheck (argument) is the lower in the | ||
117 | * hierarchy | ||
118 | */ | ||
119 | int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) { | ||
120 | if (subcheck.output == NULL) { | ||
121 | die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "Sub check output is NULL"); | ||
122 | } | ||
123 | |||
124 | mp_subcheck_list *tmp = NULL; | ||
125 | |||
126 | if (check->subchecks == NULL) { | ||
127 | check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list)); | ||
128 | if (check->subchecks == NULL) { | ||
129 | die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed"); | ||
130 | } | ||
131 | |||
132 | tmp = check->subchecks; | ||
133 | } else { | ||
134 | // Search for the end | ||
135 | tmp = check->subchecks; | ||
136 | |||
137 | while (tmp->next != NULL) { | ||
138 | tmp = tmp->next; | ||
139 | } | ||
140 | |||
141 | tmp->next = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list)); | ||
142 | if (tmp->next == NULL) { | ||
143 | die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed"); | ||
144 | } | ||
145 | |||
146 | tmp = tmp->next; | ||
147 | } | ||
148 | |||
149 | tmp->subcheck = subcheck; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Add a manual summary to a mp_check object, effectively replacing | ||
156 | * the autogenerated one | ||
157 | */ | ||
158 | void mp_add_summary(mp_check check[static 1], char *summary) { check->summary = summary; } | ||
159 | |||
160 | /* | ||
161 | * Generate the summary string of a mp_check object based on it's subchecks | ||
162 | */ | ||
163 | char *get_subcheck_summary(mp_check check) { | ||
164 | mp_subcheck_list *subchecks = check.subchecks; | ||
165 | |||
166 | unsigned int ok = 0; | ||
167 | unsigned int warning = 0; | ||
168 | unsigned int critical = 0; | ||
169 | unsigned int unknown = 0; | ||
170 | while (subchecks != NULL) { | ||
171 | switch (subchecks->subcheck.state) { | ||
172 | case STATE_OK: | ||
173 | ok++; | ||
174 | break; | ||
175 | case STATE_WARNING: | ||
176 | warning++; | ||
177 | break; | ||
178 | case STATE_CRITICAL: | ||
179 | critical++; | ||
180 | break; | ||
181 | case STATE_UNKNOWN: | ||
182 | unknown++; | ||
183 | break; | ||
184 | default: | ||
185 | die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary"); | ||
186 | } | ||
187 | subchecks = subchecks->next; | ||
188 | } | ||
189 | char *result = NULL; | ||
190 | asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown); | ||
191 | return result; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Generate the result state of a mp_subcheck object based on it's own state and it's subchecks states | ||
196 | */ | ||
197 | mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) { | ||
198 | if (check.state_set_explicitly) { | ||
199 | return check.state; | ||
200 | } | ||
201 | |||
202 | mp_subcheck_list *scl = check.subchecks; | ||
203 | mp_state_enum result = check.default_state; | ||
204 | |||
205 | while (scl != NULL) { | ||
206 | result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck)); | ||
207 | scl = scl->next; | ||
208 | } | ||
209 | |||
210 | return result; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Generate the result state of a mp_check object based on it's own state and it's subchecks states | ||
215 | */ | ||
216 | mp_state_enum mp_compute_check_state(const mp_check check) { | ||
217 | assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here | ||
218 | |||
219 | mp_subcheck_list *scl = check.subchecks; | ||
220 | mp_state_enum result = STATE_OK; | ||
221 | |||
222 | while (scl != NULL) { | ||
223 | result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck)); | ||
224 | scl = scl->next; | ||
225 | } | ||
226 | |||
227 | return result; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Generate output string for a mp_check object | ||
232 | * Non static to be available for testing functions | ||
233 | */ | ||
234 | char *mp_fmt_output(mp_check check) { | ||
235 | char *result = NULL; | ||
236 | |||
237 | switch (check.format) { | ||
238 | case MP_FORMAT_MULTI_LINE: { | ||
239 | if (check.summary == NULL) { | ||
240 | check.summary = get_subcheck_summary(check); | ||
241 | } | ||
242 | |||
243 | asprintf(&result, "[%s] - %s", state_text(mp_compute_check_state(check)), check.summary); | ||
244 | |||
245 | mp_subcheck_list *subchecks = check.subchecks; | ||
246 | |||
247 | while (subchecks != NULL) { | ||
248 | asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1)); | ||
249 | subchecks = subchecks->next; | ||
250 | } | ||
251 | |||
252 | char *pd_string = NULL; | ||
253 | subchecks = check.subchecks; | ||
254 | |||
255 | while (subchecks != NULL) { | ||
256 | if (pd_string == NULL) { | ||
257 | asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck)); | ||
258 | } else { | ||
259 | asprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck)); | ||
260 | } | ||
261 | |||
262 | subchecks = subchecks->next; | ||
263 | } | ||
264 | |||
265 | if (pd_string != NULL && strlen(pd_string) > 0) { | ||
266 | asprintf(&result, "%s|%s", result, pd_string); | ||
267 | } | ||
268 | |||
269 | break; | ||
270 | } | ||
271 | case MP_FORMAT_TEST_JSON: { | ||
272 | cJSON *resultObject = cJSON_CreateObject(); | ||
273 | if (resultObject == NULL) { | ||
274 | die(STATE_UNKNOWN, "cJSON_CreateObject failed"); | ||
275 | } | ||
276 | |||
277 | cJSON *resultState = cJSON_CreateString(state_text(mp_compute_check_state(check))); | ||
278 | cJSON_AddItemToObject(resultObject, "state", resultState); | ||
279 | |||
280 | if (check.summary == NULL) { | ||
281 | check.summary = get_subcheck_summary(check); | ||
282 | } | ||
283 | |||
284 | cJSON *summary = cJSON_CreateString(check.summary); | ||
285 | cJSON_AddItemToObject(resultObject, "summary", summary); | ||
286 | |||
287 | if (check.subchecks != NULL) { | ||
288 | cJSON *subchecks = cJSON_CreateArray(); | ||
289 | |||
290 | mp_subcheck_list *sc = check.subchecks; | ||
291 | |||
292 | while (sc != NULL) { | ||
293 | cJSON *sc_json = json_serialize_subcheck(sc->subcheck); | ||
294 | cJSON_AddItemToArray(subchecks, sc_json); | ||
295 | sc = sc->next; | ||
296 | } | ||
297 | |||
298 | cJSON_AddItemToObject(resultObject, "checks", subchecks); | ||
299 | } | ||
300 | |||
301 | result = cJSON_PrintUnformatted(resultObject); | ||
302 | break; | ||
303 | } | ||
304 | default: | ||
305 | die(STATE_UNKNOWN, "Invalid format"); | ||
306 | } | ||
307 | |||
308 | return result; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Helper function to properly indent the output lines when using multiline | ||
313 | * formats | ||
314 | */ | ||
315 | static char *generate_indentation_string(unsigned int indentation) { | ||
316 | char *result = calloc(indentation + 1, sizeof(char)); | ||
317 | |||
318 | for (unsigned int i = 0; i < indentation; i++) { | ||
319 | result[i] = '\t'; | ||
320 | } | ||
321 | |||
322 | return result; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * Helper function to generate the output string of mp_subcheck | ||
327 | */ | ||
328 | static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation) { | ||
329 | char *result = NULL; | ||
330 | mp_subcheck_list *subchecks = NULL; | ||
331 | |||
332 | switch (output_format) { | ||
333 | case MP_FORMAT_MULTI_LINE: | ||
334 | asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)), | ||
335 | check.output); | ||
336 | |||
337 | subchecks = check.subchecks; | ||
338 | |||
339 | while (subchecks != NULL) { | ||
340 | asprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1)); | ||
341 | subchecks = subchecks->next; | ||
342 | } | ||
343 | return result; | ||
344 | default: | ||
345 | die(STATE_UNKNOWN, "Invalid format"); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | static inline cJSON *json_serialise_pd_value(mp_perfdata_value value) { | ||
350 | cJSON *result = cJSON_CreateObject(); | ||
351 | |||
352 | switch (value.type) { | ||
353 | case PD_TYPE_DOUBLE: | ||
354 | cJSON_AddStringToObject(result, "type", "double"); | ||
355 | break; | ||
356 | case PD_TYPE_INT: | ||
357 | cJSON_AddStringToObject(result, "type", "int"); | ||
358 | break; | ||
359 | case PD_TYPE_UINT: | ||
360 | cJSON_AddStringToObject(result, "type", "uint"); | ||
361 | break; | ||
362 | case PD_TYPE_NONE: | ||
363 | die(STATE_UNKNOWN, "Perfdata type was None in json_serialise_pd_value"); | ||
364 | } | ||
365 | cJSON_AddStringToObject(result, "value", pd_value_to_string(value)); | ||
366 | |||
367 | return result; | ||
368 | } | ||
369 | |||
370 | static inline cJSON *json_serialise_range(mp_range range) { | ||
371 | cJSON *result = cJSON_CreateObject(); | ||
372 | |||
373 | if (range.alert_on_inside_range) { | ||
374 | cJSON_AddBoolToObject(result, "alert_on_inside", true); | ||
375 | } else { | ||
376 | cJSON_AddBoolToObject(result, "alert_on_inside", false); | ||
377 | } | ||
378 | |||
379 | if (range.end_infinity) { | ||
380 | cJSON_AddStringToObject(result, "end", "inf"); | ||
381 | } else { | ||
382 | cJSON_AddItemToObject(result, "end", json_serialise_pd_value(range.end)); | ||
383 | } | ||
384 | |||
385 | if (range.start_infinity) { | ||
386 | cJSON_AddStringToObject(result, "start", "inf"); | ||
387 | } else { | ||
388 | cJSON_AddItemToObject(result, "start", json_serialise_pd_value(range.end)); | ||
389 | } | ||
390 | |||
391 | return result; | ||
392 | } | ||
393 | |||
394 | static inline cJSON *json_serialise_pd(mp_perfdata pd_val) { | ||
395 | cJSON *result = cJSON_CreateObject(); | ||
396 | |||
397 | // Label | ||
398 | cJSON_AddStringToObject(result, "label", pd_val.label); | ||
399 | |||
400 | // Value | ||
401 | cJSON_AddItemToObject(result, "value", json_serialise_pd_value(pd_val.value)); | ||
402 | |||
403 | // Uom | ||
404 | cJSON_AddStringToObject(result, "uom", pd_val.uom); | ||
405 | |||
406 | // Warn/Crit | ||
407 | if (pd_val.warn_present) { | ||
408 | cJSON *warn = json_serialise_range(pd_val.warn); | ||
409 | cJSON_AddItemToObject(result, "warn", warn); | ||
410 | } | ||
411 | if (pd_val.crit_present) { | ||
412 | cJSON *crit = json_serialise_range(pd_val.crit); | ||
413 | cJSON_AddItemToObject(result, "crit", crit); | ||
414 | } | ||
415 | |||
416 | if (pd_val.min_present) { | ||
417 | cJSON_AddItemToObject(result, "min", json_serialise_pd_value(pd_val.min)); | ||
418 | } | ||
419 | if (pd_val.max_present) { | ||
420 | cJSON_AddItemToObject(result, "max", json_serialise_pd_value(pd_val.max)); | ||
421 | } | ||
422 | |||
423 | return result; | ||
424 | } | ||
425 | |||
426 | static inline cJSON *json_serialise_pd_list(pd_list *list) { | ||
427 | cJSON *result = cJSON_CreateArray(); | ||
428 | |||
429 | do { | ||
430 | cJSON *pd_value = json_serialise_pd(list->data); | ||
431 | cJSON_AddItemToArray(result, pd_value); | ||
432 | list = list->next; | ||
433 | } while (list != NULL); | ||
434 | |||
435 | return result; | ||
436 | } | ||
437 | |||
438 | static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck) { | ||
439 | cJSON *result = cJSON_CreateObject(); | ||
440 | |||
441 | // Human readable output | ||
442 | cJSON *output = cJSON_CreateString(subcheck.output); | ||
443 | cJSON_AddItemToObject(result, "output", output); | ||
444 | |||
445 | // Test state (aka Exit Code) | ||
446 | cJSON *state = cJSON_CreateString(state_text(mp_compute_subcheck_state(subcheck))); | ||
447 | cJSON_AddItemToObject(result, "state", state); | ||
448 | |||
449 | // Perfdata | ||
450 | if (subcheck.perfdata != NULL) { | ||
451 | cJSON *perfdata = json_serialise_pd_list(subcheck.perfdata); | ||
452 | cJSON_AddItemToObject(result, "perfdata", perfdata); | ||
453 | } | ||
454 | |||
455 | if (subcheck.subchecks != NULL) { | ||
456 | cJSON *subchecks = cJSON_CreateArray(); | ||
457 | |||
458 | mp_subcheck_list *sc = subcheck.subchecks; | ||
459 | |||
460 | while (sc != NULL) { | ||
461 | cJSON *sc_json = json_serialize_subcheck(sc->subcheck); | ||
462 | cJSON_AddItemToArray(subchecks, sc_json); | ||
463 | sc = sc->next; | ||
464 | } | ||
465 | |||
466 | cJSON_AddItemToObject(result, "checks", subchecks); | ||
467 | } | ||
468 | |||
469 | return result; | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * Wrapper function to print the output string of a mp_check object | ||
474 | * Use this in concrete plugins. | ||
475 | */ | ||
476 | void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); } | ||
477 | |||
478 | /* | ||
479 | * Convenience function to print the output string of a mp_check object and exit | ||
480 | * the program with the resulting state. | ||
481 | * Intended to be used to exit a monitoring plugin. | ||
482 | */ | ||
483 | void mp_exit(mp_check check) { | ||
484 | mp_print_output(check); | ||
485 | if (check.format == MP_FORMAT_TEST_JSON) { | ||
486 | exit(0); | ||
487 | } | ||
488 | |||
489 | exit(mp_compute_check_state(check)); | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * Function to set the result state of a mp_subcheck object explicitly. | ||
494 | * This will overwrite the default state AND states derived from it's subchecks | ||
495 | */ | ||
496 | mp_subcheck mp_set_subcheck_state(mp_subcheck check, mp_state_enum state) { | ||
497 | check.state = state; | ||
498 | check.state_set_explicitly = true; | ||
499 | return check; | ||
500 | } | ||
501 | |||
502 | /* | ||
503 | * Function to set the default result state of a mp_subcheck object. This state | ||
504 | * will be used if neither an explicit state is set (see *mp_set_subcheck_state*) | ||
505 | * nor does it include other subchecks | ||
506 | */ | ||
507 | mp_subcheck mp_set_subcheck_default_state(mp_subcheck check, mp_state_enum state) { | ||
508 | check.default_state = state; | ||
509 | return check; | ||
510 | } | ||
511 | |||
512 | char *mp_output_format_map[] = { | ||
513 | [MP_FORMAT_MULTI_LINE] = "multi-line", | ||
514 | [MP_FORMAT_TEST_JSON] = "mp-test-json", | ||
515 | }; | ||
516 | |||
517 | /* | ||
518 | * Function to parse the output from a string | ||
519 | */ | ||
520 | parsed_output_format mp_parse_output_format(char *format_string) { | ||
521 | parsed_output_format result = { | ||
522 | .parsing_success = false, | ||
523 | .output_format = MP_FORMAT_DEFAULT, | ||
524 | }; | ||
525 | |||
526 | for (mp_output_format i = 0; i < (sizeof(mp_output_format_map) / sizeof(char *)); i++) { | ||
527 | if (strcasecmp(mp_output_format_map[i], format_string) == 0) { | ||
528 | result.parsing_success = true; | ||
529 | result.output_format = i; | ||
530 | break; | ||
531 | } | ||
532 | } | ||
533 | |||
534 | return result; | ||
535 | } | ||
diff --git a/lib/output.h b/lib/output.h new file mode 100644 index 00000000..ffc36f53 --- /dev/null +++ b/lib/output.h | |||
@@ -0,0 +1,85 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "../config.h" | ||
4 | #include "./perfdata.h" | ||
5 | #include "./states.h" | ||
6 | |||
7 | /* | ||
8 | * A partial check result | ||
9 | */ | ||
10 | typedef struct { | ||
11 | mp_state_enum state; // OK, Warning, Critical ... set explicitly | ||
12 | mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly | ||
13 | bool state_set_explicitly; // was the state set explicitly (or should it be derived from subchecks) | ||
14 | |||
15 | char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP connection to..") | ||
16 | pd_list *perfdata; // Performance data for this check | ||
17 | struct subcheck_list *subchecks; // subchecks deeper in the hierarchy | ||
18 | } mp_subcheck; | ||
19 | |||
20 | /* | ||
21 | * A list of subchecks, used in subchecks and the main check | ||
22 | */ | ||
23 | typedef struct subcheck_list { | ||
24 | mp_subcheck subcheck; | ||
25 | struct subcheck_list *next; | ||
26 | } mp_subcheck_list; | ||
27 | |||
28 | /* | ||
29 | * Possible output formats | ||
30 | */ | ||
31 | typedef enum output_format { | ||
32 | MP_FORMAT_MULTI_LINE, | ||
33 | MP_FORMAT_TEST_JSON, | ||
34 | } mp_output_format; | ||
35 | |||
36 | #define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE | ||
37 | |||
38 | /* | ||
39 | * The main state object of a plugin. Exists only ONCE per plugin. | ||
40 | * This is the "root" of a tree of singular checks. | ||
41 | * The final result is always derived from the children and the "worst" state | ||
42 | * in the first layer of subchecks | ||
43 | */ | ||
44 | typedef struct { | ||
45 | mp_output_format format; // The output format | ||
46 | char *summary; // Overall summary, if not set a summary will be automatically generated | ||
47 | mp_subcheck_list *subchecks; | ||
48 | } mp_check; | ||
49 | |||
50 | mp_check mp_check_init(void); | ||
51 | mp_subcheck mp_subcheck_init(void); | ||
52 | |||
53 | mp_subcheck mp_set_subcheck_state(mp_subcheck, mp_state_enum); | ||
54 | mp_subcheck mp_set_subcheck_default_state(mp_subcheck, mp_state_enum); | ||
55 | |||
56 | int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck); | ||
57 | int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck); | ||
58 | |||
59 | void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], mp_perfdata); | ||
60 | |||
61 | void mp_add_summary(mp_check check[static 1], char *summary); | ||
62 | |||
63 | mp_state_enum mp_compute_check_state(mp_check); | ||
64 | mp_state_enum mp_compute_subcheck_state(mp_subcheck); | ||
65 | |||
66 | typedef struct { | ||
67 | bool parsing_success; | ||
68 | mp_output_format output_format; | ||
69 | } parsed_output_format; | ||
70 | parsed_output_format mp_parse_output_format(char *format_string); | ||
71 | |||
72 | // TODO free and stuff | ||
73 | // void mp_cleanup_check(mp_check check[static 1]); | ||
74 | |||
75 | char *mp_fmt_output(mp_check); | ||
76 | |||
77 | void mp_print_output(mp_check); | ||
78 | |||
79 | /* | ||
80 | * ================== | ||
81 | * Exit functionality | ||
82 | * ================== | ||
83 | */ | ||
84 | |||
85 | void mp_exit(mp_check) __attribute__((noreturn)); | ||
diff --git a/lib/parse_ini.c b/lib/parse_ini.c index 09c0dc4f..1289aae2 100644 --- a/lib/parse_ini.c +++ b/lib/parse_ini.c | |||
@@ -1,25 +1,25 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Monitoring Plugins parse_ini library | 3 | * Monitoring Plugins parse_ini library |
4 | * | 4 | * |
5 | * License: GPL | 5 | * License: GPL |
6 | * Copyright (c) 2007 Monitoring Plugins Development Team | 6 | * Copyright (c) 2007 - 2024 Monitoring Plugins Development Team |
7 | * | 7 | * |
8 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation, either version 3 of the License, or | 10 | * the Free Software Foundation, either version 3 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | * | 20 | * |
21 | * | 21 | * |
22 | *****************************************************************************/ | 22 | *****************************************************************************/ |
23 | 23 | ||
24 | #include "common.h" | 24 | #include "common.h" |
25 | #include "idpriv.h" | 25 | #include "idpriv.h" |
@@ -40,31 +40,20 @@ typedef struct { | |||
40 | char *stanza; | 40 | char *stanza; |
41 | } np_ini_info; | 41 | } np_ini_info; |
42 | 42 | ||
43 | static char *default_ini_file_names[] = { | 43 | static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini", "nagios-plugins.ini", NULL}; |
44 | "monitoring-plugins.ini", | ||
45 | "plugins.ini", | ||
46 | "nagios-plugins.ini", | ||
47 | NULL | ||
48 | }; | ||
49 | 44 | ||
50 | static char *default_ini_path_names[] = { | 45 | static char *default_ini_path_names[] = { |
51 | "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", | 46 | "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", "/usr/local/etc/monitoring-plugins.ini", |
52 | "/usr/local/etc/monitoring-plugins.ini", | 47 | "/etc/monitoring-plugins/monitoring-plugins.ini", "/etc/monitoring-plugins.ini", |
53 | "/etc/monitoring-plugins/monitoring-plugins.ini", | ||
54 | "/etc/monitoring-plugins.ini", | ||
55 | /* deprecated path names (for backward compatibility): */ | 48 | /* deprecated path names (for backward compatibility): */ |
56 | "/etc/nagios/plugins.ini", | 49 | "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini", "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini", |
57 | "/usr/local/nagios/etc/plugins.ini", | 50 | "/etc/nagios-plugins.ini", "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL}; |
58 | "/usr/local/etc/nagios/plugins.ini", | ||
59 | "/etc/opt/nagios/plugins.ini", | ||
60 | "/etc/nagios-plugins.ini", | ||
61 | "/usr/local/etc/nagios-plugins.ini", | ||
62 | "/etc/opt/nagios-plugins.ini", | ||
63 | NULL | ||
64 | }; | ||
65 | 51 | ||
66 | /* eat all characters from a FILE pointer until n is encountered */ | 52 | /* eat all characters from a FILE pointer until n is encountered */ |
67 | #define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) | 53 | #define GOBBLE_TO(f, c, n) \ |
54 | do { \ | ||
55 | (c) = fgetc((f)); \ | ||
56 | } while ((c) != EOF && (c) != (n)) | ||
68 | 57 | ||
69 | /* internal function that returns the constructed defaults options */ | 58 | /* internal function that returns the constructed defaults options */ |
70 | static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); | 59 | static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); |
@@ -81,9 +70,7 @@ static char *default_file_in_path(void); | |||
81 | * [stanza][@filename] | 70 | * [stanza][@filename] |
82 | * into its separate parts. | 71 | * into its separate parts. |
83 | */ | 72 | */ |
84 | static void | 73 | static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) { |
85 | parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) | ||
86 | { | ||
87 | size_t locator_len = 0, stanza_len = 0; | 74 | size_t locator_len = 0, stanza_len = 0; |
88 | 75 | ||
89 | /* if locator is NULL we'll use default values */ | 76 | /* if locator is NULL we'll use default values */ |
@@ -96,7 +83,7 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) | |||
96 | i->stanza = malloc(sizeof(char) * (stanza_len + 1)); | 83 | i->stanza = malloc(sizeof(char) * (stanza_len + 1)); |
97 | strncpy(i->stanza, locator, stanza_len); | 84 | strncpy(i->stanza, locator, stanza_len); |
98 | i->stanza[stanza_len] = '\0'; | 85 | i->stanza[stanza_len] = '\0'; |
99 | } else {/* otherwise we use the default stanza */ | 86 | } else { /* otherwise we use the default stanza */ |
100 | i->stanza = strdup(def_stanza); | 87 | i->stanza = strdup(def_stanza); |
101 | } | 88 | } |
102 | 89 | ||
@@ -105,7 +92,7 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) | |||
105 | 92 | ||
106 | /* check whether there's an @file part */ | 93 | /* check whether there's an @file part */ |
107 | if (stanza_len == locator_len) { | 94 | if (stanza_len == locator_len) { |
108 | i->file = default_file(); | 95 | i->file = default_file(); |
109 | i->file_string_on_heap = false; | 96 | i->file_string_on_heap = false; |
110 | } else { | 97 | } else { |
111 | i->file = strdup(&(locator[stanza_len + 1])); | 98 | i->file = strdup(&(locator[stanza_len + 1])); |
@@ -113,35 +100,28 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) | |||
113 | } | 100 | } |
114 | 101 | ||
115 | if (i->file == NULL || i->file[0] == '\0') | 102 | if (i->file == NULL || i->file[0] == '\0') |
116 | die(STATE_UNKNOWN, | 103 | die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n")); |
117 | _("Cannot find config file in any standard location.\n")); | ||
118 | } | 104 | } |
119 | 105 | ||
120 | /* | 106 | /* |
121 | * This is the externally visible function used by extra_opts. | 107 | * This is the externally visible function used by extra_opts. |
122 | */ | 108 | */ |
123 | np_arg_list * | 109 | np_arg_list *np_get_defaults(const char *locator, const char *default_section) { |
124 | np_get_defaults(const char *locator, const char *default_section) | ||
125 | { | ||
126 | FILE *inifile = NULL; | 110 | FILE *inifile = NULL; |
127 | np_arg_list *defaults = NULL; | 111 | np_arg_list *defaults = NULL; |
128 | np_ini_info i; | 112 | np_ini_info i; |
129 | int is_suid_plugin = mp_suid(); | 113 | int is_suid_plugin = mp_suid(); |
130 | 114 | ||
131 | if (is_suid_plugin && idpriv_temp_drop() == -1) | 115 | if (is_suid_plugin && idpriv_temp_drop() == -1) |
132 | die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), | 116 | die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno)); |
133 | strerror(errno)); | ||
134 | 117 | ||
135 | parse_locator(locator, default_section, &i); | 118 | parse_locator(locator, default_section, &i); |
136 | inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); | 119 | inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); |
137 | 120 | ||
138 | if (inifile == NULL) | 121 | if (inifile == NULL) |
139 | die(STATE_UNKNOWN, _("Can't read config file: %s\n"), | 122 | die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno)); |
140 | strerror(errno)); | ||
141 | if (!read_defaults(inifile, i.stanza, &defaults)) | 123 | if (!read_defaults(inifile, i.stanza, &defaults)) |
142 | die(STATE_UNKNOWN, | 124 | die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), i.stanza, i.file); |
143 | _("Invalid section '%s' in config file '%s'\n"), i.stanza, | ||
144 | i.file); | ||
145 | 125 | ||
146 | if (i.file_string_on_heap) { | 126 | if (i.file_string_on_heap) { |
147 | free(i.file); | 127 | free(i.file); |
@@ -151,8 +131,7 @@ np_get_defaults(const char *locator, const char *default_section) | |||
151 | fclose(inifile); | 131 | fclose(inifile); |
152 | free(i.stanza); | 132 | free(i.stanza); |
153 | if (is_suid_plugin && idpriv_temp_restore() == -1) | 133 | if (is_suid_plugin && idpriv_temp_restore() == -1) |
154 | die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), | 134 | die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno)); |
155 | strerror(errno)); | ||
156 | 135 | ||
157 | return defaults; | 136 | return defaults; |
158 | } | 137 | } |
@@ -164,13 +143,15 @@ np_get_defaults(const char *locator, const char *default_section) | |||
164 | * be extra careful about user-supplied input (i.e. avoiding possible | 143 | * be extra careful about user-supplied input (i.e. avoiding possible |
165 | * format string vulnerabilities, etc). | 144 | * format string vulnerabilities, etc). |
166 | */ | 145 | */ |
167 | static int | 146 | static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) { |
168 | read_defaults(FILE *f, const char *stanza, np_arg_list **opts) | ||
169 | { | ||
170 | int c = 0; | 147 | int c = 0; |
171 | bool status = false; | 148 | bool status = false; |
172 | size_t i, stanza_len; | 149 | size_t i, stanza_len; |
173 | enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate = NOSTANZA; | 150 | enum { |
151 | NOSTANZA, | ||
152 | WRONGSTANZA, | ||
153 | RIGHTSTANZA | ||
154 | } stanzastate = NOSTANZA; | ||
174 | 155 | ||
175 | stanza_len = strlen(stanza); | 156 | stanza_len = strlen(stanza); |
176 | 157 | ||
@@ -217,8 +198,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts) | |||
217 | * we're dealing with a config error | 198 | * we're dealing with a config error |
218 | */ | 199 | */ |
219 | case NOSTANZA: | 200 | case NOSTANZA: |
220 | die(STATE_UNKNOWN, "%s\n", | 201 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); |
221 | _("Config file error")); | ||
222 | /* we're in a stanza, but for a different plugin */ | 202 | /* we're in a stanza, but for a different plugin */ |
223 | case WRONGSTANZA: | 203 | case WRONGSTANZA: |
224 | GOBBLE_TO(f, c, '\n'); | 204 | GOBBLE_TO(f, c, '\n'); |
@@ -227,8 +207,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts) | |||
227 | case RIGHTSTANZA: | 207 | case RIGHTSTANZA: |
228 | ungetc(c, f); | 208 | ungetc(c, f); |
229 | if (add_option(f, opts)) { | 209 | if (add_option(f, opts)) { |
230 | die(STATE_UNKNOWN, "%s\n", | 210 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); |
231 | _("Config file error")); | ||
232 | } | 211 | } |
233 | status = true; | 212 | status = true; |
234 | break; | 213 | break; |
@@ -246,9 +225,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts) | |||
246 | * --option[=value] | 225 | * --option[=value] |
247 | * appending it to the linked list optbuf. | 226 | * appending it to the linked list optbuf. |
248 | */ | 227 | */ |
249 | static int | 228 | static int add_option(FILE *f, np_arg_list **optlst) { |
250 | add_option(FILE *f, np_arg_list **optlst) | ||
251 | { | ||
252 | np_arg_list *opttmp = *optlst, *optnew; | 229 | np_arg_list *opttmp = *optlst, *optnew; |
253 | char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; | 230 | char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; |
254 | char *eqptr = NULL, *valptr = NULL, *valend = NULL; | 231 | char *eqptr = NULL, *valptr = NULL, *valend = NULL; |
@@ -295,8 +272,7 @@ add_option(FILE *f, np_arg_list **optlst) | |||
295 | if (optptr == eqptr) | 272 | if (optptr == eqptr) |
296 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); | 273 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); |
297 | /* continue from '=' to start of value or EOL */ | 274 | /* continue from '=' to start of value or EOL */ |
298 | for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); | 275 | for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++) |
299 | valptr++) | ||
300 | continue; | 276 | continue; |
301 | /* continue to the end of value */ | 277 | /* continue to the end of value */ |
302 | for (valend = valptr; valend < lineend; valend++) | 278 | for (valend = valptr; valend < lineend; valend++) |
@@ -365,13 +341,10 @@ add_option(FILE *f, np_arg_list **optlst) | |||
365 | return 0; | 341 | return 0; |
366 | } | 342 | } |
367 | 343 | ||
368 | static char * | 344 | static char *default_file(void) { |
369 | default_file(void) | 345 | char *ini_file; |
370 | { | ||
371 | char *ini_file; | ||
372 | 346 | ||
373 | if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || | 347 | if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || (ini_file = default_file_in_path()) != NULL) { |
374 | (ini_file = default_file_in_path()) != NULL) { | ||
375 | return ini_file; | 348 | return ini_file; |
376 | } | 349 | } |
377 | 350 | ||
@@ -383,9 +356,7 @@ default_file(void) | |||
383 | return NULL; | 356 | return NULL; |
384 | } | 357 | } |
385 | 358 | ||
386 | static char * | 359 | static char *default_file_in_path(void) { |
387 | default_file_in_path(void) | ||
388 | { | ||
389 | char *config_path, **file; | 360 | char *config_path, **file; |
390 | char *dir, *ini_file, *tokens; | 361 | char *dir, *ini_file, *tokens; |
391 | 362 | ||
diff --git a/lib/parse_ini.h b/lib/parse_ini.h index e37601b5..d17409e3 100644 --- a/lib/parse_ini.h +++ b/lib/parse_ini.h | |||
@@ -19,4 +19,3 @@ typedef struct np_arg_el { | |||
19 | np_arg_list *np_get_defaults(const char *locator, const char *default_section); | 19 | np_arg_list *np_get_defaults(const char *locator, const char *default_section); |
20 | 20 | ||
21 | #endif /* _PARSE_INI_H_ */ | 21 | #endif /* _PARSE_INI_H_ */ |
22 | |||
diff --git a/lib/perfdata.c b/lib/perfdata.c new file mode 100644 index 00000000..661756c5 --- /dev/null +++ b/lib/perfdata.c | |||
@@ -0,0 +1,516 @@ | |||
1 | #include "./perfdata.h" | ||
2 | #include "../plugins/common.h" | ||
3 | #include "../plugins/utils.h" | ||
4 | #include "utils_base.h" | ||
5 | |||
6 | #include <assert.h> | ||
7 | #include <limits.h> | ||
8 | #include <stdlib.h> | ||
9 | |||
10 | char *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 | |||
33 | char *pd_to_string(mp_perfdata pd) { | ||
34 | assert(pd.label != NULL); | ||
35 | char *result = NULL; | ||
36 | asprintf(&result, "%s=", pd.label); | ||
37 | |||
38 | asprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); | ||
39 | |||
40 | if (pd.uom != NULL) { | ||
41 | asprintf(&result, "%s%s", result, pd.uom); | ||
42 | } | ||
43 | |||
44 | if (pd.warn_present) { | ||
45 | asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn)); | ||
46 | } else { | ||
47 | asprintf(&result, "%s;", result); | ||
48 | } | ||
49 | |||
50 | if (pd.crit_present) { | ||
51 | asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit)); | ||
52 | } else { | ||
53 | asprintf(&result, "%s;", result); | ||
54 | } | ||
55 | if (pd.min_present) { | ||
56 | asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min)); | ||
57 | } else { | ||
58 | asprintf(&result, "%s;", result); | ||
59 | } | ||
60 | |||
61 | if (pd.max_present) { | ||
62 | asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max)); | ||
63 | } | ||
64 | |||
65 | /*printf("pd_to_string: %s\n", result); */ | ||
66 | |||
67 | return result; | ||
68 | } | ||
69 | |||
70 | char *pd_list_to_string(const pd_list pd) { | ||
71 | char *result = pd_to_string(pd.data); | ||
72 | |||
73 | for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) { | ||
74 | asprintf(&result, "%s %s", result, pd_to_string(elem->data)); | ||
75 | } | ||
76 | |||
77 | return result; | ||
78 | } | ||
79 | |||
80 | mp_perfdata perfdata_init() { | ||
81 | mp_perfdata pd = {}; | ||
82 | return pd; | ||
83 | } | ||
84 | |||
85 | pd_list *pd_list_init() { | ||
86 | pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list)); | ||
87 | if (tmp == NULL) { | ||
88 | die(STATE_UNKNOWN, "calloc failed\n"); | ||
89 | } | ||
90 | tmp->next = NULL; | ||
91 | return tmp; | ||
92 | } | ||
93 | |||
94 | mp_range mp_range_init() { | ||
95 | mp_range result = { | ||
96 | .alert_on_inside_range = OUTSIDE, | ||
97 | .start = {}, | ||
98 | .start_infinity = true, | ||
99 | .end = {}, | ||
100 | .end_infinity = true, | ||
101 | }; | ||
102 | |||
103 | return result; | ||
104 | } | ||
105 | |||
106 | mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) { | ||
107 | input.start = perf_val; | ||
108 | input.start_infinity = false; | ||
109 | return input; | ||
110 | } | ||
111 | |||
112 | mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) { | ||
113 | input.end = perf_val; | ||
114 | input.end_infinity = false; | ||
115 | return input; | ||
116 | } | ||
117 | |||
118 | void pd_list_append(pd_list pdl[1], const mp_perfdata pd) { | ||
119 | assert(pdl != NULL); | ||
120 | |||
121 | if (pdl->data.value.type == PD_TYPE_NONE) { | ||
122 | // first entry is still empty | ||
123 | pdl->data = pd; | ||
124 | } else { | ||
125 | // find last element in the list | ||
126 | pd_list *curr = pdl; | ||
127 | pd_list *next = pdl->next; | ||
128 | |||
129 | while (next != NULL) { | ||
130 | curr = next; | ||
131 | next = next->next; | ||
132 | } | ||
133 | |||
134 | if (curr->data.value.type == PD_TYPE_NONE) { | ||
135 | // still empty | ||
136 | curr->data = pd; | ||
137 | } else { | ||
138 | // new a new one | ||
139 | curr->next = pd_list_init(); | ||
140 | curr->next->data = pd; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void pd_list_free(pd_list pdl[1]) { | ||
146 | while (pdl != NULL) { | ||
147 | pd_list *old = pdl; | ||
148 | pdl = pdl->next; | ||
149 | free(old); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * returns -1 if a < b, 0 if a == b, 1 if a > b | ||
155 | */ | ||
156 | int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) { | ||
157 | // Test if types are different | ||
158 | if (a.type == b.type) { | ||
159 | |||
160 | switch (a.type) { | ||
161 | case PD_TYPE_UINT: | ||
162 | if (a.pd_uint < b.pd_uint) { | ||
163 | return -1; | ||
164 | } else if (a.pd_uint == b.pd_uint) { | ||
165 | return 0; | ||
166 | } else { | ||
167 | return 1; | ||
168 | } | ||
169 | break; | ||
170 | case PD_TYPE_INT: | ||
171 | if (a.pd_int < b.pd_int) { | ||
172 | return -1; | ||
173 | } else if (a.pd_int == b.pd_int) { | ||
174 | return 0; | ||
175 | } else { | ||
176 | return 1; | ||
177 | } | ||
178 | break; | ||
179 | case PD_TYPE_DOUBLE: | ||
180 | if (a.pd_int < b.pd_int) { | ||
181 | return -1; | ||
182 | } else if (a.pd_int == b.pd_int) { | ||
183 | return 0; | ||
184 | } else { | ||
185 | return 1; | ||
186 | } | ||
187 | break; | ||
188 | default: | ||
189 | die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | // Get dirty here | ||
194 | long double floating_a = 0; | ||
195 | |||
196 | switch (a.type) { | ||
197 | case PD_TYPE_UINT: | ||
198 | floating_a = a.pd_uint; | ||
199 | break; | ||
200 | case PD_TYPE_INT: | ||
201 | floating_a = a.pd_int; | ||
202 | break; | ||
203 | case PD_TYPE_DOUBLE: | ||
204 | floating_a = a.pd_double; | ||
205 | break; | ||
206 | default: | ||
207 | die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); | ||
208 | } | ||
209 | |||
210 | long double floating_b = 0; | ||
211 | switch (b.type) { | ||
212 | case PD_TYPE_UINT: | ||
213 | floating_b = b.pd_uint; | ||
214 | break; | ||
215 | case PD_TYPE_INT: | ||
216 | floating_b = b.pd_int; | ||
217 | break; | ||
218 | case PD_TYPE_DOUBLE: | ||
219 | floating_b = b.pd_double; | ||
220 | break; | ||
221 | default: | ||
222 | die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); | ||
223 | } | ||
224 | |||
225 | if (floating_a < floating_b) { | ||
226 | return -1; | ||
227 | } | ||
228 | if (floating_a == floating_b) { | ||
229 | return 0; | ||
230 | } | ||
231 | return 1; | ||
232 | } | ||
233 | |||
234 | char *mp_range_to_string(const mp_range input) { | ||
235 | char *result = ""; | ||
236 | if (input.alert_on_inside_range == INSIDE) { | ||
237 | asprintf(&result, "@"); | ||
238 | } | ||
239 | |||
240 | if (input.start_infinity) { | ||
241 | asprintf(&result, "%s~:", result); | ||
242 | } else { | ||
243 | asprintf(&result, "%s%s:", result, pd_value_to_string(input.start)); | ||
244 | } | ||
245 | |||
246 | if (!input.end_infinity) { | ||
247 | asprintf(&result, "%s%s", result, pd_value_to_string(input.end)); | ||
248 | } | ||
249 | return result; | ||
250 | } | ||
251 | |||
252 | mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); } | ||
253 | |||
254 | mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { | ||
255 | pd.value.pd_double = value; | ||
256 | pd.value.type = PD_TYPE_DOUBLE; | ||
257 | return pd; | ||
258 | } | ||
259 | |||
260 | mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); } | ||
261 | |||
262 | mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } | ||
263 | |||
264 | mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); } | ||
265 | |||
266 | mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) { | ||
267 | return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); | ||
268 | } | ||
269 | |||
270 | mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) { | ||
271 | pd.value.pd_int = value; | ||
272 | pd.value.type = PD_TYPE_INT; | ||
273 | return pd; | ||
274 | } | ||
275 | |||
276 | mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) { | ||
277 | pd.value.pd_uint = value; | ||
278 | pd.value.type = PD_TYPE_UINT; | ||
279 | return pd; | ||
280 | } | ||
281 | |||
282 | mp_perfdata_value mp_create_pd_value_double(double value) { | ||
283 | mp_perfdata_value res = {0}; | ||
284 | res.type = PD_TYPE_DOUBLE; | ||
285 | res.pd_double = value; | ||
286 | return res; | ||
287 | } | ||
288 | |||
289 | mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); } | ||
290 | |||
291 | mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); } | ||
292 | |||
293 | mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | ||
294 | |||
295 | mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); } | ||
296 | |||
297 | mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | ||
298 | |||
299 | mp_perfdata_value mp_create_pd_value_long_long(long long value) { | ||
300 | mp_perfdata_value res = {0}; | ||
301 | res.type = PD_TYPE_INT; | ||
302 | res.pd_int = value; | ||
303 | return res; | ||
304 | } | ||
305 | |||
306 | mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) { | ||
307 | mp_perfdata_value res = {0}; | ||
308 | res.type = PD_TYPE_UINT; | ||
309 | res.pd_uint = value; | ||
310 | return res; | ||
311 | } | ||
312 | |||
313 | char *fmt_range(range foo) { return foo.text; } | ||
314 | |||
315 | typedef struct integer_parser_wrapper { | ||
316 | int error; | ||
317 | mp_perfdata_value value; | ||
318 | } integer_parser_wrapper; | ||
319 | |||
320 | typedef struct double_parser_wrapper { | ||
321 | int error; | ||
322 | mp_perfdata_value value; | ||
323 | } double_parser_wrapper; | ||
324 | |||
325 | typedef struct perfdata_value_parser_wrapper { | ||
326 | int error; | ||
327 | mp_perfdata_value value; | ||
328 | } perfdata_value_parser_wrapper; | ||
329 | |||
330 | double_parser_wrapper parse_double(const char *input); | ||
331 | integer_parser_wrapper parse_integer(const char *input); | ||
332 | perfdata_value_parser_wrapper parse_pd_value(const char *input); | ||
333 | |||
334 | mp_range_parsed mp_parse_range_string(const char *input) { | ||
335 | if (input == NULL) { | ||
336 | mp_range_parsed result = { | ||
337 | .error = MP_RANGE_PARSING_FAILURE, | ||
338 | }; | ||
339 | return result; | ||
340 | } | ||
341 | |||
342 | if (strlen(input) == 0) { | ||
343 | mp_range_parsed result = { | ||
344 | .error = MP_RANGE_PARSING_FAILURE, | ||
345 | }; | ||
346 | return result; | ||
347 | } | ||
348 | |||
349 | mp_range_parsed result = { | ||
350 | .range = mp_range_init(), | ||
351 | .error = MP_PARSING_SUCCES, | ||
352 | }; | ||
353 | |||
354 | if (input[0] == '@') { | ||
355 | // found an '@' at beginning, so invert the range logic | ||
356 | result.range.alert_on_inside_range = INSIDE; | ||
357 | |||
358 | // advance the pointer one symbol | ||
359 | input++; | ||
360 | } | ||
361 | |||
362 | char *working_copy = strdup(input); | ||
363 | input = working_copy; | ||
364 | |||
365 | char *separator = index(working_copy, ':'); | ||
366 | if (separator != NULL) { | ||
367 | // Found a separator | ||
368 | // set the separator to 0, so we have two different strings | ||
369 | *separator = '\0'; | ||
370 | |||
371 | if (input[0] == '~') { | ||
372 | // the beginning starts with '~', so it might be infinity | ||
373 | if (&input[1] != separator) { | ||
374 | // the next symbol after '~' is not the separator! | ||
375 | // so input is probably wrong | ||
376 | result.error = MP_RANGE_PARSING_FAILURE; | ||
377 | free(working_copy); | ||
378 | return result; | ||
379 | } | ||
380 | |||
381 | result.range.start_infinity = true; | ||
382 | } else { | ||
383 | // No '~' at the beginning, so this should be a number | ||
384 | result.range.start_infinity = false; | ||
385 | perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input); | ||
386 | |||
387 | if (parsed_pd.error != MP_PARSING_SUCCES) { | ||
388 | result.error = parsed_pd.error; | ||
389 | free(working_copy); | ||
390 | return result; | ||
391 | } | ||
392 | |||
393 | result.range.start = parsed_pd.value; | ||
394 | result.range.start_infinity = false; | ||
395 | } | ||
396 | // got the first part now | ||
397 | // advance the pointer | ||
398 | input = separator + 1; | ||
399 | } | ||
400 | |||
401 | // End part or no separator | ||
402 | if (input[0] == '\0') { | ||
403 | // the end is infinite | ||
404 | result.range.end_infinity = true; | ||
405 | } else { | ||
406 | perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input); | ||
407 | |||
408 | if (parsed_pd.error != MP_PARSING_SUCCES) { | ||
409 | result.error = parsed_pd.error; | ||
410 | return result; | ||
411 | } | ||
412 | result.range.end = parsed_pd.value; | ||
413 | result.range.end_infinity = false; | ||
414 | } | ||
415 | free(working_copy); | ||
416 | return result; | ||
417 | } | ||
418 | |||
419 | double_parser_wrapper parse_double(const char *input) { | ||
420 | double_parser_wrapper result = { | ||
421 | .error = MP_PARSING_SUCCES, | ||
422 | }; | ||
423 | |||
424 | if (input == NULL) { | ||
425 | result.error = MP_PARSING_FAILURE; | ||
426 | return result; | ||
427 | } | ||
428 | |||
429 | char *endptr = NULL; | ||
430 | errno = 0; | ||
431 | double tmp = strtod(input, &endptr); | ||
432 | |||
433 | if (input == endptr) { | ||
434 | // man 3 strtod says, no conversion performed | ||
435 | result.error = MP_PARSING_FAILURE; | ||
436 | return result; | ||
437 | } | ||
438 | |||
439 | if (errno) { | ||
440 | // some other error | ||
441 | // TODO maybe differentiate a little bit | ||
442 | result.error = MP_PARSING_FAILURE; | ||
443 | return result; | ||
444 | } | ||
445 | |||
446 | result.value = mp_create_pd_value(tmp); | ||
447 | return result; | ||
448 | } | ||
449 | |||
450 | integer_parser_wrapper parse_integer(const char *input) { | ||
451 | integer_parser_wrapper result = { | ||
452 | .error = MP_PARSING_SUCCES, | ||
453 | }; | ||
454 | |||
455 | if (input == NULL) { | ||
456 | result.error = MP_PARSING_FAILURE; | ||
457 | return result; | ||
458 | } | ||
459 | |||
460 | char *endptr = NULL; | ||
461 | errno = 0; | ||
462 | long long tmp = strtoll(input, &endptr, 0); | ||
463 | |||
464 | // validating *sigh* | ||
465 | if (*endptr != '\0') { | ||
466 | // something went wrong in strtoll | ||
467 | if (tmp == LLONG_MIN) { | ||
468 | // underflow | ||
469 | result.error = MP_RANGE_PARSING_UNDERFLOW; | ||
470 | return result; | ||
471 | } | ||
472 | |||
473 | if (tmp == LLONG_MAX) { | ||
474 | // overflow | ||
475 | result.error = MP_RANGE_PARSING_OVERFLOW; | ||
476 | return result; | ||
477 | } | ||
478 | |||
479 | // still wrong, but not sure why, probably invalid characters | ||
480 | if (errno == EINVAL) { | ||
481 | result.error = MP_RANGE_PARSING_INVALID_CHAR; | ||
482 | return result; | ||
483 | } | ||
484 | |||
485 | // some other error, do catch all here | ||
486 | result.error = MP_RANGE_PARSING_FAILURE; | ||
487 | return result; | ||
488 | } | ||
489 | |||
490 | // no error, should be fine | ||
491 | result.value = mp_create_pd_value(tmp); | ||
492 | return result; | ||
493 | } | ||
494 | |||
495 | perfdata_value_parser_wrapper parse_pd_value(const char *input) { | ||
496 | // try integer first | ||
497 | integer_parser_wrapper tmp_int = parse_integer(input); | ||
498 | |||
499 | if (tmp_int.error == MP_PARSING_SUCCES) { | ||
500 | perfdata_value_parser_wrapper result = { | ||
501 | .error = tmp_int.error, | ||
502 | .value = tmp_int.value, | ||
503 | }; | ||
504 | return result; | ||
505 | } | ||
506 | |||
507 | double_parser_wrapper tmp_double = parse_double(input); | ||
508 | perfdata_value_parser_wrapper result = {}; | ||
509 | if (tmp_double.error == MP_PARSING_SUCCES) { | ||
510 | result.error = tmp_double.error; | ||
511 | result.value = tmp_double.value; | ||
512 | } else { | ||
513 | result.error = tmp_double.error; | ||
514 | } | ||
515 | return result; | ||
516 | } | ||
diff --git a/lib/perfdata.h b/lib/perfdata.h new file mode 100644 index 00000000..74583ee5 --- /dev/null +++ b/lib/perfdata.h | |||
@@ -0,0 +1,203 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "../config.h" | ||
4 | |||
5 | #include <inttypes.h> | ||
6 | #include <stdbool.h> | ||
7 | |||
8 | // Enum for the specific type of a perfdata_value | ||
9 | typedef 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 | |||
16 | typedef 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 | */ | ||
31 | typedef struct mp_range_struct { | ||
32 | mp_perfdata_value start; | ||
33 | bool start_infinity; /* false (default) or true */ | ||
34 | |||
35 | mp_perfdata_value end; | ||
36 | bool end_infinity; | ||
37 | |||
38 | bool alert_on_inside_range; /* OUTSIDE (default) or INSIDE */ | ||
39 | } mp_range; | ||
40 | |||
41 | /* | ||
42 | * Old range type with floating point values | ||
43 | */ | ||
44 | typedef struct range_struct { | ||
45 | double start; | ||
46 | bool start_infinity; | ||
47 | double end; | ||
48 | int end_infinity; | ||
49 | int alert_on; /* OUTSIDE (default) or INSIDE */ | ||
50 | char *text; /* original unparsed text input */ | ||
51 | } range; | ||
52 | |||
53 | /* | ||
54 | * Perfdata type for storing perfdata output | ||
55 | */ | ||
56 | typedef struct perfdata_struct { | ||
57 | char *label; | ||
58 | char *uom; | ||
59 | mp_perfdata_value value; | ||
60 | |||
61 | bool warn_present; | ||
62 | mp_range warn; | ||
63 | |||
64 | bool crit_present; | ||
65 | mp_range crit; | ||
66 | |||
67 | bool min_present; | ||
68 | mp_perfdata_value min; | ||
69 | |||
70 | bool max_present; | ||
71 | mp_perfdata_value max; | ||
72 | } mp_perfdata; | ||
73 | |||
74 | /* | ||
75 | * List of mp_perfdata values | ||
76 | */ | ||
77 | typedef 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 | */ | ||
90 | mp_perfdata perfdata_init(void); | ||
91 | |||
92 | /* | ||
93 | * Initialize pd_list value. Always use this to generate a new one | ||
94 | */ | ||
95 | pd_list *pd_list_init(void); | ||
96 | |||
97 | /* | ||
98 | * Initialize a new mp_range value, with unset values (start and end are infinite | ||
99 | */ | ||
100 | mp_range mp_range_init(void); | ||
101 | |||
102 | /* | ||
103 | * Worker functions | ||
104 | */ | ||
105 | |||
106 | mp_range mp_range_set_start(mp_range, mp_perfdata_value); | ||
107 | mp_range mp_range_set_end(mp_range, mp_perfdata_value); | ||
108 | |||
109 | /* | ||
110 | * Parsing a range from a string | ||
111 | */ | ||
112 | |||
113 | typedef 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 | |||
122 | typedef struct mp_range_parsed { | ||
123 | mp_range_parser_error error; | ||
124 | mp_range range; | ||
125 | } mp_range_parsed; | ||
126 | |||
127 | mp_range_parsed mp_parse_range_string(const char * /*input*/); | ||
128 | |||
129 | /* | ||
130 | * Appends a mp_perfdata value to a pd_list | ||
131 | */ | ||
132 | void 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 | |||
145 | mp_perfdata mp_set_pd_value_float(mp_perfdata, float); | ||
146 | mp_perfdata mp_set_pd_value_double(mp_perfdata, double); | ||
147 | mp_perfdata mp_set_pd_value_int(mp_perfdata, int); | ||
148 | mp_perfdata mp_set_pd_value_u_int(mp_perfdata, unsigned int); | ||
149 | mp_perfdata mp_set_pd_value_long(mp_perfdata, long); | ||
150 | mp_perfdata mp_set_pd_value_u_long(mp_perfdata, unsigned long); | ||
151 | mp_perfdata mp_set_pd_value_long_long(mp_perfdata, long long); | ||
152 | mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long); | ||
153 | |||
154 | #define mp_create_pd_value(V) \ | ||
155 | _Generic((V), \ | ||
156 | float: mp_create_pd_value_float, \ | ||
157 | double: mp_create_pd_value_double, \ | ||
158 | int: mp_create_pd_value_int, \ | ||
159 | unsigned int: mp_create_pd_value_u_int, \ | ||
160 | long: mp_create_pd_value_long, \ | ||
161 | unsigned long: mp_create_pd_value_u_long, \ | ||
162 | long long: mp_create_pd_value_long_long, \ | ||
163 | unsigned long long: mp_create_pd_value_u_long_long)(V) | ||
164 | |||
165 | mp_perfdata_value mp_create_pd_value_float(float); | ||
166 | mp_perfdata_value mp_create_pd_value_double(double); | ||
167 | mp_perfdata_value mp_create_pd_value_int(int); | ||
168 | mp_perfdata_value mp_create_pd_value_u_int(unsigned int); | ||
169 | mp_perfdata_value mp_create_pd_value_long(long); | ||
170 | mp_perfdata_value mp_create_pd_value_u_long(unsigned long); | ||
171 | mp_perfdata_value mp_create_pd_value_long_long(long long); | ||
172 | mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long); | ||
173 | |||
174 | /* | ||
175 | * Free the memory used by a pd_list | ||
176 | */ | ||
177 | void pd_list_free(pd_list[1]); | ||
178 | |||
179 | int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value); | ||
180 | |||
181 | // ================= | ||
182 | // String formatters | ||
183 | // ================= | ||
184 | /* | ||
185 | * Generate string from mp_perfdata value | ||
186 | */ | ||
187 | char *pd_to_string(mp_perfdata); | ||
188 | |||
189 | /* | ||
190 | * Generate string from perfdata_value value | ||
191 | */ | ||
192 | char *pd_value_to_string(mp_perfdata_value); | ||
193 | |||
194 | /* | ||
195 | * Generate string from pd_list value for the final output | ||
196 | */ | ||
197 | char *pd_list_to_string(pd_list); | ||
198 | |||
199 | /* | ||
200 | * Generate string from a mp_range value | ||
201 | */ | ||
202 | char *mp_range_to_string(mp_range); | ||
203 | char *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 | |||
7 | typedef 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 | |||
23 | static 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 | |||
52 | static inline mp_state_enum max_state_alt(mp_state_enum a, mp_state_enum b) { | ||
53 | if (a == STATE_CRITICAL || b == STATE_CRITICAL) { | ||
54 | return STATE_CRITICAL; | ||
55 | } | ||
56 | if (a == STATE_WARNING || b == STATE_WARNING) { | ||
57 | return STATE_WARNING; | ||
58 | } | ||
59 | if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) { | ||
60 | return STATE_UNKNOWN; | ||
61 | } | ||
62 | if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) { | ||
63 | return STATE_DEPENDENT; | ||
64 | } | ||
65 | if (a == STATE_OK || b == STATE_OK) { | ||
66 | return STATE_OK; | ||
67 | } | ||
68 | return MAX(a, b); | ||
69 | } | ||
70 | |||
71 | #endif | ||
diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am index 31d79df6..9be94f6d 100644 --- a/lib/tests/Makefile.am +++ b/lib/tests/Makefile.am | |||
@@ -8,9 +8,9 @@ check_PROGRAMS = @EXTRA_TEST@ | |||
8 | AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ | 8 | AM_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 | ||
11 | EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 | 11 | EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output |
12 | 12 | ||
13 | np_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 | 13 | np_test_scripts = test_base64.t test_cmd.t test_disk.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t test_generic_output.t |
14 | np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini | 14 | np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini |
15 | EXTRA_DIST = $(np_test_scripts) $(np_test_files) var | 15 | EXTRA_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) | |||
29 | AM_LDFLAGS = $(tap_ldflags) -ltap | 29 | AM_LDFLAGS = $(tap_ldflags) -ltap |
30 | LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO) | 30 | LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO) |
31 | 31 | ||
32 | SOURCES = 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 | 32 | SOURCES = test_utils.c test_disk.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c test_generic_output.c |
33 | 33 | ||
34 | test: ${noinst_PROGRAMS} | 34 | test: ${noinst_PROGRAMS} |
35 | perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS) | 35 | perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS) |
diff --git a/lib/tests/test_base64.c b/lib/tests/test_base64.c index 05dd7943..94cb5aa9 100644 --- a/lib/tests/test_base64.c +++ b/lib/tests/test_base64.c | |||
@@ -1,29 +1,27 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | * | 16 | * |
17 | *****************************************************************************/ | 17 | *****************************************************************************/ |
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "gl/base64.h" | 20 | #include "gl/base64.h" |
21 | #include "tap.h" | 21 | #include "tap.h" |
22 | 22 | ||
23 | int | 23 | int main(int argc, char **argv) { |
24 | main (int argc, char **argv) | 24 | #if 0 /* The current base64 function doesn't work on 8bit data */ |
25 | { | ||
26 | #if 0 /* The current base64 function doesn't work on 8bit data */ | ||
27 | char random[1024] = { | 25 | char random[1024] = { |
28 | 0x8b,0xb0,0xc4,0xe2,0xfc,0x22,0x9f,0x0d,0x85,0xe7,0x2c,0xaa,0x39,0xa1,0x46,0x88, | 26 | 0x8b,0xb0,0xc4,0xe2,0xfc,0x22,0x9f,0x0d,0x85,0xe7,0x2c,0xaa,0x39,0xa1,0x46,0x88, |
29 | 0x50,0xe6,0x34,0x37,0x0b,0x45,0x4b,0xb8,0xb2,0x86,0x7a,0x3e,0x7f,0x0c,0x40,0x18, | 27 | 0x50,0xe6,0x34,0x37,0x0b,0x45,0x4b,0xb8,0xb2,0x86,0x7a,0x3e,0x7f,0x0c,0x40,0x18, |
@@ -182,168 +180,124 @@ main (int argc, char **argv) | |||
182 | #endif | 180 | #endif |
183 | 181 | ||
184 | char random[1024] = { | 182 | char random[1024] = { |
185 | 0x0b,0x30,0x44,0x62,0x7c,0x22,0x1f,0x0d,0x05,0x67,0x2c,0x2a,0x39,0x21,0x46,0x08, | 183 | 0x0b, 0x30, 0x44, 0x62, 0x7c, 0x22, 0x1f, 0x0d, 0x05, 0x67, 0x2c, 0x2a, 0x39, 0x21, 0x46, 0x08, 0x50, 0x66, 0x34, 0x37, 0x0b, 0x45, |
186 | 0x50,0x66,0x34,0x37,0x0b,0x45,0x4b,0x38,0x32,0x06,0x7a,0x3e,0x7f,0x0c,0x40,0x18, | 184 | 0x4b, 0x38, 0x32, 0x06, 0x7a, 0x3e, 0x7f, 0x0c, 0x40, 0x18, 0x6b, 0x2d, 0x60, 0x4c, 0x60, 0x0c, 0x23, 0x43, 0x3b, 0x3e, 0x1b, 0x16, |
187 | 0x6b,0x2d,0x60,0x4c,0x60,0x0c,0x23,0x43,0x3b,0x3e,0x1b,0x16,0x04,0x46,0x58,0x3f, | 185 | 0x04, 0x46, 0x58, 0x3f, 0x40, 0x6a, 0x11, 0x05, 0x63, 0x71, 0x14, 0x35, 0x47, 0x79, 0x13, 0x6f, 0x6b, 0x27, 0x18, 0x5b, 0x48, 0x27, |
188 | 0x40,0x6a,0x11,0x05,0x63,0x71,0x14,0x35,0x47,0x79,0x13,0x6f,0x6b,0x27,0x18,0x5b, | 186 | 0x3e, 0x6f, 0x15, 0x33, 0x4f, 0x3e, 0x5e, 0x51, 0x73, 0x68, 0x25, 0x0f, 0x06, 0x5b, 0x7c, 0x72, 0x75, 0x3e, 0x3f, 0x1b, 0x5c, 0x6d, |
189 | 0x48,0x27,0x3e,0x6f,0x15,0x33,0x4f,0x3e,0x5e,0x51,0x73,0x68,0x25,0x0f,0x06,0x5b, | 187 | 0x6a, 0x39, 0x7c, 0x63, 0x63, 0x60, 0x6c, 0x7a, 0x33, 0x76, 0x52, 0x13, 0x25, 0x33, 0x7d, 0x65, 0x23, 0x27, 0x11, 0x06, 0x06, 0x47, |
190 | 0x7c,0x72,0x75,0x3e,0x3f,0x1b,0x5c,0x6d,0x6a,0x39,0x7c,0x63,0x63,0x60,0x6c,0x7a, | 188 | 0x71, 0x1e, 0x14, 0x74, 0x63, 0x70, 0x2d, 0x15, 0x27, 0x18, 0x51, 0x06, 0x05, 0x33, 0x11, 0x2c, 0x6b, 0x00, 0x2d, 0x77, 0x20, 0x48, |
191 | 0x33,0x76,0x52,0x13,0x25,0x33,0x7d,0x65,0x23,0x27,0x11,0x06,0x06,0x47,0x71,0x1e, | 189 | 0x0d, 0x73, 0x51, 0x45, 0x25, 0x7f, 0x7f, 0x35, 0x26, 0x2e, 0x26, 0x53, 0x24, 0x68, 0x1e, 0x0e, 0x58, 0x3a, 0x59, 0x50, 0x56, 0x37, |
192 | 0x14,0x74,0x63,0x70,0x2d,0x15,0x27,0x18,0x51,0x06,0x05,0x33,0x11,0x2c,0x6b,0x00, | 190 | 0x5f, 0x66, 0x01, 0x4c, 0x5a, 0x64, 0x32, 0x50, 0x7b, 0x6a, 0x20, 0x72, 0x2b, 0x1d, 0x7e, 0x43, 0x7b, 0x61, 0x42, 0x0b, 0x61, 0x73, |
193 | 0x2d,0x77,0x20,0x48,0x0d,0x73,0x51,0x45,0x25,0x7f,0x7f,0x35,0x26,0x2e,0x26,0x53, | 191 | 0x24, 0x79, 0x3a, 0x6b, 0x4a, 0x79, 0x6e, 0x09, 0x0f, 0x27, 0x2d, 0x0c, 0x5e, 0x32, 0x4b, 0x0d, 0x79, 0x46, 0x39, 0x21, 0x0a, 0x26, |
194 | 0x24,0x68,0x1e,0x0e,0x58,0x3a,0x59,0x50,0x56,0x37,0x5f,0x66,0x01,0x4c,0x5a,0x64, | 192 | 0x5f, 0x3a, 0x00, 0x26, 0x3f, 0x13, 0x2e, 0x7e, 0x50, 0x2b, 0x67, 0x46, 0x72, 0x3f, 0x3b, 0x01, 0x46, 0x1b, 0x0b, 0x35, 0x49, 0x39, |
195 | 0x32,0x50,0x7b,0x6a,0x20,0x72,0x2b,0x1d,0x7e,0x43,0x7b,0x61,0x42,0x0b,0x61,0x73, | 193 | 0x19, 0x70, 0x3d, 0x02, 0x41, 0x0e, 0x38, 0x05, 0x76, 0x65, 0x4f, 0x31, 0x6c, 0x5e, 0x17, 0x04, 0x15, 0x36, 0x26, 0x64, 0x34, 0x14, |
196 | 0x24,0x79,0x3a,0x6b,0x4a,0x79,0x6e,0x09,0x0f,0x27,0x2d,0x0c,0x5e,0x32,0x4b,0x0d, | 194 | 0x17, 0x7c, 0x0e, 0x0b, 0x5b, 0x55, 0x53, 0x6b, 0x00, 0x42, 0x41, 0x4f, 0x02, 0x5c, 0x13, 0x0a, 0x2c, 0x2c, 0x3e, 0x10, 0x14, 0x33, |
197 | 0x79,0x46,0x39,0x21,0x0a,0x26,0x5f,0x3a,0x00,0x26,0x3f,0x13,0x2e,0x7e,0x50,0x2b, | 195 | 0x45, 0x7c, 0x7a, 0x5a, 0x31, 0x61, 0x39, 0x08, 0x22, 0x6a, 0x1e, 0x0f, 0x6f, 0x1b, 0x6c, 0x13, 0x5e, 0x79, 0x20, 0x79, 0x50, 0x62, |
198 | 0x67,0x46,0x72,0x3f,0x3b,0x01,0x46,0x1b,0x0b,0x35,0x49,0x39,0x19,0x70,0x3d,0x02, | 196 | 0x06, 0x2c, 0x76, 0x17, 0x04, 0x2b, 0x2a, 0x75, 0x1f, 0x0c, 0x37, 0x4e, 0x0f, 0x7b, 0x2d, 0x34, 0x75, 0x60, 0x31, 0x74, 0x2e, 0x0a, |
199 | 0x41,0x0e,0x38,0x05,0x76,0x65,0x4f,0x31,0x6c,0x5e,0x17,0x04,0x15,0x36,0x26,0x64, | 197 | 0x4a, 0x11, 0x6c, 0x49, 0x25, 0x01, 0x3a, 0x3d, 0x22, 0x1e, 0x6d, 0x18, 0x51, 0x78, 0x2d, 0x62, 0x31, 0x4c, 0x50, 0x40, 0x17, 0x4b, |
200 | 0x34,0x14,0x17,0x7c,0x0e,0x0b,0x5b,0x55,0x53,0x6b,0x00,0x42,0x41,0x4f,0x02,0x5c, | 198 | 0x6f, 0x22, 0x00, 0x7f, 0x61, 0x2a, 0x34, 0x3e, 0x00, 0x5f, 0x2f, 0x5f, 0x2f, 0x14, 0x2a, 0x55, 0x27, 0x1f, 0x46, 0x1f, 0x12, 0x46, |
201 | 0x13,0x0a,0x2c,0x2c,0x3e,0x10,0x14,0x33,0x45,0x7c,0x7a,0x5a,0x31,0x61,0x39,0x08, | 199 | 0x5e, 0x1e, 0x0c, 0x7c, 0x38, 0x01, 0x61, 0x64, 0x76, 0x22, 0x6e, 0x08, 0x20, 0x38, 0x4f, 0x73, 0x72, 0x55, 0x12, 0x42, 0x19, 0x50, |
202 | 0x22,0x6a,0x1e,0x0f,0x6f,0x1b,0x6c,0x13,0x5e,0x79,0x20,0x79,0x50,0x62,0x06,0x2c, | 200 | 0x61, 0x43, 0x77, 0x7d, 0x41, 0x2e, 0x35, 0x4f, 0x3d, 0x31, 0x28, 0x58, 0x67, 0x1b, 0x03, 0x51, 0x20, 0x32, 0x1c, 0x08, 0x6e, 0x37, |
203 | 0x76,0x17,0x04,0x2b,0x2a,0x75,0x1f,0x0c,0x37,0x4e,0x0f,0x7b,0x2d,0x34,0x75,0x60, | 201 | 0x75, 0x37, 0x44, 0x4f, 0x68, 0x19, 0x07, 0x64, 0x14, 0x28, 0x25, 0x2b, 0x69, 0x35, 0x18, 0x27, 0x26, 0x14, 0x13, 0x70, 0x42, 0x19, |
204 | 0x31,0x74,0x2e,0x0a,0x4a,0x11,0x6c,0x49,0x25,0x01,0x3a,0x3d,0x22,0x1e,0x6d,0x18, | 202 | 0x12, 0x75, 0x3e, 0x02, 0x5d, 0x7c, 0x13, 0x1f, 0x16, 0x53, 0x3b, 0x74, 0x48, 0x3c, 0x5e, 0x39, 0x6c, 0x1c, 0x1c, 0x74, 0x39, 0x1f, |
205 | 0x51,0x78,0x2d,0x62,0x31,0x4c,0x50,0x40,0x17,0x4b,0x6f,0x22,0x00,0x7f,0x61,0x2a, | 203 | 0x00, 0x1b, 0x06, 0x0a, 0x68, 0x3b, 0x52, 0x4f, 0x1e, 0x6e, 0x3c, 0x35, 0x0c, 0x38, 0x0e, 0x0b, 0x3b, 0x1a, 0x76, 0x23, 0x29, 0x53, |
206 | 0x34,0x3e,0x00,0x5f,0x2f,0x5f,0x2f,0x14,0x2a,0x55,0x27,0x1f,0x46,0x1f,0x12,0x46, | 204 | 0x1e, 0x5f, 0x41, 0x0c, 0x4b, 0x0a, 0x65, 0x28, 0x78, 0x67, 0x48, 0x59, 0x26, 0x6d, 0x31, 0x76, 0x23, 0x70, 0x61, 0x64, 0x3b, 0x38, |
207 | 0x5e,0x1e,0x0c,0x7c,0x38,0x01,0x61,0x64,0x76,0x22,0x6e,0x08,0x20,0x38,0x4f,0x73, | 205 | 0x79, 0x66, 0x74, 0x53, 0x2c, 0x64, 0x64, 0x54, 0x03, 0x54, 0x65, 0x44, 0x4c, 0x18, 0x4f, 0x48, 0x20, 0x4f, 0x72, 0x10, 0x3f, 0x0c, |
208 | 0x72,0x55,0x12,0x42,0x19,0x50,0x61,0x43,0x77,0x7d,0x41,0x2e,0x35,0x4f,0x3d,0x31, | 206 | 0x52, 0x2d, 0x03, 0x14, 0x03, 0x51, 0x42, 0x10, 0x77, 0x6a, 0x34, 0x06, 0x32, 0x03, 0x72, 0x14, 0x7c, 0x08, 0x5d, 0x52, 0x1a, 0x62, |
209 | 0x28,0x58,0x67,0x1b,0x03,0x51,0x20,0x32,0x1c,0x08,0x6e,0x37,0x75,0x37,0x44,0x4f, | 207 | 0x7c, 0x3e, 0x30, 0x7e, 0x5f, 0x7f, 0x54, 0x0f, 0x44, 0x49, 0x5d, 0x5e, 0x10, 0x6a, 0x06, 0x2b, 0x06, 0x53, 0x10, 0x39, 0x37, 0x32, |
210 | 0x68,0x19,0x07,0x64,0x14,0x28,0x25,0x2b,0x69,0x35,0x18,0x27,0x26,0x14,0x13,0x70, | 208 | 0x4a, 0x4e, 0x3d, 0x2b, 0x65, 0x38, 0x39, 0x07, 0x72, 0x54, 0x64, 0x4d, 0x56, 0x6a, 0x03, 0x22, 0x70, 0x7b, 0x5f, 0x60, 0x0b, 0x2a, |
211 | 0x42,0x19,0x12,0x75,0x3e,0x02,0x5d,0x7c,0x13,0x1f,0x16,0x53,0x3b,0x74,0x48,0x3c, | 209 | 0x0b, 0x6b, 0x10, 0x64, 0x14, 0x05, 0x22, 0x00, 0x73, 0x40, 0x23, 0x5b, 0x51, 0x1f, 0x2b, 0x1a, 0x5d, 0x69, 0x7a, 0x46, 0x0c, 0x5f, |
212 | 0x5e,0x39,0x6c,0x1c,0x1c,0x74,0x39,0x1f,0x00,0x1b,0x06,0x0a,0x68,0x3b,0x52,0x4f, | 210 | 0x32, 0x4b, 0x4a, 0x28, 0x52, 0x79, 0x5b, 0x12, 0x42, 0x18, 0x00, 0x5d, 0x27, 0x31, 0x53, 0x3c, 0x4c, 0x36, 0x4e, 0x38, 0x3f, 0x72, |
213 | 0x1e,0x6e,0x3c,0x35,0x0c,0x38,0x0e,0x0b,0x3b,0x1a,0x76,0x23,0x29,0x53,0x1e,0x5f, | 211 | 0x03, 0x71, 0x02, 0x5b, 0x36, 0x59, 0x7f, 0x75, 0x6e, 0x08, 0x54, 0x0d, 0x34, 0x1c, 0x34, 0x57, 0x5d, 0x69, 0x48, 0x00, 0x3b, 0x05, |
214 | 0x41,0x0c,0x4b,0x0a,0x65,0x28,0x78,0x67,0x48,0x59,0x26,0x6d,0x31,0x76,0x23,0x70, | 212 | 0x07, 0x6e, 0x27, 0x65, 0x6e, 0x40, 0x3d, 0x3a, 0x4f, 0x72, 0x5d, 0x39, 0x16, 0x0f, 0x63, 0x12, 0x12, 0x15, 0x3a, 0x70, 0x0d, 0x57, |
215 | 0x61,0x64,0x3b,0x38,0x79,0x66,0x74,0x53,0x2c,0x64,0x64,0x54,0x03,0x54,0x65,0x44, | 213 | 0x18, 0x0d, 0x5e, 0x3d, 0x22, 0x68, 0x68, 0x7c, 0x6d, 0x4f, 0x0c, 0x7b, 0x09, 0x2d, 0x4a, 0x73, 0x20, 0x47, 0x07, 0x57, 0x75, 0x5d, |
216 | 0x4c,0x18,0x4f,0x48,0x20,0x4f,0x72,0x10,0x3f,0x0c,0x52,0x2d,0x03,0x14,0x03,0x51, | 214 | 0x53, 0x70, 0x34, 0x21, 0x40, 0x57, 0x51, 0x5e, 0x49, 0x44, 0x00, 0x54, 0x27, 0x04, 0x68, 0x7e, 0x59, 0x56, 0x58, 0x74, 0x14, 0x3c, |
217 | 0x42,0x10,0x77,0x6a,0x34,0x06,0x32,0x03,0x72,0x14,0x7c,0x08,0x5d,0x52,0x1a,0x62, | 215 | 0x16, 0x33, 0x41, 0x16, 0x4b, 0x2f, 0x49, 0x37, 0x0a, 0x54, 0x08, 0x08, 0x1f, 0x39, 0x67, 0x76, 0x28, 0x28, 0x07, 0x1d, 0x61, 0x47, |
218 | 0x7c,0x3e,0x30,0x7e,0x5f,0x7f,0x54,0x0f,0x44,0x49,0x5d,0x5e,0x10,0x6a,0x06,0x2b, | 216 | 0x51, 0x4d, 0x75, 0x26, 0x52, 0x47, 0x47, 0x0c, 0x57, 0x58, 0x74, 0x3e, 0x62, 0x6c, 0x58, 0x3a, 0x44, 0x1e, 0x16, 0x2e, 0x21, 0x1c, |
219 | 0x06,0x53,0x10,0x39,0x37,0x32,0x4a,0x4e,0x3d,0x2b,0x65,0x38,0x39,0x07,0x72,0x54, | 217 | 0x73, 0x45, 0x67, 0x74, 0x4f, 0x33, 0x66, 0x0e, 0x74, 0x66, 0x26, 0x1f, 0x2e, 0x38, 0x44, 0x40, 0x7e, 0x2a, 0x50, 0x52, 0x5e, 0x43, |
220 | 0x64,0x4d,0x56,0x6a,0x03,0x22,0x70,0x7b,0x5f,0x60,0x0b,0x2a,0x0b,0x6b,0x10,0x64, | 218 | 0x01, 0x7a, 0x38, 0x49, 0x3c, 0x55, 0x4d, 0x5a, 0x44, 0x08, 0x26, 0x59, 0x4d, 0x45, 0x0b, 0x48, 0x0a, 0x33, 0x5e, 0x4a, 0x4d, 0x75, |
221 | 0x14,0x05,0x22,0x00,0x73,0x40,0x23,0x5b,0x51,0x1f,0x2b,0x1a,0x5d,0x69,0x7a,0x46, | 219 | 0x16, 0x17, 0x63, 0x46, 0x01, 0x2a, 0x55, 0x7b, 0x0f, 0x02, 0x73, 0x6a, 0x4b, 0x7f, 0x75, 0x65, 0x3c, 0x4c, 0x33, 0x39, 0x6c, 0x74, |
222 | 0x0c,0x5f,0x32,0x4b,0x4a,0x28,0x52,0x79,0x5b,0x12,0x42,0x18,0x00,0x5d,0x27,0x31, | 220 | 0x05, 0x60, 0x0f, 0x7f, 0x2d, 0x41, 0x4d, 0x4d, 0x46, 0x71, 0x09, 0x6f, 0x4f, 0x60, 0x15, 0x0f, 0x46, 0x73, 0x63, 0x4c, 0x5e, 0x74, |
223 | 0x53,0x3c,0x4c,0x36,0x4e,0x38,0x3f,0x72,0x03,0x71,0x02,0x5b,0x36,0x59,0x7f,0x75, | 221 | 0x30, 0x0d, 0x28, 0x43, 0x08, 0x72, 0x32, 0x04, 0x2e, 0x31, 0x29, 0x27, 0x44, 0x6d, 0x13, 0x17, 0x48, 0x0f, 0x49, 0x52, 0x10, 0x13, |
224 | 0x6e,0x08,0x54,0x0d,0x34,0x1c,0x34,0x57,0x5d,0x69,0x48,0x00,0x3b,0x05,0x07,0x6e, | 222 | 0x7f, 0x17, 0x16, 0x62, 0x79, 0x35, 0x78, 0x3e, 0x01, 0x7c, 0x2e, 0x0f, 0x76, 0x3e, 0x5e, 0x53, 0x6c, 0x5b, 0x5f, 0x7c, 0x19, 0x41, |
225 | 0x27,0x65,0x6e,0x40,0x3d,0x3a,0x4f,0x72,0x5d,0x39,0x16,0x0f,0x63,0x12,0x12,0x15, | 223 | 0x02, 0x2f, 0x17, 0x64, 0x41, 0x75, 0x10, 0x04, 0x47, 0x7c, 0x3d, 0x4b, 0x52, 0x00, 0x10, 0x5d, 0x51, 0x4e, 0x7a, 0x27, 0x25, 0x55, |
226 | 0x3a,0x70,0x0d,0x57,0x18,0x0d,0x5e,0x3d,0x22,0x68,0x68,0x7c,0x6d,0x4f,0x0c,0x7b, | 224 | 0x40, 0x12, 0x35, 0x60, 0x05, 0x1b, 0x34, 0x2d, 0x04, 0x7a, 0x6a, 0x69, 0x02, 0x79, 0x03, 0x3a, 0x2f, 0x06, 0x0a, 0x79, 0x7b, 0x12, |
227 | 0x09,0x2d,0x4a,0x73,0x20,0x47,0x07,0x57,0x75,0x5d,0x53,0x70,0x34,0x21,0x40,0x57, | 225 | 0x5d, 0x7c, 0x52, 0x29, 0x47, 0x58, 0x12, 0x73, 0x3f, 0x27, 0x56, 0x05, 0x0c, 0x48, 0x32, 0x58, 0x6b, 0x57, 0x5c, 0x03, 0x64, 0x56, |
228 | 0x51,0x5e,0x49,0x44,0x00,0x54,0x27,0x04,0x68,0x7e,0x59,0x56,0x58,0x74,0x14,0x3c, | 226 | 0x11, 0x52, 0x7a, 0x30, 0x36, 0x29, 0x17, 0x3b, 0x68, 0x7a, 0x7c, 0x05, 0x6b, 0x6b, 0x13, 0x6a, 0x24, 0x5c, 0x68, 0x42, 0x18, 0x32, |
229 | 0x16,0x33,0x41,0x16,0x4b,0x2f,0x49,0x37,0x0a,0x54,0x08,0x08,0x1f,0x39,0x67,0x76, | 227 | 0x03, 0x73, 0x6e, 0x04, 0x21, 0x2e, 0x01, 0x04, 0x63, 0x7d, 0x44, 0x41, 0x12, 0x31, 0x0b, 0x15, 0x1f, 0x70, 0x00, 0x2e, 0x66, 0x14, |
230 | 0x28,0x28,0x07,0x1d,0x61,0x47,0x51,0x4d,0x75,0x26,0x52,0x47,0x47,0x0c,0x57,0x58, | 228 | 0x3c, 0x7f, 0x2b, 0x00, 0x1f, 0x0c, 0x28, 0x59, 0x0a, 0x16, 0x49, 0x5a, 0x5c, 0x64, 0x65, 0x4b, 0x11, 0x29, 0x15, 0x36, 0x5a, 0x65, |
231 | 0x74,0x3e,0x62,0x6c,0x58,0x3a,0x44,0x1e,0x16,0x2e,0x21,0x1c,0x73,0x45,0x67,0x74, | 229 | 0x19, 0x4f, 0x60, 0x23, 0x3a, 0x3a, 0x13, 0x25, 0x02, 0x78, 0x4c, 0x54}; |
232 | 0x4f,0x33,0x66,0x0e,0x74,0x66,0x26,0x1f,0x2e,0x38,0x44,0x40,0x7e,0x2a,0x50,0x52, | 230 | char b64_known[1369] = { |
233 | 0x5e,0x43,0x01,0x7a,0x38,0x49,0x3c,0x55,0x4d,0x5a,0x44,0x08,0x26,0x59,0x4d,0x45, | 231 | 0x43, 0x7a, 0x42, 0x45, 0x59, 0x6e, 0x77, 0x69, 0x48, 0x77, 0x30, 0x46, 0x5a, 0x79, 0x77, 0x71, 0x4f, 0x53, 0x46, 0x47, 0x43, 0x46, |
234 | 0x0b,0x48,0x0a,0x33,0x5e,0x4a,0x4d,0x75,0x16,0x17,0x63,0x46,0x01,0x2a,0x55,0x7b, | 232 | 0x42, 0x6d, 0x4e, 0x44, 0x63, 0x4c, 0x52, 0x55, 0x73, 0x34, 0x4d, 0x67, 0x5a, 0x36, 0x50, 0x6e, 0x38, 0x4d, 0x51, 0x42, 0x68, 0x72, |
235 | 0x0f,0x02,0x73,0x6a,0x4b,0x7f,0x75,0x65,0x3c,0x4c,0x33,0x39,0x6c,0x74,0x05,0x60, | 233 | 0x4c, 0x57, 0x42, 0x4d, 0x59, 0x41, 0x77, 0x6a, 0x51, 0x7a, 0x73, 0x2b, 0x47, 0x78, 0x59, 0x45, 0x52, 0x6c, 0x67, 0x2f, 0x51, 0x47, |
236 | 0x0f,0x7f,0x2d,0x41,0x4d,0x4d,0x46,0x71,0x09,0x6f,0x4f,0x60,0x15,0x0f,0x46,0x73, | 234 | 0x6f, 0x52, 0x42, 0x57, 0x4e, 0x78, 0x46, 0x44, 0x56, 0x48, 0x65, 0x52, 0x4e, 0x76, 0x61, 0x79, 0x63, 0x59, 0x57, 0x30, 0x67, 0x6e, |
237 | 0x63,0x4c,0x5e,0x74,0x30,0x0d,0x28,0x43,0x08,0x72,0x32,0x04,0x2e,0x31,0x29,0x27, | 235 | 0x50, 0x6d, 0x38, 0x56, 0x4d, 0x30, 0x38, 0x2b, 0x58, 0x6c, 0x46, 0x7a, 0x61, 0x43, 0x55, 0x50, 0x42, 0x6c, 0x74, 0x38, 0x63, 0x6e, |
238 | 0x44,0x6d,0x13,0x17,0x48,0x0f,0x49,0x52,0x10,0x13,0x7f,0x17,0x16,0x62,0x79,0x35, | 236 | 0x55, 0x2b, 0x50, 0x78, 0x74, 0x63, 0x62, 0x57, 0x6f, 0x35, 0x66, 0x47, 0x4e, 0x6a, 0x59, 0x47, 0x78, 0x36, 0x4d, 0x33, 0x5a, 0x53, |
239 | 0x78,0x3e,0x01,0x7c,0x2e,0x0f,0x76,0x3e,0x5e,0x53,0x6c,0x5b,0x5f,0x7c,0x19,0x41, | 237 | 0x45, 0x79, 0x55, 0x7a, 0x66, 0x57, 0x55, 0x6a, 0x4a, 0x78, 0x45, 0x47, 0x42, 0x6b, 0x64, 0x78, 0x48, 0x68, 0x52, 0x30, 0x59, 0x33, |
240 | 0x02,0x2f,0x17,0x64,0x41,0x75,0x10,0x04,0x47,0x7c,0x3d,0x4b,0x52,0x00,0x10,0x5d, | 238 | 0x41, 0x74, 0x46, 0x53, 0x63, 0x59, 0x55, 0x51, 0x59, 0x46, 0x4d, 0x78, 0x45, 0x73, 0x61, 0x77, 0x41, 0x74, 0x64, 0x79, 0x42, 0x49, |
241 | 0x51,0x4e,0x7a,0x27,0x25,0x55,0x40,0x12,0x35,0x60,0x05,0x1b,0x34,0x2d,0x04,0x7a, | 239 | 0x44, 0x58, 0x4e, 0x52, 0x52, 0x53, 0x56, 0x2f, 0x66, 0x7a, 0x55, 0x6d, 0x4c, 0x69, 0x5a, 0x54, 0x4a, 0x47, 0x67, 0x65, 0x44, 0x6c, |
242 | 0x6a,0x69,0x02,0x79,0x03,0x3a,0x2f,0x06,0x0a,0x79,0x7b,0x12,0x5d,0x7c,0x52,0x29, | 240 | 0x67, 0x36, 0x57, 0x56, 0x42, 0x57, 0x4e, 0x31, 0x39, 0x6d, 0x41, 0x55, 0x78, 0x61, 0x5a, 0x44, 0x4a, 0x51, 0x65, 0x32, 0x6f, 0x67, |
243 | 0x47,0x58,0x12,0x73,0x3f,0x27,0x56,0x05,0x0c,0x48,0x32,0x58,0x6b,0x57,0x5c,0x03, | 241 | 0x63, 0x69, 0x73, 0x64, 0x66, 0x6b, 0x4e, 0x37, 0x59, 0x55, 0x49, 0x4c, 0x59, 0x58, 0x4d, 0x6b, 0x65, 0x54, 0x70, 0x72, 0x53, 0x6e, |
244 | 0x64,0x56,0x11,0x52,0x7a,0x30,0x36,0x29,0x17,0x3b,0x68,0x7a,0x7c,0x05,0x6b,0x6b, | 242 | 0x6c, 0x75, 0x43, 0x51, 0x38, 0x6e, 0x4c, 0x51, 0x78, 0x65, 0x4d, 0x6b, 0x73, 0x4e, 0x65, 0x55, 0x59, 0x35, 0x49, 0x51, 0x6f, 0x6d, |
245 | 0x13,0x6a,0x24,0x5c,0x68,0x42,0x18,0x32,0x03,0x73,0x6e,0x04,0x21,0x2e,0x01,0x04, | 243 | 0x58, 0x7a, 0x6f, 0x41, 0x4a, 0x6a, 0x38, 0x54, 0x4c, 0x6e, 0x35, 0x51, 0x4b, 0x32, 0x64, 0x47, 0x63, 0x6a, 0x38, 0x37, 0x41, 0x55, |
246 | 0x63,0x7d,0x44,0x41,0x12,0x31,0x0b,0x15,0x1f,0x70,0x00,0x2e,0x66,0x14,0x3c,0x7f, | 244 | 0x59, 0x62, 0x43, 0x7a, 0x56, 0x4a, 0x4f, 0x52, 0x6c, 0x77, 0x50, 0x51, 0x4a, 0x42, 0x44, 0x6a, 0x67, 0x46, 0x64, 0x6d, 0x56, 0x50, |
247 | 0x2b,0x00,0x1f,0x0c,0x28,0x59,0x0a,0x16,0x49,0x5a,0x5c,0x64,0x65,0x4b,0x11,0x29, | 245 | 0x4d, 0x57, 0x78, 0x65, 0x46, 0x77, 0x51, 0x56, 0x4e, 0x69, 0x5a, 0x6b, 0x4e, 0x42, 0x51, 0x58, 0x66, 0x41, 0x34, 0x4c, 0x57, 0x31, |
248 | 0x15,0x36,0x5a,0x65,0x19,0x4f,0x60,0x23,0x3a,0x3a,0x13,0x25,0x02,0x78,0x4c,0x54 | 246 | 0x56, 0x54, 0x61, 0x77, 0x42, 0x43, 0x51, 0x55, 0x38, 0x43, 0x58, 0x42, 0x4d, 0x4b, 0x4c, 0x43, 0x77, 0x2b, 0x45, 0x42, 0x51, 0x7a, |
249 | }; | 247 | 0x52, 0x58, 0x78, 0x36, 0x57, 0x6a, 0x46, 0x68, 0x4f, 0x51, 0x67, 0x69, 0x61, 0x68, 0x34, 0x50, 0x62, 0x78, 0x74, 0x73, 0x45, 0x31, |
250 | char b64_known[1369] = { | 248 | 0x35, 0x35, 0x49, 0x48, 0x6c, 0x51, 0x59, 0x67, 0x59, 0x73, 0x64, 0x68, 0x63, 0x45, 0x4b, 0x79, 0x70, 0x31, 0x48, 0x77, 0x77, 0x33, |
251 | 0x43,0x7a,0x42,0x45,0x59,0x6e,0x77,0x69,0x48,0x77,0x30,0x46,0x5a,0x79,0x77,0x71, | 249 | 0x54, 0x67, 0x39, 0x37, 0x4c, 0x54, 0x52, 0x31, 0x59, 0x44, 0x46, 0x30, 0x4c, 0x67, 0x70, 0x4b, 0x45, 0x57, 0x78, 0x4a, 0x4a, 0x51, |
252 | 0x4f,0x53,0x46,0x47,0x43,0x46,0x42,0x6d,0x4e,0x44,0x63,0x4c,0x52,0x55,0x73,0x34, | 250 | 0x45, 0x36, 0x50, 0x53, 0x49, 0x65, 0x62, 0x52, 0x68, 0x52, 0x65, 0x43, 0x31, 0x69, 0x4d, 0x55, 0x78, 0x51, 0x51, 0x42, 0x64, 0x4c, |
253 | 0x4d,0x67,0x5a,0x36,0x50,0x6e,0x38,0x4d,0x51,0x42,0x68,0x72,0x4c,0x57,0x42,0x4d, | 251 | 0x62, 0x79, 0x49, 0x41, 0x66, 0x32, 0x45, 0x71, 0x4e, 0x44, 0x34, 0x41, 0x58, 0x79, 0x39, 0x66, 0x4c, 0x78, 0x51, 0x71, 0x56, 0x53, |
254 | 0x59,0x41,0x77,0x6a,0x51,0x7a,0x73,0x2b,0x47,0x78,0x59,0x45,0x52,0x6c,0x67,0x2f, | 252 | 0x63, 0x66, 0x52, 0x68, 0x38, 0x53, 0x52, 0x6c, 0x34, 0x65, 0x44, 0x48, 0x77, 0x34, 0x41, 0x57, 0x46, 0x6b, 0x64, 0x69, 0x4a, 0x75, |
255 | 0x51,0x47,0x6f,0x52,0x42,0x57,0x4e,0x78,0x46,0x44,0x56,0x48,0x65,0x52,0x4e,0x76, | 253 | 0x43, 0x43, 0x41, 0x34, 0x54, 0x33, 0x4e, 0x79, 0x56, 0x52, 0x4a, 0x43, 0x47, 0x56, 0x42, 0x68, 0x51, 0x33, 0x64, 0x39, 0x51, 0x53, |
256 | 0x61,0x79,0x63,0x59,0x57,0x30,0x67,0x6e,0x50,0x6d,0x38,0x56,0x4d,0x30,0x38,0x2b, | 254 | 0x34, 0x31, 0x54, 0x7a, 0x30, 0x78, 0x4b, 0x46, 0x68, 0x6e, 0x47, 0x77, 0x4e, 0x52, 0x49, 0x44, 0x49, 0x63, 0x43, 0x47, 0x34, 0x33, |
257 | 0x58,0x6c,0x46,0x7a,0x61,0x43,0x55,0x50,0x42,0x6c,0x74,0x38,0x63,0x6e,0x55,0x2b, | 255 | 0x64, 0x54, 0x64, 0x45, 0x54, 0x32, 0x67, 0x5a, 0x42, 0x32, 0x51, 0x55, 0x4b, 0x43, 0x55, 0x72, 0x61, 0x54, 0x55, 0x59, 0x4a, 0x79, |
258 | 0x50,0x78,0x74,0x63,0x62,0x57,0x6f,0x35,0x66,0x47,0x4e,0x6a,0x59,0x47,0x78,0x36, | 256 | 0x59, 0x55, 0x45, 0x33, 0x42, 0x43, 0x47, 0x52, 0x4a, 0x31, 0x50, 0x67, 0x4a, 0x64, 0x66, 0x42, 0x4d, 0x66, 0x46, 0x6c, 0x4d, 0x37, |
259 | 0x4d,0x33,0x5a,0x53,0x45,0x79,0x55,0x7a,0x66,0x57,0x55,0x6a,0x4a,0x78,0x45,0x47, | 257 | 0x64, 0x45, 0x67, 0x38, 0x58, 0x6a, 0x6c, 0x73, 0x48, 0x42, 0x78, 0x30, 0x4f, 0x52, 0x38, 0x41, 0x47, 0x77, 0x59, 0x4b, 0x61, 0x44, |
260 | 0x42,0x6b,0x64,0x78,0x48,0x68,0x52,0x30,0x59,0x33,0x41,0x74,0x46,0x53,0x63,0x59, | 258 | 0x74, 0x53, 0x54, 0x78, 0x35, 0x75, 0x50, 0x44, 0x55, 0x4d, 0x4f, 0x41, 0x34, 0x4c, 0x4f, 0x78, 0x70, 0x32, 0x49, 0x79, 0x6c, 0x54, |
261 | 0x55,0x51,0x59,0x46,0x4d,0x78,0x45,0x73,0x61,0x77,0x41,0x74,0x64,0x79,0x42,0x49, | 259 | 0x48, 0x6c, 0x39, 0x42, 0x44, 0x45, 0x73, 0x4b, 0x5a, 0x53, 0x68, 0x34, 0x5a, 0x30, 0x68, 0x5a, 0x4a, 0x6d, 0x30, 0x78, 0x64, 0x69, |
262 | 0x44,0x58,0x4e,0x52,0x52,0x53,0x56,0x2f,0x66,0x7a,0x55,0x6d,0x4c,0x69,0x5a,0x54, | 260 | 0x4e, 0x77, 0x59, 0x57, 0x51, 0x37, 0x4f, 0x48, 0x6c, 0x6d, 0x64, 0x46, 0x4d, 0x73, 0x5a, 0x47, 0x52, 0x55, 0x41, 0x31, 0x52, 0x6c, |
263 | 0x4a,0x47,0x67,0x65,0x44,0x6c,0x67,0x36,0x57,0x56,0x42,0x57,0x4e,0x31,0x39,0x6d, | 261 | 0x52, 0x45, 0x77, 0x59, 0x54, 0x30, 0x67, 0x67, 0x54, 0x33, 0x49, 0x51, 0x50, 0x77, 0x78, 0x53, 0x4c, 0x51, 0x4d, 0x55, 0x41, 0x31, |
264 | 0x41,0x55,0x78,0x61,0x5a,0x44,0x4a,0x51,0x65,0x32,0x6f,0x67,0x63,0x69,0x73,0x64, | 262 | 0x46, 0x43, 0x45, 0x48, 0x64, 0x71, 0x4e, 0x41, 0x59, 0x79, 0x41, 0x33, 0x49, 0x55, 0x66, 0x41, 0x68, 0x64, 0x55, 0x68, 0x70, 0x69, |
265 | 0x66,0x6b,0x4e,0x37,0x59,0x55,0x49,0x4c,0x59,0x58,0x4d,0x6b,0x65,0x54,0x70,0x72, | 263 | 0x66, 0x44, 0x34, 0x77, 0x66, 0x6c, 0x39, 0x2f, 0x56, 0x41, 0x39, 0x45, 0x53, 0x56, 0x31, 0x65, 0x45, 0x47, 0x6f, 0x47, 0x4b, 0x77, |
266 | 0x53,0x6e,0x6c,0x75,0x43,0x51,0x38,0x6e,0x4c,0x51,0x78,0x65,0x4d,0x6b,0x73,0x4e, | 264 | 0x5a, 0x54, 0x45, 0x44, 0x6b, 0x33, 0x4d, 0x6b, 0x70, 0x4f, 0x50, 0x53, 0x74, 0x6c, 0x4f, 0x44, 0x6b, 0x48, 0x63, 0x6c, 0x52, 0x6b, |
267 | 0x65,0x55,0x59,0x35,0x49,0x51,0x6f,0x6d,0x58,0x7a,0x6f,0x41,0x4a,0x6a,0x38,0x54, | 265 | 0x54, 0x56, 0x5a, 0x71, 0x41, 0x79, 0x4a, 0x77, 0x65, 0x31, 0x39, 0x67, 0x43, 0x79, 0x6f, 0x4c, 0x61, 0x78, 0x42, 0x6b, 0x46, 0x41, |
268 | 0x4c,0x6e,0x35,0x51,0x4b,0x32,0x64,0x47,0x63,0x6a,0x38,0x37,0x41,0x55,0x59,0x62, | 266 | 0x55, 0x69, 0x41, 0x48, 0x4e, 0x41, 0x49, 0x31, 0x74, 0x52, 0x48, 0x79, 0x73, 0x61, 0x58, 0x57, 0x6c, 0x36, 0x52, 0x67, 0x78, 0x66, |
269 | 0x43,0x7a,0x56,0x4a,0x4f,0x52,0x6c,0x77,0x50,0x51,0x4a,0x42,0x44,0x6a,0x67,0x46, | 267 | 0x4d, 0x6b, 0x74, 0x4b, 0x4b, 0x46, 0x4a, 0x35, 0x57, 0x78, 0x4a, 0x43, 0x47, 0x41, 0x42, 0x64, 0x4a, 0x7a, 0x46, 0x54, 0x50, 0x45, |
270 | 0x64,0x6d,0x56,0x50,0x4d,0x57,0x78,0x65,0x46,0x77,0x51,0x56,0x4e,0x69,0x5a,0x6b, | 268 | 0x77, 0x32, 0x54, 0x6a, 0x67, 0x2f, 0x63, 0x67, 0x4e, 0x78, 0x41, 0x6c, 0x73, 0x32, 0x57, 0x58, 0x39, 0x31, 0x62, 0x67, 0x68, 0x55, |
271 | 0x4e,0x42,0x51,0x58,0x66,0x41,0x34,0x4c,0x57,0x31,0x56,0x54,0x61,0x77,0x42,0x43, | 269 | 0x44, 0x54, 0x51, 0x63, 0x4e, 0x46, 0x64, 0x64, 0x61, 0x55, 0x67, 0x41, 0x4f, 0x77, 0x55, 0x48, 0x62, 0x69, 0x64, 0x6c, 0x62, 0x6b, |
272 | 0x51,0x55,0x38,0x43,0x58,0x42,0x4d,0x4b,0x4c,0x43,0x77,0x2b,0x45,0x42,0x51,0x7a, | 270 | 0x41, 0x39, 0x4f, 0x6b, 0x39, 0x79, 0x58, 0x54, 0x6b, 0x57, 0x44, 0x32, 0x4d, 0x53, 0x45, 0x68, 0x55, 0x36, 0x63, 0x41, 0x31, 0x58, |
273 | 0x52,0x58,0x78,0x36,0x57,0x6a,0x46,0x68,0x4f,0x51,0x67,0x69,0x61,0x68,0x34,0x50, | 271 | 0x47, 0x41, 0x31, 0x65, 0x50, 0x53, 0x4a, 0x6f, 0x61, 0x48, 0x78, 0x74, 0x54, 0x77, 0x78, 0x37, 0x43, 0x53, 0x31, 0x4b, 0x63, 0x79, |
274 | 0x62,0x78,0x74,0x73,0x45,0x31,0x35,0x35,0x49,0x48,0x6c,0x51,0x59,0x67,0x59,0x73, | 272 | 0x42, 0x48, 0x42, 0x31, 0x64, 0x31, 0x58, 0x56, 0x4e, 0x77, 0x4e, 0x43, 0x46, 0x41, 0x56, 0x31, 0x46, 0x65, 0x53, 0x55, 0x51, 0x41, |
275 | 0x64,0x68,0x63,0x45,0x4b,0x79,0x70,0x31,0x48,0x77,0x77,0x33,0x54,0x67,0x39,0x37, | 273 | 0x56, 0x43, 0x63, 0x45, 0x61, 0x48, 0x35, 0x5a, 0x56, 0x6c, 0x68, 0x30, 0x46, 0x44, 0x77, 0x57, 0x4d, 0x30, 0x45, 0x57, 0x53, 0x79, |
276 | 0x4c,0x54,0x52,0x31,0x59,0x44,0x46,0x30,0x4c,0x67,0x70,0x4b,0x45,0x57,0x78,0x4a, | 274 | 0x39, 0x4a, 0x4e, 0x77, 0x70, 0x55, 0x43, 0x41, 0x67, 0x66, 0x4f, 0x57, 0x64, 0x32, 0x4b, 0x43, 0x67, 0x48, 0x48, 0x57, 0x46, 0x48, |
277 | 0x4a,0x51,0x45,0x36,0x50,0x53,0x49,0x65,0x62,0x52,0x68,0x52,0x65,0x43,0x31,0x69, | 275 | 0x55, 0x55, 0x31, 0x31, 0x4a, 0x6c, 0x4a, 0x48, 0x52, 0x77, 0x78, 0x58, 0x57, 0x48, 0x51, 0x2b, 0x59, 0x6d, 0x78, 0x59, 0x4f, 0x6b, |
278 | 0x4d,0x55,0x78,0x51,0x51,0x42,0x64,0x4c,0x62,0x79,0x49,0x41,0x66,0x32,0x45,0x71, | 276 | 0x51, 0x65, 0x46, 0x69, 0x34, 0x68, 0x48, 0x48, 0x4e, 0x46, 0x5a, 0x33, 0x52, 0x50, 0x4d, 0x32, 0x59, 0x4f, 0x64, 0x47, 0x59, 0x6d, |
279 | 0x4e,0x44,0x34,0x41,0x58,0x79,0x39,0x66,0x4c,0x78,0x51,0x71,0x56,0x53,0x63,0x66, | 277 | 0x48, 0x79, 0x34, 0x34, 0x52, 0x45, 0x42, 0x2b, 0x4b, 0x6c, 0x42, 0x53, 0x58, 0x6b, 0x4d, 0x42, 0x65, 0x6a, 0x68, 0x4a, 0x50, 0x46, |
280 | 0x52,0x68,0x38,0x53,0x52,0x6c,0x34,0x65,0x44,0x48,0x77,0x34,0x41,0x57,0x46,0x6b, | 278 | 0x56, 0x4e, 0x57, 0x6b, 0x51, 0x49, 0x4a, 0x6c, 0x6c, 0x4e, 0x52, 0x51, 0x74, 0x49, 0x43, 0x6a, 0x4e, 0x65, 0x53, 0x6b, 0x31, 0x31, |
281 | 0x64,0x69,0x4a,0x75,0x43,0x43,0x41,0x34,0x54,0x33,0x4e,0x79,0x56,0x52,0x4a,0x43, | 279 | 0x46, 0x68, 0x64, 0x6a, 0x52, 0x67, 0x45, 0x71, 0x56, 0x58, 0x73, 0x50, 0x41, 0x6e, 0x4e, 0x71, 0x53, 0x33, 0x39, 0x31, 0x5a, 0x54, |
282 | 0x47,0x56,0x42,0x68,0x51,0x33,0x64,0x39,0x51,0x53,0x34,0x31,0x54,0x7a,0x30,0x78, | 280 | 0x78, 0x4d, 0x4d, 0x7a, 0x6c, 0x73, 0x64, 0x41, 0x56, 0x67, 0x44, 0x33, 0x38, 0x74, 0x51, 0x55, 0x31, 0x4e, 0x52, 0x6e, 0x45, 0x4a, |
283 | 0x4b,0x46,0x68,0x6e,0x47,0x77,0x4e,0x52,0x49,0x44,0x49,0x63,0x43,0x47,0x34,0x33, | 281 | 0x62, 0x30, 0x39, 0x67, 0x46, 0x51, 0x39, 0x47, 0x63, 0x32, 0x4e, 0x4d, 0x58, 0x6e, 0x51, 0x77, 0x44, 0x53, 0x68, 0x44, 0x43, 0x48, |
284 | 0x64,0x54,0x64,0x45,0x54,0x32,0x67,0x5a,0x42,0x32,0x51,0x55,0x4b,0x43,0x55,0x72, | 282 | 0x49, 0x79, 0x42, 0x43, 0x34, 0x78, 0x4b, 0x53, 0x64, 0x45, 0x62, 0x52, 0x4d, 0x58, 0x53, 0x41, 0x39, 0x4a, 0x55, 0x68, 0x41, 0x54, |
285 | 0x61,0x54,0x55,0x59,0x4a,0x79,0x59,0x55,0x45,0x33,0x42,0x43,0x47,0x52,0x4a,0x31, | 283 | 0x66, 0x78, 0x63, 0x57, 0x59, 0x6e, 0x6b, 0x31, 0x65, 0x44, 0x34, 0x42, 0x66, 0x43, 0x34, 0x50, 0x64, 0x6a, 0x35, 0x65, 0x55, 0x32, |
286 | 0x50,0x67,0x4a,0x64,0x66,0x42,0x4d,0x66,0x46,0x6c,0x4d,0x37,0x64,0x45,0x67,0x38, | 284 | 0x78, 0x62, 0x58, 0x33, 0x77, 0x5a, 0x51, 0x51, 0x49, 0x76, 0x46, 0x32, 0x52, 0x42, 0x64, 0x52, 0x41, 0x45, 0x52, 0x33, 0x77, 0x39, |
287 | 0x58,0x6a,0x6c,0x73,0x48,0x42,0x78,0x30,0x4f,0x52,0x38,0x41,0x47,0x77,0x59,0x4b, | 285 | 0x53, 0x31, 0x49, 0x41, 0x45, 0x46, 0x31, 0x52, 0x54, 0x6e, 0x6f, 0x6e, 0x4a, 0x56, 0x56, 0x41, 0x45, 0x6a, 0x56, 0x67, 0x42, 0x52, |
288 | 0x61,0x44,0x74,0x53,0x54,0x78,0x35,0x75,0x50,0x44,0x55,0x4d,0x4f,0x41,0x34,0x4c, | 286 | 0x73, 0x30, 0x4c, 0x51, 0x52, 0x36, 0x61, 0x6d, 0x6b, 0x43, 0x65, 0x51, 0x4d, 0x36, 0x4c, 0x77, 0x59, 0x4b, 0x65, 0x58, 0x73, 0x53, |
289 | 0x4f,0x78,0x70,0x32,0x49,0x79,0x6c,0x54,0x48,0x6c,0x39,0x42,0x44,0x45,0x73,0x4b, | 287 | 0x58, 0x58, 0x78, 0x53, 0x4b, 0x55, 0x64, 0x59, 0x45, 0x6e, 0x4d, 0x2f, 0x4a, 0x31, 0x59, 0x46, 0x44, 0x45, 0x67, 0x79, 0x57, 0x47, |
290 | 0x5a,0x53,0x68,0x34,0x5a,0x30,0x68,0x5a,0x4a,0x6d,0x30,0x78,0x64,0x69,0x4e,0x77, | 288 | 0x74, 0x58, 0x58, 0x41, 0x4e, 0x6b, 0x56, 0x68, 0x46, 0x53, 0x65, 0x6a, 0x41, 0x32, 0x4b, 0x52, 0x63, 0x37, 0x61, 0x48, 0x70, 0x38, |
291 | 0x59,0x57,0x51,0x37,0x4f,0x48,0x6c,0x6d,0x64,0x46,0x4d,0x73,0x5a,0x47,0x52,0x55, | 289 | 0x42, 0x57, 0x74, 0x72, 0x45, 0x32, 0x6f, 0x6b, 0x58, 0x47, 0x68, 0x43, 0x47, 0x44, 0x49, 0x44, 0x63, 0x32, 0x34, 0x45, 0x49, 0x53, |
292 | 0x41,0x31,0x52,0x6c,0x52,0x45,0x77,0x59,0x54,0x30,0x67,0x67,0x54,0x33,0x49,0x51, | 290 | 0x34, 0x42, 0x42, 0x47, 0x4e, 0x39, 0x52, 0x45, 0x45, 0x53, 0x4d, 0x51, 0x73, 0x56, 0x48, 0x33, 0x41, 0x41, 0x4c, 0x6d, 0x59, 0x55, |
293 | 0x50,0x77,0x78,0x53,0x4c,0x51,0x4d,0x55,0x41,0x31,0x46,0x43,0x45,0x48,0x64,0x71, | 291 | 0x50, 0x48, 0x38, 0x72, 0x41, 0x42, 0x38, 0x4d, 0x4b, 0x46, 0x6b, 0x4b, 0x46, 0x6b, 0x6c, 0x61, 0x58, 0x47, 0x52, 0x6c, 0x53, 0x78, |
294 | 0x4e,0x41,0x59,0x79,0x41,0x33,0x49,0x55,0x66,0x41,0x68,0x64,0x55,0x68,0x70,0x69, | 292 | 0x45, 0x70, 0x46, 0x54, 0x5a, 0x61, 0x5a, 0x52, 0x6c, 0x50, 0x59, 0x43, 0x4d, 0x36, 0x4f, 0x68, 0x4d, 0x6c, 0x41, 0x6e, 0x68, 0x4d, |
295 | 0x66,0x44,0x34,0x77,0x66,0x6c,0x39,0x2f,0x56,0x41,0x39,0x45,0x53,0x56,0x31,0x65, | 293 | 0x56, 0x41, 0x3d, 0x3d, 0x00}; |
296 | 0x45,0x47,0x6f,0x47,0x4b,0x77,0x5a,0x54,0x45,0x44,0x6b,0x33,0x4d,0x6b,0x70,0x4f, | ||
297 | 0x50,0x53,0x74,0x6c,0x4f,0x44,0x6b,0x48,0x63,0x6c,0x52,0x6b,0x54,0x56,0x5a,0x71, | ||
298 | 0x41,0x79,0x4a,0x77,0x65,0x31,0x39,0x67,0x43,0x79,0x6f,0x4c,0x61,0x78,0x42,0x6b, | ||
299 | 0x46,0x41,0x55,0x69,0x41,0x48,0x4e,0x41,0x49,0x31,0x74,0x52,0x48,0x79,0x73,0x61, | ||
300 | 0x58,0x57,0x6c,0x36,0x52,0x67,0x78,0x66,0x4d,0x6b,0x74,0x4b,0x4b,0x46,0x4a,0x35, | ||
301 | 0x57,0x78,0x4a,0x43,0x47,0x41,0x42,0x64,0x4a,0x7a,0x46,0x54,0x50,0x45,0x77,0x32, | ||
302 | 0x54,0x6a,0x67,0x2f,0x63,0x67,0x4e,0x78,0x41,0x6c,0x73,0x32,0x57,0x58,0x39,0x31, | ||
303 | 0x62,0x67,0x68,0x55,0x44,0x54,0x51,0x63,0x4e,0x46,0x64,0x64,0x61,0x55,0x67,0x41, | ||
304 | 0x4f,0x77,0x55,0x48,0x62,0x69,0x64,0x6c,0x62,0x6b,0x41,0x39,0x4f,0x6b,0x39,0x79, | ||
305 | 0x58,0x54,0x6b,0x57,0x44,0x32,0x4d,0x53,0x45,0x68,0x55,0x36,0x63,0x41,0x31,0x58, | ||
306 | 0x47,0x41,0x31,0x65,0x50,0x53,0x4a,0x6f,0x61,0x48,0x78,0x74,0x54,0x77,0x78,0x37, | ||
307 | 0x43,0x53,0x31,0x4b,0x63,0x79,0x42,0x48,0x42,0x31,0x64,0x31,0x58,0x56,0x4e,0x77, | ||
308 | 0x4e,0x43,0x46,0x41,0x56,0x31,0x46,0x65,0x53,0x55,0x51,0x41,0x56,0x43,0x63,0x45, | ||
309 | 0x61,0x48,0x35,0x5a,0x56,0x6c,0x68,0x30,0x46,0x44,0x77,0x57,0x4d,0x30,0x45,0x57, | ||
310 | 0x53,0x79,0x39,0x4a,0x4e,0x77,0x70,0x55,0x43,0x41,0x67,0x66,0x4f,0x57,0x64,0x32, | ||
311 | 0x4b,0x43,0x67,0x48,0x48,0x57,0x46,0x48,0x55,0x55,0x31,0x31,0x4a,0x6c,0x4a,0x48, | ||
312 | 0x52,0x77,0x78,0x58,0x57,0x48,0x51,0x2b,0x59,0x6d,0x78,0x59,0x4f,0x6b,0x51,0x65, | ||
313 | 0x46,0x69,0x34,0x68,0x48,0x48,0x4e,0x46,0x5a,0x33,0x52,0x50,0x4d,0x32,0x59,0x4f, | ||
314 | 0x64,0x47,0x59,0x6d,0x48,0x79,0x34,0x34,0x52,0x45,0x42,0x2b,0x4b,0x6c,0x42,0x53, | ||
315 | 0x58,0x6b,0x4d,0x42,0x65,0x6a,0x68,0x4a,0x50,0x46,0x56,0x4e,0x57,0x6b,0x51,0x49, | ||
316 | 0x4a,0x6c,0x6c,0x4e,0x52,0x51,0x74,0x49,0x43,0x6a,0x4e,0x65,0x53,0x6b,0x31,0x31, | ||
317 | 0x46,0x68,0x64,0x6a,0x52,0x67,0x45,0x71,0x56,0x58,0x73,0x50,0x41,0x6e,0x4e,0x71, | ||
318 | 0x53,0x33,0x39,0x31,0x5a,0x54,0x78,0x4d,0x4d,0x7a,0x6c,0x73,0x64,0x41,0x56,0x67, | ||
319 | 0x44,0x33,0x38,0x74,0x51,0x55,0x31,0x4e,0x52,0x6e,0x45,0x4a,0x62,0x30,0x39,0x67, | ||
320 | 0x46,0x51,0x39,0x47,0x63,0x32,0x4e,0x4d,0x58,0x6e,0x51,0x77,0x44,0x53,0x68,0x44, | ||
321 | 0x43,0x48,0x49,0x79,0x42,0x43,0x34,0x78,0x4b,0x53,0x64,0x45,0x62,0x52,0x4d,0x58, | ||
322 | 0x53,0x41,0x39,0x4a,0x55,0x68,0x41,0x54,0x66,0x78,0x63,0x57,0x59,0x6e,0x6b,0x31, | ||
323 | 0x65,0x44,0x34,0x42,0x66,0x43,0x34,0x50,0x64,0x6a,0x35,0x65,0x55,0x32,0x78,0x62, | ||
324 | 0x58,0x33,0x77,0x5a,0x51,0x51,0x49,0x76,0x46,0x32,0x52,0x42,0x64,0x52,0x41,0x45, | ||
325 | 0x52,0x33,0x77,0x39,0x53,0x31,0x49,0x41,0x45,0x46,0x31,0x52,0x54,0x6e,0x6f,0x6e, | ||
326 | 0x4a,0x56,0x56,0x41,0x45,0x6a,0x56,0x67,0x42,0x52,0x73,0x30,0x4c,0x51,0x52,0x36, | ||
327 | 0x61,0x6d,0x6b,0x43,0x65,0x51,0x4d,0x36,0x4c,0x77,0x59,0x4b,0x65,0x58,0x73,0x53, | ||
328 | 0x58,0x58,0x78,0x53,0x4b,0x55,0x64,0x59,0x45,0x6e,0x4d,0x2f,0x4a,0x31,0x59,0x46, | ||
329 | 0x44,0x45,0x67,0x79,0x57,0x47,0x74,0x58,0x58,0x41,0x4e,0x6b,0x56,0x68,0x46,0x53, | ||
330 | 0x65,0x6a,0x41,0x32,0x4b,0x52,0x63,0x37,0x61,0x48,0x70,0x38,0x42,0x57,0x74,0x72, | ||
331 | 0x45,0x32,0x6f,0x6b,0x58,0x47,0x68,0x43,0x47,0x44,0x49,0x44,0x63,0x32,0x34,0x45, | ||
332 | 0x49,0x53,0x34,0x42,0x42,0x47,0x4e,0x39,0x52,0x45,0x45,0x53,0x4d,0x51,0x73,0x56, | ||
333 | 0x48,0x33,0x41,0x41,0x4c,0x6d,0x59,0x55,0x50,0x48,0x38,0x72,0x41,0x42,0x38,0x4d, | ||
334 | 0x4b,0x46,0x6b,0x4b,0x46,0x6b,0x6c,0x61,0x58,0x47,0x52,0x6c,0x53,0x78,0x45,0x70, | ||
335 | 0x46,0x54,0x5a,0x61,0x5a,0x52,0x6c,0x50,0x59,0x43,0x4d,0x36,0x4f,0x68,0x4d,0x6c, | ||
336 | 0x41,0x6e,0x68,0x4d,0x56,0x41,0x3d,0x3d,0x00 | ||
337 | }; | ||
338 | char *b64_test; | 294 | char *b64_test; |
339 | 295 | ||
340 | plan_tests(1); | 296 | plan_tests(1); |
341 | 297 | ||
342 | base64_encode_alloc (random, 1024, &b64_test); | 298 | base64_encode_alloc(random, 1024, &b64_test); |
343 | 299 | ||
344 | ok(strcmp(b64_known, b64_test) == 0, | 300 | ok(strcmp(b64_known, b64_test) == 0, "Test matching a base64 encoded 1024 bytes random string"); |
345 | "Test matching a base64 encoded 1024 bytes random string"); | ||
346 | 301 | ||
347 | return exit_status(); | 302 | return exit_status(); |
348 | } | 303 | } |
349 | |||
diff --git a/lib/tests/test_cmd.c b/lib/tests/test_cmd.c index 02ae11f5..c8867dfb 100644 --- a/lib/tests/test_cmd.c +++ b/lib/tests/test_cmd.c | |||
@@ -1,20 +1,20 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | * | 16 | * |
17 | *****************************************************************************/ | 17 | *****************************************************************************/ |
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "utils_cmd.h" | 20 | #include "utils_cmd.h" |
@@ -22,27 +22,23 @@ | |||
22 | #include "tap.h" | 22 | #include "tap.h" |
23 | 23 | ||
24 | #define COMMAND_LINE 1024 | 24 | #define COMMAND_LINE 1024 |
25 | #define UNSET 65530 | 25 | #define UNSET 65530 |
26 | 26 | ||
27 | char * | 27 | char *get_command(char *const *line) { |
28 | get_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 | ||
42 | int | 40 | int main(int argc, char **argv) { |
43 | main (int argc, char **argv) | 41 | char **command_line = malloc(sizeof(char *) * COMMAND_LINE); |
44 | { | ||
45 | char **command_line = malloc (sizeof (char *) * COMMAND_LINE); | ||
46 | char *command = NULL; | 42 | char *command = NULL; |
47 | char *perl; | 43 | char *perl; |
48 | output chld_out, chld_err; | 44 | output chld_out, chld_err; |
@@ -51,183 +47,154 @@ main (int argc, char **argv) | |||
51 | 47 | ||
52 | plan_tests(51); | 48 | plan_tests(51); |
53 | 49 | ||
54 | diag ("Running plain echo command, set one"); | 50 | diag("Running plain echo command, set one"); |
55 | 51 | ||
56 | /* ensure everything is empty before we begin */ | 52 | /* ensure everything is empty before we begin */ |
57 | memset (&chld_out, 0, sizeof (output)); | 53 | memset(&chld_out, 0, sizeof(output)); |
58 | memset (&chld_err, 0, sizeof (output)); | 54 | memset(&chld_err, 0, sizeof(output)); |
59 | ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); | 55 | ok(chld_out.lines == 0, "(initialised) Checking stdout is reset"); |
60 | ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); | 56 | ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); |
61 | ok (result == UNSET, "(initialised) Checking exit code is reset"); | 57 | ok(result == UNSET, "(initialised) Checking exit code is reset"); |
62 | 58 | ||
63 | command_line[0] = strdup ("/bin/echo"); | 59 | command_line[0] = strdup("/bin/echo"); |
64 | command_line[1] = strdup ("this"); | 60 | command_line[1] = strdup("this"); |
65 | command_line[2] = strdup ("is"); | 61 | command_line[2] = strdup("is"); |
66 | command_line[3] = strdup ("test"); | 62 | command_line[3] = strdup("test"); |
67 | command_line[4] = strdup ("one"); | 63 | command_line[4] = strdup("one"); |
68 | 64 | ||
69 | command = get_command (command_line); | 65 | command = get_command(command_line); |
70 | 66 | ||
71 | result = cmd_run_array (command_line, &chld_out, &chld_err, 0); | 67 | result = cmd_run_array(command_line, &chld_out, &chld_err, 0); |
72 | ok (chld_out.lines == 1, | 68 | ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines"); |
73 | "(array) Check for expected number of stdout lines"); | 69 | ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines"); |
74 | ok (chld_err.lines == 0, | 70 | ok(strcmp(chld_out.line[0], "this is test one") == 0, "(array) Check for expected stdout output"); |
75 | "(array) Check for expected number of stderr lines"); | 71 | ok(result == 0, "(array) Checking exit code"); |
76 | ok (strcmp (chld_out.line[0], "this is test one") == 0, | ||
77 | "(array) Check for expected stdout output"); | ||
78 | ok (result == 0, "(array) Checking exit code"); | ||
79 | 72 | ||
80 | /* ensure everything is empty again */ | 73 | /* ensure everything is empty again */ |
81 | memset (&chld_out, 0, sizeof (output)); | 74 | memset(&chld_out, 0, sizeof(output)); |
82 | memset (&chld_err, 0, sizeof (output)); | 75 | memset(&chld_err, 0, sizeof(output)); |
83 | result = UNSET; | 76 | result = UNSET; |
84 | ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); | 77 | ok(chld_out.lines == 0, "(initialised) Checking stdout is reset"); |
85 | ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); | 78 | ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); |
86 | ok (result == UNSET, "(initialised) Checking exit code is reset"); | 79 | ok(result == UNSET, "(initialised) Checking exit code is reset"); |
87 | 80 | ||
88 | result = cmd_run (command, &chld_out, &chld_err, 0); | 81 | result = cmd_run(command, &chld_out, &chld_err, 0); |
89 | 82 | ||
90 | ok (chld_out.lines == 1, | 83 | ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines"); |
91 | "(string) Check for expected number of stdout lines"); | 84 | ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines"); |
92 | ok (chld_err.lines == 0, | 85 | ok(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output"); |
93 | "(string) Check for expected number of stderr lines"); | 86 | ok(result == 0, "(string) Checking exit code"); |
94 | ok (strcmp (chld_out.line[0], "this is test one") == 0, | ||
95 | "(string) Check for expected stdout output"); | ||
96 | ok (result == 0, "(string) Checking exit code"); | ||
97 | 87 | ||
98 | diag ("Running plain echo command, set two"); | 88 | diag("Running plain echo command, set two"); |
99 | 89 | ||
100 | /* ensure everything is empty again */ | 90 | /* ensure everything is empty again */ |
101 | memset (&chld_out, 0, sizeof (output)); | 91 | memset(&chld_out, 0, sizeof(output)); |
102 | memset (&chld_err, 0, sizeof (output)); | 92 | memset(&chld_err, 0, sizeof(output)); |
103 | result = UNSET; | 93 | result = UNSET; |
104 | ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); | 94 | ok(chld_out.lines == 0, "(initialised) Checking stdout is reset"); |
105 | ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); | 95 | ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); |
106 | ok (result == UNSET, "(initialised) Checking exit code is reset"); | 96 | ok(result == UNSET, "(initialised) Checking exit code is reset"); |
107 | 97 | ||
108 | command_line[0] = strdup ("/bin/echo"); | 98 | command_line[0] = strdup("/bin/echo"); |
109 | command_line[1] = strdup ("this is test two"); | 99 | command_line[1] = strdup("this is test two"); |
110 | command_line[2] = NULL; | 100 | command_line[2] = NULL; |
111 | command_line[3] = NULL; | 101 | command_line[3] = NULL; |
112 | command_line[4] = NULL; | 102 | command_line[4] = NULL; |
113 | 103 | ||
114 | result = cmd_run_array (command_line, &chld_out, &chld_err, 0); | 104 | result = cmd_run_array(command_line, &chld_out, &chld_err, 0); |
115 | ok (chld_out.lines == 1, | 105 | ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines"); |
116 | "(array) Check for expected number of stdout lines"); | 106 | ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines"); |
117 | ok (chld_err.lines == 0, | 107 | ok(strcmp(chld_out.line[0], "this is test two") == 0, "(array) Check for expected stdout output"); |
118 | "(array) Check for expected number of stderr lines"); | 108 | ok(result == 0, "(array) Checking exit code"); |
119 | ok (strcmp (chld_out.line[0], "this is test two") == 0, | ||
120 | "(array) Check for expected stdout output"); | ||
121 | ok (result == 0, "(array) Checking exit code"); | ||
122 | 109 | ||
123 | /* ensure everything is empty again */ | 110 | /* ensure everything is empty again */ |
124 | memset (&chld_out, 0, sizeof (output)); | 111 | memset(&chld_out, 0, sizeof(output)); |
125 | memset (&chld_err, 0, sizeof (output)); | 112 | memset(&chld_err, 0, sizeof(output)); |
126 | result = UNSET; | 113 | result = UNSET; |
127 | ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); | 114 | ok(chld_out.lines == 0, "(initialised) Checking stdout is reset"); |
128 | ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); | 115 | ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); |
129 | ok (result == UNSET, "(initialised) Checking exit code is reset"); | 116 | ok(result == UNSET, "(initialised) Checking exit code is reset"); |
130 | |||
131 | result = cmd_run (command, &chld_out, &chld_err, 0); | ||
132 | 117 | ||
133 | ok (chld_out.lines == 1, | 118 | result = cmd_run(command, &chld_out, &chld_err, 0); |
134 | "(string) Check for expected number of stdout lines"); | ||
135 | ok (chld_err.lines == 0, | ||
136 | "(string) Check for expected number of stderr lines"); | ||
137 | ok (strcmp (chld_out.line[0], "this is test one") == 0, | ||
138 | "(string) Check for expected stdout output"); | ||
139 | ok (result == 0, "(string) Checking exit code"); | ||
140 | 119 | ||
120 | ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines"); | ||
121 | ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines"); | ||
122 | ok(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output"); | ||
123 | ok(result == 0, "(string) Checking exit code"); | ||
141 | 124 | ||
142 | /* ensure everything is empty again */ | 125 | /* ensure everything is empty again */ |
143 | memset (&chld_out, 0, sizeof (output)); | 126 | memset(&chld_out, 0, sizeof(output)); |
144 | memset (&chld_err, 0, sizeof (output)); | 127 | memset(&chld_err, 0, sizeof(output)); |
145 | result = UNSET; | 128 | result = UNSET; |
146 | ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); | 129 | ok(chld_out.lines == 0, "(initialised) Checking stdout is reset"); |
147 | ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); | 130 | ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); |
148 | ok (result == UNSET, "(initialised) Checking exit code is reset"); | 131 | ok(result == UNSET, "(initialised) Checking exit code is reset"); |
149 | 132 | ||
150 | /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */ | 133 | /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */ |
151 | command_line[0] = strdup("/bin/echo"); | 134 | command_line[0] = strdup("/bin/echo"); |
152 | command_line[1] = strdup("this is a test via echo\nline two\nit's line 3"); | 135 | command_line[1] = strdup("this is a test via echo\nline two\nit's line 3"); |
153 | command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated"); | 136 | command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated"); |
154 | 137 | ||
155 | result = cmd_run_array (command_line, &chld_out, &chld_err, 0); | 138 | result = cmd_run_array(command_line, &chld_out, &chld_err, 0); |
156 | ok (chld_out.lines == 3, | 139 | ok(chld_out.lines == 3, "(array) Check for expected number of stdout lines"); |
157 | "(array) Check for expected number of stdout lines"); | 140 | ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines"); |
158 | ok (chld_err.lines == 0, | 141 | ok(strcmp(chld_out.line[0], "this is a test via echo") == 0, "(array) Check line 1 for expected stdout output"); |
159 | "(array) Check for expected number of stderr lines"); | 142 | ok(strcmp(chld_out.line[1], "line two") == 0, "(array) Check line 2 for expected stdout output"); |
160 | ok (strcmp (chld_out.line[0], "this is a test via echo") == 0, | 143 | ok(strcmp(chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0, |
161 | "(array) Check line 1 for expected stdout output"); | 144 | "(array) Check line 3 for expected stdout output"); |
162 | ok (strcmp (chld_out.line[1], "line two") == 0, | 145 | ok(result == 0, "(array) Checking exit code"); |
163 | "(array) Check line 2 for expected stdout output"); | ||
164 | ok (strcmp (chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0, | ||
165 | "(array) Check line 3 for expected stdout output"); | ||
166 | ok (result == 0, "(array) Checking exit code"); | ||
167 | |||
168 | |||
169 | 146 | ||
170 | /* ensure everything is empty again */ | 147 | /* ensure everything is empty again */ |
171 | memset (&chld_out, 0, sizeof (output)); | 148 | memset(&chld_out, 0, sizeof(output)); |
172 | memset (&chld_err, 0, sizeof (output)); | 149 | memset(&chld_err, 0, sizeof(output)); |
173 | result = UNSET; | 150 | result = UNSET; |
174 | ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); | 151 | ok(chld_out.lines == 0, "(initialised) Checking stdout is reset"); |
175 | ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); | 152 | ok(chld_err.lines == 0, "(initialised) Checking stderr is reset"); |
176 | ok (result == UNSET, "(initialised) Checking exit code is reset"); | 153 | ok(result == UNSET, "(initialised) Checking exit code is reset"); |
177 | 154 | ||
178 | command = (char *)malloc(COMMAND_LINE); | 155 | command = (char *)malloc(COMMAND_LINE); |
179 | strcpy(command, "/bin/echo3456 non-existent command"); | 156 | strcpy(command, "/bin/echo3456 non-existent command"); |
180 | result = cmd_run (command, &chld_out, &chld_err, 0); | 157 | result = cmd_run(command, &chld_out, &chld_err, 0); |
181 | |||
182 | ok (chld_out.lines == 0, | ||
183 | "Non existent command, so no output"); | ||
184 | ok (chld_err.lines == 0, | ||
185 | "No stderr either"); | ||
186 | ok (result == 3, "Get return code 3 (?) for non-existent command"); | ||
187 | 158 | ||
159 | ok(chld_out.lines == 0, "Non existent command, so no output"); | ||
160 | ok(chld_err.lines == 0, "No stderr either"); | ||
161 | ok(result == 3, "Get return code 3 (?) for non-existent command"); | ||
188 | 162 | ||
189 | /* ensure everything is empty again */ | 163 | /* ensure everything is empty again */ |
190 | memset (&chld_out, 0, sizeof (output)); | 164 | memset(&chld_out, 0, sizeof(output)); |
191 | memset (&chld_err, 0, sizeof (output)); | 165 | memset(&chld_err, 0, sizeof(output)); |
192 | result = UNSET; | 166 | result = UNSET; |
193 | 167 | ||
194 | command = (char *)malloc(COMMAND_LINE); | 168 | command = (char *)malloc(COMMAND_LINE); |
195 | strcpy(command, "/bin/sh non-existent-file"); | 169 | strcpy(command, "/bin/sh non-existent-file"); |
196 | result = cmd_run (command, &chld_out, &chld_err, 0); | 170 | result = cmd_run(command, &chld_out, &chld_err, 0); |
197 | |||
198 | ok (chld_out.lines == 0, | ||
199 | "/bin/sh returns no stdout when file is missing..."); | ||
200 | ok (chld_err.lines == 1, | ||
201 | "...but does give an error line"); | ||
202 | ok (strstr(chld_err.line[0],"non-existent-file") != NULL, "And missing filename is in error message"); | ||
203 | ok (result != 0, "Get non-zero return code from /bin/sh"); | ||
204 | 171 | ||
172 | ok(chld_out.lines == 0, "/bin/sh returns no stdout when file is missing..."); | ||
173 | ok(chld_err.lines == 1, "...but does give an error line"); | ||
174 | ok(strstr(chld_err.line[0], "non-existent-file") != NULL, "And missing filename is in error message"); | ||
175 | ok(result != 0, "Get non-zero return code from /bin/sh"); | ||
205 | 176 | ||
206 | /* ensure everything is empty again */ | 177 | /* ensure everything is empty again */ |
207 | result = UNSET; | 178 | result = UNSET; |
208 | 179 | ||
209 | command = (char *)malloc(COMMAND_LINE); | 180 | command = (char *)malloc(COMMAND_LINE); |
210 | strcpy(command, "/bin/sh -c 'exit 7'"); | 181 | strcpy(command, "/bin/sh -c 'exit 7'"); |
211 | result = cmd_run (command, NULL, NULL, 0); | 182 | result = cmd_run(command, NULL, NULL, 0); |
212 | |||
213 | ok (result == 7, "Get return code 7 from /bin/sh"); | ||
214 | 183 | ||
184 | ok(result == 7, "Get return code 7 from /bin/sh"); | ||
215 | 185 | ||
216 | /* ensure everything is empty again */ | 186 | /* ensure everything is empty again */ |
217 | memset (&chld_out, 0, sizeof (output)); | 187 | memset(&chld_out, 0, sizeof(output)); |
218 | memset (&chld_err, 0, sizeof (output)); | 188 | memset(&chld_err, 0, sizeof(output)); |
219 | result = UNSET; | 189 | result = UNSET; |
220 | 190 | ||
221 | command = (char *)malloc(COMMAND_LINE); | 191 | command = (char *)malloc(COMMAND_LINE); |
222 | strcpy(command, "/bin/non-existent-command"); | 192 | strcpy(command, "/bin/non-existent-command"); |
223 | result = cmd_run (command, &chld_out, &chld_err, 0); | 193 | result = cmd_run(command, &chld_out, &chld_err, 0); |
224 | |||
225 | ok (chld_out.lines == 0, | ||
226 | "/bin/non-existent-command returns no stdout..."); | ||
227 | ok (chld_err.lines == 0, | ||
228 | "...and no stderr output either"); | ||
229 | ok (result == 3, "Get return code 3 = UNKNOWN when command does not exist"); | ||
230 | 194 | ||
195 | ok(chld_out.lines == 0, "/bin/non-existent-command returns no stdout..."); | ||
196 | ok(chld_err.lines == 0, "...and no stderr output either"); | ||
197 | ok(result == 3, "Get return code 3 = UNKNOWN when command does not exist"); | ||
231 | 198 | ||
232 | return exit_status (); | 199 | return exit_status(); |
233 | } | 200 | } |
diff --git a/lib/tests/test_disk.c b/lib/tests/test_disk.c index e283fe2e..c18db7a4 100644 --- a/lib/tests/test_disk.c +++ b/lib/tests/test_disk.c | |||
@@ -1,36 +1,31 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | * | 16 | * |
17 | *****************************************************************************/ | 17 | *****************************************************************************/ |
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "utils_disk.h" | 20 | #include "utils_disk.h" |
21 | #include "tap.h" | 21 | #include "tap.h" |
22 | #include "regex.h" | 22 | #include "regex.h" |
23 | 23 | ||
24 | void np_test_mount_entry_regex (struct mount_entry *dummy_mount_list, | 24 | void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc); |
25 | char *regstr, int cflags, int expect, | ||
26 | char *desc); | ||
27 | 25 | ||
28 | 26 | int main(int argc, char **argv) { | |
29 | int | 27 | struct name_list *exclude_filesystem = NULL; |
30 | main (int argc, char **argv) | 28 | struct name_list *exclude_fstype = NULL; |
31 | { | ||
32 | struct name_list *exclude_filesystem=NULL; | ||
33 | struct name_list *exclude_fstype=NULL; | ||
34 | struct name_list *dummy_mountlist = NULL; | 29 | struct name_list *dummy_mountlist = NULL; |
35 | struct name_list *temp_name; | 30 | struct name_list *temp_name; |
36 | struct parameter_list *paths = NULL; | 31 | struct parameter_list *paths = NULL; |
@@ -44,19 +39,19 @@ main (int argc, char **argv) | |||
44 | 39 | ||
45 | plan_tests(33); | 40 | plan_tests(33); |
46 | 41 | ||
47 | ok( np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list"); | 42 | ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list"); |
48 | np_add_name(&exclude_filesystem, "/var/log"); | 43 | np_add_name(&exclude_filesystem, "/var/log"); |
49 | ok( np_find_name(exclude_filesystem, "/var/log") == true, "is in list now"); | 44 | ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now"); |
50 | ok( np_find_name(exclude_filesystem, "/home") == false, "/home not in list"); | 45 | ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list"); |
51 | np_add_name(&exclude_filesystem, "/home"); | 46 | np_add_name(&exclude_filesystem, "/home"); |
52 | ok( np_find_name(exclude_filesystem, "/home") == true, "is in list now"); | 47 | ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now"); |
53 | ok( np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list"); | 48 | ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list"); |
54 | 49 | ||
55 | ok( np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list"); | 50 | ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list"); |
56 | np_add_name(&exclude_fstype, "iso9660"); | 51 | np_add_name(&exclude_fstype, "iso9660"); |
57 | ok( np_find_name(exclude_fstype, "iso9660") == true, "is in list now"); | 52 | ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now"); |
58 | 53 | ||
59 | ok( np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables"); | 54 | ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables"); |
60 | 55 | ||
61 | /* | 56 | /* |
62 | for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) { | 57 | for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) { |
@@ -64,55 +59,35 @@ main (int argc, char **argv) | |||
64 | } | 59 | } |
65 | */ | 60 | */ |
66 | 61 | ||
67 | me = (struct mount_entry *) malloc(sizeof *me); | 62 | me = (struct mount_entry *)malloc(sizeof *me); |
68 | me->me_devname = strdup("/dev/c0t0d0s0"); | 63 | me->me_devname = strdup("/dev/c0t0d0s0"); |
69 | me->me_mountdir = strdup("/"); | 64 | me->me_mountdir = strdup("/"); |
70 | *mtail = me; | 65 | *mtail = me; |
71 | mtail = &me->me_next; | 66 | mtail = &me->me_next; |
72 | 67 | ||
73 | me = (struct mount_entry *) malloc(sizeof *me); | 68 | me = (struct mount_entry *)malloc(sizeof *me); |
74 | me->me_devname = strdup("/dev/c1t0d1s0"); | 69 | me->me_devname = strdup("/dev/c1t0d1s0"); |
75 | me->me_mountdir = strdup("/var"); | 70 | me->me_mountdir = strdup("/var"); |
76 | *mtail = me; | 71 | *mtail = me; |
77 | mtail = &me->me_next; | 72 | mtail = &me->me_next; |
78 | 73 | ||
79 | me = (struct mount_entry *) malloc(sizeof *me); | 74 | me = (struct mount_entry *)malloc(sizeof *me); |
80 | me->me_devname = strdup("/dev/c2t0d0s0"); | 75 | me->me_devname = strdup("/dev/c2t0d0s0"); |
81 | me->me_mountdir = strdup("/home"); | 76 | me->me_mountdir = strdup("/home"); |
82 | *mtail = me; | 77 | *mtail = me; |
83 | mtail = &me->me_next; | 78 | mtail = &me->me_next; |
84 | 79 | ||
85 | np_test_mount_entry_regex(dummy_mount_list, strdup("/"), | 80 | np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a")); |
86 | cflags, 3, strdup("a")); | 81 | np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3, strdup("regex on dev names:")); |
87 | np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), | 82 | np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0, strdup("regex on non existent dev/path:")); |
88 | cflags, 3,strdup("regex on dev names:")); | 83 | np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0, strdup("regi on non existent dev/path:")); |
89 | np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), | 84 | np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3, strdup("partial devname regex match:")); |
90 | cflags, 0, | 85 | np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1, strdup("partial devname regex match:")); |
91 | strdup("regex on non existent dev/path:")); | 86 | np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:")); |
92 | np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), | 87 | np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1, strdup("partial pathname regex match:")); |
93 | cflags | REG_ICASE,0, | 88 | np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:")); |
94 | strdup("regi on non existent dev/path:")); | 89 | np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:")); |
95 | np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), | 90 | np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:")); |
96 | cflags, 3, | ||
97 | strdup("partial devname regex match:")); | ||
98 | np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), | ||
99 | cflags, 1, | ||
100 | strdup("partial devname regex match:")); | ||
101 | np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), | ||
102 | cflags | REG_ICASE, 1, | ||
103 | strdup("partial devname regi match:")); | ||
104 | np_test_mount_entry_regex(dummy_mount_list, strdup("home"), | ||
105 | cflags, 1, | ||
106 | strdup("partial pathname regex match:")); | ||
107 | np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), | ||
108 | cflags | REG_ICASE, 1, | ||
109 | strdup("partial pathname regi match:")); | ||
110 | np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), | ||
111 | cflags, 2, | ||
112 | strdup("grouped regex pathname match:")); | ||
113 | np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), | ||
114 | cflags | REG_ICASE, 2, | ||
115 | strdup("grouped regi pathname match:")); | ||
116 | 91 | ||
117 | np_add_parameter(&paths, "/home/groups"); | 92 | np_add_parameter(&paths, "/home/groups"); |
118 | np_add_parameter(&paths, "/var"); | 93 | np_add_parameter(&paths, "/var"); |
@@ -124,20 +99,20 @@ main (int argc, char **argv) | |||
124 | for (p = paths; p; p = p->name_next) { | 99 | for (p = paths; p; p = p->name_next) { |
125 | struct mount_entry *temp_me; | 100 | struct mount_entry *temp_me; |
126 | temp_me = p->best_match; | 101 | temp_me = p->best_match; |
127 | if (! strcmp(p->name, "/home/groups")) { | 102 | if (!strcmp(p->name, "/home/groups")) { |
128 | ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home"); | 103 | ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home"); |
129 | } else if (! strcmp(p->name, "/var")) { | 104 | } else if (!strcmp(p->name, "/var")) { |
130 | ok( temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var"); | 105 | ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var"); |
131 | } else if (! strcmp(p->name, "/tmp")) { | 106 | } else if (!strcmp(p->name, "/tmp")) { |
132 | ok( temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /"); | 107 | ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /"); |
133 | } else if (! strcmp(p->name, "/home/tonvoon")) { | 108 | } else if (!strcmp(p->name, "/home/tonvoon")) { |
134 | ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home"); | 109 | ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home"); |
135 | } else if (! strcmp(p->name, "/dev/c2t0d0s0")) { | 110 | } else if (!strcmp(p->name, "/dev/c2t0d0s0")) { |
136 | ok( temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0"); | 111 | ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0"); |
137 | } | 112 | } |
138 | } | 113 | } |
139 | 114 | ||
140 | paths = NULL; /* Bad boy - should free, but this is a test suite */ | 115 | paths = NULL; /* Bad boy - should free, but this is a test suite */ |
141 | np_add_parameter(&paths, "/home/groups"); | 116 | np_add_parameter(&paths, "/home/groups"); |
142 | np_add_parameter(&paths, "/var"); | 117 | np_add_parameter(&paths, "/var"); |
143 | np_add_parameter(&paths, "/tmp"); | 118 | np_add_parameter(&paths, "/tmp"); |
@@ -146,31 +121,31 @@ main (int argc, char **argv) | |||
146 | 121 | ||
147 | np_set_best_match(paths, dummy_mount_list, true); | 122 | np_set_best_match(paths, dummy_mount_list, true); |
148 | for (p = paths; p; p = p->name_next) { | 123 | for (p = paths; p; p = p->name_next) { |
149 | if (! strcmp(p->name, "/home/groups")) { | 124 | if (!strcmp(p->name, "/home/groups")) { |
150 | ok( ! p->best_match , "/home/groups correctly not found"); | 125 | ok(!p->best_match, "/home/groups correctly not found"); |
151 | } else if (! strcmp(p->name, "/var")) { | 126 | } else if (!strcmp(p->name, "/var")) { |
152 | ok( p->best_match, "/var found"); | 127 | ok(p->best_match, "/var found"); |
153 | } else if (! strcmp(p->name, "/tmp")) { | 128 | } else if (!strcmp(p->name, "/tmp")) { |
154 | ok(! p->best_match, "/tmp correctly not found"); | 129 | ok(!p->best_match, "/tmp correctly not found"); |
155 | } else if (! strcmp(p->name, "/home/tonvoon")) { | 130 | } else if (!strcmp(p->name, "/home/tonvoon")) { |
156 | ok(! p->best_match, "/home/tonvoon not found"); | 131 | ok(!p->best_match, "/home/tonvoon not found"); |
157 | } else if (! strcmp(p->name, "/home")) { | 132 | } else if (!strcmp(p->name, "/home")) { |
158 | ok( p->best_match, "/home found"); | 133 | ok(p->best_match, "/home found"); |
159 | } | 134 | } |
160 | } | 135 | } |
161 | 136 | ||
162 | /* test deleting first element in paths */ | 137 | /* test deleting first element in paths */ |
163 | paths = np_del_parameter(paths, NULL); | 138 | paths = np_del_parameter(paths, NULL); |
164 | for (p = paths; p; p = p->name_next) { | 139 | for (p = paths; p; p = p->name_next) { |
165 | if (! strcmp(p->name, "/home/groups")) | 140 | if (!strcmp(p->name, "/home/groups")) |
166 | found = 1; | 141 | found = 1; |
167 | } | 142 | } |
168 | ok(found == 0, "first element successfully deleted"); | 143 | ok(found == 0, "first element successfully deleted"); |
169 | found = 0; | 144 | found = 0; |
170 | 145 | ||
171 | p=paths; | 146 | p = paths; |
172 | while (p) { | 147 | while (p) { |
173 | if (! strcmp(p->name, "/tmp")) | 148 | if (!strcmp(p->name, "/tmp")) |
174 | p = np_del_parameter(p, prev); | 149 | p = np_del_parameter(p, prev); |
175 | else { | 150 | else { |
176 | prev = p; | 151 | prev = p; |
@@ -179,7 +154,7 @@ main (int argc, char **argv) | |||
179 | } | 154 | } |
180 | 155 | ||
181 | for (p = paths; p; p = p->name_next) { | 156 | for (p = paths; p; p = p->name_next) { |
182 | if (! strcmp(p->name, "/tmp")) | 157 | if (!strcmp(p->name, "/tmp")) |
183 | found = 1; | 158 | found = 1; |
184 | if (p->name_next) | 159 | if (p->name_next) |
185 | prev = p; | 160 | prev = p; |
@@ -190,7 +165,7 @@ main (int argc, char **argv) | |||
190 | 165 | ||
191 | p = np_del_parameter(last, prev); | 166 | p = np_del_parameter(last, prev); |
192 | for (p = paths; p; p = p->name_next) { | 167 | for (p = paths; p; p = p->name_next) { |
193 | if (! strcmp(p->name, "/home")) | 168 | if (!strcmp(p->name, "/home")) |
194 | found = 1; | 169 | found = 1; |
195 | last = p; | 170 | last = p; |
196 | count++; | 171 | count++; |
@@ -198,27 +173,20 @@ main (int argc, char **argv) | |||
198 | ok(found == 0, "last (/home) element successfully deleted"); | 173 | ok(found == 0, "last (/home) element successfully deleted"); |
199 | ok(count == 2, "two elements remaining"); | 174 | ok(count == 2, "two elements remaining"); |
200 | 175 | ||
201 | |||
202 | return exit_status(); | 176 | return exit_status(); |
203 | } | 177 | } |
204 | 178 | ||
205 | 179 | void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) { | |
206 | void | ||
207 | np_test_mount_entry_regex (struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) | ||
208 | { | ||
209 | int matches = 0; | 180 | int matches = 0; |
210 | regex_t re; | 181 | regex_t re; |
211 | struct mount_entry *me; | 182 | struct mount_entry *me; |
212 | if (regcomp(&re,regstr, cflags) == 0) { | 183 | if (regcomp(&re, regstr, cflags) == 0) { |
213 | for (me = dummy_mount_list; me; me= me->me_next) { | 184 | for (me = dummy_mount_list; me; me = me->me_next) { |
214 | if(np_regex_match_mount_entry(me,&re)) | 185 | if (np_regex_match_mount_entry(me, &re)) |
215 | matches++; | 186 | matches++; |
216 | } | 187 | } |
217 | ok( matches == expect, | 188 | ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches); |
218 | "%s '%s' matched %i/3 entries. ok: %i/3", | ||
219 | desc, regstr, expect, matches); | ||
220 | 189 | ||
221 | } else | 190 | } else |
222 | ok ( false, "regex '%s' not compilable", regstr); | 191 | ok(false, "regex '%s' not compilable", regstr); |
223 | } | 192 | } |
224 | |||
diff --git a/lib/tests/test_generic_output b/lib/tests/test_generic_output new file mode 100755 index 00000000..51e299a0 --- /dev/null +++ b/lib/tests/test_generic_output | |||
Binary files differ | |||
diff --git a/lib/tests/test_generic_output.c b/lib/tests/test_generic_output.c new file mode 100644 index 00000000..e67aefc9 --- /dev/null +++ b/lib/tests/test_generic_output.c | |||
@@ -0,0 +1,315 @@ | |||
1 | #include "../lib/output.h" | ||
2 | #include "../../tap/tap.h" | ||
3 | #include "./states.h" | ||
4 | |||
5 | #include <string.h> | ||
6 | |||
7 | void test_one_subcheck(void); | ||
8 | void test_two_subchecks(void); | ||
9 | |||
10 | void test_perfdata_formatting(void); | ||
11 | void test_perfdata_formatting2(void); | ||
12 | |||
13 | void test_deep_check_hierarchy(void); | ||
14 | void test_deep_check_hierarchy2(void); | ||
15 | |||
16 | void test_default_states1(void); | ||
17 | void test_default_states2(void); | ||
18 | |||
19 | int 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 | |||
49 | void 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 | |||
74 | void 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 | |||
94 | void 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 | |||
107 | void test_two_subchecks(void) { | ||
108 | mp_subcheck sc1 = mp_subcheck_init(); | ||
109 | |||
110 | sc1.output = "foobar"; | ||
111 | sc1 = mp_set_subcheck_state(sc1, STATE_WARNING); | ||
112 | |||
113 | ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state directly after setting it"); | ||
114 | |||
115 | mp_perfdata pd1 = perfdata_init(); | ||
116 | |||
117 | pd1 = mp_set_pd_value(pd1, 23); | ||
118 | |||
119 | pd1.uom = "s"; | ||
120 | pd1.label = "foo"; | ||
121 | |||
122 | mp_add_perfdata_to_subcheck(&sc1, pd1); | ||
123 | |||
124 | mp_subcheck sc2 = mp_subcheck_init(); | ||
125 | sc2.output = "baz"; | ||
126 | sc2 = mp_set_subcheck_state(sc2, STATE_OK); | ||
127 | |||
128 | ok(mp_compute_subcheck_state(sc2) == STATE_OK, "Test subcheck 2 state after setting it"); | ||
129 | |||
130 | mp_add_subcheck_to_subcheck(&sc1, sc2); | ||
131 | |||
132 | ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state after adding a subcheck"); | ||
133 | |||
134 | mp_check check = mp_check_init(); | ||
135 | mp_add_subcheck_to_check(&check, sc1); | ||
136 | |||
137 | ok(mp_compute_check_state(check) == STATE_WARNING, "Test main check result"); | ||
138 | |||
139 | char *output = mp_fmt_output(check); | ||
140 | |||
141 | // diag("Formatted output. Length: %u", strlen(output)); | ||
142 | // diag(output); | ||
143 | |||
144 | ok(output != NULL, "Output should not be NULL"); | ||
145 | |||
146 | char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n" | ||
147 | "\t\\_[WARNING] - foobar\n" | ||
148 | "\t\t\\_[OK] - baz\n" | ||
149 | "|foo=23s;;; \n"; | ||
150 | |||
151 | // diag("Expected output. Length: %u", strlen(expected)); | ||
152 | // diag(expected); | ||
153 | |||
154 | ok(strcmp(output, expected) == 0, "Output is as expected"); | ||
155 | } | ||
156 | |||
157 | void test_deep_check_hierarchy(void) { | ||
158 | // level 4 | ||
159 | mp_subcheck sc4 = mp_subcheck_init(); | ||
160 | sc4.output = "level4"; | ||
161 | sc4 = mp_set_subcheck_state(sc4, STATE_OK); | ||
162 | |||
163 | // level 3 | ||
164 | mp_subcheck sc3 = mp_subcheck_init(); | ||
165 | sc3.output = "level3"; | ||
166 | sc3 = mp_set_subcheck_state(sc3, STATE_OK); | ||
167 | |||
168 | // level 2 | ||
169 | mp_subcheck sc2 = mp_subcheck_init(); | ||
170 | sc2.output = "baz"; | ||
171 | sc2 = mp_set_subcheck_state(sc2, STATE_OK); | ||
172 | |||
173 | // level 1 | ||
174 | mp_subcheck sc1 = mp_subcheck_init(); | ||
175 | |||
176 | sc1.output = "foobar"; | ||
177 | sc1 = mp_set_subcheck_state(sc1, STATE_WARNING); | ||
178 | |||
179 | mp_perfdata pd1 = perfdata_init(); | ||
180 | |||
181 | pd1.uom = "s"; | ||
182 | pd1.label = "foo"; | ||
183 | pd1 = mp_set_pd_value(pd1, 23); | ||
184 | |||
185 | mp_add_perfdata_to_subcheck(&sc1, pd1); | ||
186 | |||
187 | // main check | ||
188 | mp_check check = mp_check_init(); | ||
189 | |||
190 | mp_add_subcheck_to_subcheck(&sc3, sc4); | ||
191 | mp_add_subcheck_to_subcheck(&sc2, sc3); | ||
192 | mp_add_subcheck_to_subcheck(&sc1, sc2); | ||
193 | mp_add_subcheck_to_check(&check, sc1); | ||
194 | |||
195 | char *output = mp_fmt_output(check); | ||
196 | |||
197 | size_t output_length = strlen(output); | ||
198 | |||
199 | // diag("Formatted output of length %i", output_length); | ||
200 | // diag(output); | ||
201 | |||
202 | ok(output != NULL, "Output should not be NULL"); | ||
203 | |||
204 | char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n" | ||
205 | "\t\\_[WARNING] - foobar\n" | ||
206 | "\t\t\\_[OK] - baz\n" | ||
207 | "\t\t\t\\_[OK] - level3\n" | ||
208 | "\t\t\t\t\\_[OK] - level4\n" | ||
209 | "|foo=23s;;; \n"; | ||
210 | |||
211 | size_t expected_length = strlen(expected); | ||
212 | |||
213 | // diag("Expected output of length: %i", expected_length); | ||
214 | // diag(expected); | ||
215 | |||
216 | ok(output_length == expected_length, "Outputs are of equal length"); | ||
217 | ok(strcmp(output, expected) == 0, "Output is as expected"); | ||
218 | } | ||
219 | |||
220 | void test_deep_check_hierarchy2(void) { | ||
221 | // level 1 | ||
222 | mp_subcheck sc1 = mp_subcheck_init(); | ||
223 | |||
224 | sc1.output = "foobar"; | ||
225 | sc1 = mp_set_subcheck_state(sc1, STATE_WARNING); | ||
226 | |||
227 | mp_perfdata pd1 = perfdata_init(); | ||
228 | pd1.uom = "s"; | ||
229 | pd1.label = "foo"; | ||
230 | pd1 = mp_set_pd_value(pd1, 23); | ||
231 | |||
232 | mp_add_perfdata_to_subcheck(&sc1, pd1); | ||
233 | |||
234 | // level 2 | ||
235 | mp_subcheck sc2 = mp_subcheck_init(); | ||
236 | sc2.output = "baz"; | ||
237 | sc2 = mp_set_subcheck_state(sc2, STATE_OK); | ||
238 | |||
239 | mp_perfdata pd2 = perfdata_init(); | ||
240 | pd2.uom = "B"; | ||
241 | pd2.label = "baz"; | ||
242 | pd2 = mp_set_pd_value(pd2, 1024); | ||
243 | mp_add_perfdata_to_subcheck(&sc2, pd2); | ||
244 | |||
245 | // level 3 | ||
246 | mp_subcheck sc3 = mp_subcheck_init(); | ||
247 | sc3.output = "level3"; | ||
248 | sc3 = mp_set_subcheck_state(sc3, STATE_OK); | ||
249 | |||
250 | mp_perfdata pd3 = perfdata_init(); | ||
251 | pd3.label = "floatMe"; | ||
252 | pd3 = mp_set_pd_value(pd3, 1024.1024); | ||
253 | mp_add_perfdata_to_subcheck(&sc3, pd3); | ||
254 | |||
255 | // level 4 | ||
256 | mp_subcheck sc4 = mp_subcheck_init(); | ||
257 | sc4.output = "level4"; | ||
258 | sc4 = mp_set_subcheck_state(sc4, STATE_OK); | ||
259 | |||
260 | mp_check check = mp_check_init(); | ||
261 | |||
262 | mp_add_subcheck_to_subcheck(&sc3, sc4); | ||
263 | mp_add_subcheck_to_subcheck(&sc2, sc3); | ||
264 | mp_add_subcheck_to_subcheck(&sc1, sc2); | ||
265 | mp_add_subcheck_to_check(&check, sc1); | ||
266 | |||
267 | char *output = mp_fmt_output(check); | ||
268 | |||
269 | // diag("Formatted output of length: %i", strlen(output)); | ||
270 | // diag(output); | ||
271 | |||
272 | ok(output != NULL, "Output should not be NULL"); | ||
273 | |||
274 | char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n" | ||
275 | "\t\\_[WARNING] - foobar\n" | ||
276 | "\t\t\\_[OK] - baz\n" | ||
277 | "\t\t\t\\_[OK] - level3\n" | ||
278 | "\t\t\t\t\\_[OK] - level4\n" | ||
279 | "|foo=23s;;; baz=1024B;;; floatMe=1024.102400;;; \n"; | ||
280 | |||
281 | // diag("Expected output of length: %i", strlen(expected)); | ||
282 | // diag(expected); | ||
283 | |||
284 | ok(strcmp(output, expected) == 0, "Output is as expected"); | ||
285 | } | ||
286 | |||
287 | void test_default_states1(void) { | ||
288 | mp_subcheck sc = mp_subcheck_init(); | ||
289 | |||
290 | mp_state_enum state1 = mp_compute_subcheck_state(sc); | ||
291 | ok(state1 == STATE_UNKNOWN, "Default default state is Unknown"); | ||
292 | |||
293 | sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL); | ||
294 | |||
295 | mp_state_enum state2 = mp_compute_subcheck_state(sc); | ||
296 | ok(state2 == STATE_CRITICAL, "Default state is Critical"); | ||
297 | |||
298 | sc = mp_set_subcheck_state(sc, STATE_OK); | ||
299 | |||
300 | mp_state_enum state3 = mp_compute_subcheck_state(sc); | ||
301 | ok(state3 == STATE_OK, "Default state is Critical"); | ||
302 | } | ||
303 | |||
304 | void test_default_states2(void) { | ||
305 | mp_check check = mp_check_init(); | ||
306 | |||
307 | mp_subcheck sc = mp_subcheck_init(); | ||
308 | sc.output = "placeholder"; | ||
309 | sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL); | ||
310 | |||
311 | mp_add_subcheck_to_check(&check, sc); | ||
312 | |||
313 | mp_state_enum result_state = mp_compute_check_state(check); | ||
314 | ok(result_state == STATE_CRITICAL, "Derived state is the proper default state"); | ||
315 | } | ||
diff --git a/lib/tests/test_generic_output.t b/lib/tests/test_generic_output.t new file mode 100644 index 00000000..48c2ddf4 --- /dev/null +++ b/lib/tests/test_generic_output.t | |||
@@ -0,0 +1,6 @@ | |||
1 | #!/usr/bin/perl | ||
2 | use Test::More; | ||
3 | if (! -e "./test_generic_output") { | ||
4 | plan skip_all => "./test_generic_output not compiled - please enable libtap library to test"; | ||
5 | } | ||
6 | exec "./test_generic_output"; | ||
diff --git a/lib/tests/test_ini1.c b/lib/tests/test_ini1.c index 6843bac2..246c1250 100644 --- a/lib/tests/test_ini1.c +++ b/lib/tests/test_ini1.c | |||
@@ -1,20 +1,20 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | * | 16 | * |
17 | *****************************************************************************/ | 17 | *****************************************************************************/ |
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "utils_base.h" | 20 | #include "utils_base.h" |
@@ -29,81 +29,93 @@ void my_free(char *string) { | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | char* | 32 | char *list2str(np_arg_list *optlst) { |
33 | list2str(np_arg_list *optlst) | 33 | char *optstr = NULL; |
34 | { | ||
35 | char *optstr=NULL; | ||
36 | np_arg_list *optltmp; | 34 | np_arg_list *optltmp; |
37 | 35 | ||
38 | /* Put everything as a space-separated string */ | 36 | /* Put everything as a space-separated string */ |
39 | asprintf(&optstr, ""); | 37 | asprintf(&optstr, ""); |
40 | while (optlst) { | 38 | while (optlst) { |
41 | asprintf(&optstr, "%s%s ", optstr, optlst->arg); | 39 | asprintf(&optstr, "%s%s ", optstr, optlst->arg); |
42 | optltmp=optlst; | 40 | optltmp = optlst; |
43 | optlst=optlst->next; | 41 | optlst = optlst->next; |
44 | free(optltmp); | 42 | free(optltmp); |
45 | } | 43 | } |
46 | /* Strip last whitespace */ | 44 | /* Strip last whitespace */ |
47 | if (strlen(optstr)>1) optstr[strlen(optstr)-1]='\0'; | 45 | if (strlen(optstr) > 1) |
46 | optstr[strlen(optstr) - 1] = '\0'; | ||
48 | 47 | ||
49 | return optstr; | 48 | return optstr; |
50 | } | 49 | } |
51 | 50 | ||
52 | int | 51 | int main(int argc, char **argv) { |
53 | main (int argc, char **argv) | 52 | char *optstr = NULL; |
54 | { | ||
55 | char *optstr=NULL; | ||
56 | 53 | ||
57 | plan_tests(12); | 54 | plan_tests(12); |
58 | 55 | ||
59 | optstr=list2str(np_get_defaults("section@./config-tiny.ini", "check_disk")); | 56 | optstr = list2str(np_get_defaults("section@./config-tiny.ini", "check_disk")); |
60 | ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "config-tiny.ini's section as expected"); | 57 | ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "config-tiny.ini's section as expected"); |
61 | my_free(optstr); | 58 | my_free(optstr); |
62 | 59 | ||
63 | optstr=list2str(np_get_defaults("@./config-tiny.ini", "section")); | 60 | optstr = list2str(np_get_defaults("@./config-tiny.ini", "section")); |
64 | ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "Used default section name, without specific"); | 61 | ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "Used default section name, without specific"); |
65 | my_free(optstr); | 62 | my_free(optstr); |
66 | 63 | ||
67 | optstr=list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); | 64 | optstr = list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); |
68 | ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); | 65 | ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); |
69 | my_free(optstr); | 66 | my_free(optstr); |
70 | 67 | ||
71 | optstr=list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk")); | 68 | optstr = list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk")); |
72 | ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name"); | 69 | ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name"); |
73 | my_free(optstr); | 70 | my_free(optstr); |
74 | 71 | ||
75 | optstr=list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk")); | 72 | optstr = list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk")); |
76 | ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's section2 with whitespace before section name"); | 73 | ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section2 with whitespace before section name"); |
77 | my_free(optstr); | 74 | my_free(optstr); |
78 | 75 | ||
79 | optstr=list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk")); | 76 | optstr = list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk")); |
80 | ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's section3 with whitespace after section name"); | 77 | ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section3 with whitespace after section name"); |
81 | my_free(optstr); | 78 | my_free(optstr); |
82 | 79 | ||
83 | optstr=list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); | 80 | optstr = list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); |
84 | ok( !strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected"); | 81 | ok(!strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected"); |
85 | my_free(optstr); | 82 | my_free(optstr); |
86 | 83 | ||
87 | optstr=list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk")); | 84 | optstr = list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk")); |
88 | ok( !strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected"); | 85 | ok(!strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected"); |
89 | my_free(optstr); | 86 | my_free(optstr); |
90 | 87 | ||
91 | optstr=list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk")); | 88 | optstr = list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk")); |
92 | ok( !strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments"); | 89 | ok(!strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments"); |
93 | my_free(optstr); | 90 | my_free(optstr); |
94 | 91 | ||
95 | optstr=list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk")); | 92 | optstr = list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk")); |
96 | ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected"); | 93 | ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected"); |
97 | my_free(optstr); | 94 | my_free(optstr); |
98 | 95 | ||
99 | optstr=list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk")); | 96 | optstr = list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk")); |
100 | ok( !strcmp(optstr, "--foo=bar --bar=foo"), "plugin.ini's section_twice defined twice in the file"); | 97 | ok(!strcmp(optstr, "--foo=bar --bar=foo"), "plugin.ini's section_twice defined twice in the file"); |
101 | my_free(optstr); | 98 | my_free(optstr); |
102 | 99 | ||
103 | optstr=list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp")); | 100 | optstr = list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp")); |
104 | ok( !strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --jail"), "Long options"); | 101 | ok(!strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar " |
102 | "BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
103 | "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " | ||
104 | "yadda yadda Foo bar BAZ yadda yadda yadda Foo " | ||
105 | "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
106 | "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " | ||
107 | "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --expect=Foo bar BAZ yadda yadda " | ||
108 | "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " | ||
109 | "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo " | ||
110 | "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
111 | "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " | ||
112 | "yadda yadda Foo bar BAZ yadda yadda yadda Foo " | ||
113 | "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
114 | "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " | ||
115 | "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo " | ||
116 | "bar BAZ yadda yadda yadda --jail"), | ||
117 | "Long options"); | ||
105 | my_free(optstr); | 118 | my_free(optstr); |
106 | 119 | ||
107 | return exit_status(); | 120 | return exit_status(); |
108 | } | 121 | } |
109 | |||
diff --git a/lib/tests/test_ini3.c b/lib/tests/test_ini3.c index 8a2a0414..2186e4bb 100644 --- a/lib/tests/test_ini3.c +++ b/lib/tests/test_ini3.c | |||
@@ -1,26 +1,24 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | * | 16 | * |
17 | *****************************************************************************/ | 17 | *****************************************************************************/ |
18 | 18 | ||
19 | #include "parse_ini.h" | 19 | #include "parse_ini.h" |
20 | 20 | ||
21 | int | 21 | int main(int argc, char **argv) { |
22 | main (int argc, char **argv) | ||
23 | { | ||
24 | 22 | ||
25 | /* | 23 | /* |
26 | * This is for testing arguments expected to die. | 24 | * This is for testing arguments expected to die. |
@@ -30,4 +28,3 @@ main (int argc, char **argv) | |||
30 | 28 | ||
31 | return 0; | 29 | return 0; |
32 | } | 30 | } |
33 | |||
diff --git a/lib/tests/test_opts1.c b/lib/tests/test_opts1.c index 077c5b63..984183d3 100644 --- a/lib/tests/test_opts1.c +++ b/lib/tests/test_opts1.c | |||
@@ -1,19 +1,19 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | *****************************************************************************/ | 16 | *****************************************************************************/ |
17 | 17 | ||
18 | #include "common.h" | 18 | #include "common.h" |
19 | #include "utils_base.h" | 19 | #include "utils_base.h" |
@@ -40,23 +40,24 @@ void my_free(int *argc, char **newargv, char **argv) { | |||
40 | #else | 40 | #else |
41 | void my_free(int *argc, char **newargv, char **argv) { | 41 | void my_free(int *argc, char **newargv, char **argv) { |
42 | /* Free stuff (and print while we're at it) */ | 42 | /* Free stuff (and print while we're at it) */ |
43 | int i, freeflag=1; | 43 | int i, freeflag = 1; |
44 | printf (" Arg(%i): ", *argc+1); | 44 | printf(" Arg(%i): ", *argc + 1); |
45 | printf ("'%s' ", newargv[0]); | 45 | printf("'%s' ", newargv[0]); |
46 | for (i=1; i<*argc; i++) { | 46 | for (i = 1; i < *argc; i++) { |
47 | printf ("'%s' ", newargv[i]); | 47 | printf("'%s' ", newargv[i]); |
48 | /* Stop freeing when we get to the start of the original array */ | 48 | /* Stop freeing when we get to the start of the original array */ |
49 | if (freeflag) { | 49 | if (freeflag) { |
50 | if (newargv[i] == argv[1]) | 50 | if (newargv[i] == argv[1]) |
51 | freeflag=0; | 51 | freeflag = 0; |
52 | else | 52 | else |
53 | free(newargv[i]); | 53 | free(newargv[i]); |
54 | } | 54 | } |
55 | } | 55 | } |
56 | printf ("\n"); | 56 | printf("\n"); |
57 | /* Free only if it's a different array */ | 57 | /* Free only if it's a different array */ |
58 | if (newargv != argv) free(newargv); | 58 | if (newargv != argv) |
59 | *argc=0; | 59 | free(newargv); |
60 | *argc = 0; | ||
60 | } | 61 | } |
61 | #endif | 62 | #endif |
62 | 63 | ||
@@ -67,9 +68,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) { | |||
67 | printf(" Argument count doesn't match!\n"); | 68 | printf(" Argument count doesn't match!\n"); |
68 | return 0; | 69 | return 0; |
69 | } | 70 | } |
70 | for (i=0; i<=i1; i++) { | 71 | for (i = 0; i <= i1; i++) { |
71 | if (a1[i]==NULL && a2[i]==NULL) continue; | 72 | if (a1[i] == NULL && a2[i] == NULL) |
72 | if (a1[i]==NULL || a2[i]==NULL) { | 73 | continue; |
74 | if (a1[i] == NULL || a2[i] == NULL) { | ||
73 | printf(" Argument # %i null in one array!\n", i); | 75 | printf(" Argument # %i null in one array!\n", i); |
74 | return 0; | 76 | return 0; |
75 | } | 77 | } |
@@ -81,59 +83,58 @@ int array_diff(int i1, char **a1, int i2, char **a2) { | |||
81 | return 1; | 83 | return 1; |
82 | } | 84 | } |
83 | 85 | ||
84 | int | 86 | int main(int argc, char **argv) { |
85 | main (int argc, char **argv) | 87 | char **argv_new = NULL; |
86 | { | ||
87 | char **argv_new=NULL; | ||
88 | int i, argc_test; | 88 | int i, argc_test; |
89 | 89 | ||
90 | plan_tests(5); | 90 | plan_tests(5); |
91 | 91 | ||
92 | { | 92 | { |
93 | char *argv_test[] = {"prog_name", (char *) NULL}; | 93 | char *argv_test[] = {"prog_name", (char *)NULL}; |
94 | argc_test=1; | 94 | argc_test = 1; |
95 | char *argv_known[] = {"prog_name", (char *) NULL}; | 95 | char *argv_known[] = {"prog_name", (char *)NULL}; |
96 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 96 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
97 | ok(array_diff(argc_test, argv_new, 1, argv_known), "No opts, returns correct argv/argc"); | 97 | ok(array_diff(argc_test, argv_new, 1, argv_known), "No opts, returns correct argv/argc"); |
98 | my_free(&argc_test, argv_new, argv_test); | 98 | my_free(&argc_test, argv_new, argv_test); |
99 | } | 99 | } |
100 | 100 | ||
101 | { | 101 | { |
102 | char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; | 102 | char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL}; |
103 | argc_test=5; | 103 | argc_test = 5; |
104 | char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; | 104 | char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL}; |
105 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 105 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
106 | ok(array_diff(argc_test, argv_new, 5, argv_known), "No extra opts, verbatim copy of argv"); | 106 | ok(array_diff(argc_test, argv_new, 5, argv_known), "No extra opts, verbatim copy of argv"); |
107 | my_free(&argc_test, argv_new, argv_test); | 107 | my_free(&argc_test, argv_new, argv_test); |
108 | } | 108 | } |
109 | 109 | ||
110 | { | 110 | { |
111 | char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *) NULL}; | 111 | char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *)NULL}; |
112 | argc_test=2; | 112 | argc_test = 2; |
113 | char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *) NULL}; | 113 | char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *)NULL}; |
114 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 114 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
115 | ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section"); | 115 | ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section"); |
116 | my_free(&argc_test, argv_new, argv_test); | 116 | my_free(&argc_test, argv_new, argv_test); |
117 | } | 117 | } |
118 | 118 | ||
119 | { | 119 | { |
120 | char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *) NULL}; | 120 | char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *)NULL}; |
121 | argc_test=4; | 121 | argc_test = 4; |
122 | char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *) NULL}; | 122 | char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *)NULL}; |
123 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 123 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
124 | ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice"); | 124 | ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice"); |
125 | my_free(&argc_test, argv_new, argv_test); | 125 | my_free(&argc_test, argv_new, argv_test); |
126 | } | 126 | } |
127 | 127 | ||
128 | { | 128 | { |
129 | char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini", "--arg2", (char *) NULL}; | 129 | char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini", |
130 | argc_test=6; | 130 | "--arg2", (char *)NULL}; |
131 | char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two", "--arg1=val1", "--arg2", (char *) NULL}; | 131 | argc_test = 6; |
132 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 132 | char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two", |
133 | "--arg1=val1", "--arg2", (char *)NULL}; | ||
134 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); | ||
133 | ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections"); | 135 | ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections"); |
134 | my_free(&argc_test, argv_new, argv_test); | 136 | my_free(&argc_test, argv_new, argv_test); |
135 | } | 137 | } |
136 | 138 | ||
137 | return exit_status(); | 139 | return exit_status(); |
138 | } | 140 | } |
139 | |||
diff --git a/lib/tests/test_opts2.c b/lib/tests/test_opts2.c index 780220ee..23496617 100644 --- a/lib/tests/test_opts2.c +++ b/lib/tests/test_opts2.c | |||
@@ -1,19 +1,19 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | *****************************************************************************/ | 16 | *****************************************************************************/ |
17 | 17 | ||
18 | #include "common.h" | 18 | #include "common.h" |
19 | #include "utils_base.h" | 19 | #include "utils_base.h" |
@@ -23,23 +23,24 @@ | |||
23 | 23 | ||
24 | void my_free(int *argc, char **newargv, char **argv) { | 24 | void my_free(int *argc, char **newargv, char **argv) { |
25 | /* Free stuff (and print while we're at it) */ | 25 | /* Free stuff (and print while we're at it) */ |
26 | int i, freeflag=1; | 26 | int i, freeflag = 1; |
27 | printf (" Arg(%i): ", *argc+1); | 27 | printf(" Arg(%i): ", *argc + 1); |
28 | printf ("'%s' ", newargv[0]); | 28 | printf("'%s' ", newargv[0]); |
29 | for (i=1; i<*argc; i++) { | 29 | for (i = 1; i < *argc; i++) { |
30 | printf ("'%s' ", newargv[i]); | 30 | printf("'%s' ", newargv[i]); |
31 | /* Stop freeing when we get to the start of the original array */ | 31 | /* Stop freeing when we get to the start of the original array */ |
32 | if (freeflag) { | 32 | if (freeflag) { |
33 | if (newargv[i] == argv[1]) | 33 | if (newargv[i] == argv[1]) |
34 | freeflag=0; | 34 | freeflag = 0; |
35 | else | 35 | else |
36 | free(newargv[i]); | 36 | free(newargv[i]); |
37 | } | 37 | } |
38 | } | 38 | } |
39 | printf ("\n"); | 39 | printf("\n"); |
40 | /* Free only if it's a different array */ | 40 | /* Free only if it's a different array */ |
41 | if (newargv != argv) free(newargv); | 41 | if (newargv != argv) |
42 | *argc=0; | 42 | free(newargv); |
43 | *argc = 0; | ||
43 | } | 44 | } |
44 | 45 | ||
45 | int array_diff(int i1, char **a1, int i2, char **a2) { | 46 | int array_diff(int i1, char **a1, int i2, char **a2) { |
@@ -49,9 +50,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) { | |||
49 | printf(" Argument count doesn't match!\n"); | 50 | printf(" Argument count doesn't match!\n"); |
50 | return 0; | 51 | return 0; |
51 | } | 52 | } |
52 | for (i=0; i<=i1; i++) { | 53 | for (i = 0; i <= i1; i++) { |
53 | if (a1[i]==NULL && a2[i]==NULL) continue; | 54 | if (a1[i] == NULL && a2[i] == NULL) |
54 | if (a1[i]==NULL || a2[i]==NULL) { | 55 | continue; |
56 | if (a1[i] == NULL || a2[i] == NULL) { | ||
55 | printf(" Argument # %i null in one array!\n", i); | 57 | printf(" Argument # %i null in one array!\n", i); |
56 | return 0; | 58 | return 0; |
57 | } | 59 | } |
@@ -63,59 +65,77 @@ int array_diff(int i1, char **a1, int i2, char **a2) { | |||
63 | return 1; | 65 | return 1; |
64 | } | 66 | } |
65 | 67 | ||
66 | int | 68 | int main(int argc, char **argv) { |
67 | main (int argc, char **argv) | 69 | char **argv_new = NULL; |
68 | { | ||
69 | char **argv_new=NULL; | ||
70 | int i, argc_test; | 70 | int i, argc_test; |
71 | 71 | ||
72 | plan_tests(5); | 72 | plan_tests(5); |
73 | 73 | ||
74 | { | 74 | { |
75 | char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *) NULL}; | 75 | char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *)NULL}; |
76 | argc_test=5; | 76 | argc_test = 5; |
77 | char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *) NULL}; | 77 | char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *)NULL}; |
78 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 78 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
79 | ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1"); | 79 | ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1"); |
80 | my_free(&argc_test, argv_new, argv_test); | 80 | my_free(&argc_test, argv_new, argv_test); |
81 | } | 81 | } |
82 | 82 | ||
83 | { | 83 | { |
84 | char *argv_test[] = {"prog_name", "--extra-opts", (char *) NULL}; | 84 | char *argv_test[] = {"prog_name", "--extra-opts", (char *)NULL}; |
85 | argc_test=2; | 85 | argc_test = 2; |
86 | char *argv_known[] = {"prog_name", "--foo=bar", (char *) NULL}; | 86 | char *argv_known[] = {"prog_name", "--foo=bar", (char *)NULL}; |
87 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 87 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
88 | ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2"); | 88 | ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2"); |
89 | my_free(&argc_test, argv_new, argv_test); | 89 | my_free(&argc_test, argv_new, argv_test); |
90 | } | 90 | } |
91 | 91 | ||
92 | { | 92 | { |
93 | char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *) NULL}; | 93 | char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *)NULL}; |
94 | argc_test=5; | 94 | argc_test = 5; |
95 | char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *) NULL}; | 95 | char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *)NULL}; |
96 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 96 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
97 | ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3"); | 97 | ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3"); |
98 | my_free(&argc_test, argv_new, argv_test); | 98 | my_free(&argc_test, argv_new, argv_test); |
99 | } | 99 | } |
100 | 100 | ||
101 | { | 101 | { |
102 | char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *) NULL}; | 102 | char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *)NULL}; |
103 | argc_test=5; | 103 | argc_test = 5; |
104 | char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *) NULL}; | 104 | char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *)NULL}; |
105 | argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); | 105 | argv_new = np_extra_opts(&argc_test, argv_test, "check_disk"); |
106 | ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4"); | 106 | ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4"); |
107 | my_free(&argc_test, argv_new, argv_test); | 107 | my_free(&argc_test, argv_new, argv_test); |
108 | } | 108 | } |
109 | 109 | ||
110 | { | 110 | { |
111 | char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *) NULL}; | 111 | char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *)NULL}; |
112 | argc_test=3; | 112 | argc_test = 3; |
113 | char *argv_known[] = {"check_tcp", "--timeout=10", "--escape", "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", "--jail", (char *) NULL}; | 113 | char *argv_known[] = { |
114 | argv_new=np_extra_opts(&argc_test, argv_test, "check_tcp"); | 114 | "check_tcp", |
115 | "--timeout=10", | ||
116 | "--escape", | ||
117 | "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
118 | "yadda Foo bar BAZ yadda " | ||
119 | "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
120 | "yadda Foo bar BAZ " | ||
121 | "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " | ||
122 | "yadda yadda Foo bar " | ||
123 | "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", | ||
124 | "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
125 | "yadda Foo bar BAZ yadda " | ||
126 | "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda " | ||
127 | "yadda Foo bar BAZ " | ||
128 | "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda " | ||
129 | "yadda yadda Foo bar " | ||
130 | "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ " | ||
131 | "yadda yadda yadda Foo " | ||
132 | "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda", | ||
133 | "--jail", | ||
134 | (char *)NULL}; | ||
135 | argv_new = np_extra_opts(&argc_test, argv_test, "check_tcp"); | ||
115 | ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test"); | 136 | ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test"); |
116 | my_free(&argc_test, argv_new, argv_test); | 137 | my_free(&argc_test, argv_new, argv_test); |
117 | } | 138 | } |
118 | 139 | ||
119 | return exit_status(); | 140 | return exit_status(); |
120 | } | 141 | } |
121 | |||
diff --git a/lib/tests/test_opts3.c b/lib/tests/test_opts3.c index b64270da..cecea437 100644 --- a/lib/tests/test_opts3.c +++ b/lib/tests/test_opts3.c | |||
@@ -1,31 +1,28 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | *****************************************************************************/ | 16 | *****************************************************************************/ |
17 | 17 | ||
18 | #include "extra_opts.h" | 18 | #include "extra_opts.h" |
19 | 19 | ||
20 | int | 20 | int main(int argc, char **argv) { |
21 | main (int argc, char **argv) | ||
22 | { | ||
23 | 21 | ||
24 | /* | 22 | /* |
25 | * This is for testing arguments expected to die. | 23 | * This is for testing arguments expected to die. |
26 | */ | 24 | */ |
27 | argv=np_extra_opts(&argc, argv, argv[0]); | 25 | argv = np_extra_opts(&argc, argv, argv[0]); |
28 | 26 | ||
29 | return 0; | 27 | return 0; |
30 | } | 28 | } |
31 | |||
diff --git a/lib/tests/test_tcp.c b/lib/tests/test_tcp.c index 1954b0fb..1b3003e9 100644 --- a/lib/tests/test_tcp.c +++ b/lib/tests/test_tcp.c | |||
@@ -1,34 +1,32 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | * | 16 | * |
17 | *****************************************************************************/ | 17 | *****************************************************************************/ |
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "utils_tcp.h" | 20 | #include "utils_tcp.h" |
21 | #include "tap.h" | 21 | #include "tap.h" |
22 | 22 | ||
23 | int | 23 | int main(void) { |
24 | main(void) | ||
25 | { | ||
26 | char **server_expect; | 24 | char **server_expect; |
27 | int server_expect_count = 3; | 25 | int server_expect_count = 3; |
28 | 26 | ||
29 | plan_tests(9); | 27 | plan_tests(9); |
30 | 28 | ||
31 | server_expect = malloc(sizeof(char*) * server_expect_count); | 29 | server_expect = malloc(sizeof(char *) * server_expect_count); |
32 | 30 | ||
33 | server_expect[0] = strdup("AA"); | 31 | server_expect[0] = strdup("AA"); |
34 | server_expect[1] = strdup("bb"); | 32 | server_expect[1] = strdup("bb"); |
@@ -42,17 +40,13 @@ main(void) | |||
42 | "Test matching any string at the beginning (substring match)"); | 40 | "Test matching any string at the beginning (substring match)"); |
43 | ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, | 41 | ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, |
44 | "Test with strings not matching at the beginning"); | 42 | "Test with strings not matching at the beginning"); |
45 | ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, | 43 | ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, "Test matching any string"); |
46 | "Test matching any string"); | 44 | ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY, "Test not matching any string"); |
47 | ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY, | ||
48 | "Test not matching any string"); | ||
49 | ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_SUCCESS, | 45 | ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_SUCCESS, |
50 | "Test matching all strings"); | 46 | "Test matching all strings"); |
51 | ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, | 47 | ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, "Test not matching all strings"); |
52 | "Test not matching all strings"); | ||
53 | ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, | 48 | ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, |
54 | "Test not matching any string (testing all)"); | 49 | "Test not matching any string (testing all)"); |
55 | 50 | ||
56 | |||
57 | return exit_status(); | 51 | return exit_status(); |
58 | } | 52 | } |
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c index 01afacdc..c3150f00 100644 --- a/lib/tests/test_utils.c +++ b/lib/tests/test_utils.c | |||
@@ -1,20 +1,20 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * This program is free software: you can redistribute it and/or modify | 3 | * This program is free software: you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by | 4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation, either version 3 of the License, or | 5 | * the Free Software Foundation, either version 3 of the License, or |
6 | * (at your option) any later version. | 6 | * (at your option) any later version. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it will be useful, | 8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | * | 15 | * |
16 | * | 16 | * |
17 | *****************************************************************************/ | 17 | *****************************************************************************/ |
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "utils_base.h" | 20 | #include "utils_base.h" |
@@ -27,331 +27,323 @@ | |||
27 | 27 | ||
28 | #include "utils_base.c" | 28 | #include "utils_base.c" |
29 | 29 | ||
30 | int | 30 | int main(int argc, char **argv) { |
31 | main (int argc, char **argv) | ||
32 | { | ||
33 | char state_path[1024]; | 31 | char state_path[1024]; |
34 | range *range; | 32 | range *range; |
35 | double temp; | 33 | double temp; |
36 | thresholds *thresholds = NULL; | 34 | thresholds *thresholds = NULL; |
37 | int i, rc; | 35 | int i, rc; |
38 | char *temp_string; | 36 | char *temp_string; |
39 | state_key *temp_state_key = NULL; | 37 | state_key *temp_state_key = NULL; |
40 | state_data *temp_state_data; | 38 | state_data *temp_state_data; |
41 | time_t current_time; | 39 | time_t current_time; |
42 | 40 | ||
43 | plan_tests(185); | 41 | plan_tests(185); |
44 | 42 | ||
45 | ok( this_monitoring_plugin==NULL, "monitoring_plugin not initialised"); | 43 | ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised"); |
46 | 44 | ||
47 | np_init( "check_test", argc, argv ); | 45 | np_init("check_test", argc, argv); |
48 | 46 | ||
49 | ok( this_monitoring_plugin!=NULL, "monitoring_plugin now initialised"); | 47 | ok(this_monitoring_plugin != NULL, "monitoring_plugin now initialised"); |
50 | ok( !strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised" ); | 48 | ok(!strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised"); |
51 | 49 | ||
52 | ok( this_monitoring_plugin->argc==argc, "Argc set" ); | 50 | ok(this_monitoring_plugin->argc == argc, "Argc set"); |
53 | ok( this_monitoring_plugin->argv==argv, "Argv set" ); | 51 | ok(this_monitoring_plugin->argv == argv, "Argv set"); |
54 | 52 | ||
55 | np_set_args(0,0); | 53 | np_set_args(0, 0); |
56 | 54 | ||
57 | ok( this_monitoring_plugin->argc==0, "argc changed" ); | 55 | ok(this_monitoring_plugin->argc == 0, "argc changed"); |
58 | ok( this_monitoring_plugin->argv==0, "argv changed" ); | 56 | ok(this_monitoring_plugin->argv == 0, "argv changed"); |
59 | 57 | ||
60 | np_set_args(argc, argv); | 58 | np_set_args(argc, argv); |
61 | 59 | ||
62 | range = parse_range_string("6"); | 60 | range = parse_range_string("6"); |
63 | ok( range != NULL, "'6' is valid range"); | 61 | ok(range != NULL, "'6' is valid range"); |
64 | ok( range->start == 0, "Start correct"); | 62 | ok(range->start == 0, "Start correct"); |
65 | ok( range->start_infinity == false, "Not using negative infinity"); | 63 | ok(range->start_infinity == false, "Not using negative infinity"); |
66 | ok( range->end == 6, "End correct"); | 64 | ok(range->end == 6, "End correct"); |
67 | ok( range->end_infinity == false, "Not using infinity"); | 65 | ok(range->end_infinity == false, "Not using infinity"); |
68 | free(range); | 66 | free(range); |
69 | 67 | ||
70 | range = parse_range_string("1:12%%"); | 68 | range = parse_range_string("1:12%%"); |
71 | ok( range != NULL, "'1:12%%' is valid - percentages are ignored"); | 69 | ok(range != NULL, "'1:12%%' is valid - percentages are ignored"); |
72 | ok( range->start == 1, "Start correct"); | 70 | ok(range->start == 1, "Start correct"); |
73 | ok( range->start_infinity == false, "Not using negative infinity"); | 71 | ok(range->start_infinity == false, "Not using negative infinity"); |
74 | ok( range->end == 12, "End correct"); | 72 | ok(range->end == 12, "End correct"); |
75 | ok( range->end_infinity == false, "Not using infinity"); | 73 | ok(range->end_infinity == false, "Not using infinity"); |
76 | free(range); | 74 | free(range); |
77 | 75 | ||
78 | range = parse_range_string("-7:23"); | 76 | range = parse_range_string("-7:23"); |
79 | ok( range != NULL, "'-7:23' is valid range"); | 77 | ok(range != NULL, "'-7:23' is valid range"); |
80 | ok( range->start == -7, "Start correct"); | 78 | ok(range->start == -7, "Start correct"); |
81 | ok( range->start_infinity == false, "Not using negative infinity"); | 79 | ok(range->start_infinity == false, "Not using negative infinity"); |
82 | ok( range->end == 23, "End correct"); | 80 | ok(range->end == 23, "End correct"); |
83 | ok( range->end_infinity == false, "Not using infinity"); | 81 | ok(range->end_infinity == false, "Not using infinity"); |
84 | free(range); | 82 | free(range); |
85 | 83 | ||
86 | range = parse_range_string(":5.75"); | 84 | range = parse_range_string(":5.75"); |
87 | ok( range != NULL, "':5.75' is valid range"); | 85 | ok(range != NULL, "':5.75' is valid range"); |
88 | ok( range->start == 0, "Start correct"); | 86 | ok(range->start == 0, "Start correct"); |
89 | ok( range->start_infinity == false, "Not using negative infinity"); | 87 | ok(range->start_infinity == false, "Not using negative infinity"); |
90 | ok( range->end == 5.75, "End correct"); | 88 | ok(range->end == 5.75, "End correct"); |
91 | ok( range->end_infinity == false, "Not using infinity"); | 89 | ok(range->end_infinity == false, "Not using infinity"); |
92 | free(range); | 90 | free(range); |
93 | 91 | ||
94 | range = parse_range_string("~:-95.99"); | 92 | range = parse_range_string("~:-95.99"); |
95 | ok( range != NULL, "~:-95.99' is valid range"); | 93 | ok(range != NULL, "~:-95.99' is valid range"); |
96 | ok( range->start_infinity == true, "Using negative infinity"); | 94 | ok(range->start_infinity == true, "Using negative infinity"); |
97 | ok( range->end == -95.99, "End correct (with rounding errors)"); | 95 | ok(range->end == -95.99, "End correct (with rounding errors)"); |
98 | ok( range->end_infinity == false, "Not using infinity"); | 96 | ok(range->end_infinity == false, "Not using infinity"); |
99 | free(range); | 97 | free(range); |
100 | 98 | ||
101 | range = parse_range_string("12345678901234567890:"); | 99 | range = parse_range_string("12345678901234567890:"); |
102 | temp = atof("12345678901234567890"); /* Can't just use this because number too large */ | 100 | temp = atof("12345678901234567890"); /* Can't just use this because number too large */ |
103 | ok( range != NULL, "'12345678901234567890:' is valid range"); | 101 | ok(range != NULL, "'12345678901234567890:' is valid range"); |
104 | ok( range->start == temp, "Start correct"); | 102 | ok(range->start == temp, "Start correct"); |
105 | ok( range->start_infinity == false, "Not using negative infinity"); | 103 | ok(range->start_infinity == false, "Not using negative infinity"); |
106 | ok( range->end_infinity == true, "Using infinity"); | 104 | ok(range->end_infinity == true, "Using infinity"); |
107 | /* Cannot do a "-1" on temp, as it appears to be same value */ | 105 | /* Cannot do a "-1" on temp, as it appears to be same value */ |
108 | ok( check_range(temp/1.1, range) == true, "12345678901234567890/1.1 - alert"); | 106 | ok(check_range(temp / 1.1, range) == true, "12345678901234567890/1.1 - alert"); |
109 | ok( check_range(temp, range) == false, "12345678901234567890 - no alert"); | 107 | ok(check_range(temp, range) == false, "12345678901234567890 - no alert"); |
110 | ok( check_range(temp*2, range) == false, "12345678901234567890*2 - no alert"); | 108 | ok(check_range(temp * 2, range) == false, "12345678901234567890*2 - no alert"); |
111 | free(range); | 109 | free(range); |
112 | 110 | ||
113 | range = parse_range_string("~:0"); | 111 | range = parse_range_string("~:0"); |
114 | ok( range != NULL, "'~:0' is valid range"); | 112 | ok(range != NULL, "'~:0' is valid range"); |
115 | ok( range->start_infinity == true, "Using negative infinity"); | 113 | ok(range->start_infinity == true, "Using negative infinity"); |
116 | ok( range->end == 0, "End correct"); | 114 | ok(range->end == 0, "End correct"); |
117 | ok( range->end_infinity == false, "Not using infinity"); | 115 | ok(range->end_infinity == false, "Not using infinity"); |
118 | ok( range->alert_on == OUTSIDE, "Will alert on outside of this range"); | 116 | ok(range->alert_on == OUTSIDE, "Will alert on outside of this range"); |
119 | ok( check_range(0.5, range) == true, "0.5 - alert"); | 117 | ok(check_range(0.5, range) == true, "0.5 - alert"); |
120 | ok( check_range(-10, range) == false, "-10 - no alert"); | 118 | ok(check_range(-10, range) == false, "-10 - no alert"); |
121 | ok( check_range(0, range) == false, "0 - no alert"); | 119 | ok(check_range(0, range) == false, "0 - no alert"); |
122 | free(range); | 120 | free(range); |
123 | 121 | ||
124 | range = parse_range_string("@0:657.8210567"); | 122 | range = parse_range_string("@0:657.8210567"); |
125 | ok( range != 0, "@0:657.8210567' is a valid range"); | 123 | ok(range != 0, "@0:657.8210567' is a valid range"); |
126 | ok( range->start == 0, "Start correct"); | 124 | ok(range->start == 0, "Start correct"); |
127 | ok( range->start_infinity == false, "Not using negative infinity"); | 125 | ok(range->start_infinity == false, "Not using negative infinity"); |
128 | ok( range->end == 657.8210567, "End correct"); | 126 | ok(range->end == 657.8210567, "End correct"); |
129 | ok( range->end_infinity == false, "Not using infinity"); | 127 | ok(range->end_infinity == false, "Not using infinity"); |
130 | ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); | 128 | ok(range->alert_on == INSIDE, "Will alert on inside of this range"); |
131 | ok( check_range(32.88, range) == true, "32.88 - alert"); | 129 | ok(check_range(32.88, range) == true, "32.88 - alert"); |
132 | ok( check_range(-2, range) == false, "-2 - no alert"); | 130 | ok(check_range(-2, range) == false, "-2 - no alert"); |
133 | ok( check_range(657.8210567, range) == true, "657.8210567 - alert"); | 131 | ok(check_range(657.8210567, range) == true, "657.8210567 - alert"); |
134 | ok( check_range(0, range) == true, "0 - alert"); | 132 | ok(check_range(0, range) == true, "0 - alert"); |
135 | free(range); | 133 | free(range); |
136 | 134 | ||
137 | range = parse_range_string("@1:1"); | 135 | range = parse_range_string("@1:1"); |
138 | ok( range != NULL, "'@1:1' is a valid range"); | 136 | ok(range != NULL, "'@1:1' is a valid range"); |
139 | ok( range->start == 1, "Start correct"); | 137 | ok(range->start == 1, "Start correct"); |
140 | ok( range->start_infinity == false, "Not using negative infinity"); | 138 | ok(range->start_infinity == false, "Not using negative infinity"); |
141 | ok( range->end == 1, "End correct"); | 139 | ok(range->end == 1, "End correct"); |
142 | ok( range->end_infinity == false, "Not using infinity"); | 140 | ok(range->end_infinity == false, "Not using infinity"); |
143 | ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); | 141 | ok(range->alert_on == INSIDE, "Will alert on inside of this range"); |
144 | ok( check_range(0.5, range) == false, "0.5 - no alert"); | 142 | ok(check_range(0.5, range) == false, "0.5 - no alert"); |
145 | ok( check_range(1, range) == true, "1 - alert"); | 143 | ok(check_range(1, range) == true, "1 - alert"); |
146 | ok( check_range(5.2, range) == false, "5.2 - no alert"); | 144 | ok(check_range(5.2, range) == false, "5.2 - no alert"); |
147 | free(range); | 145 | free(range); |
148 | 146 | ||
149 | range = parse_range_string("1:1"); | 147 | range = parse_range_string("1:1"); |
150 | ok( range != NULL, "'1:1' is a valid range"); | 148 | ok(range != NULL, "'1:1' is a valid range"); |
151 | ok( range->start == 1, "Start correct"); | 149 | ok(range->start == 1, "Start correct"); |
152 | ok( range->start_infinity == false, "Not using negative infinity"); | 150 | ok(range->start_infinity == false, "Not using negative infinity"); |
153 | ok( range->end == 1, "End correct"); | 151 | ok(range->end == 1, "End correct"); |
154 | ok( range->end_infinity == false, "Not using infinity"); | 152 | ok(range->end_infinity == false, "Not using infinity"); |
155 | ok( check_range(0.5, range) == true, "0.5 - alert"); | 153 | ok(check_range(0.5, range) == true, "0.5 - alert"); |
156 | ok( check_range(1, range) == false, "1 - no alert"); | 154 | ok(check_range(1, range) == false, "1 - no alert"); |
157 | ok( check_range(5.2, range) == true, "5.2 - alert"); | 155 | ok(check_range(5.2, range) == true, "5.2 - alert"); |
158 | free(range); | 156 | free(range); |
159 | 157 | ||
160 | range = parse_range_string("2:1"); | 158 | range = parse_range_string("2:1"); |
161 | ok( range == NULL, "'2:1' rejected"); | 159 | ok(range == NULL, "'2:1' rejected"); |
162 | 160 | ||
163 | rc = _set_thresholds(&thresholds, NULL, NULL); | 161 | rc = _set_thresholds(&thresholds, NULL, NULL); |
164 | ok( rc == 0, "Thresholds (NULL, NULL) set"); | 162 | ok(rc == 0, "Thresholds (NULL, NULL) set"); |
165 | ok( thresholds->warning == NULL, "Warning not set"); | 163 | ok(thresholds->warning == NULL, "Warning not set"); |
166 | ok( thresholds->critical == NULL, "Critical not set"); | 164 | ok(thresholds->critical == NULL, "Critical not set"); |
167 | 165 | ||
168 | rc = _set_thresholds(&thresholds, NULL, "80"); | 166 | rc = _set_thresholds(&thresholds, NULL, "80"); |
169 | ok( rc == 0, "Thresholds (NULL, '80') set"); | 167 | ok(rc == 0, "Thresholds (NULL, '80') set"); |
170 | ok( thresholds->warning == NULL, "Warning not set"); | 168 | ok(thresholds->warning == NULL, "Warning not set"); |
171 | ok( thresholds->critical->end == 80, "Critical set correctly"); | 169 | ok(thresholds->critical->end == 80, "Critical set correctly"); |
172 | 170 | ||
173 | rc = _set_thresholds(&thresholds, "5:33", NULL); | 171 | rc = _set_thresholds(&thresholds, "5:33", NULL); |
174 | ok( rc == 0, "Thresholds ('5:33', NULL) set"); | 172 | ok(rc == 0, "Thresholds ('5:33', NULL) set"); |
175 | ok( thresholds->warning->start == 5, "Warning start set"); | 173 | ok(thresholds->warning->start == 5, "Warning start set"); |
176 | ok( thresholds->warning->end == 33, "Warning end set"); | 174 | ok(thresholds->warning->end == 33, "Warning end set"); |
177 | ok( thresholds->critical == NULL, "Critical not set"); | 175 | ok(thresholds->critical == NULL, "Critical not set"); |
178 | 176 | ||
179 | rc = _set_thresholds(&thresholds, "30", "60"); | 177 | rc = _set_thresholds(&thresholds, "30", "60"); |
180 | ok( rc == 0, "Thresholds ('30', '60') set"); | 178 | ok(rc == 0, "Thresholds ('30', '60') set"); |
181 | ok( thresholds->warning->end == 30, "Warning set correctly"); | 179 | ok(thresholds->warning->end == 30, "Warning set correctly"); |
182 | ok( thresholds->critical->end == 60, "Critical set correctly"); | 180 | ok(thresholds->critical->end == 60, "Critical set correctly"); |
183 | ok( get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); | 181 | ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); |
184 | ok( get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); | 182 | ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); |
185 | ok( get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); | 183 | ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); |
186 | 184 | ||
187 | rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); | 185 | rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); |
188 | ok( rc == 0, "Thresholds ('-30:20', '-10:-2') set"); | 186 | ok(rc == 0, "Thresholds ('-30:20', '-10:-2') set"); |
189 | ok( thresholds->warning->start == -10, "Warning start set correctly"); | 187 | ok(thresholds->warning->start == -10, "Warning start set correctly"); |
190 | ok( thresholds->warning->end == -2, "Warning end set correctly"); | 188 | ok(thresholds->warning->end == -2, "Warning end set correctly"); |
191 | ok( thresholds->critical->start == -30, "Critical start set correctly"); | 189 | ok(thresholds->critical->start == -30, "Critical start set correctly"); |
192 | ok( thresholds->critical->end == 20, "Critical end set correctly"); | 190 | ok(thresholds->critical->end == 20, "Critical end set correctly"); |
193 | ok( get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical"); | 191 | ok(get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical"); |
194 | ok( get_status(-29, thresholds) == STATE_WARNING, "-29 - warning"); | 192 | ok(get_status(-29, thresholds) == STATE_WARNING, "-29 - warning"); |
195 | ok( get_status(-11, thresholds) == STATE_WARNING, "-11 - warning"); | 193 | ok(get_status(-11, thresholds) == STATE_WARNING, "-11 - warning"); |
196 | ok( get_status(-10, thresholds) == STATE_OK, "-10 - ok"); | 194 | ok(get_status(-10, thresholds) == STATE_OK, "-10 - ok"); |
197 | ok( get_status(-2, thresholds) == STATE_OK, "-2 - ok"); | 195 | ok(get_status(-2, thresholds) == STATE_OK, "-2 - ok"); |
198 | ok( get_status(-1, thresholds) == STATE_WARNING, "-1 - warning"); | 196 | ok(get_status(-1, thresholds) == STATE_WARNING, "-1 - warning"); |
199 | ok( get_status(19, thresholds) == STATE_WARNING, "19 - warning"); | 197 | ok(get_status(19, thresholds) == STATE_WARNING, "19 - warning"); |
200 | ok( get_status(21, thresholds) == STATE_CRITICAL, "21 - critical"); | 198 | ok(get_status(21, thresholds) == STATE_CRITICAL, "21 - critical"); |
201 | 199 | ||
202 | char *test; | 200 | char *test; |
203 | test = np_escaped_string("bob\\n"); | 201 | test = np_escaped_string("bob\\n"); |
204 | ok( strcmp(test, "bob\n") == 0, "bob\\n ok"); | 202 | ok(strcmp(test, "bob\n") == 0, "bob\\n ok"); |
205 | free(test); | 203 | free(test); |
206 | 204 | ||
207 | test = np_escaped_string("rhuba\\rb"); | 205 | test = np_escaped_string("rhuba\\rb"); |
208 | ok( strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay"); | 206 | ok(strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay"); |
209 | free(test); | 207 | free(test); |
210 | 208 | ||
211 | test = np_escaped_string("ba\\nge\\r"); | 209 | test = np_escaped_string("ba\\nge\\r"); |
212 | ok( strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay"); | 210 | ok(strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay"); |
213 | free(test); | 211 | free(test); |
214 | 212 | ||
215 | test = np_escaped_string("\\rabbi\\t"); | 213 | test = np_escaped_string("\\rabbi\\t"); |
216 | ok( strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay"); | 214 | ok(strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay"); |
217 | free(test); | 215 | free(test); |
218 | 216 | ||
219 | test = np_escaped_string("and\\\\or"); | 217 | test = np_escaped_string("and\\\\or"); |
220 | ok( strcmp(test, "and\\or") == 0, "and\\\\or okay"); | 218 | ok(strcmp(test, "and\\or") == 0, "and\\\\or okay"); |
221 | free(test); | 219 | free(test); |
222 | 220 | ||
223 | test = np_escaped_string("bo\\gus"); | 221 | test = np_escaped_string("bo\\gus"); |
224 | ok( strcmp(test, "bogus") == 0, "bo\\gus okay"); | 222 | ok(strcmp(test, "bogus") == 0, "bo\\gus okay"); |
225 | free(test); | 223 | free(test); |
226 | 224 | ||
227 | test = np_escaped_string("everything"); | 225 | test = np_escaped_string("everything"); |
228 | ok( strcmp(test, "everything") == 0, "everything okay"); | 226 | ok(strcmp(test, "everything") == 0, "everything okay"); |
229 | 227 | ||
230 | /* np_extract_ntpvar tests (23) */ | 228 | /* np_extract_ntpvar tests (23) */ |
231 | test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo"); | 229 | test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo"); |
232 | ok(test && !strcmp(test, "bar"), "1st test as expected"); | 230 | ok(test && !strcmp(test, "bar"), "1st test as expected"); |
233 | free(test); | 231 | free(test); |
234 | 232 | ||
235 | test=np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar"); | 233 | test = np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar"); |
236 | ok(test && !strcmp(test, "foo"), "2nd test as expected"); | 234 | ok(test && !strcmp(test, "foo"), "2nd test as expected"); |
237 | free(test); | 235 | free(test); |
238 | 236 | ||
239 | test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar"); | 237 | test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar"); |
240 | ok(test && !strcmp(test, "barfoo"), "3rd test as expected"); | 238 | ok(test && !strcmp(test, "barfoo"), "3rd test as expected"); |
241 | free(test); | 239 | free(test); |
242 | 240 | ||
243 | test=np_extract_ntpvar("foo=bar\n", "foo"); | 241 | test = np_extract_ntpvar("foo=bar\n", "foo"); |
244 | ok(test && !strcmp(test, "bar"), "Single test as expected"); | 242 | ok(test && !strcmp(test, "bar"), "Single test as expected"); |
245 | free(test); | 243 | free(test); |
246 | 244 | ||
247 | test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd"); | 245 | test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd"); |
248 | ok(!test, "Key not found 1"); | 246 | ok(!test, "Key not found 1"); |
249 | 247 | ||
250 | test=np_extract_ntpvar("foo=bar\n", "abcd"); | 248 | test = np_extract_ntpvar("foo=bar\n", "abcd"); |
251 | ok(!test, "Key not found 2"); | 249 | ok(!test, "Key not found 2"); |
252 | 250 | ||
253 | test=np_extract_ntpvar("foo=bar=foobar", "foo"); | 251 | test = np_extract_ntpvar("foo=bar=foobar", "foo"); |
254 | ok(test && !strcmp(test, "bar=foobar"), "Strange string 1"); | 252 | ok(test && !strcmp(test, "bar=foobar"), "Strange string 1"); |
255 | free(test); | 253 | free(test); |
256 | 254 | ||
257 | test=np_extract_ntpvar("foo", "foo"); | 255 | test = np_extract_ntpvar("foo", "foo"); |
258 | ok(!test, "Malformed string 1"); | 256 | ok(!test, "Malformed string 1"); |
259 | 257 | ||
260 | test=np_extract_ntpvar("foo,", "foo"); | 258 | test = np_extract_ntpvar("foo,", "foo"); |
261 | ok(!test, "Malformed string 2"); | 259 | ok(!test, "Malformed string 2"); |
262 | 260 | ||
263 | test=np_extract_ntpvar("foo=", "foo"); | 261 | test = np_extract_ntpvar("foo=", "foo"); |
264 | ok(!test, "Malformed string 3"); | 262 | ok(!test, "Malformed string 3"); |
265 | 263 | ||
266 | test=np_extract_ntpvar("foo=,bar=foo", "foo"); | 264 | test = np_extract_ntpvar("foo=,bar=foo", "foo"); |
267 | ok(!test, "Malformed string 4"); | 265 | ok(!test, "Malformed string 4"); |
268 | 266 | ||
269 | test=np_extract_ntpvar(",foo", "foo"); | 267 | test = np_extract_ntpvar(",foo", "foo"); |
270 | ok(!test, "Malformed string 5"); | 268 | ok(!test, "Malformed string 5"); |
271 | 269 | ||
272 | test=np_extract_ntpvar("=foo", "foo"); | 270 | test = np_extract_ntpvar("=foo", "foo"); |
273 | ok(!test, "Malformed string 6"); | 271 | ok(!test, "Malformed string 6"); |
274 | 272 | ||
275 | test=np_extract_ntpvar("=foo,", "foo"); | 273 | test = np_extract_ntpvar("=foo,", "foo"); |
276 | ok(!test, "Malformed string 7"); | 274 | ok(!test, "Malformed string 7"); |
277 | 275 | ||
278 | test=np_extract_ntpvar(",,,", "foo"); | 276 | test = np_extract_ntpvar(",,,", "foo"); |
279 | ok(!test, "Malformed string 8"); | 277 | ok(!test, "Malformed string 8"); |
280 | 278 | ||
281 | test=np_extract_ntpvar("===", "foo"); | 279 | test = np_extract_ntpvar("===", "foo"); |
282 | ok(!test, "Malformed string 9"); | 280 | ok(!test, "Malformed string 9"); |
283 | 281 | ||
284 | test=np_extract_ntpvar(",=,=,", "foo"); | 282 | test = np_extract_ntpvar(",=,=,", "foo"); |
285 | ok(!test, "Malformed string 10"); | 283 | ok(!test, "Malformed string 10"); |
286 | 284 | ||
287 | test=np_extract_ntpvar("=,=,=", "foo"); | 285 | test = np_extract_ntpvar("=,=,=", "foo"); |
288 | ok(!test, "Malformed string 11"); | 286 | ok(!test, "Malformed string 11"); |
289 | 287 | ||
290 | test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo"); | 288 | test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo"); |
291 | ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1"); | 289 | ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1"); |
292 | free(test); | 290 | free(test); |
293 | 291 | ||
294 | test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar"); | 292 | test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar"); |
295 | ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2"); | 293 | ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2"); |
296 | free(test); | 294 | free(test); |
297 | 295 | ||
298 | test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar"); | 296 | test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar"); |
299 | ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3"); | 297 | ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3"); |
300 | free(test); | 298 | free(test); |
301 | 299 | ||
302 | test=np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar"); | 300 | test = np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar"); |
303 | ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4"); | 301 | ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4"); |
304 | free(test); | 302 | free(test); |
305 | 303 | ||
306 | test=np_extract_ntpvar("", "foo"); | 304 | test = np_extract_ntpvar("", "foo"); |
307 | ok(!test, "Empty string return NULL"); | 305 | ok(!test, "Empty string return NULL"); |
308 | 306 | ||
309 | |||
310 | /* This is the result of running ./test_utils */ | 307 | /* This is the result of running ./test_utils */ |
311 | temp_string = (char *) _np_state_generate_key(); | 308 | temp_string = (char *)_np_state_generate_key(); |
312 | ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters" ) || | 309 | ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters") || |
313 | diag( "You are probably running in wrong directory. Must run as ./test_utils" ); | 310 | diag("You are probably running in wrong directory. Must run as ./test_utils"); |
314 | |||
315 | 311 | ||
316 | this_monitoring_plugin->argc=4; | 312 | this_monitoring_plugin->argc = 4; |
317 | this_monitoring_plugin->argv[0] = "./test_utils"; | 313 | this_monitoring_plugin->argv[0] = "./test_utils"; |
318 | this_monitoring_plugin->argv[1] = "here"; | 314 | this_monitoring_plugin->argv[1] = "here"; |
319 | this_monitoring_plugin->argv[2] = "--and"; | 315 | this_monitoring_plugin->argv[2] = "--and"; |
320 | this_monitoring_plugin->argv[3] = "now"; | 316 | this_monitoring_plugin->argv[3] = "now"; |
321 | temp_string = (char *) _np_state_generate_key(); | 317 | temp_string = (char *)_np_state_generate_key(); |
322 | ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv" ); | 318 | ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv"); |
323 | 319 | ||
324 | unsetenv("MP_STATE_PATH"); | 320 | unsetenv("MP_STATE_PATH"); |
325 | temp_string = (char *) _np_state_calculate_location_prefix(); | 321 | temp_string = (char *)_np_state_calculate_location_prefix(); |
326 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory" ); | 322 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory"); |
327 | 323 | ||
328 | setenv("MP_STATE_PATH", "", 1); | 324 | setenv("MP_STATE_PATH", "", 1); |
329 | temp_string = (char *) _np_state_calculate_location_prefix(); | 325 | temp_string = (char *)_np_state_calculate_location_prefix(); |
330 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string" ); | 326 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string"); |
331 | 327 | ||
332 | setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1); | 328 | setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1); |
333 | temp_string = (char *) _np_state_calculate_location_prefix(); | 329 | temp_string = (char *)_np_state_calculate_location_prefix(); |
334 | ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory" ); | 330 | ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory"); |
335 | |||
336 | 331 | ||
332 | ok(temp_state_key == NULL, "temp_state_key initially empty"); | ||
337 | 333 | ||
338 | ok(temp_state_key==NULL, "temp_state_key initially empty"); | 334 | this_monitoring_plugin->argc = 1; |
339 | |||
340 | this_monitoring_plugin->argc=1; | ||
341 | this_monitoring_plugin->argv[0] = "./test_utils"; | 335 | this_monitoring_plugin->argv[0] = "./test_utils"; |
342 | np_enable_state(NULL, 51); | 336 | np_enable_state(NULL, 51); |
343 | temp_state_key = this_monitoring_plugin->state; | 337 | temp_state_key = this_monitoring_plugin->state; |
344 | ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); | 338 | ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name"); |
345 | ok( !strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename" ); | 339 | ok(!strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename"); |
346 | |||
347 | 340 | ||
348 | np_enable_state("allowedchars_in_keyname", 77); | 341 | np_enable_state("allowedchars_in_keyname", 77); |
349 | temp_state_key = this_monitoring_plugin->state; | 342 | temp_state_key = this_monitoring_plugin->state; |
350 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid()); | 343 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid()); |
351 | ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); | 344 | ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name"); |
352 | ok( !strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars" ); | 345 | ok(!strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars"); |
353 | ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" ); | 346 | ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename"); |
354 | |||
355 | 347 | ||
356 | /* Don't do this test just yet. Will die */ | 348 | /* Don't do this test just yet. Will die */ |
357 | /* | 349 | /* |
@@ -363,73 +355,65 @@ main (int argc, char **argv) | |||
363 | np_enable_state("funnykeyname", 54); | 355 | np_enable_state("funnykeyname", 54); |
364 | temp_state_key = this_monitoring_plugin->state; | 356 | temp_state_key = this_monitoring_plugin->state; |
365 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid()); | 357 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid()); |
366 | ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); | 358 | ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name"); |
367 | ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" ); | 359 | ok(!strcmp(temp_state_key->name, "funnykeyname"), "Got key name"); |
368 | 360 | ||
369 | 361 | ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename"); | |
370 | 362 | ok(temp_state_key->data_version == 54, "Version set"); | |
371 | ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" ); | ||
372 | ok( temp_state_key->data_version==54, "Version set" ); | ||
373 | 363 | ||
374 | temp_state_data = np_state_read(); | 364 | temp_state_data = np_state_read(); |
375 | ok( temp_state_data==NULL, "Got no state data as file does not exist" ); | 365 | ok(temp_state_data == NULL, "Got no state data as file does not exist"); |
376 | |||
377 | 366 | ||
378 | /* | 367 | /* |
379 | temp_fp = fopen("var/statefile", "r"); | 368 | temp_fp = fopen("var/statefile", "r"); |
380 | if (temp_fp==NULL) | 369 | if (temp_fp==NULL) |
381 | printf("Error opening. errno=%d\n", errno); | 370 | printf("Error opening. errno=%d\n", errno); |
382 | printf("temp_fp=%s\n", temp_fp); | 371 | printf("temp_fp=%s\n", temp_fp); |
383 | ok( _np_state_read_file(temp_fp) == true, "Can read state file" ); | 372 | ok( _np_state_read_file(temp_fp) == true, "Can read state file" ); |
384 | fclose(temp_fp); | 373 | fclose(temp_fp); |
385 | */ | 374 | */ |
386 | 375 | ||
387 | temp_state_key->_filename="var/statefile"; | 376 | temp_state_key->_filename = "var/statefile"; |
388 | temp_state_data = np_state_read(); | 377 | temp_state_data = np_state_read(); |
389 | ok( this_monitoring_plugin->state->state_data!=NULL, "Got state data now" ) || diag("Are you running in right directory? Will get coredump next if not"); | 378 | ok(this_monitoring_plugin->state->state_data != NULL, "Got state data now") || |
390 | ok( this_monitoring_plugin->state->state_data->time==1234567890, "Got time" ); | 379 | diag("Are you running in right directory? Will get coredump next if not"); |
391 | ok( !strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected" ); | 380 | ok(this_monitoring_plugin->state->state_data->time == 1234567890, "Got time"); |
381 | ok(!strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected"); | ||
392 | 382 | ||
393 | temp_state_key->data_version=53; | 383 | temp_state_key->data_version = 53; |
394 | temp_state_data = np_state_read(); | 384 | temp_state_data = np_state_read(); |
395 | ok( temp_state_data==NULL, "Older data version gives NULL" ); | 385 | ok(temp_state_data == NULL, "Older data version gives NULL"); |
396 | temp_state_key->data_version=54; | 386 | temp_state_key->data_version = 54; |
397 | 387 | ||
398 | temp_state_key->_filename="var/nonexistent"; | 388 | temp_state_key->_filename = "var/nonexistent"; |
399 | temp_state_data = np_state_read(); | 389 | temp_state_data = np_state_read(); |
400 | ok( temp_state_data==NULL, "Missing file gives NULL" ); | 390 | ok(temp_state_data == NULL, "Missing file gives NULL"); |
401 | ok( this_monitoring_plugin->state->state_data==NULL, "No state information" ); | 391 | ok(this_monitoring_plugin->state->state_data == NULL, "No state information"); |
402 | 392 | ||
403 | temp_state_key->_filename="var/oldformat"; | 393 | temp_state_key->_filename = "var/oldformat"; |
404 | temp_state_data = np_state_read(); | 394 | temp_state_data = np_state_read(); |
405 | ok( temp_state_data==NULL, "Old file format gives NULL" ); | 395 | ok(temp_state_data == NULL, "Old file format gives NULL"); |
406 | 396 | ||
407 | temp_state_key->_filename="var/baddate"; | 397 | temp_state_key->_filename = "var/baddate"; |
408 | temp_state_data = np_state_read(); | 398 | temp_state_data = np_state_read(); |
409 | ok( temp_state_data==NULL, "Bad date gives NULL" ); | 399 | ok(temp_state_data == NULL, "Bad date gives NULL"); |
410 | 400 | ||
411 | temp_state_key->_filename="var/missingdataline"; | 401 | temp_state_key->_filename = "var/missingdataline"; |
412 | temp_state_data = np_state_read(); | 402 | temp_state_data = np_state_read(); |
413 | ok( temp_state_data==NULL, "Missing data line gives NULL" ); | 403 | ok(temp_state_data == NULL, "Missing data line gives NULL"); |
414 | |||
415 | |||
416 | |||
417 | 404 | ||
418 | unlink("var/generated"); | 405 | unlink("var/generated"); |
419 | temp_state_key->_filename="var/generated"; | 406 | temp_state_key->_filename = "var/generated"; |
420 | current_time=1234567890; | 407 | current_time = 1234567890; |
421 | np_state_write_string(current_time, "String to read"); | 408 | np_state_write_string(current_time, "String to read"); |
422 | ok(system("cmp var/generated var/statefile")==0, "Generated file same as expected"); | 409 | ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected"); |
423 | |||
424 | |||
425 | |||
426 | 410 | ||
427 | unlink("var/generated_directory/statefile"); | 411 | unlink("var/generated_directory/statefile"); |
428 | unlink("var/generated_directory"); | 412 | unlink("var/generated_directory"); |
429 | temp_state_key->_filename="var/generated_directory/statefile"; | 413 | temp_state_key->_filename = "var/generated_directory/statefile"; |
430 | current_time=1234567890; | 414 | current_time = 1234567890; |
431 | np_state_write_string(current_time, "String to read"); | 415 | np_state_write_string(current_time, "String to read"); |
432 | ok(system("cmp var/generated_directory/statefile var/statefile")==0, "Have created directory"); | 416 | ok(system("cmp var/generated_directory/statefile var/statefile") == 0, "Have created directory"); |
433 | 417 | ||
434 | /* This test to check cannot write to dir - can't automate yet */ | 418 | /* This test to check cannot write to dir - can't automate yet */ |
435 | /* | 419 | /* |
@@ -438,15 +422,13 @@ main (int argc, char **argv) | |||
438 | np_state_write_string(current_time, "String to read"); | 422 | np_state_write_string(current_time, "String to read"); |
439 | */ | 423 | */ |
440 | 424 | ||
441 | 425 | temp_state_key->_filename = "var/generated"; | |
442 | temp_state_key->_filename="var/generated"; | ||
443 | time(¤t_time); | 426 | time(¤t_time); |
444 | np_state_write_string(0, "String to read"); | 427 | np_state_write_string(0, "String to read"); |
445 | temp_state_data = np_state_read(); | 428 | temp_state_data = np_state_read(); |
446 | /* Check time is set to current_time */ | 429 | /* Check time is set to current_time */ |
447 | ok(system("cmp var/generated var/statefile > /dev/null")!=0, "Generated file should be different this time"); | 430 | ok(system("cmp var/generated var/statefile > /dev/null") != 0, "Generated file should be different this time"); |
448 | ok(this_monitoring_plugin->state->state_data->time-current_time<=1, "Has time generated from current time"); | 431 | ok(this_monitoring_plugin->state->state_data->time - current_time <= 1, "Has time generated from current time"); |
449 | |||
450 | 432 | ||
451 | /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */ | 433 | /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */ |
452 | /* | 434 | /* |
@@ -454,23 +436,16 @@ main (int argc, char **argv) | |||
454 | np_state_write_string(0, "Bad file"); | 436 | np_state_write_string(0, "Bad file"); |
455 | */ | 437 | */ |
456 | 438 | ||
457 | |||
458 | np_cleanup(); | 439 | np_cleanup(); |
459 | 440 | ||
460 | ok(this_monitoring_plugin==NULL, "Free'd this_monitoring_plugin"); | 441 | ok(this_monitoring_plugin == NULL, "Free'd this_monitoring_plugin"); |
461 | 442 | ||
462 | ok(mp_suid() == false, "Test aren't suid"); | 443 | ok(mp_suid() == false, "Test aren't suid"); |
463 | 444 | ||
464 | /* base states with random case */ | 445 | /* base states with random case */ |
465 | char *states[] = { | 446 | char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL}; |
466 | "Ok", | 447 | |
467 | "wArnINg", | 448 | for (i = 0; states[i] != NULL; i++) { |
468 | "cRiTIcaL", | ||
469 | "UnKNoWN", | ||
470 | NULL | ||
471 | }; | ||
472 | |||
473 | for (i=0; states[i]!=NULL; i++) { | ||
474 | /* out of the random case states, create the lower and upper versions + numeric string one */ | 449 | /* out of the random case states, create the lower and upper versions + numeric string one */ |
475 | char *statelower = strdup(states[i]); | 450 | char *statelower = strdup(states[i]); |
476 | char *stateupper = strdup(states[i]); | 451 | char *stateupper = strdup(states[i]); |
@@ -488,23 +463,23 @@ main (int argc, char **argv) | |||
488 | char testname[64] = "Translate state string: "; | 463 | char testname[64] = "Translate state string: "; |
489 | int tlen = strlen(testname); | 464 | int tlen = strlen(testname); |
490 | 465 | ||
491 | strcpy(testname+tlen, states[i]); | 466 | strcpy(testname + tlen, states[i]); |
492 | ok(i==mp_translate_state(states[i]), testname); | 467 | ok(i == mp_translate_state(states[i]), testname); |
493 | 468 | ||
494 | strcpy(testname+tlen, statelower); | 469 | strcpy(testname + tlen, statelower); |
495 | ok(i==mp_translate_state(statelower), testname); | 470 | ok(i == mp_translate_state(statelower), testname); |
496 | 471 | ||
497 | strcpy(testname+tlen, stateupper); | 472 | strcpy(testname + tlen, stateupper); |
498 | ok(i==mp_translate_state(stateupper), testname); | 473 | ok(i == mp_translate_state(stateupper), testname); |
499 | 474 | ||
500 | strcpy(testname+tlen, statenum); | 475 | strcpy(testname + tlen, statenum); |
501 | ok(i==mp_translate_state(statenum), testname); | 476 | ok(i == mp_translate_state(statenum), testname); |
502 | } | 477 | } |
503 | ok(ERROR==mp_translate_state("warningfewgw"), "Translate state string with garbage"); | 478 | ok(ERROR == mp_translate_state("warningfewgw"), "Translate state string with garbage"); |
504 | ok(ERROR==mp_translate_state("00"), "Translate state string: bad numeric string 1"); | 479 | ok(ERROR == mp_translate_state("00"), "Translate state string: bad numeric string 1"); |
505 | ok(ERROR==mp_translate_state("01"), "Translate state string: bad numeric string 2"); | 480 | ok(ERROR == mp_translate_state("01"), "Translate state string: bad numeric string 2"); |
506 | ok(ERROR==mp_translate_state("10"), "Translate state string: bad numeric string 3"); | 481 | ok(ERROR == mp_translate_state("10"), "Translate state string: bad numeric string 3"); |
507 | ok(ERROR==mp_translate_state(""), "Translate state string: empty string"); | 482 | ok(ERROR == mp_translate_state(""), "Translate state string: empty string"); |
508 | 483 | ||
509 | return exit_status(); | 484 | return exit_status(); |
510 | } | 485 | } |
diff --git a/lib/thresholds.c b/lib/thresholds.c new file mode 100644 index 00000000..ddefae37 --- /dev/null +++ b/lib/thresholds.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include "./thresholds.h" | ||
2 | #include "./utils_base.h" | ||
3 | #include "perfdata.h" | ||
4 | |||
5 | #include <stddef.h> | ||
6 | |||
7 | mp_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 | |||
17 | char *fmt_threshold_warning(const thresholds th) { | ||
18 | if (th.warning == NULL) { | ||
19 | return ""; | ||
20 | } | ||
21 | |||
22 | return fmt_range(*th.warning); | ||
23 | } | ||
24 | |||
25 | char *fmt_threshold_critical(const thresholds th) { | ||
26 | if (th.critical == NULL) { | ||
27 | return ""; | ||
28 | } | ||
29 | return fmt_range(*th.critical); | ||
30 | } | ||
31 | |||
32 | mp_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 | |||
46 | mp_state_enum mp_get_pd_status(mp_perfdata perfdata) { | ||
47 | if (perfdata.crit_present) { | ||
48 | if (mp_check_range(perfdata.value, perfdata.crit)) { | ||
49 | return STATE_CRITICAL; | ||
50 | } | ||
51 | } | ||
52 | if (perfdata.warn_present) { | ||
53 | if (mp_check_range(perfdata.value, perfdata.warn)) { | ||
54 | return STATE_CRITICAL; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | return STATE_OK; | ||
59 | } | ||
diff --git a/lib/thresholds.h b/lib/thresholds.h new file mode 100644 index 00000000..4e7defee --- /dev/null +++ b/lib/thresholds.h | |||
@@ -0,0 +1,28 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "./perfdata.h" | ||
4 | #include "states.h" | ||
5 | |||
6 | /* | ||
7 | * Old threshold type using the old range type | ||
8 | */ | ||
9 | typedef struct thresholds_struct { | ||
10 | range *warning; | ||
11 | range *critical; | ||
12 | } thresholds; | ||
13 | |||
14 | typedef struct mp_thresholds_struct { | ||
15 | bool warning_is_set; | ||
16 | mp_range warning; | ||
17 | bool critical_is_set; | ||
18 | mp_range critical; | ||
19 | } mp_thresholds; | ||
20 | |||
21 | mp_thresholds mp_thresholds_init(void); | ||
22 | |||
23 | mp_perfdata mp_pd_set_thresholds(mp_perfdata /* pd */, mp_thresholds /* th */); | ||
24 | |||
25 | mp_state_enum mp_get_pd_status(mp_perfdata /* pd */); | ||
26 | |||
27 | char *fmt_threshold_warning(thresholds th); | ||
28 | char *fmt_threshold_critical(thresholds th); | ||
diff --git a/lib/utils_base.c b/lib/utils_base.c index f8592f41..ff9540c7 100644 --- a/lib/utils_base.c +++ b/lib/utils_base.c | |||
@@ -1,28 +1,28 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * utils_base.c | 3 | * utils_base.c |
4 | * | 4 | * |
5 | * License: GPL | 5 | * License: GPL |
6 | * Copyright (c) 2006 Monitoring Plugins Development Team | 6 | * Copyright (c) 2006 - 2024 Monitoring Plugins Development Team |
7 | * | 7 | * |
8 | * Library of useful functions for plugins | 8 | * Library of useful functions for plugins |
9 | * | 9 | * |
10 | * | 10 | * |
11 | * This program is free software: you can redistribute it and/or modify | 11 | * This program is free software: you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation, either version 3 of the License, or | 13 | * the Free Software Foundation, either version 3 of the License, or |
14 | * (at your option) any later version. | 14 | * (at your option) any later version. |
15 | * | 15 | * |
16 | * This program is distributed in the hope that it will be useful, | 16 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. | 19 | * GNU General Public License for more details. |
20 | * | 20 | * |
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 22 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 | * | 23 | * |
24 | * | 24 | * |
25 | *****************************************************************************/ | 25 | *****************************************************************************/ |
26 | 26 | ||
27 | #include "../plugins/common.h" | 27 | #include "../plugins/common.h" |
28 | #include <stdarg.h> | 28 | #include <stdarg.h> |
@@ -33,43 +33,49 @@ | |||
33 | #include <unistd.h> | 33 | #include <unistd.h> |
34 | #include <sys/types.h> | 34 | #include <sys/types.h> |
35 | 35 | ||
36 | #define np_free(ptr) { if(ptr) { free(ptr); ptr = NULL; } } | 36 | #define np_free(ptr) \ |
37 | { \ | ||
38 | if (ptr) { \ | ||
39 | free(ptr); \ | ||
40 | ptr = NULL; \ | ||
41 | } \ | ||
42 | } | ||
37 | 43 | ||
38 | monitoring_plugin *this_monitoring_plugin=NULL; | 44 | monitoring_plugin *this_monitoring_plugin = NULL; |
39 | 45 | ||
40 | int timeout_state = STATE_CRITICAL; | 46 | int timeout_state = STATE_CRITICAL; |
41 | unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; | 47 | unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; |
42 | 48 | ||
43 | bool _np_state_read_file(FILE *); | 49 | bool _np_state_read_file(FILE *); |
44 | 50 | ||
45 | void np_init( char *plugin_name, int argc, char **argv ) { | 51 | void np_init(char *plugin_name, int argc, char **argv) { |
46 | if (this_monitoring_plugin==NULL) { | 52 | if (this_monitoring_plugin == NULL) { |
47 | this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin)); | 53 | this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin)); |
48 | if (this_monitoring_plugin==NULL) { | 54 | if (this_monitoring_plugin == NULL) { |
49 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 55 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
50 | strerror(errno)); | ||
51 | } | 56 | } |
52 | this_monitoring_plugin->plugin_name = strdup(plugin_name); | 57 | this_monitoring_plugin->plugin_name = strdup(plugin_name); |
53 | if (this_monitoring_plugin->plugin_name==NULL) | 58 | if (this_monitoring_plugin->plugin_name == NULL) { |
54 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | 59 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); |
60 | } | ||
55 | this_monitoring_plugin->argc = argc; | 61 | this_monitoring_plugin->argc = argc; |
56 | this_monitoring_plugin->argv = argv; | 62 | this_monitoring_plugin->argv = argv; |
57 | } | 63 | } |
58 | } | 64 | } |
59 | 65 | ||
60 | void np_set_args( int argc, char **argv ) { | 66 | void np_set_args(int argc, char **argv) { |
61 | if (this_monitoring_plugin==NULL) | 67 | if (this_monitoring_plugin == NULL) { |
62 | die(STATE_UNKNOWN, _("This requires np_init to be called")); | 68 | die(STATE_UNKNOWN, _("This requires np_init to be called")); |
69 | } | ||
63 | 70 | ||
64 | this_monitoring_plugin->argc = argc; | 71 | this_monitoring_plugin->argc = argc; |
65 | this_monitoring_plugin->argv = argv; | 72 | this_monitoring_plugin->argv = argv; |
66 | } | 73 | } |
67 | 74 | ||
68 | 75 | void np_cleanup(void) { | |
69 | void np_cleanup() { | 76 | if (this_monitoring_plugin != NULL) { |
70 | if (this_monitoring_plugin!=NULL) { | 77 | if (this_monitoring_plugin->state != NULL) { |
71 | if(this_monitoring_plugin->state!=NULL) { | 78 | if (this_monitoring_plugin->state->state_data) { |
72 | if(this_monitoring_plugin->state->state_data) { | ||
73 | np_free(this_monitoring_plugin->state->state_data->data); | 79 | np_free(this_monitoring_plugin->state->state_data->data); |
74 | np_free(this_monitoring_plugin->state->state_data); | 80 | np_free(this_monitoring_plugin->state->state_data); |
75 | } | 81 | } |
@@ -79,48 +85,43 @@ void np_cleanup() { | |||
79 | np_free(this_monitoring_plugin->plugin_name); | 85 | np_free(this_monitoring_plugin->plugin_name); |
80 | np_free(this_monitoring_plugin); | 86 | np_free(this_monitoring_plugin); |
81 | } | 87 | } |
82 | this_monitoring_plugin=NULL; | 88 | this_monitoring_plugin = NULL; |
83 | } | 89 | } |
84 | 90 | ||
85 | /* Hidden function to get a pointer to this_monitoring_plugin for testing */ | 91 | /* Hidden function to get a pointer to this_monitoring_plugin for testing */ |
86 | void _get_monitoring_plugin( monitoring_plugin **pointer ){ | 92 | void _get_monitoring_plugin(monitoring_plugin **pointer) { *pointer = this_monitoring_plugin; } |
87 | *pointer = this_monitoring_plugin; | ||
88 | } | ||
89 | 93 | ||
90 | void | 94 | void die(int result, const char *fmt, ...) { |
91 | die (int result, const char *fmt, ...) | 95 | if (fmt != NULL) { |
92 | { | ||
93 | if(fmt!=NULL) { | ||
94 | va_list ap; | 96 | va_list ap; |
95 | va_start (ap, fmt); | 97 | va_start(ap, fmt); |
96 | vprintf (fmt, ap); | 98 | vprintf(fmt, ap); |
97 | va_end (ap); | 99 | va_end(ap); |
98 | } | 100 | } |
99 | 101 | ||
100 | if(this_monitoring_plugin!=NULL) { | 102 | if (this_monitoring_plugin != NULL) { |
101 | np_cleanup(); | 103 | np_cleanup(); |
102 | } | 104 | } |
103 | exit (result); | 105 | exit(result); |
104 | } | 106 | } |
105 | 107 | ||
106 | void set_range_start (range *this, double value) { | 108 | void set_range_start(range *this, double value) { |
107 | this->start = value; | 109 | this->start = value; |
108 | this->start_infinity = false; | 110 | this->start_infinity = false; |
109 | } | 111 | } |
110 | 112 | ||
111 | void set_range_end (range *this, double value) { | 113 | void set_range_end(range *this, double value) { |
112 | this->end = value; | 114 | this->end = value; |
113 | this->end_infinity = false; | 115 | this->end_infinity = false; |
114 | } | 116 | } |
115 | 117 | ||
116 | range | 118 | range *parse_range_string(char *str) { |
117 | *parse_range_string (char *str) { | ||
118 | range *temp_range; | 119 | range *temp_range; |
119 | double start; | 120 | double start; |
120 | double end; | 121 | double end; |
121 | char *end_str; | 122 | char *end_str; |
122 | 123 | ||
123 | temp_range = (range *) calloc(1, sizeof(range)); | 124 | temp_range = (range *)calloc(1, sizeof(range)); |
124 | 125 | ||
125 | /* Set defaults */ | 126 | /* Set defaults */ |
126 | temp_range->start = 0; | 127 | temp_range->start = 0; |
@@ -140,10 +141,10 @@ range | |||
140 | if (str[0] == '~') { | 141 | if (str[0] == '~') { |
141 | temp_range->start_infinity = true; | 142 | temp_range->start_infinity = true; |
142 | } else { | 143 | } else { |
143 | start = strtod(str, NULL); /* Will stop at the ':' */ | 144 | start = strtod(str, NULL); /* Will stop at the ':' */ |
144 | set_range_start(temp_range, start); | 145 | set_range_start(temp_range, start); |
145 | } | 146 | } |
146 | end_str++; /* Move past the ':' */ | 147 | end_str++; /* Move past the ':' */ |
147 | } else { | 148 | } else { |
148 | end_str = str; | 149 | end_str = str; |
149 | } | 150 | } |
@@ -152,9 +153,7 @@ range | |||
152 | set_range_end(temp_range, end); | 153 | set_range_end(temp_range, end); |
153 | } | 154 | } |
154 | 155 | ||
155 | if (temp_range->start_infinity == true || | 156 | if (temp_range->start_infinity == true || temp_range->end_infinity == true || temp_range->start <= temp_range->end) { |
156 | temp_range->end_infinity == true || | ||
157 | temp_range->start <= temp_range->end) { | ||
158 | return temp_range; | 157 | return temp_range; |
159 | } | 158 | } |
160 | free(temp_range); | 159 | free(temp_range); |
@@ -162,14 +161,12 @@ range | |||
162 | } | 161 | } |
163 | 162 | ||
164 | /* returns 0 if okay, otherwise 1 */ | 163 | /* returns 0 if okay, otherwise 1 */ |
165 | int | 164 | int _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) { |
166 | _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) | ||
167 | { | ||
168 | thresholds *temp_thresholds = NULL; | 165 | thresholds *temp_thresholds = NULL; |
169 | 166 | ||
170 | if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) | 167 | if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) { |
171 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 168 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
172 | strerror(errno)); | 169 | } |
173 | 170 | ||
174 | temp_thresholds->warning = NULL; | 171 | temp_thresholds->warning = NULL; |
175 | temp_thresholds->critical = NULL; | 172 | temp_thresholds->critical = NULL; |
@@ -190,9 +187,7 @@ _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_st | |||
190 | return 0; | 187 | return 0; |
191 | } | 188 | } |
192 | 189 | ||
193 | void | 190 | void set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) { |
194 | set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) | ||
195 | { | ||
196 | switch (_set_thresholds(my_thresholds, warn_string, critical_string)) { | 191 | switch (_set_thresholds(my_thresholds, warn_string, critical_string)) { |
197 | case 0: | 192 | case 0: |
198 | return; | 193 | return; |
@@ -206,7 +201,7 @@ set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_str | |||
206 | 201 | ||
207 | void print_thresholds(const char *threshold_name, thresholds *my_threshold) { | 202 | void print_thresholds(const char *threshold_name, thresholds *my_threshold) { |
208 | printf("%s - ", threshold_name); | 203 | printf("%s - ", threshold_name); |
209 | if (! my_threshold) { | 204 | if (!my_threshold) { |
210 | printf("Threshold not set"); | 205 | printf("Threshold not set"); |
211 | } else { | 206 | } else { |
212 | if (my_threshold->warning) { | 207 | if (my_threshold->warning) { |
@@ -223,9 +218,48 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) { | |||
223 | printf("\n"); | 218 | printf("\n"); |
224 | } | 219 | } |
225 | 220 | ||
221 | /* Returns true if alert should be raised based on the range, false otherwise */ | ||
222 | bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) { | ||
223 | bool is_inside = false; | ||
224 | |||
225 | if (my_range.end_infinity == false && my_range.start_infinity == false) { | ||
226 | // range: .........|---inside---|........... | ||
227 | // value | ||
228 | if ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0)) { | ||
229 | is_inside = true; | ||
230 | } else { | ||
231 | is_inside = false; | ||
232 | } | ||
233 | } else if (my_range.start_infinity == false && my_range.end_infinity == true) { | ||
234 | // range: .........|---inside--------- | ||
235 | // value | ||
236 | if (cmp_perfdata_value(my_range.start, value) < 0) { | ||
237 | is_inside = true; | ||
238 | } else { | ||
239 | is_inside = false; | ||
240 | } | ||
241 | } else if (my_range.start_infinity == true && my_range.end_infinity == false) { | ||
242 | // range: -inside--------|.................... | ||
243 | // value | ||
244 | if (cmp_perfdata_value(value, my_range.end) == -1) { | ||
245 | is_inside = true; | ||
246 | } else { | ||
247 | is_inside = false; | ||
248 | } | ||
249 | } else { | ||
250 | // range from -inf to inf, so always inside | ||
251 | is_inside = true; | ||
252 | } | ||
253 | |||
254 | if ((is_inside && my_range.alert_on_inside_range == INSIDE) || (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) { | ||
255 | return true; | ||
256 | } | ||
257 | |||
258 | return false; | ||
259 | } | ||
260 | |||
226 | /* Returns true if alert should be raised based on the range */ | 261 | /* Returns true if alert should be raised based on the range */ |
227 | bool check_range(double value, range *my_range) | 262 | bool check_range(double value, range *my_range) { |
228 | { | ||
229 | bool no = false; | 263 | bool no = false; |
230 | bool yes = true; | 264 | bool yes = true; |
231 | 265 | ||
@@ -237,30 +271,28 @@ bool check_range(double value, range *my_range) | |||
237 | if (my_range->end_infinity == false && my_range->start_infinity == false) { | 271 | if (my_range->end_infinity == false && my_range->start_infinity == false) { |
238 | if ((my_range->start <= value) && (value <= my_range->end)) { | 272 | if ((my_range->start <= value) && (value <= my_range->end)) { |
239 | return no; | 273 | return no; |
240 | } else { | ||
241 | return yes; | ||
242 | } | 274 | } |
243 | } else if (my_range->start_infinity == false && my_range->end_infinity == true) { | 275 | return yes; |
276 | } | ||
277 | |||
278 | if (my_range->start_infinity == false && my_range->end_infinity == true) { | ||
244 | if (my_range->start <= value) { | 279 | if (my_range->start <= value) { |
245 | return no; | 280 | return no; |
246 | } else { | ||
247 | return yes; | ||
248 | } | 281 | } |
249 | } else if (my_range->start_infinity == true && my_range->end_infinity == false) { | 282 | return yes; |
283 | } | ||
284 | |||
285 | if (my_range->start_infinity == true && my_range->end_infinity == false) { | ||
250 | if (value <= my_range->end) { | 286 | if (value <= my_range->end) { |
251 | return no; | 287 | return no; |
252 | } else { | ||
253 | return yes; | ||
254 | } | 288 | } |
255 | } else { | 289 | return yes; |
256 | return no; | ||
257 | } | 290 | } |
291 | return no; | ||
258 | } | 292 | } |
259 | 293 | ||
260 | /* Returns status */ | 294 | /* Returns status */ |
261 | int | 295 | int get_status(double value, thresholds *my_thresholds) { |
262 | get_status(double value, thresholds *my_thresholds) | ||
263 | { | ||
264 | if (my_thresholds->critical != NULL) { | 296 | if (my_thresholds->critical != NULL) { |
265 | if (check_range(value, my_thresholds->critical) == true) { | 297 | if (check_range(value, my_thresholds->critical) == true) { |
266 | return STATE_CRITICAL; | 298 | return STATE_CRITICAL; |
@@ -274,27 +306,28 @@ get_status(double value, thresholds *my_thresholds) | |||
274 | return STATE_OK; | 306 | return STATE_OK; |
275 | } | 307 | } |
276 | 308 | ||
277 | char *np_escaped_string (const char *string) { | 309 | char *np_escaped_string(const char *string) { |
278 | char *data; | 310 | char *data; |
279 | int i, j=0; | 311 | int i; |
312 | int j = 0; | ||
280 | data = strdup(string); | 313 | data = strdup(string); |
281 | for (i=0; data[i]; i++) { | 314 | for (i = 0; data[i]; i++) { |
282 | if (data[i] == '\\') { | 315 | if (data[i] == '\\') { |
283 | switch(data[++i]) { | 316 | switch (data[++i]) { |
284 | case 'n': | 317 | case 'n': |
285 | data[j++] = '\n'; | 318 | data[j++] = '\n'; |
286 | break; | 319 | break; |
287 | case 'r': | 320 | case 'r': |
288 | data[j++] = '\r'; | 321 | data[j++] = '\r'; |
289 | break; | 322 | break; |
290 | case 't': | 323 | case 't': |
291 | data[j++] = '\t'; | 324 | data[j++] = '\t'; |
292 | break; | 325 | break; |
293 | case '\\': | 326 | case '\\': |
294 | data[j++] = '\\'; | 327 | data[j++] = '\\'; |
295 | break; | 328 | break; |
296 | default: | 329 | default: |
297 | data[j++] = data[i]; | 330 | data[j++] = data[i]; |
298 | } | 331 | } |
299 | } else { | 332 | } else { |
300 | data[j++] = data[i]; | 333 | data[j++] = data[i]; |
@@ -313,33 +346,41 @@ int np_check_if_root(void) { return (geteuid() == 0); } | |||
313 | * data strings. | 346 | * data strings. |
314 | */ | 347 | */ |
315 | char *np_extract_value(const char *varlist, const char *name, char sep) { | 348 | char *np_extract_value(const char *varlist, const char *name, char sep) { |
316 | char *tmp=NULL, *value=NULL; | 349 | char *tmp = NULL; |
350 | char *value = NULL; | ||
317 | int i; | 351 | int i; |
318 | 352 | ||
319 | while (1) { | 353 | while (1) { |
320 | /* Strip any leading space */ | 354 | /* Strip any leading space */ |
321 | for (; isspace(varlist[0]); varlist++); | 355 | for (; isspace(varlist[0]); varlist++) |
356 | ; | ||
322 | 357 | ||
323 | if (strncmp(name, varlist, strlen(name)) == 0) { | 358 | if (strncmp(name, varlist, strlen(name)) == 0) { |
324 | varlist += strlen(name); | 359 | varlist += strlen(name); |
325 | /* strip trailing spaces */ | 360 | /* strip trailing spaces */ |
326 | for (; isspace(varlist[0]); varlist++); | 361 | for (; isspace(varlist[0]); varlist++) |
362 | ; | ||
327 | 363 | ||
328 | if (varlist[0] == '=') { | 364 | if (varlist[0] == '=') { |
329 | /* We matched the key, go past the = sign */ | 365 | /* We matched the key, go past the = sign */ |
330 | varlist++; | 366 | varlist++; |
331 | /* strip leading spaces */ | 367 | /* strip leading spaces */ |
332 | for (; isspace(varlist[0]); varlist++); | 368 | for (; isspace(varlist[0]); varlist++) |
369 | ; | ||
333 | 370 | ||
334 | if ((tmp = index(varlist, sep))) { | 371 | if ((tmp = index(varlist, sep))) { |
335 | /* Value is delimited by a comma */ | 372 | /* Value is delimited by a comma */ |
336 | if (tmp-varlist == 0) continue; | 373 | if (tmp - varlist == 0) { |
337 | value = (char *)calloc(1, tmp-varlist+1); | 374 | continue; |
338 | strncpy(value, varlist, tmp-varlist); | 375 | } |
339 | value[tmp-varlist] = '\0'; | 376 | value = (char *)calloc(1, tmp - varlist + 1); |
377 | strncpy(value, varlist, tmp - varlist); | ||
378 | value[tmp - varlist] = '\0'; | ||
340 | } else { | 379 | } else { |
341 | /* Value is delimited by a \0 */ | 380 | /* Value is delimited by a \0 */ |
342 | if (strlen(varlist) == 0) continue; | 381 | if (strlen(varlist) == 0) { |
382 | continue; | ||
383 | } | ||
343 | value = (char *)calloc(1, strlen(varlist) + 1); | 384 | value = (char *)calloc(1, strlen(varlist) + 1); |
344 | strncpy(value, varlist, strlen(varlist)); | 385 | strncpy(value, varlist, strlen(varlist)); |
345 | value[strlen(varlist)] = '\0'; | 386 | value[strlen(varlist)] = '\0'; |
@@ -357,14 +398,16 @@ char *np_extract_value(const char *varlist, const char *name, char sep) { | |||
357 | } | 398 | } |
358 | 399 | ||
359 | /* Clean-up trailing spaces/newlines */ | 400 | /* Clean-up trailing spaces/newlines */ |
360 | if (value) for (i=strlen(value)-1; isspace(value[i]); i--) value[i] = '\0'; | 401 | if (value) { |
402 | for (i = strlen(value) - 1; isspace(value[i]); i--) { | ||
403 | value[i] = '\0'; | ||
404 | } | ||
405 | } | ||
361 | 406 | ||
362 | return value; | 407 | return value; |
363 | } | 408 | } |
364 | 409 | ||
365 | const char * | 410 | const char *state_text(int result) { |
366 | state_text (int result) | ||
367 | { | ||
368 | switch (result) { | 411 | switch (result) { |
369 | case STATE_OK: | 412 | case STATE_OK: |
370 | return "OK"; | 413 | return "OK"; |
@@ -383,15 +426,19 @@ state_text (int result) | |||
383 | * Read a string representing a state (ok, warning... or numeric: 0, 1) and | 426 | * Read a string representing a state (ok, warning... or numeric: 0, 1) and |
384 | * return the corresponding STATE_ value or ERROR) | 427 | * return the corresponding STATE_ value or ERROR) |
385 | */ | 428 | */ |
386 | int mp_translate_state (char *state_text) { | 429 | int mp_translate_state(char *state_text) { |
387 | if (!strcasecmp(state_text,"OK") || !strcmp(state_text,"0")) | 430 | if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) { |
388 | return STATE_OK; | 431 | return STATE_OK; |
389 | if (!strcasecmp(state_text,"WARNING") || !strcmp(state_text,"1")) | 432 | } |
433 | if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1")) { | ||
390 | return STATE_WARNING; | 434 | return STATE_WARNING; |
391 | if (!strcasecmp(state_text,"CRITICAL") || !strcmp(state_text,"2")) | 435 | } |
436 | if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2")) { | ||
392 | return STATE_CRITICAL; | 437 | return STATE_CRITICAL; |
393 | if (!strcasecmp(state_text,"UNKNOWN") || !strcmp(state_text,"3")) | 438 | } |
439 | if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3")) { | ||
394 | return STATE_UNKNOWN; | 440 | return STATE_UNKNOWN; |
441 | } | ||
395 | return ERROR; | 442 | return ERROR; |
396 | } | 443 | } |
397 | 444 | ||
@@ -400,11 +447,11 @@ int mp_translate_state (char *state_text) { | |||
400 | * hopefully a unique key per service/plugin invocation. Use the extra-opts | 447 | * hopefully a unique key per service/plugin invocation. Use the extra-opts |
401 | * parse of argv, so that uniqueness in parameters are reflected there. | 448 | * parse of argv, so that uniqueness in parameters are reflected there. |
402 | */ | 449 | */ |
403 | char *_np_state_generate_key() { | 450 | char *_np_state_generate_key(void) { |
404 | int i; | 451 | int i; |
405 | char **argv = this_monitoring_plugin->argv; | 452 | char **argv = this_monitoring_plugin->argv; |
406 | char keyname[41]; | 453 | char keyname[41]; |
407 | char *p=NULL; | 454 | char *p = NULL; |
408 | 455 | ||
409 | unsigned char result[256]; | 456 | unsigned char result[256]; |
410 | 457 | ||
@@ -418,7 +465,7 @@ char *_np_state_generate_key() { | |||
418 | 465 | ||
419 | EVP_DigestInit(ctx, EVP_sha256()); | 466 | EVP_DigestInit(ctx, EVP_sha256()); |
420 | 467 | ||
421 | for(i=0; i<this_monitoring_plugin->argc; i++) { | 468 | for (i = 0; i < this_monitoring_plugin->argc; i++) { |
422 | EVP_DigestUpdate(ctx, argv[i], strlen(argv[i])); | 469 | EVP_DigestUpdate(ctx, argv[i], strlen(argv[i])); |
423 | } | 470 | } |
424 | 471 | ||
@@ -427,28 +474,28 @@ char *_np_state_generate_key() { | |||
427 | 474 | ||
428 | struct sha256_ctx ctx; | 475 | struct sha256_ctx ctx; |
429 | 476 | ||
430 | for(i=0; i<this_monitoring_plugin->argc; i++) { | 477 | for (i = 0; i < this_monitoring_plugin->argc; i++) { |
431 | sha256_process_bytes(argv[i], strlen(argv[i]), &ctx); | 478 | sha256_process_bytes(argv[i], strlen(argv[i]), &ctx); |
432 | } | 479 | } |
433 | 480 | ||
434 | sha256_finish_ctx(&ctx, result); | 481 | sha256_finish_ctx(&ctx, result); |
435 | #endif // FOUNDOPENSSL | 482 | #endif // FOUNDOPENSSL |
436 | 483 | ||
437 | for (i=0; i<20; ++i) { | 484 | for (i = 0; i < 20; ++i) { |
438 | sprintf(&keyname[2*i], "%02x", result[i]); | 485 | sprintf(&keyname[2 * i], "%02x", result[i]); |
439 | } | 486 | } |
440 | 487 | ||
441 | keyname[40]='\0'; | 488 | keyname[40] = '\0'; |
442 | 489 | ||
443 | p = strdup(keyname); | 490 | p = strdup(keyname); |
444 | if(p==NULL) { | 491 | if (p == NULL) { |
445 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | 492 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); |
446 | } | 493 | } |
447 | return p; | 494 | return p; |
448 | } | 495 | } |
449 | 496 | ||
450 | void _cleanup_state_data() { | 497 | void _cleanup_state_data(void) { |
451 | if (this_monitoring_plugin->state->state_data!=NULL) { | 498 | if (this_monitoring_plugin->state->state_data != NULL) { |
452 | np_free(this_monitoring_plugin->state->state_data->data); | 499 | np_free(this_monitoring_plugin->state->state_data->data); |
453 | np_free(this_monitoring_plugin->state->state_data); | 500 | np_free(this_monitoring_plugin->state->state_data); |
454 | } | 501 | } |
@@ -459,19 +506,21 @@ void _cleanup_state_data() { | |||
459 | * envvar NAGIOS_PLUGIN_STATE_DIRECTORY | 506 | * envvar NAGIOS_PLUGIN_STATE_DIRECTORY |
460 | * statically compiled shared state directory | 507 | * statically compiled shared state directory |
461 | */ | 508 | */ |
462 | char* _np_state_calculate_location_prefix(){ | 509 | char *_np_state_calculate_location_prefix(void) { |
463 | char *env_dir; | 510 | char *env_dir; |
464 | 511 | ||
465 | /* Do not allow passing MP_STATE_PATH in setuid plugins | 512 | /* Do not allow passing MP_STATE_PATH in setuid plugins |
466 | * for security reasons */ | 513 | * for security reasons */ |
467 | if (!mp_suid()) { | 514 | if (!mp_suid()) { |
468 | env_dir = getenv("MP_STATE_PATH"); | 515 | env_dir = getenv("MP_STATE_PATH"); |
469 | if(env_dir && env_dir[0] != '\0') | 516 | if (env_dir && env_dir[0] != '\0') { |
470 | return env_dir; | 517 | return env_dir; |
518 | } | ||
471 | /* This is the former ENV, for backward-compatibility */ | 519 | /* This is the former ENV, for backward-compatibility */ |
472 | env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY"); | 520 | env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY"); |
473 | if(env_dir && env_dir[0] != '\0') | 521 | if (env_dir && env_dir[0] != '\0') { |
474 | return env_dir; | 522 | return env_dir; |
523 | } | ||
475 | } | 524 | } |
476 | 525 | ||
477 | return NP_STATE_DIR_PREFIX; | 526 | return NP_STATE_DIR_PREFIX; |
@@ -486,46 +535,47 @@ void np_enable_state(char *keyname, int expected_data_version) { | |||
486 | state_key *this_state = NULL; | 535 | state_key *this_state = NULL; |
487 | char *temp_filename = NULL; | 536 | char *temp_filename = NULL; |
488 | char *temp_keyname = NULL; | 537 | char *temp_keyname = NULL; |
489 | char *p=NULL; | 538 | char *p = NULL; |
490 | int ret; | 539 | int ret; |
491 | 540 | ||
492 | if(this_monitoring_plugin==NULL) | 541 | if (this_monitoring_plugin == NULL) { |
493 | die(STATE_UNKNOWN, _("This requires np_init to be called")); | 542 | die(STATE_UNKNOWN, _("This requires np_init to be called")); |
543 | } | ||
494 | 544 | ||
495 | this_state = (state_key *) calloc(1, sizeof(state_key)); | 545 | this_state = (state_key *)calloc(1, sizeof(state_key)); |
496 | if(this_state==NULL) | 546 | if (this_state == NULL) { |
497 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 547 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
498 | strerror(errno)); | 548 | } |
499 | 549 | ||
500 | if(keyname==NULL) { | 550 | if (keyname == NULL) { |
501 | temp_keyname = _np_state_generate_key(); | 551 | temp_keyname = _np_state_generate_key(); |
502 | } else { | 552 | } else { |
503 | temp_keyname = strdup(keyname); | 553 | temp_keyname = strdup(keyname); |
504 | if(temp_keyname==NULL) | 554 | if (temp_keyname == NULL) { |
505 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | 555 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); |
556 | } | ||
506 | } | 557 | } |
507 | /* Die if invalid characters used for keyname */ | 558 | /* Die if invalid characters used for keyname */ |
508 | p = temp_keyname; | 559 | p = temp_keyname; |
509 | while(*p!='\0') { | 560 | while (*p != '\0') { |
510 | if(! (isalnum(*p) || *p == '_')) { | 561 | if (!(isalnum(*p) || *p == '_')) { |
511 | die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'")); | 562 | die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'")); |
512 | } | 563 | } |
513 | p++; | 564 | p++; |
514 | } | 565 | } |
515 | this_state->name=temp_keyname; | 566 | this_state->name = temp_keyname; |
516 | this_state->plugin_name=this_monitoring_plugin->plugin_name; | 567 | this_state->plugin_name = this_monitoring_plugin->plugin_name; |
517 | this_state->data_version=expected_data_version; | 568 | this_state->data_version = expected_data_version; |
518 | this_state->state_data=NULL; | 569 | this_state->state_data = NULL; |
519 | 570 | ||
520 | /* Calculate filename */ | 571 | /* Calculate filename */ |
521 | ret = asprintf(&temp_filename, "%s/%lu/%s/%s", | 572 | ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(), |
522 | _np_state_calculate_location_prefix(), (unsigned long)geteuid(), | 573 | this_monitoring_plugin->plugin_name, this_state->name); |
523 | this_monitoring_plugin->plugin_name, this_state->name); | 574 | if (ret < 0) { |
524 | if (ret < 0) | 575 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
525 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 576 | } |
526 | strerror(errno)); | ||
527 | 577 | ||
528 | this_state->_filename=temp_filename; | 578 | this_state->_filename = temp_filename; |
529 | 579 | ||
530 | this_monitoring_plugin->state = this_state; | 580 | this_monitoring_plugin->state = this_state; |
531 | } | 581 | } |
@@ -537,24 +587,25 @@ void np_enable_state(char *keyname, int expected_data_version) { | |||
537 | * If numerically lower, then return as no previous state. die with UNKNOWN | 587 | * If numerically lower, then return as no previous state. die with UNKNOWN |
538 | * if exceptional error. | 588 | * if exceptional error. |
539 | */ | 589 | */ |
540 | state_data *np_state_read() { | 590 | state_data *np_state_read(void) { |
541 | state_data *this_state_data=NULL; | 591 | state_data *this_state_data = NULL; |
542 | FILE *statefile; | 592 | FILE *statefile; |
543 | bool rc = false; | 593 | bool rc = false; |
544 | 594 | ||
545 | if(this_monitoring_plugin==NULL) | 595 | if (this_monitoring_plugin == NULL) { |
546 | die(STATE_UNKNOWN, _("This requires np_init to be called")); | 596 | die(STATE_UNKNOWN, _("This requires np_init to be called")); |
597 | } | ||
547 | 598 | ||
548 | /* Open file. If this fails, no previous state found */ | 599 | /* Open file. If this fails, no previous state found */ |
549 | statefile = fopen( this_monitoring_plugin->state->_filename, "r" ); | 600 | statefile = fopen(this_monitoring_plugin->state->_filename, "r"); |
550 | if(statefile!=NULL) { | 601 | if (statefile != NULL) { |
551 | 602 | ||
552 | this_state_data = (state_data *) calloc(1, sizeof(state_data)); | 603 | this_state_data = (state_data *)calloc(1, sizeof(state_data)); |
553 | if(this_state_data==NULL) | 604 | if (this_state_data == NULL) { |
554 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 605 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
555 | strerror(errno)); | 606 | } |
556 | 607 | ||
557 | this_state_data->data=NULL; | 608 | this_state_data->data = NULL; |
558 | this_monitoring_plugin->state->state_data = this_state_data; | 609 | this_monitoring_plugin->state->state_data = this_state_data; |
559 | 610 | ||
560 | rc = _np_state_read_file(statefile); | 611 | rc = _np_state_read_file(statefile); |
@@ -562,7 +613,7 @@ state_data *np_state_read() { | |||
562 | fclose(statefile); | 613 | fclose(statefile); |
563 | } | 614 | } |
564 | 615 | ||
565 | if(!rc) { | 616 | if (!rc) { |
566 | _cleanup_state_data(); | 617 | _cleanup_state_data(); |
567 | } | 618 | } |
568 | 619 | ||
@@ -577,60 +628,70 @@ bool _np_state_read_file(FILE *f) { | |||
577 | size_t pos; | 628 | size_t pos; |
578 | char *line; | 629 | char *line; |
579 | int i; | 630 | int i; |
580 | int failure=0; | 631 | int failure = 0; |
581 | time_t current_time, data_time; | 632 | time_t current_time, data_time; |
582 | enum { STATE_FILE_VERSION, STATE_DATA_VERSION, STATE_DATA_TIME, STATE_DATA_TEXT, STATE_DATA_END } expected=STATE_FILE_VERSION; | 633 | enum { |
634 | STATE_FILE_VERSION, | ||
635 | STATE_DATA_VERSION, | ||
636 | STATE_DATA_TIME, | ||
637 | STATE_DATA_TEXT, | ||
638 | STATE_DATA_END | ||
639 | } expected = STATE_FILE_VERSION; | ||
583 | 640 | ||
584 | time(¤t_time); | 641 | time(¤t_time); |
585 | 642 | ||
586 | /* Note: This introduces a limit of 1024 bytes in the string data */ | 643 | /* Note: This introduces a limit of 1024 bytes in the string data */ |
587 | line = (char *) calloc(1, 1024); | 644 | line = (char *)calloc(1, 1024); |
588 | if(line==NULL) | 645 | if (line == NULL) { |
589 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 646 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
590 | strerror(errno)); | 647 | } |
591 | 648 | ||
592 | while(!failure && (fgets(line,1024,f))!=NULL){ | 649 | while (!failure && (fgets(line, 1024, f)) != NULL) { |
593 | pos=strlen(line); | 650 | pos = strlen(line); |
594 | if(line[pos-1]=='\n') { | 651 | if (line[pos - 1] == '\n') { |
595 | line[pos-1]='\0'; | 652 | line[pos - 1] = '\0'; |
596 | } | 653 | } |
597 | 654 | ||
598 | if(line[0] == '#') continue; | 655 | if (line[0] == '#') { |
656 | continue; | ||
657 | } | ||
599 | 658 | ||
600 | switch(expected) { | 659 | switch (expected) { |
601 | case STATE_FILE_VERSION: | 660 | case STATE_FILE_VERSION: |
602 | i=atoi(line); | 661 | i = atoi(line); |
603 | if(i!=NP_STATE_FORMAT_VERSION) | 662 | if (i != NP_STATE_FORMAT_VERSION) { |
604 | failure++; | 663 | failure++; |
605 | else | 664 | } else { |
606 | expected=STATE_DATA_VERSION; | 665 | expected = STATE_DATA_VERSION; |
607 | break; | 666 | } |
608 | case STATE_DATA_VERSION: | 667 | break; |
609 | i=atoi(line); | 668 | case STATE_DATA_VERSION: |
610 | if(i != this_monitoring_plugin->state->data_version) | 669 | i = atoi(line); |
611 | failure++; | 670 | if (i != this_monitoring_plugin->state->data_version) { |
612 | else | 671 | failure++; |
613 | expected=STATE_DATA_TIME; | 672 | } else { |
614 | break; | 673 | expected = STATE_DATA_TIME; |
615 | case STATE_DATA_TIME: | 674 | } |
616 | /* If time > now, error */ | 675 | break; |
617 | data_time=strtoul(line,NULL,10); | 676 | case STATE_DATA_TIME: |
618 | if(data_time > current_time) | 677 | /* If time > now, error */ |
619 | failure++; | 678 | data_time = strtoul(line, NULL, 10); |
620 | else { | 679 | if (data_time > current_time) { |
621 | this_monitoring_plugin->state->state_data->time = data_time; | 680 | failure++; |
622 | expected=STATE_DATA_TEXT; | 681 | } else { |
623 | } | 682 | this_monitoring_plugin->state->state_data->time = data_time; |
624 | break; | 683 | expected = STATE_DATA_TEXT; |
625 | case STATE_DATA_TEXT: | 684 | } |
626 | this_monitoring_plugin->state->state_data->data = strdup(line); | 685 | break; |
627 | if(this_monitoring_plugin->state->state_data->data==NULL) | 686 | case STATE_DATA_TEXT: |
628 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | 687 | this_monitoring_plugin->state->state_data->data = strdup(line); |
629 | expected=STATE_DATA_END; | 688 | if (this_monitoring_plugin->state->state_data->data == NULL) { |
630 | status=true; | 689 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); |
631 | break; | 690 | } |
632 | case STATE_DATA_END: | 691 | expected = STATE_DATA_END; |
633 | ; | 692 | status = true; |
693 | break; | ||
694 | case STATE_DATA_END:; | ||
634 | } | 695 | } |
635 | } | 696 | } |
636 | 697 | ||
@@ -647,77 +708,78 @@ bool _np_state_read_file(FILE *f) { | |||
647 | */ | 708 | */ |
648 | void np_state_write_string(time_t data_time, char *data_string) { | 709 | void np_state_write_string(time_t data_time, char *data_string) { |
649 | FILE *fp; | 710 | FILE *fp; |
650 | char *temp_file=NULL; | 711 | char *temp_file = NULL; |
651 | int fd=0, result=0; | 712 | int fd = 0, result = 0; |
652 | time_t current_time; | 713 | time_t current_time; |
653 | char *directories=NULL; | 714 | char *directories = NULL; |
654 | char *p=NULL; | 715 | char *p = NULL; |
655 | 716 | ||
656 | if(data_time==0) | 717 | if (data_time == 0) { |
657 | time(¤t_time); | 718 | time(¤t_time); |
658 | else | 719 | } else { |
659 | current_time=data_time; | 720 | current_time = data_time; |
721 | } | ||
660 | 722 | ||
661 | /* If file doesn't currently exist, create directories */ | 723 | /* If file doesn't currently exist, create directories */ |
662 | if(access(this_monitoring_plugin->state->_filename,F_OK)!=0) { | 724 | if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) { |
663 | result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename); | 725 | result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename); |
664 | if(result < 0) | 726 | if (result < 0) { |
665 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 727 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
666 | strerror(errno)); | 728 | } |
667 | 729 | ||
668 | for(p=directories+1; *p; p++) { | 730 | for (p = directories + 1; *p; p++) { |
669 | if(*p=='/') { | 731 | if (*p == '/') { |
670 | *p='\0'; | 732 | *p = '\0'; |
671 | if((access(directories,F_OK)!=0) && (mkdir(directories, S_IRWXU)!=0)) { | 733 | if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) { |
672 | /* Can't free this! Otherwise error message is wrong! */ | 734 | /* Can't free this! Otherwise error message is wrong! */ |
673 | /* np_free(directories); */ | 735 | /* np_free(directories); */ |
674 | die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories); | 736 | die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories); |
675 | } | 737 | } |
676 | *p='/'; | 738 | *p = '/'; |
677 | } | 739 | } |
678 | } | 740 | } |
679 | np_free(directories); | 741 | np_free(directories); |
680 | } | 742 | } |
681 | 743 | ||
682 | result = asprintf(&temp_file,"%s.XXXXXX",this_monitoring_plugin->state->_filename); | 744 | result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename); |
683 | if(result < 0) | 745 | if (result < 0) { |
684 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 746 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
685 | strerror(errno)); | 747 | } |
686 | 748 | ||
687 | if((fd=mkstemp(temp_file))==-1) { | 749 | if ((fd = mkstemp(temp_file)) == -1) { |
688 | np_free(temp_file); | 750 | np_free(temp_file); |
689 | die(STATE_UNKNOWN, _("Cannot create temporary filename")); | 751 | die(STATE_UNKNOWN, _("Cannot create temporary filename")); |
690 | } | 752 | } |
691 | 753 | ||
692 | fp=(FILE *)fdopen(fd,"w"); | 754 | fp = (FILE *)fdopen(fd, "w"); |
693 | if(fp==NULL) { | 755 | if (fp == NULL) { |
694 | close(fd); | 756 | close(fd); |
695 | unlink(temp_file); | 757 | unlink(temp_file); |
696 | np_free(temp_file); | 758 | np_free(temp_file); |
697 | die(STATE_UNKNOWN, _("Unable to open temporary state file")); | 759 | die(STATE_UNKNOWN, _("Unable to open temporary state file")); |
698 | } | 760 | } |
699 | 761 | ||
700 | fprintf(fp,"# NP State file\n"); | 762 | fprintf(fp, "# NP State file\n"); |
701 | fprintf(fp,"%d\n",NP_STATE_FORMAT_VERSION); | 763 | fprintf(fp, "%d\n", NP_STATE_FORMAT_VERSION); |
702 | fprintf(fp,"%d\n",this_monitoring_plugin->state->data_version); | 764 | fprintf(fp, "%d\n", this_monitoring_plugin->state->data_version); |
703 | fprintf(fp,"%lu\n",current_time); | 765 | fprintf(fp, "%lu\n", current_time); |
704 | fprintf(fp,"%s\n",data_string); | 766 | fprintf(fp, "%s\n", data_string); |
705 | 767 | ||
706 | fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP); | 768 | fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP); |
707 | 769 | ||
708 | fflush(fp); | 770 | fflush(fp); |
709 | 771 | ||
710 | result=fclose(fp); | 772 | result = fclose(fp); |
711 | 773 | ||
712 | fsync(fd); | 774 | fsync(fd); |
713 | 775 | ||
714 | if(result!=0) { | 776 | if (result != 0) { |
715 | unlink(temp_file); | 777 | unlink(temp_file); |
716 | np_free(temp_file); | 778 | np_free(temp_file); |
717 | die(STATE_UNKNOWN, _("Error writing temp file")); | 779 | die(STATE_UNKNOWN, _("Error writing temp file")); |
718 | } | 780 | } |
719 | 781 | ||
720 | if(rename(temp_file, this_monitoring_plugin->state->_filename)!=0) { | 782 | if (rename(temp_file, this_monitoring_plugin->state->_filename) != 0) { |
721 | unlink(temp_file); | 783 | unlink(temp_file); |
722 | np_free(temp_file); | 784 | np_free(temp_file); |
723 | die(STATE_UNKNOWN, _("Cannot rename state temp file")); | 785 | die(STATE_UNKNOWN, _("Cannot rename state temp file")); |
diff --git a/lib/utils_base.h b/lib/utils_base.h index 9d4dffed..123066f8 100644 --- a/lib/utils_base.h +++ b/lib/utils_base.h | |||
@@ -2,8 +2,15 @@ | |||
2 | #define _UTILS_BASE_ | 2 | #define _UTILS_BASE_ |
3 | /* Header file for Monitoring Plugins utils_base.c */ | 3 | /* Header file for Monitoring Plugins utils_base.c */ |
4 | 4 | ||
5 | #include "../config.h" | ||
6 | #include <time.h> | ||
7 | |||
8 | #include "./perfdata.h" | ||
9 | #include "./thresholds.h" | ||
10 | |||
11 | |||
5 | #ifndef USE_OPENSSL | 12 | #ifndef USE_OPENSSL |
6 | # include "sha256.h" | 13 | # include "sha256.h" |
7 | #endif | 14 | #endif |
8 | 15 | ||
9 | /* This file holds header information for thresholds - use this in preference to | 16 | /* This file holds header information for thresholds - use this in preference to |
@@ -19,49 +26,35 @@ | |||
19 | #define OUTSIDE 0 | 26 | #define OUTSIDE 0 |
20 | #define INSIDE 1 | 27 | #define INSIDE 1 |
21 | 28 | ||
22 | typedef 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 | |||
31 | typedef struct thresholds_struct { | ||
32 | range *warning; | ||
33 | range *critical; | ||
34 | } thresholds; | ||
35 | |||
36 | #define NP_STATE_FORMAT_VERSION 1 | 29 | #define NP_STATE_FORMAT_VERSION 1 |
37 | 30 | ||
38 | typedef struct state_data_struct { | 31 | typedef struct state_data_struct { |
39 | time_t time; | 32 | time_t time; |
40 | void *data; | 33 | void *data; |
41 | int length; /* Of binary data */ | 34 | int length; /* Of binary data */ |
42 | } state_data; | 35 | } state_data; |
43 | |||
44 | 36 | ||
45 | typedef struct state_key_struct { | 37 | typedef struct state_key_struct { |
46 | char *name; | 38 | char *name; |
47 | char *plugin_name; | 39 | char *plugin_name; |
48 | int data_version; | 40 | int data_version; |
49 | char *_filename; | 41 | char *_filename; |
50 | state_data *state_data; | 42 | state_data *state_data; |
51 | } state_key; | 43 | } state_key; |
52 | 44 | ||
53 | typedef struct np_struct { | 45 | typedef struct np_struct { |
54 | char *plugin_name; | 46 | char *plugin_name; |
55 | state_key *state; | 47 | state_key *state; |
56 | int argc; | 48 | int argc; |
57 | char **argv; | 49 | char **argv; |
58 | } monitoring_plugin; | 50 | } monitoring_plugin; |
59 | 51 | ||
60 | range *parse_range_string (char *); | 52 | range *parse_range_string(char *); |
61 | int _set_thresholds(thresholds **, char *, char *); | 53 | int _set_thresholds(thresholds **, char *, char *); |
62 | void set_thresholds(thresholds **, char *, char *); | 54 | void set_thresholds(thresholds **, char *, char *); |
63 | void print_thresholds(const char *, thresholds *); | 55 | void print_thresholds(const char *, thresholds *); |
64 | bool check_range(double, range *); | 56 | bool check_range(double, range *); |
57 | bool mp_check_range(mp_perfdata_value, mp_range); | ||
65 | int get_status(double, thresholds *); | 58 | int get_status(double, thresholds *); |
66 | 59 | ||
67 | /* Handle timeouts */ | 60 | /* Handle timeouts */ |
@@ -71,13 +64,13 @@ extern unsigned int timeout_interval; | |||
71 | /* All possible characters in a threshold range */ | 64 | /* All possible characters in a threshold range */ |
72 | #define NP_THRESHOLDS_CHARS "-0123456789.:@~" | 65 | #define NP_THRESHOLDS_CHARS "-0123456789.:@~" |
73 | 66 | ||
74 | char *np_escaped_string (const char *); | 67 | char *np_escaped_string(const char *); |
75 | 68 | ||
76 | void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); | 69 | void die(int, const char *, ...) __attribute__((noreturn, format(printf, 2, 3))); |
77 | 70 | ||
78 | /* Return codes for _set_thresholds */ | 71 | /* Return codes for _set_thresholds */ |
79 | #define NP_RANGE_UNPARSEABLE 1 | 72 | #define NP_RANGE_UNPARSEABLE 1 |
80 | #define NP_WARN_WITHIN_CRIT 2 | 73 | #define NP_WARN_WITHIN_CRIT 2 |
81 | 74 | ||
82 | /* a simple check to see if we're running as root. | 75 | /* a simple check to see if we're running as root. |
83 | * returns zero on failure, nonzero on success */ | 76 | * returns zero on failure, nonzero on success */ |
@@ -93,7 +86,7 @@ int np_check_if_root(void); | |||
93 | * This function can be used to parse NTP control packet data and performance | 86 | * This function can be used to parse NTP control packet data and performance |
94 | * data strings. | 87 | * data strings. |
95 | */ | 88 | */ |
96 | char *np_extract_value(const char*, const char*, char); | 89 | char *np_extract_value(const char *, const char *, char); |
97 | 90 | ||
98 | /* | 91 | /* |
99 | * Same as np_extract_value with separator suitable for NTP control packet | 92 | * Same as np_extract_value with separator suitable for NTP control packet |
@@ -105,15 +98,15 @@ char *np_extract_value(const char*, const char*, char); | |||
105 | * Read a string representing a state (ok, warning... or numeric: 0, 1) and | 98 | * Read a string representing a state (ok, warning... or numeric: 0, 1) and |
106 | * return the corresponding NP_STATE or ERROR) | 99 | * return the corresponding NP_STATE or ERROR) |
107 | */ | 100 | */ |
108 | int mp_translate_state (char *); | 101 | int mp_translate_state(char *); |
109 | 102 | ||
110 | void np_enable_state(char *, int); | 103 | void np_enable_state(char *, int); |
111 | state_data *np_state_read(); | 104 | state_data *np_state_read(void); |
112 | void np_state_write_string(time_t, char *); | 105 | void np_state_write_string(time_t, char *); |
113 | 106 | ||
114 | void np_init(char *, int argc, char **argv); | 107 | void np_init(char *, int argc, char **argv); |
115 | void np_set_args(int argc, char **argv); | 108 | void np_set_args(int argc, char **argv); |
116 | void np_cleanup(); | 109 | void np_cleanup(void); |
117 | const char *state_text (int); | 110 | const char *state_text(int); |
118 | 111 | ||
119 | #endif /* _UTILS_BASE_ */ | 112 | #endif /* _UTILS_BASE_ */ |
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c index 7957ec14..18350ac0 100644 --- a/lib/utils_cmd.c +++ b/lib/utils_cmd.c | |||
@@ -1,40 +1,40 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Monitoring run command utilities | 3 | * Monitoring run command utilities |
4 | * | 4 | * |
5 | * License: GPL | 5 | * License: GPL |
6 | * Copyright (c) 2005-2006 Monitoring Plugins Development Team | 6 | * Copyright (c) 2005-2024 Monitoring Plugins Development Team |
7 | * | 7 | * |
8 | * Description : | 8 | * Description : |
9 | * | 9 | * |
10 | * A simple interface to executing programs from other programs, using an | 10 | * A simple interface to executing programs from other programs, using an |
11 | * optimized and safe popen()-like implementation. It is considered safe | 11 | * optimized and safe popen()-like implementation. It is considered safe |
12 | * in that no shell needs to be spawned and the environment passed to the | 12 | * in that no shell needs to be spawned and the environment passed to the |
13 | * execve()'d program is essentially empty. | 13 | * execve()'d program is essentially empty. |
14 | * | 14 | * |
15 | * The code in this file is a derivative of popen.c which in turn was taken | 15 | * The code in this file is a derivative of popen.c which in turn was taken |
16 | * from "Advanced Programming for the Unix Environment" by W. Richard Stevens. | 16 | * from "Advanced Programming for the Unix Environment" by W. Richard Stevens. |
17 | * | 17 | * |
18 | * Care has been taken to make sure the functions are async-safe. The one | 18 | * Care has been taken to make sure the functions are async-safe. The one |
19 | * function which isn't is cmd_init() which it doesn't make sense to | 19 | * function which isn't is cmd_init() which it doesn't make sense to |
20 | * call twice anyway, so the api as a whole should be considered async-safe. | 20 | * call twice anyway, so the api as a whole should be considered async-safe. |
21 | * | 21 | * |
22 | * | 22 | * |
23 | * This program is free software: you can redistribute it and/or modify | 23 | * This program is free software: you can redistribute it and/or modify |
24 | * it under the terms of the GNU General Public License as published by | 24 | * it under the terms of the GNU General Public License as published by |
25 | * the Free Software Foundation, either version 3 of the License, or | 25 | * the Free Software Foundation, either version 3 of the License, or |
26 | * (at your option) any later version. | 26 | * (at your option) any later version. |
27 | * | 27 | * |
28 | * This program is distributed in the hope that it will be useful, | 28 | * This program is distributed in the hope that it will be useful, |
29 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 29 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 30 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | * GNU General Public License for more details. | 31 | * GNU General Public License for more details. |
32 | * | 32 | * |
33 | * You should have received a copy of the GNU General Public License | 33 | * You should have received a copy of the GNU General Public License |
34 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 34 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
35 | * | 35 | * |
36 | * | 36 | * |
37 | *****************************************************************************/ | 37 | *****************************************************************************/ |
38 | 38 | ||
39 | #define NAGIOSPLUG_API_C 1 | 39 | #define NAGIOSPLUG_API_C 1 |
40 | 40 | ||
@@ -59,7 +59,7 @@ static pid_t *_cmd_pids = NULL; | |||
59 | #include <fcntl.h> | 59 | #include <fcntl.h> |
60 | 60 | ||
61 | #ifdef HAVE_SYS_WAIT_H | 61 | #ifdef HAVE_SYS_WAIT_H |
62 | # include <sys/wait.h> | 62 | # include <sys/wait.h> |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | /* used in _cmd_open to pass the environment to commands */ | 65 | /* used in _cmd_open to pass the environment to commands */ |
@@ -67,57 +67,48 @@ extern char **environ; | |||
67 | 67 | ||
68 | /** macros **/ | 68 | /** macros **/ |
69 | #ifndef WEXITSTATUS | 69 | #ifndef WEXITSTATUS |
70 | # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) | 70 | # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | #ifndef WIFEXITED | 73 | #ifndef WIFEXITED |
74 | # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) | 74 | # define WIFEXITED(stat_val) (((stat_val)&255) == 0) |
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | /* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ | 77 | /* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ |
78 | #if defined(SIG_IGN) && !defined(SIG_ERR) | 78 | #if defined(SIG_IGN) && !defined(SIG_ERR) |
79 | # define SIG_ERR ((Sigfunc *)-1) | 79 | # define SIG_ERR ((Sigfunc *)-1) |
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | /** prototypes **/ | 82 | /** prototypes **/ |
83 | static int _cmd_open (char *const *, int *, int *) | 83 | static int _cmd_open(char *const *, int *, int *) __attribute__((__nonnull__(1, 2, 3))); |
84 | __attribute__ ((__nonnull__ (1, 2, 3))); | ||
85 | 84 | ||
86 | static int _cmd_fetch_output (int, output *, int) | 85 | static int _cmd_fetch_output(int, output *, int) __attribute__((__nonnull__(2))); |
87 | __attribute__ ((__nonnull__ (2))); | ||
88 | 86 | ||
89 | static int _cmd_close (int); | 87 | static int _cmd_close(int); |
90 | 88 | ||
91 | /* prototype imported from utils.h */ | 89 | /* prototype imported from utils.h */ |
92 | extern void die (int, const char *, ...) | 90 | extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3))); |
93 | __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3))); | ||
94 | |||
95 | 91 | ||
96 | /* this function is NOT async-safe. It is exported so multithreaded | 92 | /* this function is NOT async-safe. It is exported so multithreaded |
97 | * plugins (or other apps) can call it prior to running any commands | 93 | * plugins (or other apps) can call it prior to running any commands |
98 | * through this api and thus achieve async-safeness throughout the api */ | 94 | * through this api and thus achieve async-safeness throughout the api */ |
99 | void | 95 | void cmd_init(void) { |
100 | cmd_init (void) | ||
101 | { | ||
102 | long maxfd = mp_open_max(); | 96 | long maxfd = mp_open_max(); |
103 | 97 | ||
104 | /* if maxfd is unnaturally high, we force it to a lower value | 98 | /* if maxfd is unnaturally high, we force it to a lower value |
105 | * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause | 99 | * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause |
106 | * a segfault when following calloc is called ... ) */ | 100 | * a segfault when following calloc is called ... ) */ |
107 | 101 | ||
108 | if ( maxfd > MAXFD_LIMIT ) { | 102 | if (maxfd > MAXFD_LIMIT) { |
109 | maxfd = MAXFD_LIMIT; | 103 | maxfd = MAXFD_LIMIT; |
110 | } | 104 | } |
111 | 105 | ||
112 | if (!_cmd_pids) | 106 | if (!_cmd_pids) |
113 | _cmd_pids = calloc (maxfd, sizeof (pid_t)); | 107 | _cmd_pids = calloc(maxfd, sizeof(pid_t)); |
114 | } | 108 | } |
115 | 109 | ||
116 | |||
117 | /* Start running a command, array style */ | 110 | /* Start running a command, array style */ |
118 | static int | 111 | static int _cmd_open(char *const *argv, int *pfd, int *pfderr) { |
119 | _cmd_open (char *const *argv, int *pfd, int *pfderr) | ||
120 | { | ||
121 | pid_t pid; | 112 | pid_t pid; |
122 | #ifdef RLIMIT_CORE | 113 | #ifdef RLIMIT_CORE |
123 | struct rlimit limit; | 114 | struct rlimit limit; |
@@ -130,26 +121,26 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr) | |||
130 | 121 | ||
131 | setenv("LC_ALL", "C", 1); | 122 | setenv("LC_ALL", "C", 1); |
132 | 123 | ||
133 | if (pipe (pfd) < 0 || pipe (pfderr) < 0 || (pid = fork ()) < 0) | 124 | if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) |
134 | return -1; /* errno set by the failing function */ | 125 | return -1; /* errno set by the failing function */ |
135 | 126 | ||
136 | /* child runs exceve() and _exit. */ | 127 | /* child runs exceve() and _exit. */ |
137 | if (pid == 0) { | 128 | if (pid == 0) { |
138 | #ifdef RLIMIT_CORE | 129 | #ifdef RLIMIT_CORE |
139 | /* the program we execve shouldn't leave core files */ | 130 | /* the program we execve shouldn't leave core files */ |
140 | getrlimit (RLIMIT_CORE, &limit); | 131 | getrlimit(RLIMIT_CORE, &limit); |
141 | limit.rlim_cur = 0; | 132 | limit.rlim_cur = 0; |
142 | setrlimit (RLIMIT_CORE, &limit); | 133 | setrlimit(RLIMIT_CORE, &limit); |
143 | #endif | 134 | #endif |
144 | close (pfd[0]); | 135 | close(pfd[0]); |
145 | if (pfd[1] != STDOUT_FILENO) { | 136 | if (pfd[1] != STDOUT_FILENO) { |
146 | dup2 (pfd[1], STDOUT_FILENO); | 137 | dup2(pfd[1], STDOUT_FILENO); |
147 | close (pfd[1]); | 138 | close(pfd[1]); |
148 | } | 139 | } |
149 | close (pfderr[0]); | 140 | close(pfderr[0]); |
150 | if (pfderr[1] != STDERR_FILENO) { | 141 | if (pfderr[1] != STDERR_FILENO) { |
151 | dup2 (pfderr[1], STDERR_FILENO); | 142 | dup2(pfderr[1], STDERR_FILENO); |
152 | close (pfderr[1]); | 143 | close(pfderr[1]); |
153 | } | 144 | } |
154 | 145 | ||
155 | /* close all descriptors in _cmd_pids[] | 146 | /* close all descriptors in _cmd_pids[] |
@@ -158,16 +149,16 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr) | |||
158 | long maxfd = mp_open_max(); | 149 | long maxfd = mp_open_max(); |
159 | for (i = 0; i < maxfd; i++) | 150 | for (i = 0; i < maxfd; i++) |
160 | if (_cmd_pids[i] > 0) | 151 | if (_cmd_pids[i] > 0) |
161 | close (i); | 152 | close(i); |
162 | 153 | ||
163 | execve (argv[0], argv, environ); | 154 | execve(argv[0], argv, environ); |
164 | _exit (STATE_UNKNOWN); | 155 | _exit(STATE_UNKNOWN); |
165 | } | 156 | } |
166 | 157 | ||
167 | /* parent picks up execution here */ | 158 | /* parent picks up execution here */ |
168 | /* close children descriptors in our address space */ | 159 | /* close children descriptors in our address space */ |
169 | close (pfd[1]); | 160 | close(pfd[1]); |
170 | close (pfderr[1]); | 161 | close(pfderr[1]); |
171 | 162 | ||
172 | /* tag our file's entry in the pid-list and return it */ | 163 | /* tag our file's entry in the pid-list and return it */ |
173 | _cmd_pids[pfd[0]] = pid; | 164 | _cmd_pids[pfd[0]] = pid; |
@@ -175,9 +166,7 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr) | |||
175 | return pfd[0]; | 166 | return pfd[0]; |
176 | } | 167 | } |
177 | 168 | ||
178 | static int | 169 | static int _cmd_close(int fd) { |
179 | _cmd_close (int fd) | ||
180 | { | ||
181 | int status; | 170 | int status; |
182 | pid_t pid; | 171 | pid_t pid; |
183 | 172 | ||
@@ -187,40 +176,37 @@ _cmd_close (int fd) | |||
187 | return -1; | 176 | return -1; |
188 | 177 | ||
189 | _cmd_pids[fd] = 0; | 178 | _cmd_pids[fd] = 0; |
190 | if (close (fd) == -1) | 179 | if (close(fd) == -1) |
191 | return -1; | 180 | return -1; |
192 | 181 | ||
193 | /* EINTR is ok (sort of), everything else is bad */ | 182 | /* EINTR is ok (sort of), everything else is bad */ |
194 | while (waitpid (pid, &status, 0) < 0) | 183 | while (waitpid(pid, &status, 0) < 0) |
195 | if (errno != EINTR) | 184 | if (errno != EINTR) |
196 | return -1; | 185 | return -1; |
197 | 186 | ||
198 | /* return child's termination status */ | 187 | /* return child's termination status */ |
199 | return (WIFEXITED (status)) ? WEXITSTATUS (status) : -1; | 188 | return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; |
200 | } | 189 | } |
201 | 190 | ||
202 | 191 | static int _cmd_fetch_output(int fd, output *op, int flags) { | |
203 | static int | ||
204 | _cmd_fetch_output (int fd, output * op, int flags) | ||
205 | { | ||
206 | size_t len = 0, i = 0, lineno = 0; | 192 | size_t len = 0, i = 0, lineno = 0; |
207 | size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ | 193 | size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ |
208 | char *buf = NULL; | 194 | char *buf = NULL; |
209 | int ret; | 195 | int ret; |
210 | char tmpbuf[4096]; | 196 | char tmpbuf[4096]; |
211 | 197 | ||
212 | op->buf = NULL; | 198 | op->buf = NULL; |
213 | op->buflen = 0; | 199 | op->buflen = 0; |
214 | while ((ret = read (fd, tmpbuf, sizeof (tmpbuf))) > 0) { | 200 | while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) { |
215 | len = (size_t) ret; | 201 | len = (size_t)ret; |
216 | op->buf = realloc (op->buf, op->buflen + len + 1); | 202 | op->buf = realloc(op->buf, op->buflen + len + 1); |
217 | memcpy (op->buf + op->buflen, tmpbuf, len); | 203 | memcpy(op->buf + op->buflen, tmpbuf, len); |
218 | op->buflen += len; | 204 | op->buflen += len; |
219 | i++; | 205 | i++; |
220 | } | 206 | } |
221 | 207 | ||
222 | if (ret < 0) { | 208 | if (ret < 0) { |
223 | printf ("read() returned %d: %s\n", ret, strerror (errno)); | 209 | printf("read() returned %d: %s\n", ret, strerror(errno)); |
224 | return ret; | 210 | return ret; |
225 | } | 211 | } |
226 | 212 | ||
@@ -231,10 +217,9 @@ _cmd_fetch_output (int fd, output * op, int flags) | |||
231 | 217 | ||
232 | /* and some may want both */ | 218 | /* and some may want both */ |
233 | if (flags & CMD_NO_ASSOC) { | 219 | if (flags & CMD_NO_ASSOC) { |
234 | buf = malloc (op->buflen); | 220 | buf = malloc(op->buflen); |
235 | memcpy (buf, op->buf, op->buflen); | 221 | memcpy(buf, op->buf, op->buflen); |
236 | } | 222 | } else |
237 | else | ||
238 | buf = op->buf; | 223 | buf = op->buf; |
239 | 224 | ||
240 | op->line = NULL; | 225 | op->line = NULL; |
@@ -248,8 +233,8 @@ _cmd_fetch_output (int fd, output * op, int flags) | |||
248 | ary_size = op->buflen >> --rsf; | 233 | ary_size = op->buflen >> --rsf; |
249 | } while (!ary_size); | 234 | } while (!ary_size); |
250 | 235 | ||
251 | op->line = realloc (op->line, ary_size * sizeof (char *)); | 236 | op->line = realloc(op->line, ary_size * sizeof(char *)); |
252 | op->lens = realloc (op->lens, ary_size * sizeof (size_t)); | 237 | op->lens = realloc(op->lens, ary_size * sizeof(size_t)); |
253 | } | 238 | } |
254 | 239 | ||
255 | /* set the pointer to the string */ | 240 | /* set the pointer to the string */ |
@@ -261,7 +246,7 @@ _cmd_fetch_output (int fd, output * op, int flags) | |||
261 | buf[i] = '\0'; | 246 | buf[i] = '\0'; |
262 | 247 | ||
263 | /* calculate the string length using pointer difference */ | 248 | /* calculate the string length using pointer difference */ |
264 | op->lens[lineno] = (size_t) & buf[i] - (size_t) op->line[lineno]; | 249 | op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno]; |
265 | 250 | ||
266 | lineno++; | 251 | lineno++; |
267 | i++; | 252 | i++; |
@@ -270,10 +255,7 @@ _cmd_fetch_output (int fd, output * op, int flags) | |||
270 | return lineno; | 255 | return lineno; |
271 | } | 256 | } |
272 | 257 | ||
273 | 258 | int cmd_run(const char *cmdstring, output *out, output *err, int flags) { | |
274 | int | ||
275 | cmd_run (const char *cmdstring, output * out, output * err, int flags) | ||
276 | { | ||
277 | int i = 0, argc; | 259 | int i = 0, argc; |
278 | size_t cmdlen; | 260 | size_t cmdlen; |
279 | char **argv = NULL; | 261 | char **argv = NULL; |
@@ -285,120 +267,114 @@ cmd_run (const char *cmdstring, output * out, output * err, int flags) | |||
285 | 267 | ||
286 | /* initialize the structs */ | 268 | /* initialize the structs */ |
287 | if (out) | 269 | if (out) |
288 | memset (out, 0, sizeof (output)); | 270 | memset(out, 0, sizeof(output)); |
289 | if (err) | 271 | if (err) |
290 | memset (err, 0, sizeof (output)); | 272 | memset(err, 0, sizeof(output)); |
291 | 273 | ||
292 | /* make copy of command string so strtok() doesn't silently modify it */ | 274 | /* make copy of command string so strtok() doesn't silently modify it */ |
293 | /* (the calling program may want to access it later) */ | 275 | /* (the calling program may want to access it later) */ |
294 | cmdlen = strlen (cmdstring); | 276 | cmdlen = strlen(cmdstring); |
295 | if ((cmd = malloc (cmdlen + 1)) == NULL) | 277 | if ((cmd = malloc(cmdlen + 1)) == NULL) |
296 | return -1; | 278 | return -1; |
297 | memcpy (cmd, cmdstring, cmdlen); | 279 | memcpy(cmd, cmdstring, cmdlen); |
298 | cmd[cmdlen] = '\0'; | 280 | cmd[cmdlen] = '\0'; |
299 | 281 | ||
300 | /* This is not a shell, so we don't handle "???" */ | 282 | /* This is not a shell, so we don't handle "???" */ |
301 | if (strstr (cmdstring, "\"")) return -1; | 283 | if (strstr(cmdstring, "\"")) |
284 | return -1; | ||
302 | 285 | ||
303 | /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ | 286 | /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ |
304 | if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) | 287 | if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) |
305 | return -1; | 288 | return -1; |
306 | 289 | ||
307 | /* each arg must be whitespace-separated, so args can be a maximum | 290 | /* each arg must be whitespace-separated, so args can be a maximum |
308 | * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ | 291 | * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ |
309 | argc = (cmdlen >> 1) + 2; | 292 | argc = (cmdlen >> 1) + 2; |
310 | argv = calloc (sizeof (char *), argc); | 293 | argv = calloc((size_t)argc, sizeof(char *)); |
311 | 294 | ||
312 | if (argv == NULL) { | 295 | if (argv == NULL) { |
313 | printf ("%s\n", _("Could not malloc argv array in popen()")); | 296 | printf("%s\n", _("Could not malloc argv array in popen()")); |
314 | return -1; | 297 | return -1; |
315 | } | 298 | } |
316 | 299 | ||
317 | /* get command arguments (stupidly, but fairly quickly) */ | 300 | /* get command arguments (stupidly, but fairly quickly) */ |
318 | while (cmd) { | 301 | while (cmd) { |
319 | str = cmd; | 302 | str = cmd; |
320 | str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ | 303 | str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ |
321 | 304 | ||
322 | if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ | 305 | if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ |
323 | str++; | 306 | str++; |
324 | if (!strstr (str, "'")) | 307 | if (!strstr(str, "'")) |
325 | return -1; /* balanced? */ | 308 | return -1; /* balanced? */ |
326 | cmd = 1 + strstr (str, "'"); | 309 | cmd = 1 + strstr(str, "'"); |
327 | str[strcspn (str, "'")] = 0; | 310 | str[strcspn(str, "'")] = 0; |
328 | } | 311 | } else { |
329 | else { | 312 | if (strpbrk(str, " \t\r\n")) { |
330 | if (strpbrk (str, " \t\r\n")) { | 313 | cmd = 1 + strpbrk(str, " \t\r\n"); |
331 | cmd = 1 + strpbrk (str, " \t\r\n"); | 314 | str[strcspn(str, " \t\r\n")] = 0; |
332 | str[strcspn (str, " \t\r\n")] = 0; | 315 | } else { |
333 | } | ||
334 | else { | ||
335 | cmd = NULL; | 316 | cmd = NULL; |
336 | } | 317 | } |
337 | } | 318 | } |
338 | 319 | ||
339 | if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) | 320 | if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) |
340 | cmd = NULL; | 321 | cmd = NULL; |
341 | 322 | ||
342 | argv[i++] = str; | 323 | argv[i++] = str; |
343 | } | 324 | } |
344 | 325 | ||
345 | return cmd_run_array (argv, out, err, flags); | 326 | return cmd_run_array(argv, out, err, flags); |
346 | } | 327 | } |
347 | 328 | ||
348 | int | 329 | int cmd_run_array(char *const *argv, output *out, output *err, int flags) { |
349 | cmd_run_array (char *const *argv, output * out, output * err, int flags) | ||
350 | { | ||
351 | int fd, pfd_out[2], pfd_err[2]; | 330 | int fd, pfd_out[2], pfd_err[2]; |
352 | 331 | ||
353 | /* initialize the structs */ | 332 | /* initialize the structs */ |
354 | if (out) | 333 | if (out) |
355 | memset (out, 0, sizeof (output)); | 334 | memset(out, 0, sizeof(output)); |
356 | if (err) | 335 | if (err) |
357 | memset (err, 0, sizeof (output)); | 336 | memset(err, 0, sizeof(output)); |
358 | 337 | ||
359 | if ((fd = _cmd_open (argv, pfd_out, pfd_err)) == -1) | 338 | if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1) |
360 | die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); | 339 | die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); |
361 | 340 | ||
362 | if (out) | 341 | if (out) |
363 | out->lines = _cmd_fetch_output (pfd_out[0], out, flags); | 342 | out->lines = _cmd_fetch_output(pfd_out[0], out, flags); |
364 | if (err) | 343 | if (err) |
365 | err->lines = _cmd_fetch_output (pfd_err[0], err, flags); | 344 | err->lines = _cmd_fetch_output(pfd_err[0], err, flags); |
366 | 345 | ||
367 | return _cmd_close (fd); | 346 | return _cmd_close(fd); |
368 | } | 347 | } |
369 | 348 | ||
370 | int | 349 | int cmd_file_read(char *filename, output *out, int flags) { |
371 | cmd_file_read ( char *filename, output *out, int flags) | ||
372 | { | ||
373 | int fd; | 350 | int fd; |
374 | if(out) | 351 | if (out) |
375 | memset (out, 0, sizeof(output)); | 352 | memset(out, 0, sizeof(output)); |
376 | 353 | ||
377 | if ((fd = open(filename, O_RDONLY)) == -1) { | 354 | if ((fd = open(filename, O_RDONLY)) == -1) { |
378 | die( STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno) ); | 355 | die(STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno)); |
379 | } | 356 | } |
380 | 357 | ||
381 | if(out) | 358 | if (out) |
382 | out->lines = _cmd_fetch_output (fd, out, flags); | 359 | out->lines = _cmd_fetch_output(fd, out, flags); |
383 | 360 | ||
384 | if (close(fd) == -1) | 361 | if (close(fd) == -1) |
385 | die( STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno) ); | 362 | die(STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno)); |
386 | 363 | ||
387 | return 0; | 364 | return 0; |
388 | } | 365 | } |
389 | 366 | ||
390 | void | 367 | void timeout_alarm_handler(int signo) { |
391 | timeout_alarm_handler (int signo) | ||
392 | { | ||
393 | if (signo == SIGALRM) { | 368 | if (signo == SIGALRM) { |
394 | printf (_("%s - Plugin timed out after %d seconds\n"), | 369 | printf(_("%s - Plugin timed out after %d seconds\n"), state_text(timeout_state), timeout_interval); |
395 | state_text(timeout_state), timeout_interval); | ||
396 | 370 | ||
397 | long maxfd = mp_open_max(); | 371 | long maxfd = mp_open_max(); |
398 | if(_cmd_pids) for(long int i = 0; i < maxfd; i++) { | 372 | if (_cmd_pids) |
399 | if(_cmd_pids[i] != 0) kill(_cmd_pids[i], SIGKILL); | 373 | for (long int i = 0; i < maxfd; i++) { |
400 | } | 374 | if (_cmd_pids[i] != 0) |
375 | kill(_cmd_pids[i], SIGKILL); | ||
376 | } | ||
401 | 377 | ||
402 | exit (timeout_state); | 378 | exit(timeout_state); |
403 | } | 379 | } |
404 | } | 380 | } |
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h index 061f5d4f..d00069c9 100644 --- a/lib/utils_cmd.h +++ b/lib/utils_cmd.h | |||
@@ -4,12 +4,10 @@ | |||
4 | /* | 4 | /* |
5 | * Header file for Monitoring Plugins utils_cmd.c | 5 | * Header file for Monitoring Plugins utils_cmd.c |
6 | * | 6 | * |
7 | * | ||
8 | */ | 7 | */ |
9 | 8 | ||
10 | /** types **/ | 9 | /** types **/ |
11 | struct output | 10 | struct output { |
12 | { | ||
13 | char *buf; /* output buffer */ | 11 | char *buf; /* output buffer */ |
14 | size_t buflen; /* output buffer content length */ | 12 | size_t buflen; /* output buffer content length */ |
15 | char **line; /* array of lines (points to buf) */ | 13 | char **line; /* array of lines (points to buf) */ |
@@ -20,20 +18,18 @@ struct output | |||
20 | typedef struct output output; | 18 | typedef struct output output; |
21 | 19 | ||
22 | /** prototypes **/ | 20 | /** prototypes **/ |
23 | int cmd_run (const char *, output *, output *, int); | 21 | int cmd_run(const char *, output *, output *, int); |
24 | int cmd_run_array (char *const *, output *, output *, int); | 22 | int cmd_run_array(char *const *, output *, output *, int); |
25 | int cmd_file_read (char *, output *, int); | 23 | int cmd_file_read(char *, output *, int); |
26 | 24 | ||
27 | /* only multi-threaded plugins need to bother with this */ | 25 | /* only multi-threaded plugins need to bother with this */ |
28 | void cmd_init (void); | 26 | void 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 | |||
36 | void timeout_alarm_handler (int); | ||
37 | 32 | ||
33 | void timeout_alarm_handler(int); | ||
38 | 34 | ||
39 | #endif /* _UTILS_CMD_ */ | 35 | #endif /* _UTILS_CMD_ */ |
diff --git a/lib/utils_disk.c b/lib/utils_disk.c index 483be06d..2b761f5e 100644 --- a/lib/utils_disk.c +++ b/lib/utils_disk.c | |||
@@ -1,44 +1,42 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Library for check_disk | 3 | * Library for check_disk |
4 | * | 4 | * |
5 | * License: GPL | 5 | * License: GPL |
6 | * Copyright (c) 1999-2007 Monitoring Plugins Development Team | 6 | * Copyright (c) 1999-2024 Monitoring Plugins Development Team |
7 | * | 7 | * |
8 | * Description: | 8 | * Description: |
9 | * | 9 | * |
10 | * This file contains utilities for check_disk. These are tested by libtap | 10 | * This file contains utilities for check_disk. These are tested by libtap |
11 | * | 11 | * |
12 | * | 12 | * |
13 | * This program is free software: you can redistribute it and/or modify | 13 | * This program is free software: you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
15 | * the Free Software Foundation, either version 3 of the License, or | 15 | * the Free Software Foundation, either version 3 of the License, or |
16 | * (at your option) any later version. | 16 | * (at your option) any later version. |
17 | * | 17 | * |
18 | * This program is distributed in the hope that it will be useful, | 18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
22 | * | 22 | * |
23 | * You should have received a copy of the GNU General Public License | 23 | * You should have received a copy of the GNU General Public License |
24 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 24 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | * | 25 | * |
26 | * | 26 | * |
27 | *****************************************************************************/ | 27 | *****************************************************************************/ |
28 | 28 | ||
29 | #include "common.h" | 29 | #include "common.h" |
30 | #include "utils_disk.h" | 30 | #include "utils_disk.h" |
31 | #include "gl/fsusage.h" | 31 | #include "gl/fsusage.h" |
32 | #include <string.h> | 32 | #include <string.h> |
33 | 33 | ||
34 | void | 34 | void np_add_name(struct name_list **list, const char *name) { |
35 | np_add_name (struct name_list **list, const char *name) | 35 | struct name_list *new_entry; |
36 | { | 36 | new_entry = (struct name_list *)malloc(sizeof *new_entry); |
37 | struct name_list *new_entry; | 37 | new_entry->name = (char *)name; |
38 | new_entry = (struct name_list *) malloc (sizeof *new_entry); | 38 | new_entry->next = *list; |
39 | new_entry->name = (char *) name; | 39 | *list = new_entry; |
40 | new_entry->next = *list; | ||
41 | *list = new_entry; | ||
42 | } | 40 | } |
43 | 41 | ||
44 | /* @brief Initialises a new regex at the begin of list via regcomp(3) | 42 | /* @brief Initialises a new regex at the begin of list via regcomp(3) |
@@ -50,17 +48,14 @@ np_add_name (struct name_list **list, const char *name) | |||
50 | * @param regex the string containing the regex which should be inserted into the list | 48 | * @param regex the string containing the regex which should be inserted into the list |
51 | * @param clags the cflags parameter for regcomp(3) | 49 | * @param clags the cflags parameter for regcomp(3) |
52 | */ | 50 | */ |
53 | int | 51 | int np_add_regex(struct regex_list **list, const char *regex, int cflags) { |
54 | np_add_regex (struct regex_list **list, const char *regex, int cflags) | 52 | struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry); |
55 | { | ||
56 | struct regex_list *new_entry = (struct regex_list *) malloc (sizeof *new_entry); | ||
57 | 53 | ||
58 | if (new_entry == NULL) { | 54 | if (new_entry == NULL) { |
59 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), | 55 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
60 | strerror(errno)); | ||
61 | } | 56 | } |
62 | 57 | ||
63 | int regcomp_result = regcomp(&new_entry->regex, regex, cflags); | 58 | int regcomp_result = regcomp(&new_entry->regex, regex, cflags); |
64 | 59 | ||
65 | if (!regcomp_result) { | 60 | if (!regcomp_result) { |
66 | // regcomp succeeded | 61 | // regcomp succeeded |
@@ -74,197 +69,187 @@ np_add_regex (struct regex_list **list, const char *regex, int cflags) | |||
74 | 69 | ||
75 | return regcomp_result; | 70 | return regcomp_result; |
76 | } | 71 | } |
77 | |||
78 | } | 72 | } |
79 | 73 | ||
80 | /* Initialises a new parameter at the end of list */ | 74 | /* Initialises a new parameter at the end of list */ |
81 | struct parameter_list * | 75 | struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name) { |
82 | np_add_parameter(struct parameter_list **list, const char *name) | 76 | struct parameter_list *current = *list; |
83 | { | 77 | struct parameter_list *new_path; |
84 | struct parameter_list *current = *list; | 78 | new_path = (struct parameter_list *)malloc(sizeof *new_path); |
85 | struct parameter_list *new_path; | 79 | new_path->name = (char *)malloc(strlen(name) + 1); |
86 | new_path = (struct parameter_list *) malloc (sizeof *new_path); | 80 | new_path->best_match = NULL; |
87 | new_path->name = (char *) malloc(strlen(name) + 1); | 81 | new_path->name_next = NULL; |
88 | new_path->best_match = NULL; | 82 | new_path->name_prev = NULL; |
89 | new_path->name_next = NULL; | 83 | new_path->freespace_bytes = NULL; |
90 | new_path->name_prev = NULL; | 84 | new_path->freespace_units = NULL; |
91 | new_path->freespace_bytes = NULL; | 85 | new_path->freespace_percent = NULL; |
92 | new_path->freespace_units = NULL; | 86 | new_path->usedspace_bytes = NULL; |
93 | new_path->freespace_percent = NULL; | 87 | new_path->usedspace_units = NULL; |
94 | new_path->usedspace_bytes = NULL; | 88 | new_path->usedspace_percent = NULL; |
95 | new_path->usedspace_units = NULL; | 89 | new_path->usedinodes_percent = NULL; |
96 | new_path->usedspace_percent = NULL; | 90 | new_path->freeinodes_percent = NULL; |
97 | new_path->usedinodes_percent = NULL; | 91 | new_path->group = NULL; |
98 | new_path->freeinodes_percent = NULL; | 92 | new_path->dfree_pct = -1; |
99 | new_path->group = NULL; | 93 | new_path->dused_pct = -1; |
100 | new_path->dfree_pct = -1; | 94 | new_path->total = 0; |
101 | new_path->dused_pct = -1; | 95 | new_path->available = 0; |
102 | new_path->total = 0; | 96 | new_path->available_to_root = 0; |
103 | new_path->available = 0; | 97 | new_path->used = 0; |
104 | new_path->available_to_root = 0; | 98 | new_path->dused_units = 0; |
105 | new_path->used = 0; | 99 | new_path->dfree_units = 0; |
106 | new_path->dused_units = 0; | 100 | new_path->dtotal_units = 0; |
107 | new_path->dfree_units = 0; | 101 | new_path->inodes_total = 0; |
108 | new_path->dtotal_units = 0; | 102 | new_path->inodes_free = 0; |
109 | new_path->inodes_total = 0; | 103 | new_path->inodes_free_to_root = 0; |
110 | new_path->inodes_free = 0; | 104 | new_path->inodes_used = 0; |
111 | new_path->inodes_free_to_root = 0; | 105 | new_path->dused_inodes_percent = 0; |
112 | new_path->inodes_used = 0; | 106 | new_path->dfree_inodes_percent = 0; |
113 | new_path->dused_inodes_percent = 0; | 107 | |
114 | new_path->dfree_inodes_percent = 0; | 108 | strcpy(new_path->name, name); |
115 | 109 | ||
116 | strcpy(new_path->name, name); | 110 | if (current == NULL) { |
117 | 111 | *list = new_path; | |
118 | if (current == NULL) { | 112 | new_path->name_prev = NULL; |
119 | *list = new_path; | 113 | } else { |
120 | new_path->name_prev = NULL; | 114 | while (current->name_next) { |
121 | } else { | 115 | current = current->name_next; |
122 | while (current->name_next) { | 116 | } |
123 | current = current->name_next; | 117 | current->name_next = new_path; |
124 | } | 118 | new_path->name_prev = current; |
125 | current->name_next = new_path; | 119 | } |
126 | new_path->name_prev = current; | 120 | return new_path; |
127 | } | ||
128 | return new_path; | ||
129 | } | 121 | } |
130 | 122 | ||
131 | /* Delete a given parameter from list and return pointer to next element*/ | 123 | /* Delete a given parameter from list and return pointer to next element*/ |
132 | struct parameter_list * | 124 | struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev) { |
133 | np_del_parameter(struct parameter_list *item, struct parameter_list *prev) | 125 | if (item == NULL) { |
134 | { | 126 | return NULL; |
135 | if (item == NULL) { | 127 | } |
136 | return NULL; | 128 | struct parameter_list *next; |
137 | } | 129 | |
138 | struct parameter_list *next; | 130 | if (item->name_next) |
139 | 131 | next = item->name_next; | |
140 | if (item->name_next) | 132 | else |
141 | next = item->name_next; | 133 | next = NULL; |
142 | else | 134 | |
143 | next = NULL; | 135 | if (next) |
144 | 136 | next->name_prev = prev; | |
145 | if (next) | ||
146 | next->name_prev = prev; | ||
147 | |||
148 | if (prev) | ||
149 | prev->name_next = next; | ||
150 | |||
151 | if (item->name) { | ||
152 | free(item->name); | ||
153 | } | ||
154 | free(item); | ||
155 | |||
156 | return next; | ||
157 | } | ||
158 | 137 | ||
138 | if (prev) | ||
139 | prev->name_next = next; | ||
140 | |||
141 | if (item->name) { | ||
142 | free(item->name); | ||
143 | } | ||
144 | free(item); | ||
145 | |||
146 | return next; | ||
147 | } | ||
159 | 148 | ||
160 | /* returns a pointer to the struct found in the list */ | 149 | /* returns a pointer to the struct found in the list */ |
161 | struct parameter_list * | 150 | struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name) { |
162 | np_find_parameter(struct parameter_list *list, const char *name) | 151 | struct parameter_list *temp_list; |
163 | { | 152 | for (temp_list = list; temp_list; temp_list = temp_list->name_next) { |
164 | struct parameter_list *temp_list; | 153 | if (!strcmp(temp_list->name, name)) |
165 | for (temp_list = list; temp_list; temp_list = temp_list->name_next) { | 154 | return temp_list; |
166 | if (! strcmp(temp_list->name, name)) | 155 | } |
167 | return temp_list; | 156 | |
168 | } | 157 | return NULL; |
169 | |||
170 | return NULL; | ||
171 | } | 158 | } |
172 | 159 | ||
173 | void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) { | 160 | void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) { |
174 | struct parameter_list *d; | 161 | struct parameter_list *d; |
175 | for (d = desired; d; d= d->name_next) { | 162 | for (d = desired; d; d = d->name_next) { |
176 | if (! d->best_match) { | 163 | if (!d->best_match) { |
177 | struct mount_entry *me; | 164 | struct mount_entry *me; |
178 | size_t name_len = strlen(d->name); | 165 | size_t name_len = strlen(d->name); |
179 | size_t best_match_len = 0; | 166 | size_t best_match_len = 0; |
180 | struct mount_entry *best_match = NULL; | 167 | struct mount_entry *best_match = NULL; |
181 | struct fs_usage fsp; | 168 | struct fs_usage fsp; |
182 | 169 | ||
183 | /* set best match if path name exactly matches a mounted device name */ | 170 | /* set best match if path name exactly matches a mounted device name */ |
184 | for (me = mount_list; me; me = me->me_next) { | 171 | for (me = mount_list; me; me = me->me_next) { |
185 | if (strcmp(me->me_devname, d->name)==0) { | 172 | if (strcmp(me->me_devname, d->name) == 0) { |
186 | if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) { | 173 | if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) { |
187 | best_match = me; | 174 | best_match = me; |
188 | } | 175 | } |
189 | } | 176 | } |
190 | } | 177 | } |
191 | 178 | ||
192 | /* set best match by directory name if no match was found by devname */ | 179 | /* set best match by directory name if no match was found by devname */ |
193 | if (! best_match) { | 180 | if (!best_match) { |
194 | for (me = mount_list; me; me = me->me_next) { | 181 | for (me = mount_list; me; me = me->me_next) { |
195 | size_t len = strlen (me->me_mountdir); | 182 | size_t len = strlen(me->me_mountdir); |
196 | if ((!exact && (best_match_len <= len && len <= name_len && | 183 | if ((!exact && |
197 | (len == 1 || strncmp (me->me_mountdir, d->name, len) == 0))) | 184 | (best_match_len <= len && len <= name_len && (len == 1 || strncmp(me->me_mountdir, d->name, len) == 0))) || |
198 | || (exact && strcmp(me->me_mountdir, d->name)==0)) | 185 | (exact && strcmp(me->me_mountdir, d->name) == 0)) { |
199 | { | 186 | if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) { |
200 | if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) { | 187 | best_match = me; |
201 | best_match = me; | 188 | best_match_len = len; |
202 | best_match_len = len; | 189 | } |
203 | } | 190 | } |
204 | } | 191 | } |
205 | } | 192 | } |
206 | } | 193 | |
207 | 194 | if (best_match) { | |
208 | if (best_match) { | 195 | d->best_match = best_match; |
209 | d->best_match = best_match; | 196 | } else { |
210 | } else { | 197 | d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */ |
211 | d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */ | 198 | } |
212 | } | 199 | } |
213 | } | 200 | } |
214 | } | ||
215 | } | 201 | } |
216 | 202 | ||
217 | /* Returns true if name is in list */ | 203 | /* Returns true if name is in list */ |
218 | bool np_find_name (struct name_list *list, const char *name) { | 204 | bool np_find_name(struct name_list *list, const char *name) { |
219 | const struct name_list *n; | 205 | const struct name_list *n; |
220 | 206 | ||
221 | if (list == NULL || name == NULL) { | 207 | if (list == NULL || name == NULL) { |
222 | return false; | 208 | return false; |
223 | } | 209 | } |
224 | for (n = list; n; n = n->next) { | 210 | for (n = list; n; n = n->next) { |
225 | if (!strcmp(name, n->name)) { | 211 | if (!strcmp(name, n->name)) { |
226 | return true; | 212 | return true; |
227 | } | 213 | } |
228 | } | 214 | } |
229 | return false; | 215 | return false; |
230 | } | 216 | } |
231 | 217 | ||
232 | /* Returns true if name is in list */ | 218 | /* Returns true if name is in list */ |
233 | bool np_find_regmatch (struct regex_list *list, const char *name) { | 219 | bool np_find_regmatch(struct regex_list *list, const char *name) { |
234 | int len; | 220 | int len; |
235 | regmatch_t m; | 221 | regmatch_t m; |
236 | 222 | ||
237 | if (name == NULL) { | 223 | if (name == NULL) { |
238 | return false; | 224 | return false; |
239 | } | 225 | } |
240 | 226 | ||
241 | len = strlen(name); | 227 | len = strlen(name); |
242 | 228 | ||
243 | for (; list; list = list->next) { | 229 | for (; list; list = list->next) { |
244 | /* Emulate a full match as if surrounded with ^( )$ | 230 | /* Emulate a full match as if surrounded with ^( )$ |
245 | by checking whether the match spans the whole name */ | 231 | by checking whether the match spans the whole name */ |
246 | if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) { | 232 | if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) { |
247 | return true; | 233 | return true; |
248 | } | 234 | } |
249 | } | 235 | } |
250 | 236 | ||
251 | return false; | 237 | return false; |
252 | } | 238 | } |
253 | 239 | ||
254 | bool np_seen_name(struct name_list *list, const char *name) { | 240 | bool np_seen_name(struct name_list *list, const char *name) { |
255 | const struct name_list *s; | 241 | const struct name_list *s; |
256 | for (s = list; s; s=s->next) { | 242 | for (s = list; s; s = s->next) { |
257 | if (!strcmp(s->name, name)) { | 243 | if (!strcmp(s->name, name)) { |
258 | return true; | 244 | return true; |
259 | } | 245 | } |
260 | } | 246 | } |
261 | return false; | 247 | return false; |
262 | } | 248 | } |
263 | 249 | ||
264 | bool np_regex_match_mount_entry (struct mount_entry* me, regex_t* re) { | 250 | bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) { |
265 | if (regexec(re, me->me_devname, (size_t) 0, NULL, 0) == 0 || | 251 | if (regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0 || regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0) { |
266 | regexec(re, me->me_mountdir, (size_t) 0, NULL, 0) == 0 ) { | 252 | return true; |
267 | return true; | 253 | } |
268 | } | ||
269 | return false; | 254 | return false; |
270 | } | 255 | } |
diff --git a/lib/utils_disk.h b/lib/utils_disk.h index 5b2caf23..c5e81dc1 100644 --- a/lib/utils_disk.h +++ b/lib/utils_disk.h | |||
@@ -4,49 +4,45 @@ | |||
4 | #include "utils_base.h" | 4 | #include "utils_base.h" |
5 | #include "regex.h" | 5 | #include "regex.h" |
6 | 6 | ||
7 | struct name_list | 7 | struct name_list { |
8 | { | 8 | char *name; |
9 | char *name; | 9 | struct name_list *next; |
10 | struct name_list *next; | ||
11 | }; | 10 | }; |
12 | 11 | ||
13 | struct regex_list | 12 | struct regex_list { |
14 | { | 13 | regex_t regex; |
15 | regex_t regex; | 14 | struct regex_list *next; |
16 | struct regex_list *next; | ||
17 | }; | 15 | }; |
18 | 16 | ||
19 | struct parameter_list | 17 | struct parameter_list { |
20 | { | 18 | char *name; |
21 | char *name; | 19 | thresholds *freespace_bytes; |
22 | thresholds *freespace_bytes; | 20 | thresholds *freespace_units; |
23 | thresholds *freespace_units; | 21 | thresholds *freespace_percent; |
24 | thresholds *freespace_percent; | 22 | thresholds *usedspace_bytes; |
25 | thresholds *usedspace_bytes; | 23 | thresholds *usedspace_units; |
26 | thresholds *usedspace_units; | 24 | thresholds *usedspace_percent; |
27 | thresholds *usedspace_percent; | 25 | thresholds *usedinodes_percent; |
28 | thresholds *usedinodes_percent; | 26 | thresholds *freeinodes_percent; |
29 | thresholds *freeinodes_percent; | 27 | char *group; |
30 | char *group; | 28 | struct mount_entry *best_match; |
31 | struct mount_entry *best_match; | 29 | struct parameter_list *name_next; |
32 | struct parameter_list *name_next; | 30 | struct parameter_list *name_prev; |
33 | struct parameter_list *name_prev; | 31 | uintmax_t total, available, available_to_root, used, inodes_free, inodes_free_to_root, inodes_used, inodes_total; |
34 | uintmax_t total, available, available_to_root, used, | 32 | double dfree_pct, dused_pct; |
35 | inodes_free, inodes_free_to_root, inodes_used, inodes_total; | 33 | uint64_t dused_units, dfree_units, dtotal_units; |
36 | double dfree_pct, dused_pct; | 34 | double dused_inodes_percent, dfree_inodes_percent; |
37 | uint64_t dused_units, dfree_units, dtotal_units; | ||
38 | double dused_inodes_percent, dfree_inodes_percent; | ||
39 | }; | 35 | }; |
40 | 36 | ||
41 | void np_add_name (struct name_list **list, const char *name); | 37 | void np_add_name(struct name_list **list, const char *name); |
42 | bool np_find_name (struct name_list *list, const char *name); | 38 | bool np_find_name(struct name_list *list, const char *name); |
43 | bool np_seen_name (struct name_list *list, const char *name); | 39 | bool np_seen_name(struct name_list *list, const char *name); |
44 | int np_add_regex (struct regex_list **list, const char *regex, int cflags); | 40 | int np_add_regex(struct regex_list **list, const char *regex, int cflags); |
45 | bool np_find_regmatch (struct regex_list *list, const char *name); | 41 | bool np_find_regmatch(struct regex_list *list, const char *name); |
46 | struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name); | 42 | struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name); |
47 | struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name); | 43 | struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name); |
48 | struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev); | 44 | struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev); |
49 | 45 | ||
50 | int search_parameter_list (struct parameter_list *list, const char *name); | 46 | int search_parameter_list(struct parameter_list *list, const char *name); |
51 | void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact); | 47 | void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact); |
52 | bool np_regex_match_mount_entry (struct mount_entry* me, regex_t* re); | 48 | bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re); |
diff --git a/lib/utils_tcp.c b/lib/utils_tcp.c index 23ee4a95..daae1d54 100644 --- a/lib/utils_tcp.c +++ b/lib/utils_tcp.c | |||
@@ -1,51 +1,46 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Library for check_tcp | 3 | * Library for check_tcp |
4 | * | 4 | * |
5 | * License: GPL | 5 | * License: GPL |
6 | * Copyright (c) 1999-2013 Monitoring Plugins Development Team | 6 | * Copyright (c) 1999-2024 Monitoring Plugins Development Team |
7 | * | 7 | * |
8 | * Description: | 8 | * Description: |
9 | * | 9 | * |
10 | * This file contains utilities for check_tcp. These are tested by libtap | 10 | * This file contains utilities for check_tcp. These are tested by libtap |
11 | * | 11 | * |
12 | * | 12 | * |
13 | * This program is free software: you can redistribute it and/or modify | 13 | * This program is free software: you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
15 | * the Free Software Foundation, either version 3 of the License, or | 15 | * the Free Software Foundation, either version 3 of the License, or |
16 | * (at your option) any later version. | 16 | * (at your option) any later version. |
17 | * | 17 | * |
18 | * This program is distributed in the hope that it will be useful, | 18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
22 | * | 22 | * |
23 | * You should have received a copy of the GNU General Public License | 23 | * You should have received a copy of the GNU General Public License |
24 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 24 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | * | 25 | * |
26 | * | 26 | * |
27 | *****************************************************************************/ | 27 | *****************************************************************************/ |
28 | 28 | ||
29 | #include "common.h" | 29 | #include "common.h" |
30 | #include "utils_tcp.h" | 30 | #include "utils_tcp.h" |
31 | 31 | ||
32 | #define VERBOSE(message) \ | 32 | #define VERBOSE(message) \ |
33 | do { \ | 33 | do { \ |
34 | if (flags & NP_MATCH_VERBOSE) \ | 34 | if (flags & NP_MATCH_VERBOSE) \ |
35 | puts(message); \ | 35 | puts(message); \ |
36 | } while (0) | 36 | } while (0) |
37 | 37 | ||
38 | enum np_match_result | 38 | enum np_match_result np_expect_match(char *status, char **server_expect, int expect_count, int flags) { |
39 | np_expect_match(char *status, char **server_expect, int expect_count, int flags) | ||
40 | { | ||
41 | int i, match = 0, partial = 0; | 39 | int i, match = 0, partial = 0; |
42 | 40 | ||
43 | for (i = 0; i < expect_count; i++) { | 41 | for (i = 0; i < expect_count; i++) { |
44 | if (flags & NP_MATCH_VERBOSE) | 42 | if (flags & NP_MATCH_VERBOSE) |
45 | printf("looking for [%s] %s [%s]\n", server_expect[i], | 43 | printf("looking for [%s] %s [%s]\n", server_expect[i], (flags & NP_MATCH_EXACT) ? "in beginning of" : "anywhere in", status); |
46 | (flags & NP_MATCH_EXACT) ? | ||
47 | "in beginning of" : "anywhere in", | ||
48 | status); | ||
49 | 44 | ||
50 | if (flags & NP_MATCH_EXACT) { | 45 | if (flags & NP_MATCH_EXACT) { |
51 | if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) { | 46 | if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) { |
@@ -58,15 +53,14 @@ np_expect_match(char *status, char **server_expect, int expect_count, int flags) | |||
58 | continue; | 53 | continue; |
59 | } | 54 | } |
60 | } else if (strstr(status, server_expect[i]) != NULL) { | 55 | } else if (strstr(status, server_expect[i]) != NULL) { |
61 | VERBOSE("found it"); | 56 | VERBOSE("found it"); |
62 | match++; | 57 | match++; |
63 | continue; | 58 | continue; |
64 | } | 59 | } |
65 | VERBOSE("couldn't find it"); | 60 | VERBOSE("couldn't find it"); |
66 | } | 61 | } |
67 | 62 | ||
68 | if ((flags & NP_MATCH_ALL && match == expect_count) || | 63 | if ((flags & NP_MATCH_ALL && match == expect_count) || (!(flags & NP_MATCH_ALL) && match >= 1)) |
69 | (!(flags & NP_MATCH_ALL) && match >= 1)) | ||
70 | return NP_MATCH_SUCCESS; | 64 | return NP_MATCH_SUCCESS; |
71 | else if (partial > 0 || !(flags & NP_MATCH_EXACT)) | 65 | else if (partial > 0 || !(flags & NP_MATCH_EXACT)) |
72 | return NP_MATCH_RETRY; | 66 | return NP_MATCH_RETRY; |
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h index 0328a9cf..d5999e9b 100644 --- a/lib/utils_tcp.h +++ b/lib/utils_tcp.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* Header file for utils_tcp */ | 1 | /* Header file for utils_tcp */ |
2 | 2 | ||
3 | #define NP_MATCH_ALL 0x1 | 3 | #define NP_MATCH_ALL 0x1 |
4 | #define NP_MATCH_EXACT 0x2 | 4 | #define NP_MATCH_EXACT 0x2 |
5 | #define NP_MATCH_VERBOSE 0x4 | 5 | #define NP_MATCH_VERBOSE 0x4 |
6 | 6 | ||
7 | /* | 7 | /* |
8 | * The NP_MATCH_RETRY state indicates that matching might succeed if | 8 | * The NP_MATCH_RETRY state indicates that matching might succeed if |
@@ -16,7 +16,4 @@ enum np_match_result { | |||
16 | NP_MATCH_RETRY | 16 | NP_MATCH_RETRY |
17 | }; | 17 | }; |
18 | 18 | ||
19 | enum np_match_result np_expect_match(char *status, | 19 | enum np_match_result np_expect_match(char *status, char **server_expect, int server_expect_count, int flags); |
20 | char **server_expect, | ||
21 | int server_expect_count, | ||
22 | int flags); | ||
diff --git a/lib/vendor/cJSON/cJSON.c b/lib/vendor/cJSON/cJSON.c new file mode 100644 index 00000000..12076e92 --- /dev/null +++ b/lib/vendor/cJSON/cJSON.c | |||
@@ -0,0 +1,3165 @@ | |||
1 | /* | ||
2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors | ||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | of this software and associated documentation files (the "Software"), to deal | ||
6 | in the Software without restriction, including without limitation the rights | ||
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | copies of the Software, and to permit persons to whom the Software is | ||
9 | furnished to do so, subject to the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be included in | ||
12 | all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
20 | THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | /* cJSON */ | ||
24 | /* JSON parser in C. */ | ||
25 | |||
26 | /* disable warnings about old C89 functions in MSVC */ | ||
27 | #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) | ||
28 | #define _CRT_SECURE_NO_DEPRECATE | ||
29 | #endif | ||
30 | |||
31 | #ifdef __GNUC__ | ||
32 | #pragma GCC visibility push(default) | ||
33 | #endif | ||
34 | #if defined(_MSC_VER) | ||
35 | #pragma warning (push) | ||
36 | /* disable warning about single line comments in system headers */ | ||
37 | #pragma warning (disable : 4001) | ||
38 | #endif | ||
39 | |||
40 | #include "../../../config.h" | ||
41 | #include <string.h> | ||
42 | #include <stdio.h> | ||
43 | #include <math.h> | ||
44 | #include <stdlib.h> | ||
45 | #include <limits.h> | ||
46 | #include <ctype.h> | ||
47 | #include <float.h> | ||
48 | |||
49 | #ifdef ENABLE_LOCALES | ||
50 | #include <locale.h> | ||
51 | #endif | ||
52 | |||
53 | #if defined(_MSC_VER) | ||
54 | #pragma warning (pop) | ||
55 | #endif | ||
56 | #ifdef __GNUC__ | ||
57 | #pragma GCC visibility pop | ||
58 | #endif | ||
59 | |||
60 | #include "cJSON.h" | ||
61 | |||
62 | /* define our own boolean type */ | ||
63 | #ifdef true | ||
64 | #undef true | ||
65 | #endif | ||
66 | #define true ((cJSON_bool)1) | ||
67 | |||
68 | #ifdef false | ||
69 | #undef false | ||
70 | #endif | ||
71 | #define false ((cJSON_bool)0) | ||
72 | |||
73 | /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ | ||
74 | #ifndef isinf | ||
75 | #define isinf(d) (isnan((d - d)) && !isnan(d)) | ||
76 | #endif | ||
77 | #ifndef isnan | ||
78 | #define isnan(d) (d != d) | ||
79 | #endif | ||
80 | |||
81 | #ifndef NAN | ||
82 | #ifdef _WIN32 | ||
83 | #define NAN sqrt(-1.0) | ||
84 | #else | ||
85 | #define NAN 0.0/0.0 | ||
86 | #endif | ||
87 | #endif | ||
88 | |||
89 | typedef struct { | ||
90 | const unsigned char *json; | ||
91 | size_t position; | ||
92 | } error; | ||
93 | static error global_error = { NULL, 0 }; | ||
94 | |||
95 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) | ||
96 | { | ||
97 | return (const char*) (global_error.json + global_error.position); | ||
98 | } | ||
99 | |||
100 | CJSON_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 | |||
110 | CJSON_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 | |||
125 | CJSON_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 */ | ||
134 | static 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 | |||
157 | typedef 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 */ | ||
166 | static void * CJSON_CDECL internal_malloc(size_t size) | ||
167 | { | ||
168 | return malloc(size); | ||
169 | } | ||
170 | static void CJSON_CDECL internal_free(void *pointer) | ||
171 | { | ||
172 | free(pointer); | ||
173 | } | ||
174 | static 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 | |||
187 | static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; | ||
188 | |||
189 | static 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 | |||
210 | CJSON_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. */ | ||
242 | static 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. */ | ||
254 | CJSON_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 */ | ||
280 | static 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 | |||
290 | typedef 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. */ | ||
308 | static 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 | } | ||
353 | loop_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 */ | ||
385 | CJSON_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 */ | ||
404 | CJSON_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 | |||
447 | typedef 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 */ | ||
459 | static 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 */ | ||
545 | static 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 */ | ||
558 | static 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. */ | ||
565 | static 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 */ | ||
635 | static 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 */ | ||
672 | static 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 | |||
788 | fail: | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | /* Parse the input text into an unescaped cinput, and populate item. */ | ||
793 | static 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 | |||
907 | fail: | ||
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. */ | ||
923 | static 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. */ | ||
1045 | static 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. */ | ||
1051 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); | ||
1052 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); | ||
1053 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); | ||
1054 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); | ||
1055 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); | ||
1056 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); | ||
1057 | |||
1058 | /* Utility to jump whitespace and cr/lf */ | ||
1059 | static 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 */ | ||
1085 | static 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 | |||
1100 | CJSON_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. */ | ||
1116 | CJSON_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 | |||
1163 | fail: | ||
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 */ | ||
1196 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) | ||
1197 | { | ||
1198 | return cJSON_ParseWithOpts(value, 0, 0); | ||
1199 | } | ||
1200 | |||
1201 | CJSON_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 | |||
1208 | static 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 | |||
1259 | fail: | ||
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. */ | ||
1276 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) | ||
1277 | { | ||
1278 | return (char*)print(item, true, &global_hooks); | ||
1279 | } | ||
1280 | |||
1281 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) | ||
1282 | { | ||
1283 | return (char*)print(item, false, &global_hooks); | ||
1284 | } | ||
1285 | |||
1286 | CJSON_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 | |||
1317 | CJSON_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. */ | ||
1337 | static 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. */ | ||
1392 | static 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. */ | ||
1466 | static 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 | |||
1540 | success: | ||
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 | |||
1554 | fail: | ||
1555 | if (head != NULL) | ||
1556 | { | ||
1557 | cJSON_Delete(head); | ||
1558 | } | ||
1559 | |||
1560 | return false; | ||
1561 | } | ||
1562 | |||
1563 | /* Render an array to text */ | ||
1564 | static 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. */ | ||
1626 | static 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 | |||
1721 | success: | ||
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 | |||
1734 | fail: | ||
1735 | if (head != NULL) | ||
1736 | { | ||
1737 | cJSON_Delete(head); | ||
1738 | } | ||
1739 | |||
1740 | return false; | ||
1741 | } | ||
1742 | |||
1743 | /* Render an object to text. */ | ||
1744 | static 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. */ | ||
1858 | CJSON_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 | |||
1881 | static 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 | |||
1900 | CJSON_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 | |||
1910 | static 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 | |||
1942 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) | ||
1943 | { | ||
1944 | return get_object_item(object, string, false); | ||
1945 | } | ||
1946 | |||
1947 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) | ||
1948 | { | ||
1949 | return get_object_item(object, string, true); | ||
1950 | } | ||
1951 | |||
1952 | CJSON_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. */ | ||
1958 | static void suffix_object(cJSON *prev, cJSON *item) | ||
1959 | { | ||
1960 | prev->next = item; | ||
1961 | item->prev = prev; | ||
1962 | } | ||
1963 | |||
1964 | /* Utility for handling references. */ | ||
1965 | static 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 | |||
1986 | static 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. */ | ||
2020 | CJSON_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 */ | ||
2032 | static 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 | |||
2041 | static 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 | |||
2078 | CJSON_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 */ | ||
2084 | CJSON_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 | |||
2089 | CJSON_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 | |||
2099 | CJSON_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 | |||
2109 | CJSON_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 | |||
2121 | CJSON_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 | |||
2133 | CJSON_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 | |||
2145 | CJSON_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 | |||
2157 | CJSON_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 | |||
2169 | CJSON_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 | |||
2181 | CJSON_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 | |||
2193 | CJSON_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 | |||
2205 | CJSON_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 | |||
2217 | CJSON_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 | |||
2253 | CJSON_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 | |||
2263 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) | ||
2264 | { | ||
2265 | cJSON_Delete(cJSON_DetachItemFromArray(array, which)); | ||
2266 | } | ||
2267 | |||
2268 | CJSON_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 | |||
2275 | CJSON_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 | |||
2282 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) | ||
2283 | { | ||
2284 | cJSON_Delete(cJSON_DetachItemFromObject(object, string)); | ||
2285 | } | ||
2286 | |||
2287 | CJSON_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. */ | ||
2293 | CJSON_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 | |||
2327 | CJSON_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 | |||
2376 | CJSON_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 | |||
2386 | static 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 | |||
2409 | CJSON_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 | |||
2414 | CJSON_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: */ | ||
2420 | CJSON_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 | |||
2431 | CJSON_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 | |||
2442 | CJSON_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 | |||
2453 | CJSON_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 | |||
2464 | CJSON_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 | |||
2490 | CJSON_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 | |||
2507 | CJSON_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 | |||
2519 | CJSON_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 | |||
2530 | CJSON_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 | |||
2540 | CJSON_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 | |||
2557 | CJSON_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 | |||
2568 | CJSON_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: */ | ||
2580 | CJSON_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 | |||
2620 | CJSON_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 | |||
2660 | CJSON_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 | |||
2700 | CJSON_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 */ | ||
2741 | cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse); | ||
2742 | |||
2743 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) | ||
2744 | { | ||
2745 | return cJSON_Duplicate_rec(item, 0, recurse ); | ||
2746 | } | ||
2747 | |||
2748 | cJSON * 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 | |||
2825 | fail: | ||
2826 | if (newitem != NULL) | ||
2827 | { | ||
2828 | cJSON_Delete(newitem); | ||
2829 | } | ||
2830 | |||
2831 | return NULL; | ||
2832 | } | ||
2833 | |||
2834 | static 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 | |||
2847 | static 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 | |||
2861 | static 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 | |||
2883 | CJSON_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 | |||
2931 | CJSON_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 | |||
2941 | CJSON_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 | |||
2951 | CJSON_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 | |||
2962 | CJSON_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 | } | ||
2971 | CJSON_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 | |||
2981 | CJSON_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 | |||
2991 | CJSON_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 | |||
3001 | CJSON_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 | |||
3011 | CJSON_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 | |||
3021 | CJSON_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 | |||
3031 | CJSON_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 | |||
3156 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size) | ||
3157 | { | ||
3158 | return global_hooks.allocate(size); | ||
3159 | } | ||
3160 | |||
3161 | CJSON_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 | ||
27 | extern "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 | |||
39 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols | ||
40 | CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) | ||
41 | CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol | ||
42 | |||
43 | For *nix builds that support visibility attribute, you can define similar behavior by | ||
44 | |||
45 | setting default visibility to hidden by adding | ||
46 | -fvisibility=hidden (for gcc) | ||
47 | or | ||
48 | -xldscope=hidden (for sun cc) | ||
49 | to CFLAGS | ||
50 | |||
51 | then 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: */ | ||
103 | typedef 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 | |||
125 | typedef 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 | |||
132 | typedef 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 */ | ||
147 | CJSON_PUBLIC(const char*) cJSON_Version(void); | ||
148 | |||
149 | /* Supply malloc, realloc and free functions to cJSON */ | ||
150 | CJSON_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. */ | ||
154 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); | ||
155 | CJSON_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(). */ | ||
158 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); | ||
159 | CJSON_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. */ | ||
162 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); | ||
163 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ | ||
164 | CJSON_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 */ | ||
166 | CJSON_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 */ | ||
169 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); | ||
170 | /* Delete a cJSON entity and all subentities. */ | ||
171 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); | ||
172 | |||
173 | /* Returns the number of items in an array (or object). */ | ||
174 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); | ||
175 | /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ | ||
176 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); | ||
177 | /* Get item "string" from object. Case insensitive. */ | ||
178 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); | ||
179 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); | ||
180 | CJSON_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. */ | ||
182 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); | ||
183 | |||
184 | /* Check item type and return its value */ | ||
185 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); | ||
186 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); | ||
187 | |||
188 | /* These functions check the type of an item */ | ||
189 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); | ||
190 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); | ||
191 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); | ||
192 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); | ||
193 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); | ||
194 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); | ||
195 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); | ||
196 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); | ||
197 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); | ||
198 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); | ||
199 | |||
200 | /* These calls create a cJSON item of the appropriate type. */ | ||
201 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); | ||
202 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); | ||
203 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); | ||
204 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); | ||
205 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); | ||
206 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); | ||
207 | /* raw json */ | ||
208 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); | ||
209 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); | ||
210 | CJSON_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 */ | ||
214 | CJSON_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 */ | ||
217 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); | ||
218 | CJSON_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.*/ | ||
222 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); | ||
223 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); | ||
224 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); | ||
225 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); | ||
226 | |||
227 | /* Append item to the specified array/object. */ | ||
228 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); | ||
229 | CJSON_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` */ | ||
233 | CJSON_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. */ | ||
235 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); | ||
236 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); | ||
237 | |||
238 | /* Remove/Detach items from Arrays/Objects. */ | ||
239 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); | ||
240 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); | ||
241 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); | ||
242 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); | ||
243 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); | ||
244 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); | ||
245 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); | ||
246 | |||
247 | /* Update array items. */ | ||
248 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ | ||
249 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); | ||
250 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); | ||
251 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); | ||
252 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); | ||
253 | |||
254 | /* Duplicate a cJSON item */ | ||
255 | CJSON_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) */ | ||
261 | CJSON_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. */ | ||
266 | CJSON_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. */ | ||
270 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); | ||
271 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); | ||
272 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); | ||
273 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); | ||
274 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); | ||
275 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); | ||
276 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); | ||
277 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); | ||
278 | CJSON_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 */ | ||
283 | CJSON_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 */ | ||
286 | CJSON_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 */ | ||
299 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); | ||
300 | CJSON_PUBLIC(void) cJSON_free(void *object); | ||
301 | |||
302 | #ifdef __cplusplus | ||
303 | } | ||
304 | #endif | ||
305 | |||
306 | #endif | ||