summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am14
-rw-r--r--plugins/check_disk.c1299
-rw-r--r--plugins/check_disk.d/utils_disk.c517
-rw-r--r--plugins/check_disk.d/utils_disk.h157
-rw-r--r--plugins/check_fping.c114
-rw-r--r--plugins/check_fping.d/config.h24
-rw-r--r--plugins/check_http.c10
-rw-r--r--plugins/check_ide_smart.c90
-rw-r--r--plugins/check_nwstat.c1527
-rw-r--r--plugins/check_ping.c4
-rw-r--r--plugins/check_procs.c1135
-rw-r--r--plugins/check_procs.d/config.h75
-rw-r--r--plugins/check_swap.c8
-rw-r--r--plugins/check_swap.d/check_swap.h5
-rw-r--r--plugins/check_swap.d/swap.c102
-rw-r--r--plugins/common.h6
-rw-r--r--plugins/sslutils.c2
-rw-r--r--plugins/t/check_disk.t220
-rw-r--r--plugins/tests/test_check_disk.c197
-rwxr-xr-xplugins/tests/test_check_disk.t6
-rw-r--r--plugins/utils.h2
21 files changed, 2595 insertions, 2919 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 30ca63d1..20a62fb2 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -27,7 +27,7 @@ MATHLIBS = @MATHLIBS@
27#AM_CFLAGS = -Wall 27#AM_CFLAGS = -Wall
28 28
29libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ 29libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \
30 check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_nwstat check_ping \ 30 check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_ping \
31 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ 31 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
32 check_ups check_users negate \ 32 check_ups check_users negate \
33 urlize @EXTRAS@ 33 urlize @EXTRAS@
@@ -40,11 +40,13 @@ EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \
41 check_procs check_mysql_query check_apt check_dbi check_curl \ 41 check_procs check_mysql_query check_apt check_dbi check_curl \
42 \ 42 \
43 tests/test_check_swap 43 tests/test_check_swap \
44 tests/test_check_disk
44 45
45SUBDIRS = picohttpparser 46SUBDIRS = picohttpparser
46 47
47np_test_scripts = tests/test_check_swap.t 48np_test_scripts = tests/test_check_swap.t \
49 tests/test_check_disk.t
48 50
49EXTRA_DIST = t \ 51EXTRA_DIST = t \
50 tests \ 52 tests \
@@ -55,6 +57,7 @@ EXTRA_DIST = t \
55 check_hpjd.d \ 57 check_hpjd.d \
56 check_game.d \ 58 check_game.d \
57 check_radius.d \ 59 check_radius.d \
60 check_disk.d \
58 check_time.d \ 61 check_time.d \
59 check_nagios.d \ 62 check_nagios.d \
60 check_dbi.d \ 63 check_dbi.d \
@@ -69,6 +72,7 @@ EXTRA_DIST = t \
69 check_ntp_peer.d \ 72 check_ntp_peer.d \
70 check_apt.d \ 73 check_apt.d \
71 check_pgsql.d \ 74 check_pgsql.d \
75 check_procs.d \
72 check_ping.d \ 76 check_ping.d \
73 check_by_ssh.d \ 77 check_by_ssh.d \
74 check_smtp.d \ 78 check_smtp.d \
@@ -119,6 +123,7 @@ check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohtt
119check_dbi_LDADD = $(NETLIBS) $(DBILIBS) 123check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
120check_dig_LDADD = $(NETLIBS) 124check_dig_LDADD = $(NETLIBS)
121check_disk_LDADD = $(BASEOBJS) 125check_disk_LDADD = $(BASEOBJS)
126check_disk_SOURCES = check_disk.c check_disk.d/utils_disk.c
122check_dns_LDADD = $(NETLIBS) 127check_dns_LDADD = $(NETLIBS)
123check_dummy_LDADD = $(BASEOBJS) 128check_dummy_LDADD = $(BASEOBJS)
124check_fping_LDADD = $(NETLIBS) 129check_fping_LDADD = $(NETLIBS)
@@ -139,7 +144,6 @@ check_nagios_LDADD = $(BASEOBJS)
139check_nt_LDADD = $(NETLIBS) 144check_nt_LDADD = $(NETLIBS)
140check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) 145check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
141check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 146check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
142check_nwstat_LDADD = $(NETLIBS)
143check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 147check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
144check_ping_LDADD = $(NETLIBS) 148check_ping_LDADD = $(NETLIBS)
145check_procs_LDADD = $(BASEOBJS) 149check_procs_LDADD = $(BASEOBJS)
@@ -166,6 +170,8 @@ endif
166 170
167tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap 171tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
168tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c 172tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
173tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap
174tests_test_check_disk_SOURCES = tests/test_check_disk.c
169 175
170############################################################################## 176##############################################################################
171# secondary dependencies 177# secondary dependencies
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index 037a6f7a..515ddff0 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -31,24 +31,35 @@ const char *program_name = "check_disk"; /* Required for coreutils libs */
31const char *copyright = "1999-2024"; 31const char *copyright = "1999-2024";
32const char *email = "devel@monitoring-plugins.org"; 32const char *email = "devel@monitoring-plugins.org";
33 33
34#include "states.h"
34#include "common.h" 35#include "common.h"
36#include "output.h"
37#include "perfdata.h"
38#include "utils_base.h"
39#include "lib/thresholds.h"
40
35#ifdef HAVE_SYS_STAT_H 41#ifdef HAVE_SYS_STAT_H
36# include <sys/stat.h> 42# include <sys/stat.h>
37#endif 43#endif
44
38#if HAVE_INTTYPES_H 45#if HAVE_INTTYPES_H
39# include <inttypes.h> 46# include <inttypes.h>
40#endif 47#endif
48
41#include <assert.h> 49#include <assert.h>
42#include "popen.h"
43#include "utils.h"
44#include "utils_disk.h"
45#include <stdarg.h> 50#include <stdarg.h>
46#include "fsusage.h" 51#include <stdint.h>
47#include "mountlist.h"
48#include <float.h> 52#include <float.h>
53#include "./popen.h"
54#include "./utils.h"
55#include "../gl/fsusage.h"
56#include "../gl/mountlist.h"
57#include "./check_disk.d/utils_disk.h"
58
49#if HAVE_LIMITS_H 59#if HAVE_LIMITS_H
50# include <limits.h> 60# include <limits.h>
51#endif 61#endif
62
52#include "regex.h" 63#include "regex.h"
53 64
54#ifdef __CYGWIN__ 65#ifdef __CYGWIN__
@@ -57,424 +68,310 @@ const char *email = "devel@monitoring-plugins.org";
57# define ERROR -1 68# define ERROR -1
58#endif 69#endif
59 70
60/* If nonzero, show even filesystems with zero size or
61 uninteresting types. */
62static int show_all_fs = 1;
63
64/* If nonzero, show only local filesystems. */
65static int show_local_fs = 0;
66
67/* If nonzero, show only local filesystems but call stat() on remote ones. */
68static int stat_remote_fs = 0;
69
70/* If positive, the units to use when printing sizes;
71 if negative, the human-readable base. */
72/* static int output_block_size; */
73
74/* If nonzero, invoke the `sync' system call before getting any usage data.
75 Using this option can make df very slow, especially with many or very
76 busy disks. Note that this may make a difference on some systems --
77 SunOs4.1.3, for one. It is *not* necessary on Linux. */
78/* static int require_sync = 0; */
79
80/* Linked list of filesystem types to display.
81 If `fs_select_list' is NULL, list all types.
82 This table is generated dynamically from command-line options,
83 rather than hardcoding into the program what it thinks are the
84 valid filesystem types; let the user specify any filesystem type
85 they want to, and if there are any filesystems of that type, they
86 will be shown.
87
88 Some filesystem types:
89 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
90
91/* static struct parameter_list *fs_select_list; */
92
93/* Linked list of filesystem types to omit.
94 If the list is empty, don't exclude any types. */
95static struct regex_list *fs_exclude_list = NULL;
96
97/* Linked list of filesystem types to check.
98 If the list is empty, include all types. */
99static struct regex_list *fs_include_list;
100
101static struct name_list *dp_exclude_list;
102
103static struct parameter_list *path_select_list = NULL;
104
105/* Linked list of mounted filesystems. */
106static struct mount_entry *mount_list;
107
108/* For long options that have no equivalent short option, use a
109 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
110enum {
111 SYNC_OPTION = CHAR_MAX + 1,
112 NO_SYNC_OPTION,
113 BLOCK_SIZE_OPTION
114};
115
116#ifdef _AIX 71#ifdef _AIX
117# pragma alloca 72# pragma alloca
118#endif 73#endif
119 74
120static int process_arguments(int /*argc*/, char ** /*argv*/); 75typedef struct {
121static void set_all_thresholds(struct parameter_list *path); 76 int errorcode;
122static void print_help(void); 77 check_disk_config config;
78} check_disk_config_wrapper;
79static check_disk_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
80
81static void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units,
82 char *warn_freespace_percent, char *crit_freespace_percent, char *warn_freeinodes_percent,
83 char *crit_freeinodes_percent);
84static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
85static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
86
87/*
88 * Puts the values from a struct fs_usage into a parameter_list with an additional flag to control how reserved
89 * and inodes should be judged (ignored or not)
90 */
91static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp, bool freespace_ignore_reserved);
92static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit);
93
123void print_usage(void); 94void print_usage(void);
124static double calculate_percent(uintmax_t, uintmax_t); 95static void print_help(void);
125static bool stat_path(struct parameter_list *p);
126static void get_stats(struct parameter_list *p, struct fs_usage *fsp);
127static void get_path_stats(struct parameter_list *p, struct fs_usage *fsp);
128 96
129static char *units;
130static uintmax_t mult = 1024 * 1024;
131static int verbose = 0; 97static int verbose = 0;
132static bool erronly = false;
133static bool display_mntp = false;
134static bool exact_match = false;
135static bool ignore_missing = false;
136static bool freespace_ignore_reserved = false;
137static bool display_inodes_perfdata = false;
138static char *warn_freespace_units = NULL;
139static char *crit_freespace_units = NULL;
140static char *warn_freespace_percent = NULL;
141static char *crit_freespace_percent = NULL;
142static char *warn_usedspace_units = NULL;
143static char *crit_usedspace_units = NULL;
144static char *warn_usedspace_percent = NULL;
145static char *crit_usedspace_percent = NULL;
146static char *warn_usedinodes_percent = NULL;
147static char *crit_usedinodes_percent = NULL;
148static char *warn_freeinodes_percent = NULL;
149static char *crit_freeinodes_percent = NULL;
150static bool path_selected = false;
151static bool path_ignored = false;
152static char *group = NULL;
153static struct stat *stat_buf;
154static struct name_list *seen = NULL;
155 98
156int main(int argc, char **argv) { 99// This would not be necessary in C23!!
157 int result = STATE_UNKNOWN; 100const byte_unit Bytes_Factor = 1;
158 int disk_result = STATE_UNKNOWN; 101const byte_unit KibiBytes_factor = 1024;
159 char *output = NULL; 102const byte_unit MebiBytes_factor = 1048576;
160 char *ignored = NULL; 103const byte_unit GibiBytes_factor = 1073741824;
161 char *details = NULL; 104const byte_unit TebiBytes_factor = 1099511627776;
162 char *perf = NULL; 105const byte_unit PebiBytes_factor = 1125899906842624;
163 char *perf_ilabel = NULL; 106const byte_unit ExbiBytes_factor = 1152921504606846976;
164 char *preamble = " - free space:"; 107const byte_unit KiloBytes_factor = 1000;
165 char *ignored_preamble = " - ignored paths:"; 108const byte_unit MegaBytes_factor = 1000000;
166 char *flag_header = NULL; 109const byte_unit GigaBytes_factor = 1000000000;
167 int temp_result = STATE_UNKNOWN; 110const byte_unit TeraBytes_factor = 1000000000000;
168 111const byte_unit PetaBytes_factor = 1000000000000000;
169 struct mount_entry *me = NULL; 112const byte_unit ExaBytes_factor = 1000000000000000000;
170 struct fs_usage fsp = {0};
171 struct parameter_list *temp_list = NULL;
172 struct parameter_list *path = NULL;
173
174#ifdef __CYGWIN__
175 char mountdir[32];
176#endif
177 113
178 output = strdup("");
179 ignored = strdup("");
180 details = strdup("");
181 perf = strdup("");
182 perf_ilabel = strdup("");
183 stat_buf = malloc(sizeof *stat_buf);
184 114
115int main(int argc, char **argv) {
185 setlocale(LC_ALL, ""); 116 setlocale(LC_ALL, "");
186 bindtextdomain(PACKAGE, LOCALEDIR); 117 bindtextdomain(PACKAGE, LOCALEDIR);
187 textdomain(PACKAGE); 118 textdomain(PACKAGE);
188 119
189 mount_list = read_file_system_list(0); 120#ifdef __CYGWIN__
121 char mountdir[32];
122#endif
190 123
191 /* Parse extra opts if any */ 124 // Parse extra opts if any
192 argv = np_extra_opts(&argc, argv, progname); 125 argv = np_extra_opts(&argc, argv, progname);
193 126
194 if (process_arguments(argc, argv) == ERROR) 127 check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
128 if (tmp_config.errorcode == ERROR) {
195 usage4(_("Could not parse arguments")); 129 usage4(_("Could not parse arguments"));
130 }
196 131
197 /* If a list of paths has not been selected, find entire 132 check_disk_config config = tmp_config.config;
198 mount list and create list of paths 133
199 */ 134 if (config.output_format_is_set) {
200 if (path_selected == false && path_ignored == false) { 135 mp_set_format(config.output_format);
201 for (me = mount_list; me; me = me->me_next) {
202 if (!(path = np_find_parameter(path_select_list, me->me_mountdir))) {
203 path = np_add_parameter(&path_select_list, me->me_mountdir);
204 }
205 path->best_match = me;
206 path->group = group;
207 set_all_thresholds(path);
208 }
209 } 136 }
210 137
211 if (path_ignored == false) { 138 if (config.erronly) {
212 np_set_best_match(path_select_list, mount_list, exact_match); 139 mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
213 } 140 }
214 141
215 /* Error if no match found for specified paths */ 142 if (!config.path_ignored) {
216 temp_list = path_select_list; 143 mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list, config.exact_match);
144 }
217 145
218 while (path_select_list) { 146 // Error if no match found for specified paths
219 if (!path_select_list->best_match && ignore_missing == true) { 147 for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
220 /* If the first element will be deleted, the temp_list must be updated with the new start address as well */ 148 if (!elem->best_match && config.ignore_missing) {
221 if (path_select_list == temp_list) {
222 temp_list = path_select_list->name_next;
223 }
224 /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
225 xasprintf(&ignored, "%s %s;", ignored, path_select_list->name);
226 /* Delete the path from the list so that it is not stat-checked later in the code. */ 149 /* Delete the path from the list so that it is not stat-checked later in the code. */
227 path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev); 150 elem = mp_int_fs_list_del(&config.path_select_list, elem);
228 } else if (!path_select_list->best_match) { 151 continue;
152 }
153 if (!elem->best_match) {
229 /* Without --ignore-missing option, exit with Critical state. */ 154 /* Without --ignore-missing option, exit with Critical state. */
230 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name); 155 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name);
231 } else {
232 /* Continue jumping through the list */
233 path_select_list = path_select_list->name_next;
234 } 156 }
235 }
236 157
237 path_select_list = temp_list; 158 elem = mp_int_fs_list_get_next(elem);
159 }
238 160
239 if (!path_select_list && ignore_missing == true) { 161 mp_check overall = mp_check_init();
240 result = STATE_OK; 162 if (config.path_select_list.length == 0) {
241 if (verbose >= 2) { 163 mp_subcheck none_sc = mp_subcheck_init();
242 printf("None of the provided paths were found\n"); 164 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
165 if (config.ignore_missing) {
166 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
167 } else {
168 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
169 if (verbose >= 2) {
170 printf("None of the provided paths were found\n");
171 }
243 } 172 }
173 mp_add_subcheck_to_check(&overall, none_sc);
174 mp_exit(overall);
244 } 175 }
245 176
246 /* Process for every path in list */ 177 // Filter list first
247 for (path = path_select_list; path; path = path->name_next) { 178 for (parameter_list_elem *path = config.path_select_list.first; path;) {
248 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL) 179 if (!path->best_match) {
249 printf("Thresholds(pct) for %s warn: %f crit %f\n", path->name, path->freespace_percent->warning->end, 180 path = mp_int_fs_list_del(&config.path_select_list, path);
250 path->freespace_percent->critical->end);
251
252 if (verbose >= 3 && path->group != NULL)
253 printf("Group of %s: %s\n", path->name, path->group);
254
255 /* reset disk result */
256 disk_result = STATE_UNKNOWN;
257
258 me = path->best_match;
259
260 if (!me) {
261 continue; 181 continue;
262 } 182 }
263 183
184 struct mount_entry *mount_entry = path->best_match;
185
264#ifdef __CYGWIN__ 186#ifdef __CYGWIN__
265 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 187 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
188 path = mp_int_fs_list_del(&config.path_select_list, path);
266 continue; 189 continue;
190 }
191
192 char *mountdir = NULL;
267 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 193 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
268 if (GetDriveType(mountdir) != DRIVE_FIXED) 194 if (GetDriveType(mountdir) != DRIVE_FIXED) {
269 me->me_remote = 1; 195 mount_entry->me_remote = 1;
196 }
270#endif 197#endif
271 /* Filters */
272 198
273 /* Remove filesystems already seen */ 199 /* Remove filesystems already seen */
274 if (np_seen_name(seen, me->me_mountdir)) { 200 if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
201 path = mp_int_fs_list_del(&config.path_select_list, path);
275 continue; 202 continue;
276 } 203 }
277 np_add_name(&seen, me->me_mountdir);
278 204
279 if (path->group == NULL) { 205 if (path->group == NULL) {
280 /* Skip remote filesystems if we're not interested in them */ 206 if (config.fs_exclude_list && np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
281 if (me->me_remote && show_local_fs) { 207 // Skip excluded fs's
282 if (stat_remote_fs) { 208 path = mp_int_fs_list_del(&config.path_select_list, path);
283 if (!stat_path(path) && ignore_missing == true) {
284 result = STATE_OK;
285 xasprintf(&ignored, "%s %s;", ignored, path->name);
286 }
287 }
288 continue;
289 /* Skip pseudo fs's if we haven't asked for all fs's */
290 }
291 if (me->me_dummy && !show_all_fs) {
292 continue; 209 continue;
293 /* Skip excluded fstypes */
294 } 210 }
295 if (fs_exclude_list && np_find_regmatch(fs_exclude_list, me->me_type)) { 211
212 if (config.device_path_exclude_list && (np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
213 np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
214 // Skip excluded device or mount paths
215 path = mp_int_fs_list_del(&config.path_select_list, path);
296 continue; 216 continue;
297 /* Skip excluded fs's */
298 } 217 }
299 if (dp_exclude_list && (np_find_name(dp_exclude_list, me->me_devname) || np_find_name(dp_exclude_list, me->me_mountdir))) { 218
219 if (config.fs_include_list && !np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
220 // Skip not included fstypes
221 path = mp_int_fs_list_del(&config.path_select_list, path);
300 continue; 222 continue;
301 /* Skip not included fstypes */
302 } 223 }
303 if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) { 224
225 /* Skip remote filesystems if we're not interested in them */
226 if (mount_entry->me_remote && config.show_local_fs) {
227 if (config.stat_remote_fs) {
228 // TODO Stat here
229 if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
230 }
231 }
304 continue; 232 continue;
305 } 233 }
306 }
307 234
308 if (!stat_path(path)) { 235 // TODO why stat here? remove unstatable fs?
309 if (ignore_missing == true) { 236 if (!stat_path(path, config.ignore_missing)) {
310 result = STATE_OK; 237 // if (config.ignore_missing) {
311 xasprintf(&ignored, "%s %s;", ignored, path->name); 238 // xasprintf(&ignored, "%s %s;", ignored, path->name);
239 // }
240 // not accessible, remove from list
241 path = mp_int_fs_list_del(&config.path_select_list, path);
242 continue;
312 } 243 }
313 continue;
314 } 244 }
315 get_fs_usage(me->me_mountdir, me->me_devname, &fsp);
316 245
317 if (fsp.fsu_blocks && strcmp("none", me->me_mountdir)) { 246 path = mp_int_fs_list_get_next(path);
318 get_stats(path, &fsp); 247 }
319
320 if (verbose >= 3) {
321 printf("For %s, used_pct=%f free_pct=%f used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%f "
322 "free_inodes_pct=%f fsp.fsu_blocksize=%lu mult=%lu\n",
323 me->me_mountdir, path->dused_pct, path->dfree_pct, path->dused_units, path->dfree_units, path->dtotal_units,
324 path->dused_inodes_percent, path->dfree_inodes_percent, fsp.fsu_blocksize, mult);
325 }
326
327 /* Threshold comparisons */
328
329 temp_result = get_status(path->dfree_units, path->freespace_units);
330 if (verbose >= 3)
331 printf("Freespace_units result=%d\n", temp_result);
332 disk_result = max_state(disk_result, temp_result);
333
334 temp_result = get_status(path->dfree_pct, path->freespace_percent);
335 if (verbose >= 3)
336 printf("Freespace%% result=%d\n", temp_result);
337 disk_result = max_state(disk_result, temp_result);
338
339 temp_result = get_status(path->dused_units, path->usedspace_units);
340 if (verbose >= 3)
341 printf("Usedspace_units result=%d\n", temp_result);
342 disk_result = max_state(disk_result, temp_result);
343
344 temp_result = get_status(path->dused_pct, path->usedspace_percent);
345 if (verbose >= 3)
346 printf("Usedspace_percent result=%d\n", temp_result);
347 disk_result = max_state(disk_result, temp_result);
348
349 temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
350 if (verbose >= 3)
351 printf("Usedinodes_percent result=%d\n", temp_result);
352 disk_result = max_state(disk_result, temp_result);
353
354 temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
355 if (verbose >= 3)
356 printf("Freeinodes_percent result=%d\n", temp_result);
357 disk_result = max_state(disk_result, temp_result);
358
359 result = max_state(result, disk_result);
360 248
361 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes! 249 // now get the actual measurements
362 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf 250 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
363 data. Assumption that start=0. Roll on new syntax... 251 // Get actual metrics here
364 */ 252 struct mount_entry *mount_entry = filesystem->best_match;
253 struct fs_usage fsp = {0};
254 get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
365 255
366 /* *_high_tide must be reinitialized at each run */ 256 if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
367 uint64_t warning_high_tide = UINT64_MAX; 257 *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
368 258
369 if (path->freespace_units->warning != NULL) { 259 if (verbose >= 3) {
370 warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult; 260 printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
371 } 261 "fsp.fsu_blocksize=%lu\n",
372 if (path->freespace_percent->warning != NULL) { 262 mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes, filesystem->total_bytes,
373 warning_high_tide = 263 fsp.fsu_blocksize);
374 min(warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end / 100) * (path->dtotal_units * mult)));
375 }
376
377 uint64_t critical_high_tide = UINT64_MAX;
378
379 if (path->freespace_units->critical != NULL) {
380 critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
381 }
382 if (path->freespace_percent->critical != NULL) {
383 critical_high_tide =
384 min(critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end / 100) * (path->dtotal_units * mult)));
385 } 264 }
265 } else {
266 // failed to retrieve file system data or not mounted?
267 filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
268 continue;
269 }
270 filesystem = mp_int_fs_list_get_next(filesystem);
271 }
386 272
387 /* Nb: *_high_tide are unset when == UINT64_MAX */ 273 if (verbose > 2) {
388 xasprintf(&perf, "%s %s", perf, 274 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
389 perfdata_uint64((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, 275 filesystem = mp_int_fs_list_get_next(filesystem)) {
390 path->dused_units * mult, "B", (warning_high_tide == UINT64_MAX ? false : true), warning_high_tide, 276 assert(filesystem->best_match != NULL);
391 (critical_high_tide == UINT64_MAX ? false : true), critical_high_tide, true, 0, true, 277 if (filesystem->best_match == NULL) {
392 path->dtotal_units * mult)); 278 printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
393 279 } else {
394 if (display_inodes_perfdata) { 280 // printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
395 /* *_high_tide must be reinitialized at each run */
396 warning_high_tide = UINT64_MAX;
397 critical_high_tide = UINT64_MAX;
398
399 if (path->freeinodes_percent->warning != NULL) {
400 warning_high_tide = (uint64_t)fabs(
401 min((double)warning_high_tide, (double)(1.0 - path->freeinodes_percent->warning->end / 100) * path->inodes_total));
402 }
403 if (path->freeinodes_percent->critical != NULL) {
404 critical_high_tide = (uint64_t)fabs(min(
405 (double)critical_high_tide, (double)(1.0 - path->freeinodes_percent->critical->end / 100) * path->inodes_total));
406 }
407
408 xasprintf(&perf_ilabel, "%s (inodes)",
409 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
410 /* Nb: *_high_tide are unset when == UINT64_MAX */
411 xasprintf(&perf, "%s %s", perf,
412 perfdata_uint64(perf_ilabel, path->inodes_used, "", (warning_high_tide != UINT64_MAX ? true : false),
413 warning_high_tide, (critical_high_tide != UINT64_MAX ? true : false), critical_high_tide, true, 0,
414 true, path->inodes_total));
415 } 281 }
282 }
283 }
416 284
417 if (disk_result == STATE_OK && erronly && !verbose) 285 measurement_unit_list *measurements = NULL;
418 continue; 286 measurement_unit_list *current = NULL;
419 287 // create measuring units, because of groups
420 if (disk_result && verbose >= 1) { 288 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem; filesystem = mp_int_fs_list_get_next(filesystem)) {
421 xasprintf(&flag_header, " %s [", state_text(disk_result)); 289 assert(filesystem->best_match != NULL);
290
291 if (filesystem->group == NULL) {
292 // create a measurement unit for the fs
293 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
294 if (measurements == NULL) {
295 measurements = current = add_measurement_list(NULL, unit);
422 } else { 296 } else {
423 xasprintf(&flag_header, ""); 297 current = add_measurement_list(measurements, unit);
424 } 298 }
425 xasprintf(&output, "%s%s %s %llu%s (%.1f%%", output, flag_header, 299 } else {
426 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, path->dfree_units, units, 300 // Grouped elements are consecutive
427 path->dfree_pct); 301 if (measurements == NULL) {
428 if (path->dused_inodes_percent < 0) { 302 // first entry
429 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : "")); 303 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
304 unit.name = strdup(filesystem->group);
305 measurements = current = add_measurement_list(NULL, unit);
430 } else { 306 } else {
431 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : "")); 307 // if this is the first element of a group, the name of the previous entry is different
308 if (strcmp(filesystem->group, current->unit.name) != 0) {
309 // so, this must be the first element of a group
310 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
311 unit.name = filesystem->group;
312 current = add_measurement_list(measurements, unit);
313
314 } else {
315 // NOT the first entry of a group, add info to the other one
316 current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
317 }
432 } 318 }
433 free(flag_header);
434 } 319 }
435 } 320 }
436 321
437 if (verbose >= 2) 322 /* Process for every path in list */
438 xasprintf(&output, "%s%s", output, details); 323 if (measurements != NULL) {
324 for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
325 mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata, config.display_unit);
326 mp_add_subcheck_to_check(&overall, unit_sc);
327 }
328 } else {
329 // Apparently no machting fs found
330 mp_subcheck none_sc = mp_subcheck_init();
331 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
439 332
440 if (strcmp(output, "") == 0 && !erronly) { 333 if (config.ignore_missing) {
441 preamble = ""; 334 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
442 xasprintf(&output, " - No disks were found for provided parameters"); 335 } else {
336 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
337 }
338 mp_add_subcheck_to_check(&overall, none_sc);
443 } 339 }
444 340
445 printf("DISK %s%s%s%s%s|%s\n", state_text(result), ((erronly && result == STATE_OK)) ? "" : preamble, output, 341 mp_exit(overall);
446 (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
447 return result;
448} 342}
449 343
450double calculate_percent(uintmax_t value, uintmax_t total) { 344double calculate_percent(uintmax_t value, uintmax_t total) {
451 double pct = -1; 345 double pct = -1;
452 if (value <= DBL_MAX && total != 0) { 346 if (value <= DBL_MAX && total != 0) {
453 pct = (double)value / total * 100.0; 347 pct = (double)value / (double)total * 100.0;
454 } 348 }
349
455 return pct; 350 return pct;
456} 351}
457 352
458/* process command-line arguments */ 353/* process command-line arguments */
459int process_arguments(int argc, char **argv) { 354check_disk_config_wrapper process_arguments(int argc, char **argv) {
460 int c; 355
461 int err; 356 check_disk_config_wrapper result = {
462 struct parameter_list *se; 357 .errorcode = OK,
463 struct parameter_list *temp_list = NULL; 358 .config = check_disk_config_init(),
464 struct parameter_list *previous = NULL; 359 };
465 struct mount_entry *me; 360
466 regex_t re; 361 if (argc < 2) {
467 int cflags = REG_NOSUB | REG_EXTENDED; 362 result.errorcode = ERROR;
468 int default_cflags = cflags; 363 return result;
469 char errbuf[MAX_INPUT_BUFFER]; 364 }
470 int fnd = 0; 365
366 enum {
367 output_format_index = CHAR_MAX + 1,
368 display_unit_index,
369 };
471 370
472 int option = 0;
473 static struct option longopts[] = {{"timeout", required_argument, 0, 't'}, 371 static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
474 {"warning", required_argument, 0, 'w'}, 372 {"warning", required_argument, 0, 'w'},
475 {"critical", required_argument, 0, 'c'}, 373 {"critical", required_argument, 0, 'c'},
476 {"iwarning", required_argument, 0, 'W'}, 374 {"iwarning", required_argument, 0, 'W'},
477 /* Dang, -C is taken. We might want to reshuffle this. */
478 {"icritical", required_argument, 0, 'K'}, 375 {"icritical", required_argument, 0, 'K'},
479 {"kilobytes", no_argument, 0, 'k'}, 376 {"kilobytes", no_argument, 0, 'k'},
480 {"megabytes", no_argument, 0, 'm'}, 377 {"megabytes", no_argument, 0, 'm'},
@@ -507,24 +404,42 @@ int process_arguments(int argc, char **argv) {
507 {"clear", no_argument, 0, 'C'}, 404 {"clear", no_argument, 0, 'C'},
508 {"version", no_argument, 0, 'V'}, 405 {"version", no_argument, 0, 'V'},
509 {"help", no_argument, 0, 'h'}, 406 {"help", no_argument, 0, 'h'},
407 {"output-format", required_argument, 0, output_format_index},
408 {"display-unit", required_argument, 0, display_unit_index},
510 {0, 0, 0, 0}}; 409 {0, 0, 0, 0}};
511 410
512 if (argc < 2) 411 for (int index = 1; index < argc; index++) {
513 return ERROR; 412 if (strcmp("-to", argv[index]) == 0) {
413 strcpy(argv[index], "-t");
414 }
415 }
416
417 int cflags = REG_NOSUB | REG_EXTENDED;
418 int default_cflags = cflags;
419 char *warn_freespace_units = NULL;
420 char *crit_freespace_units = NULL;
421 char *warn_freespace_percent = NULL;
422 char *crit_freespace_percent = NULL;
423 char *warn_freeinodes_percent = NULL;
424 char *crit_freeinodes_percent = NULL;
425
426 bool path_selected = false;
427 char *group = NULL;
428 byte_unit unit = MebiBytes_factor;
514 429
515 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED); 430 result.config.mount_list = read_file_system_list(false);
516 431
517 for (c = 1; c < argc; c++) 432 np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
518 if (strcmp("-to", argv[c]) == 0)
519 strcpy(argv[c], "-t");
520 433
521 while (1) { 434 while (true) {
522 c = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option); 435 int option = 0;
436 int option_index = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
523 437
524 if (c == -1 || c == EOF) 438 if (option_index == -1 || option_index == EOF) {
525 break; 439 break;
440 }
526 441
527 switch (c) { 442 switch (option_index) {
528 case 't': /* timeout period */ 443 case 't': /* timeout period */
529 if (is_integer(optarg)) { 444 if (is_integer(optarg)) {
530 timeout_interval = atoi(optarg); 445 timeout_interval = atoi(optarg);
@@ -555,10 +470,10 @@ int process_arguments(int argc, char **argv) {
555 break; 470 break;
556 471
557 /* Awful mistake where the range values do not make sense. Normally, 472 /* Awful mistake where the range values do not make sense. Normally,
558 you alert if the value is within the range, but since we are using 473 * you alert if the value is within the range, but since we are using
559 freespace, we have to alert if outside the range. Thus we artificially 474 * freespace, we have to alert if outside the range. Thus we artificially
560 force @ at the beginning of the range, so that it is backwards compatible 475 * force @ at the beginning of the range, so that it is backwards compatible
561 */ 476 */
562 case 'c': /* critical threshold */ 477 case 'c': /* critical threshold */
563 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 478 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
564 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg); 479 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
@@ -594,181 +509,184 @@ int process_arguments(int argc, char **argv) {
594 } 509 }
595 break; 510 break;
596 case 'u': 511 case 'u':
597 if (units)
598 free(units);
599 if (!strcasecmp(optarg, "bytes")) { 512 if (!strcasecmp(optarg, "bytes")) {
600 mult = (uintmax_t)1; 513 unit = Bytes_Factor;
601 units = strdup("B");
602 } else if (!strcmp(optarg, "KiB")) { 514 } else if (!strcmp(optarg, "KiB")) {
603 mult = (uintmax_t)1024; 515 unit = KibiBytes_factor;
604 units = strdup("KiB");
605 } else if (!strcmp(optarg, "kB")) { 516 } else if (!strcmp(optarg, "kB")) {
606 mult = (uintmax_t)1000; 517 unit = KiloBytes_factor;
607 units = strdup("kB");
608 } else if (!strcmp(optarg, "MiB")) { 518 } else if (!strcmp(optarg, "MiB")) {
609 mult = (uintmax_t)1024 * 1024; 519 unit = MebiBytes_factor;
610 units = strdup("MiB");
611 } else if (!strcmp(optarg, "MB")) { 520 } else if (!strcmp(optarg, "MB")) {
612 mult = (uintmax_t)1000 * 1000; 521 unit = MegaBytes_factor;
613 units = strdup("MB");
614 } else if (!strcmp(optarg, "GiB")) { 522 } else if (!strcmp(optarg, "GiB")) {
615 mult = (uintmax_t)1024 * 1024 * 1024; 523 unit = GibiBytes_factor;
616 units = strdup("GiB");
617 } else if (!strcmp(optarg, "GB")) { 524 } else if (!strcmp(optarg, "GB")) {
618 mult = (uintmax_t)1000 * 1000 * 1000; 525 unit = GigaBytes_factor;
619 units = strdup("GB");
620 } else if (!strcmp(optarg, "TiB")) { 526 } else if (!strcmp(optarg, "TiB")) {
621 mult = (uintmax_t)1024 * 1024 * 1024 * 1024; 527 unit = TebiBytes_factor;
622 units = strdup("TiB");
623 } else if (!strcmp(optarg, "TB")) { 528 } else if (!strcmp(optarg, "TB")) {
624 mult = (uintmax_t)1000 * 1000 * 1000 * 1000; 529 unit = TeraBytes_factor;
625 units = strdup("TB");
626 } else if (!strcmp(optarg, "PiB")) { 530 } else if (!strcmp(optarg, "PiB")) {
627 mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024; 531 unit = PebiBytes_factor;
628 units = strdup("PiB");
629 } else if (!strcmp(optarg, "PB")) { 532 } else if (!strcmp(optarg, "PB")) {
630 mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000; 533 unit = PetaBytes_factor;
631 units = strdup("PB");
632 } else { 534 } else {
633 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg); 535 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
634 } 536 }
635 if (units == NULL)
636 die(STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
637 break; 537 break;
638 case 'k': /* display mountpoint */ 538 case 'k':
639 mult = 1024; 539 unit = KibiBytes_factor;
640 if (units) 540 break;
641 free(units); 541 case 'm':
642 units = strdup("kiB"); 542 unit = MebiBytes_factor;
643 break; 543 break;
644 case 'm': /* display mountpoint */ 544 case display_unit_index:
645 mult = 1024 * 1024; 545 if (!strcasecmp(optarg, "bytes")) {
646 if (units) 546 result.config.display_unit = Bytes;
647 free(units); 547 } else if (!strcmp(optarg, "KiB")) {
648 units = strdup("MiB"); 548 result.config.display_unit = KibiBytes;
549 } else if (!strcmp(optarg, "kB")) {
550 result.config.display_unit = KiloBytes;
551 } else if (!strcmp(optarg, "MiB")) {
552 result.config.display_unit = MebiBytes;
553 } else if (!strcmp(optarg, "MB")) {
554 result.config.display_unit = MegaBytes;
555 } else if (!strcmp(optarg, "GiB")) {
556 result.config.display_unit = GibiBytes;
557 } else if (!strcmp(optarg, "GB")) {
558 result.config.display_unit = GigaBytes;
559 } else if (!strcmp(optarg, "TiB")) {
560 result.config.display_unit = TebiBytes;
561 } else if (!strcmp(optarg, "TB")) {
562 result.config.display_unit = TeraBytes;
563 } else if (!strcmp(optarg, "PiB")) {
564 result.config.display_unit = PebiBytes;
565 } else if (!strcmp(optarg, "PB")) {
566 result.config.display_unit = PetaBytes;
567 } else {
568 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
569 }
649 break; 570 break;
650 case 'L': 571 case 'L':
651 stat_remote_fs = 1; 572 result.config.stat_remote_fs = true;
652 /* fallthrough */ 573 /* fallthrough */
653 case 'l': 574 case 'l':
654 show_local_fs = 1; 575 result.config.show_local_fs = true;
655 break; 576 break;
656 case 'P': 577 case 'P':
657 display_inodes_perfdata = 1; 578 result.config.display_inodes_perfdata = true;
658 break; 579 break;
659 case 'p': /* select path */ 580 case 'p': /* select path */ {
660 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent || 581 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
661 warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent || 582 warn_freeinodes_percent || crit_freeinodes_percent)) {
662 warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
663 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n")); 583 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
664 } 584 }
665 585
666 /* add parameter if not found. overwrite thresholds if path has already been added */ 586 /* add parameter if not found. overwrite thresholds if path has already been added */
667 if (!(se = np_find_parameter(path_select_list, optarg))) { 587 parameter_list_elem *search_entry;
668 se = np_add_parameter(&path_select_list, optarg); 588 if (!(search_entry = mp_int_fs_list_find(result.config.path_select_list, optarg))) {
669 589 search_entry = mp_int_fs_list_append(&result.config.path_select_list, optarg);
670 if (stat(optarg, &stat_buf[0]) && ignore_missing == true) { 590
671 path_ignored = true; 591 // struct stat stat_buf = {};
672 break; 592 // if (stat(optarg, &stat_buf) && result.config.ignore_missing) {
673 } 593 // result.config.path_ignored = true;
594 // break;
595 // }
674 } 596 }
675 se->group = group; 597 search_entry->group = group;
676 set_all_thresholds(se); 598 set_all_thresholds(search_entry, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
599
600 warn_freeinodes_percent, crit_freeinodes_percent);
677 601
678 /* With autofs, it is required to stat() the path before re-populating the mount_list */ 602 /* With autofs, it is required to stat() the path before re-populating the mount_list */
679 if (!stat_path(se)) { 603 // if (!stat_path(se, result.config.ignore_missing)) {
680 break; 604 // break;
681 } 605 // }
682 /* NB: We can't free the old mount_list "just like that": both list pointers and struct 606 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
683 * pointers are copied around. One of the reason it wasn't done yet is that other parts
684 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
685 mount_list = read_file_system_list(0);
686 np_set_best_match(se, mount_list, exact_match);
687 607
688 path_selected = true; 608 path_selected = true;
689 break; 609 } break;
690 case 'x': /* exclude path or partition */ 610 case 'x': /* exclude path or partition */
691 np_add_name(&dp_exclude_list, optarg); 611 np_add_name(&result.config.device_path_exclude_list, optarg);
692 break; 612 break;
693 case 'X': /* exclude file system type */ 613 case 'X': /* exclude file system type */ {
694 err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED); 614 int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
695 if (err != 0) { 615 if (err != 0) {
696 regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER); 616 char errbuf[MAX_INPUT_BUFFER];
617 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
697 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 618 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
698 } 619 }
699 break; 620 break;
700 case 'N': /* include file system type */ 621 case 'N': /* include file system type */
701 err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED); 622 err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
702 if (err != 0) { 623 if (err != 0) {
703 regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER); 624 char errbuf[MAX_INPUT_BUFFER];
625 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
704 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 626 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
705 } 627 }
706 break; 628 } break;
707 case 'v': /* verbose */ 629 case 'v': /* verbose */
708 verbose++; 630 verbose++;
709 break; 631 break;
710 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */ 632 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
711 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */ 633 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
712 erronly = true; 634 result.config.erronly = true;
713 break; 635 break;
714 case 'e': 636 case 'e':
715 erronly = true; 637 result.config.erronly = true;
716 break; 638 break;
717 case 'E': 639 case 'E':
718 if (path_selected) 640 if (path_selected) {
719 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n")); 641 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
720 exact_match = true; 642 }
643 result.config.exact_match = true;
721 break; 644 break;
722 case 'f': 645 case 'f':
723 freespace_ignore_reserved = true; 646 result.config.freespace_ignore_reserved = true;
724 break; 647 break;
725 case 'g': 648 case 'g':
726 if (path_selected) 649 if (path_selected) {
727 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n")); 650 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
651 }
728 group = optarg; 652 group = optarg;
729 break; 653 break;
730 case 'I': 654 case 'I':
731 cflags |= REG_ICASE; 655 cflags |= REG_ICASE;
732 // Intentional fallthrough 656 // Intentional fallthrough
733 case 'i': 657 case 'i': {
734 if (!path_selected) 658 if (!path_selected) {
735 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), 659 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
736 _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly")); 660 _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
737 err = regcomp(&re, optarg, cflags); 661 }
662 regex_t regex;
663 int err = regcomp(&regex, optarg, cflags);
738 if (err != 0) { 664 if (err != 0) {
739 regerror(err, &re, errbuf, MAX_INPUT_BUFFER); 665 char errbuf[MAX_INPUT_BUFFER];
666 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
740 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 667 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
741 } 668 }
742 669
743 temp_list = path_select_list; 670 for (parameter_list_elem *elem = result.config.path_select_list.first; elem;) {
744 671 if (elem->best_match) {
745 previous = NULL; 672 if (np_regex_match_mount_entry(elem->best_match, &regex)) {
746 while (temp_list) {
747 if (temp_list->best_match) {
748 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
749 673
750 if (verbose >= 3) 674 if (verbose >= 3) {
751 printf("ignoring %s matching regex\n", temp_list->name); 675 printf("ignoring %s matching regex\n", elem->name);
676 }
752 677
753 temp_list = np_del_parameter(temp_list, previous); 678 elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
754 /* pointer to first element needs to be updated if first item gets deleted */ 679 continue;
755 if (previous == NULL)
756 path_select_list = temp_list;
757 } else {
758 previous = temp_list;
759 temp_list = temp_list->name_next;
760 } 680 }
761 } else {
762 previous = temp_list;
763 temp_list = temp_list->name_next;
764 } 681 }
682
683 elem = mp_int_fs_list_get_next(elem);
765 } 684 }
766 685
767 cflags = default_cflags; 686 cflags = default_cflags;
768 break; 687 } break;
769
770 case 'n': 688 case 'n':
771 ignore_missing = true; 689 result.config.ignore_missing = true;
772 break; 690 break;
773 case 'A': 691 case 'A':
774 optarg = strdup(".*"); 692 optarg = strdup(".*");
@@ -776,80 +694,83 @@ int process_arguments(int argc, char **argv) {
776 case 'R': 694 case 'R':
777 cflags |= REG_ICASE; 695 cflags |= REG_ICASE;
778 // Intentional fallthrough 696 // Intentional fallthrough
779 case 'r': 697 case 'r': {
780 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent || 698 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
781 warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent || 699 warn_freeinodes_percent || crit_freeinodes_percent)) {
782 warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
783 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), 700 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
784 _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n")); 701 _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
785 } 702 }
786 703
787 err = regcomp(&re, optarg, cflags); 704 regex_t regex;
705 int err = regcomp(&regex, optarg, cflags);
788 if (err != 0) { 706 if (err != 0) {
789 regerror(err, &re, errbuf, MAX_INPUT_BUFFER); 707 char errbuf[MAX_INPUT_BUFFER];
708 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
790 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 709 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
791 } 710 }
792 711
793 for (me = mount_list; me; me = me->me_next) { 712 bool found = false;
794 if (np_regex_match_mount_entry(me, &re)) { 713 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
795 fnd = true; 714 if (np_regex_match_mount_entry(me, &regex)) {
796 if (verbose >= 3) 715 found = true;
716 if (verbose >= 3) {
797 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg); 717 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
718 }
798 719
799 /* add parameter if not found. overwrite thresholds if path has already been added */ 720 /* add parameter if not found. overwrite thresholds if path has already been added */
800 if (!(se = np_find_parameter(path_select_list, me->me_mountdir))) { 721 parameter_list_elem *se = NULL;
801 se = np_add_parameter(&path_select_list, me->me_mountdir); 722 if (!(se = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
723 se = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
802 } 724 }
803 se->group = group; 725 se->group = group;
804 set_all_thresholds(se); 726 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
727 warn_freeinodes_percent, crit_freeinodes_percent);
805 } 728 }
806 } 729 }
807 730
808 if (!fnd && ignore_missing == true) { 731 if (!found) {
809 path_ignored = true; 732 if (result.config.ignore_missing) {
810 path_selected = true; 733 result.config.path_ignored = true;
811 break; 734 path_selected = true;
812 } 735 break;
813 if (!fnd) 736 }
737
814 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg); 738 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
739 }
815 740
816 fnd = false;
817 path_selected = true; 741 path_selected = true;
818 np_set_best_match(path_select_list, mount_list, exact_match); 742 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
819 cflags = default_cflags; 743 cflags = default_cflags;
820 744
821 break; 745 } break;
822 case 'M': /* display mountpoint */ 746 case 'M': /* display mountpoint */
823 display_mntp = true; 747 result.config.display_mntp = true;
824 break; 748 break;
825 case 'C': 749 case 'C': {
826 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */ 750 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
827 if (path_selected == false) { 751 if (!path_selected) {
828 struct parameter_list *path; 752 parameter_list_elem *path;
829 for (me = mount_list; me; me = me->me_next) { 753 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
830 if (!(path = np_find_parameter(path_select_list, me->me_mountdir))) 754 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
831 path = np_add_parameter(&path_select_list, me->me_mountdir); 755 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
756 }
832 path->best_match = me; 757 path->best_match = me;
833 path->group = group; 758 path->group = group;
834 set_all_thresholds(path); 759 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
760 warn_freeinodes_percent, crit_freeinodes_percent);
835 } 761 }
836 } 762 }
763
837 warn_freespace_units = NULL; 764 warn_freespace_units = NULL;
838 crit_freespace_units = NULL; 765 crit_freespace_units = NULL;
839 warn_usedspace_units = NULL;
840 crit_usedspace_units = NULL;
841 warn_freespace_percent = NULL; 766 warn_freespace_percent = NULL;
842 crit_freespace_percent = NULL; 767 crit_freespace_percent = NULL;
843 warn_usedspace_percent = NULL;
844 crit_usedspace_percent = NULL;
845 warn_usedinodes_percent = NULL;
846 crit_usedinodes_percent = NULL;
847 warn_freeinodes_percent = NULL; 768 warn_freeinodes_percent = NULL;
848 crit_freeinodes_percent = NULL; 769 crit_freeinodes_percent = NULL;
849 770
850 path_selected = false; 771 path_selected = false;
851 group = NULL; 772 group = NULL;
852 break; 773 } break;
853 case 'V': /* version */ 774 case 'V': /* version */
854 print_revision(progname, NP_VERSION); 775 print_revision(progname, NP_VERSION);
855 exit(STATE_UNKNOWN); 776 exit(STATE_UNKNOWN);
@@ -858,50 +779,145 @@ int process_arguments(int argc, char **argv) {
858 exit(STATE_UNKNOWN); 779 exit(STATE_UNKNOWN);
859 case '?': /* help */ 780 case '?': /* help */
860 usage(_("Unknown argument")); 781 usage(_("Unknown argument"));
782 case output_format_index: {
783 parsed_output_format parser = mp_parse_output_format(optarg);
784 if (!parser.parsing_success) {
785 // TODO List all available formats here, maybe add anothoer usage function
786 printf("Invalid output format: %s\n", optarg);
787 exit(STATE_UNKNOWN);
788 }
789
790 result.config.output_format_is_set = true;
791 result.config.output_format = parser.output_format;
792 break;
793 }
861 } 794 }
862 } 795 }
863 796
864 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */ 797 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
865 c = optind; 798 int index = optind;
866 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c])) 799
867 warn_usedspace_percent = argv[c++]; 800 if (argc > index && is_intnonneg(argv[index])) {
801 if (verbose > 0) {
802 printf("Got an positional warn threshold: %s\n", argv[index]);
803 }
804 char *range = argv[index++];
805 mp_range_parsed tmp = mp_parse_range_string(range);
806 if (tmp.error != MP_PARSING_SUCCES) {
807 die(STATE_UNKNOWN, "failed to parse warning threshold");
808 }
809
810 mp_range tmp_range = tmp.range;
811 // Invert range to use it for free instead of used
812 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
868 813
869 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c])) 814 warn_freespace_percent = mp_range_to_string(tmp_range);
870 crit_usedspace_percent = argv[c++];
871 815
872 if (argc > c) { 816 if (verbose > 0) {
873 se = np_add_parameter(&path_select_list, strdup(argv[c++])); 817 printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
818 }
819 }
820
821 if (argc > index && is_intnonneg(argv[index])) {
822 if (verbose > 0) {
823 printf("Got an positional crit threshold: %s\n", argv[index]);
824 }
825 char *range = argv[index++];
826 mp_range_parsed tmp = mp_parse_range_string(range);
827 if (tmp.error != MP_PARSING_SUCCES) {
828 die(STATE_UNKNOWN, "failed to parse warning threshold");
829 }
830
831 mp_range tmp_range = tmp.range;
832 // Invert range to use it for free instead of used
833 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
834
835 crit_freespace_percent = mp_range_to_string(tmp_range);
836
837 if (verbose > 0) {
838 printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
839 }
840 }
841
842 if (argc > index) {
843 if (verbose > 0) {
844 printf("Got an positional filesystem: %s\n", argv[index]);
845 }
846 struct parameter_list *se = mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
874 path_selected = true; 847 path_selected = true;
875 set_all_thresholds(se); 848 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
849 warn_freeinodes_percent, crit_freeinodes_percent);
850 }
851
852 // If a list of paths has not been explicitly selected, find entire
853 // mount list and create list of paths
854 if (!path_selected && !result.config.path_ignored) {
855 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
856 if (me->me_dummy != 0) {
857 // just do not add dummy filesystems
858 continue;
859 }
860
861 parameter_list_elem *path = NULL;
862 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
863 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
864 }
865 path->best_match = me;
866 path->group = group;
867 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
868 warn_freeinodes_percent, crit_freeinodes_percent);
869 }
876 } 870 }
877 871
878 if (units == NULL) { 872 // Set thresholds to the appropriate unit
879 units = strdup("MiB"); 873 for (parameter_list_elem *tmp = result.config.path_select_list.first; tmp; tmp = mp_int_fs_list_get_next(tmp)) {
880 mult = (uintmax_t)1024 * 1024; 874
875 mp_perfdata_value factor = mp_create_pd_value(unit);
876
877 if (tmp->freespace_units.critical_is_set) {
878 tmp->freespace_units.critical = mp_range_multiply(tmp->freespace_units.critical, factor);
879 }
880 if (tmp->freespace_units.warning_is_set) {
881 tmp->freespace_units.warning = mp_range_multiply(tmp->freespace_units.warning, factor);
882 }
881 } 883 }
882 884
883 return true; 885 return result;
884} 886}
885 887
886void set_all_thresholds(struct parameter_list *path) { 888void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units, char *warn_freespace_percent,
887 if (path->freespace_units != NULL) 889 char *crit_freespace_percent, char *warn_freeinodes_percent, char *crit_freeinodes_percent) {
888 free(path->freespace_units); 890 mp_range_parsed tmp;
889 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units); 891
890 if (path->freespace_percent != NULL) 892 if (warn_freespace_units) {
891 free(path->freespace_percent); 893 tmp = mp_parse_range_string(warn_freespace_units);
892 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent); 894 path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
893 if (path->usedspace_units != NULL) 895 }
894 free(path->usedspace_units); 896
895 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units); 897 if (crit_freespace_units) {
896 if (path->usedspace_percent != NULL) 898 tmp = mp_parse_range_string(crit_freespace_units);
897 free(path->usedspace_percent); 899 path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
898 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); 900 }
899 if (path->usedinodes_percent != NULL) 901
900 free(path->usedinodes_percent); 902 if (warn_freespace_percent) {
901 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); 903 tmp = mp_parse_range_string(warn_freespace_percent);
902 if (path->freeinodes_percent != NULL) 904 path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
903 free(path->freeinodes_percent); 905 }
904 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); 906
907 if (crit_freespace_percent) {
908 tmp = mp_parse_range_string(crit_freespace_percent);
909 path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
910 }
911
912 if (warn_freeinodes_percent) {
913 tmp = mp_parse_range_string(warn_freeinodes_percent);
914 path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
915 }
916
917 if (crit_freeinodes_percent) {
918 tmp = mp_parse_range_string(crit_freeinodes_percent);
919 path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
920 }
905} 921}
906 922
907void print_help(void) { 923void print_help(void) {
@@ -948,8 +964,6 @@ void print_help(void) {
948 printf(" %s\n", _("Display inode usage in perfdata")); 964 printf(" %s\n", _("Display inode usage in perfdata"));
949 printf(" %s\n", "-g, --group=NAME"); 965 printf(" %s\n", "-g, --group=NAME");
950 printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together")); 966 printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
951 printf(" %s\n", "-k, --kilobytes");
952 printf(" %s\n", _("Same as '--units kB'"));
953 printf(" %s\n", "-l, --local"); 967 printf(" %s\n", "-l, --local");
954 printf(" %s\n", _("Only check local filesystems")); 968 printf(" %s\n", _("Only check local filesystems"));
955 printf(" %s\n", "-L, --stat-remote-fs"); 969 printf(" %s\n", "-L, --stat-remote-fs");
@@ -957,8 +971,6 @@ void print_help(void) {
957 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)")); 971 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
958 printf(" %s\n", "-M, --mountpoint"); 972 printf(" %s\n", "-M, --mountpoint");
959 printf(" %s\n", _("Display the (block) device instead of the mount point")); 973 printf(" %s\n", _("Display the (block) device instead of the mount point"));
960 printf(" %s\n", "-m, --megabytes");
961 printf(" %s\n", _("Same as '--units MB'"));
962 printf(" %s\n", "-A, --all"); 974 printf(" %s\n", "-A, --all");
963 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'")); 975 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
964 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION"); 976 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
@@ -974,12 +986,25 @@ void print_help(void) {
974 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)")); 986 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
975 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 987 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
976 printf(" %s\n", "-u, --units=STRING"); 988 printf(" %s\n", "-u, --units=STRING");
977 printf(" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)")); 989 printf(" %s\n", _("Select the unit used for the absolute value thresholds"));
990 printf(
991 " %s\n",
992 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
993 printf(" %s\n", "-k, --kilobytes");
994 printf(" %s\n", _("Same as '--units kB'"));
995 printf(" %s\n", "--display-unit");
996 printf(" %s\n", _("Select the unit used for in the output"));
997 printf(
998 " %s\n",
999 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1000 printf(" %s\n", "-m, --megabytes");
1001 printf(" %s\n", _("Same as '--units MB'"));
978 printf(UT_VERBOSE); 1002 printf(UT_VERBOSE);
979 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX"); 1003 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
980 printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)")); 1004 printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
981 printf(" %s\n", "-N, --include-type=TYPE_REGEX"); 1005 printf(" %s\n", "-N, --include-type=TYPE_REGEX");
982 printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)")); 1006 printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1007 printf(UT_OUTPUT_FORMAT);
983 1008
984 printf("\n"); 1009 printf("\n");
985 printf("%s\n", _("General usage hints:")); 1010 printf("%s\n", _("General usage hints:"));
@@ -1009,105 +1034,187 @@ void print_usage(void) {
1009 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); 1034 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
1010} 1035}
1011 1036
1012bool stat_path(struct parameter_list *p) { 1037bool stat_path(parameter_list_elem *parameters, bool ignore_missing) {
1013 /* Stat entry to check that dir exists and is accessible */ 1038 /* Stat entry to check that dir exists and is accessible */
1014 if (verbose >= 3) 1039 if (verbose >= 3) {
1015 printf("calling stat on %s\n", p->name); 1040 printf("calling stat on %s\n", parameters->name);
1016 if (stat(p->name, &stat_buf[0])) { 1041 }
1017 if (verbose >= 3) 1042
1018 printf("stat failed on %s\n", p->name); 1043 struct stat stat_buf = {0};
1019 if (ignore_missing == true) { 1044 if (stat(parameters->name, &stat_buf)) {
1045 if (verbose >= 3) {
1046 printf("stat failed on %s\n", parameters->name);
1047 }
1048 if (ignore_missing) {
1020 return false; 1049 return false;
1021 } 1050 }
1022 printf("DISK %s - ", _("CRITICAL")); 1051 printf("DISK %s - ", _("CRITICAL"));
1023 die(STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 1052 die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"), strerror(errno));
1024 } 1053 }
1054
1025 return true; 1055 return true;
1026} 1056}
1027 1057
1028void get_stats(struct parameter_list *p, struct fs_usage *fsp) { 1058static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp, bool freespace_ignore_reserved) {
1029 struct parameter_list *p_list; 1059 uintmax_t available = fsp.fsu_bavail;
1030 struct fs_usage tmpfsp; 1060 uintmax_t available_to_root = fsp.fsu_bfree;
1031 int first = 1; 1061 uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
1062 uintmax_t total;
1032 1063
1033 if (p->group == NULL) {
1034 get_path_stats(p, fsp);
1035 } else {
1036 /* find all group members */
1037 for (p_list = path_select_list; p_list; p_list = p_list->name_next) {
1038#ifdef __CYGWIN__
1039 if (strncmp(p_list->name, "/cygdrive/", 10) != 0)
1040 continue;
1041#endif
1042 if (p_list->group && !(strcmp(p_list->group, p->group))) {
1043 if (!stat_path(p_list))
1044 continue;
1045 get_fs_usage(p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp);
1046 get_path_stats(p_list, &tmpfsp);
1047 if (verbose >= 3)
1048 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n",
1049 p_list->group, tmpfsp.fsu_blocks, tmpfsp.fsu_blocksize, p_list->best_match->me_mountdir, p_list->dused_units,
1050 p_list->dfree_units, p_list->dtotal_units, mult);
1051
1052 /* prevent counting the first FS of a group twice since its parameter_list entry
1053 * is used to carry the information of all file systems of the entire group */
1054 if (!first) {
1055 p->total += p_list->total;
1056 p->available += p_list->available;
1057 p->available_to_root += p_list->available_to_root;
1058 p->used += p_list->used;
1059
1060 p->dused_units += p_list->dused_units;
1061 p->dfree_units += p_list->dfree_units;
1062 p->dtotal_units += p_list->dtotal_units;
1063 p->inodes_total += p_list->inodes_total;
1064 p->inodes_free += p_list->inodes_free;
1065 p->inodes_free_to_root += p_list->inodes_free_to_root;
1066 p->inodes_used += p_list->inodes_used;
1067 }
1068 first = 0;
1069 }
1070 if (verbose >= 3)
1071 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n", p->group,
1072 p->dused_units, p->dfree_units, p->dtotal_units, tmpfsp.fsu_blocksize, mult);
1073 }
1074 /* modify devname and mountdir for output */
1075 p->best_match->me_mountdir = p->best_match->me_devname = p->group;
1076 }
1077 /* finally calculate percentages for either plain FS or summed up group */
1078 p->dused_pct = calculate_percent(p->used, p->used + p->available); /* used + available can never be > uintmax */
1079 p->dfree_pct = 100.0 - p->dused_pct;
1080 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
1081 p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
1082}
1083
1084void get_path_stats(struct parameter_list *p, struct fs_usage *fsp) {
1085 p->available = fsp->fsu_bavail;
1086 p->available_to_root = fsp->fsu_bfree;
1087 p->used = fsp->fsu_blocks - fsp->fsu_bfree;
1088 if (freespace_ignore_reserved) { 1064 if (freespace_ignore_reserved) {
1089 /* option activated : we subtract the root-reserved space from the total */ 1065 /* option activated : we subtract the root-reserved space from the total */
1090 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1066 total = fsp.fsu_blocks - available_to_root + available;
1091 } else { 1067 } else {
1092 /* default behaviour : take all the blocks into account */ 1068 /* default behaviour : take all the blocks into account */
1093 p->total = fsp->fsu_blocks; 1069 total = fsp.fsu_blocks;
1094 } 1070 }
1095 1071
1096 p->dused_units = p->used * fsp->fsu_blocksize / mult; 1072 parameters.used_bytes = used * fsp.fsu_blocksize;
1097 p->dfree_units = p->available * fsp->fsu_blocksize / mult; 1073 parameters.free_bytes = available * fsp.fsu_blocksize;
1098 p->dtotal_units = p->total * fsp->fsu_blocksize / mult; 1074 parameters.total_bytes = total * fsp.fsu_blocksize;
1075
1099 /* Free file nodes. Not sure the workaround is required, but in case...*/ 1076 /* Free file nodes. Not sure the workaround is required, but in case...*/
1100 p->inodes_free = fsp->fsu_ffree; 1077 parameters.inodes_free = fsp.fsu_ffree;
1101 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */ 1078 parameters.inodes_free_to_root = fsp.fsu_ffree; /* Free file nodes for root. */
1102 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree; 1079 parameters.inodes_used = fsp.fsu_files - fsp.fsu_ffree;
1080
1103 if (freespace_ignore_reserved) { 1081 if (freespace_ignore_reserved) {
1104 /* option activated : we subtract the root-reserved inodes from the total */ 1082 /* option activated : we subtract the root-reserved inodes from the total */
1105 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */ 1083 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1106 /* for others, fsp->fsu_ffree == fsp->fsu_favail */ 1084 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1107 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free; 1085 parameters.inodes_total = fsp.fsu_files - parameters.inodes_free_to_root + parameters.inodes_free;
1108 } else { 1086 } else {
1109 /* default behaviour : take all the inodes into account */ 1087 /* default behaviour : take all the inodes into account */
1110 p->inodes_total = fsp->fsu_files; 1088 parameters.inodes_total = fsp.fsu_files;
1089 }
1090
1091 return parameters;
1092}
1093
1094mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit) {
1095 mp_subcheck result = mp_subcheck_init();
1096 result = mp_set_subcheck_default_state(result, STATE_UNKNOWN);
1097 xasprintf(&result.output, "%s", measurement_unit.name);
1098
1099 if (!measurement_unit.is_group && measurement_unit.filesystem_type) {
1100 xasprintf(&result.output, "%s (%s)", result.output, measurement_unit.filesystem_type);
1111 } 1101 }
1112 np_add_name(&seen, p->best_match->me_mountdir); 1102
1103 /* Threshold comparisons */
1104
1105 // ===============================
1106 // Free space absolute values test
1107 mp_subcheck freespace_bytes_sc = mp_subcheck_init();
1108 freespace_bytes_sc = mp_set_subcheck_default_state(freespace_bytes_sc, STATE_OK);
1109
1110 if (unit != Humanized) {
1111 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %ju%s (of %ju%s)", (uintmax_t)(measurement_unit.free_bytes / unit),
1112 get_unit_string(unit), (uintmax_t)(measurement_unit.total_bytes / unit), get_unit_string(unit));
1113 } else {
1114 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %s (of %s)", humanize_byte_value(measurement_unit.free_bytes, false),
1115 humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false));
1116 }
1117
1118 mp_perfdata used_space = perfdata_init();
1119 used_space.label = measurement_unit.name;
1120 used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
1121 used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
1122 used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
1123 used_space.uom = "B";
1124 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1125 freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
1126
1127 // special case for absolute space thresholds here:
1128 // if absolute values are not set, compute the thresholds from percentage thresholds
1129 mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
1130 if (!temp_thlds.critical_is_set && measurement_unit.freespace_percent_thresholds.critical_is_set) {
1131 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
1132
1133 if (!tmp_range.end_infinity) {
1134 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1135 }
1136
1137 if (!tmp_range.start_infinity) {
1138 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1139 }
1140 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
1141 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1142 }
1143
1144 if (!temp_thlds.warning_is_set && measurement_unit.freespace_percent_thresholds.warning_is_set) {
1145 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
1146 if (!tmp_range.end_infinity) {
1147 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1148 }
1149 if (!tmp_range.start_infinity) {
1150 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1151 }
1152 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
1153 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1154 }
1155
1156 mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
1157 mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
1158
1159 // ==========================
1160 // Free space percentage test
1161 mp_subcheck freespace_percent_sc = mp_subcheck_init();
1162 freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
1163
1164 double free_percentage = calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
1165 xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
1166
1167 // Using perfdata here just to get to the test result
1168 mp_perfdata free_space_percent_pd = perfdata_init();
1169 free_space_percent_pd.value = mp_create_pd_value(free_percentage);
1170 free_space_percent_pd = mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
1171
1172 freespace_percent_sc = mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
1173 mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
1174
1175 // ================
1176 // Free inodes test
1177 // Only ever useful if the number of inodes is static (e.g. ext4),
1178 // not when it is dynamic (e.g btrfs)
1179 // Assumption: if the total number of inodes == 0, we have such a case and just skip the test
1180 if (measurement_unit.inodes_total > 0) {
1181 mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
1182 freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
1183
1184 double free_inode_percentage = calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
1185
1186 if (verbose > 0) {
1187 printf("free inode percentage computed: %g\n", free_inode_percentage);
1188 }
1189
1190 xasprintf(&freeindodes_percent_sc.output, "Inodes free: %g%% (%ju of %ju)", free_inode_percentage, measurement_unit.inodes_free,
1191 measurement_unit.inodes_total);
1192
1193 mp_perfdata inodes_pd = perfdata_init();
1194 xasprintf(&inodes_pd.label, "%s (inodes)", measurement_unit.name);
1195 inodes_pd = mp_set_pd_value(inodes_pd, measurement_unit.inodes_used);
1196 inodes_pd = mp_set_pd_max_value(inodes_pd, mp_create_pd_value(measurement_unit.inodes_total));
1197 inodes_pd = mp_set_pd_min_value(inodes_pd, mp_create_pd_value(0));
1198
1199 mp_thresholds absolut_inode_thresholds = measurement_unit.freeinodes_percent_thresholds;
1200
1201 if (absolut_inode_thresholds.critical_is_set) {
1202 absolut_inode_thresholds.critical =
1203 mp_range_multiply(absolut_inode_thresholds.critical, mp_create_pd_value(measurement_unit.inodes_total / 100));
1204 }
1205 if (absolut_inode_thresholds.warning_is_set) {
1206 absolut_inode_thresholds.warning =
1207 mp_range_multiply(absolut_inode_thresholds.warning, mp_create_pd_value(measurement_unit.inodes_total / 100));
1208 }
1209
1210 inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds);
1211
1212 freeindodes_percent_sc = mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd));
1213 if (display_inodes_perfdata) {
1214 mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd);
1215 }
1216 mp_add_subcheck_to_subcheck(&result, freeindodes_percent_sc);
1217 }
1218
1219 return result;
1113} 1220}
diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c
new file mode 100644
index 00000000..eec1282b
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.c
@@ -0,0 +1,517 @@
1/*****************************************************************************
2 *
3 * Library for check_disk
4 *
5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains utilities for check_disk. These are tested by libtap
11 *
12 *
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 *
27 *****************************************************************************/
28
29#include "../common.h"
30#include "utils_disk.h"
31#include "../../gl/fsusage.h"
32#include "../../lib/thresholds.h"
33#include "../../lib/states.h"
34#include <stdint.h>
35#include <stdio.h>
36#include <string.h>
37#include <assert.h>
38
39void np_add_name(struct name_list **list, const char *name) {
40 struct name_list *new_entry;
41 new_entry = (struct name_list *)malloc(sizeof *new_entry);
42 new_entry->name = (char *)name;
43 new_entry->next = *list;
44 *list = new_entry;
45}
46
47/* @brief Initialises a new regex at the begin of list via regcomp(3)
48 *
49 * @details if the regex fails to compile the error code of regcomp(3) is returned
50 * and list is not modified, otherwise list is modified to point to the new
51 * element
52 * @param list Pointer to a linked list of regex_list elements
53 * @param regex the string containing the regex which should be inserted into the list
54 * @param clags the cflags parameter for regcomp(3)
55 */
56int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
57 struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
58
59 if (new_entry == NULL) {
60 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
61 }
62
63 int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
64
65 if (!regcomp_result) {
66 // regcomp succeeded
67 new_entry->next = *list;
68 *list = new_entry;
69
70 return 0;
71 }
72 // regcomp failed
73 free(new_entry);
74
75 return regcomp_result;
76}
77
78parameter_list_elem parameter_list_init(const char *name) {
79 parameter_list_elem result = {
80 .name = strdup(name),
81 .best_match = NULL,
82
83 .freespace_units = mp_thresholds_init(),
84 .freespace_percent = mp_thresholds_init(),
85 .freeinodes_percent = mp_thresholds_init(),
86
87 .group = NULL,
88
89 .inodes_total = 0,
90 .inodes_free = 0,
91 .inodes_free_to_root = 0,
92 .inodes_used = 0,
93
94 .used_bytes = 0,
95 .free_bytes = 0,
96 .total_bytes = 0,
97
98 .next = NULL,
99 .prev = NULL,
100 };
101 return result;
102}
103
104/* Returns true if name is in list */
105bool np_find_name(struct name_list *list, const char *name) {
106 if (list == NULL || name == NULL) {
107 return false;
108 }
109 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
110 if (!strcmp(name, iterator->name)) {
111 return true;
112 }
113 }
114 return false;
115}
116
117/* Returns true if name is in list */
118bool np_find_regmatch(struct regex_list *list, const char *name) {
119 if (name == NULL) {
120 return false;
121 }
122
123 size_t len = strlen(name);
124
125 for (; list; list = list->next) {
126 /* Emulate a full match as if surrounded with ^( )$
127 by checking whether the match spans the whole name */
128 regmatch_t dummy_match;
129 if (!regexec(&list->regex, name, 1, &dummy_match, 0) && dummy_match.rm_so == 0 && dummy_match.rm_eo == len) {
130 return true;
131 }
132 }
133
134 return false;
135}
136
137bool np_seen_name(struct name_list *list, const char *name) {
138 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
139 if (!strcmp(iterator->name, name)) {
140 return true;
141 }
142 }
143 return false;
144}
145
146bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
147 return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) || (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0));
148}
149
150check_disk_config check_disk_config_init() {
151 check_disk_config tmp = {
152 .erronly = false,
153 .display_mntp = false,
154 .show_local_fs = false,
155 .stat_remote_fs = false,
156 .display_inodes_perfdata = false,
157
158 .exact_match = false,
159 .freespace_ignore_reserved = false,
160
161 .ignore_missing = false,
162 .path_ignored = false,
163
164 // FS Filters
165 .fs_exclude_list = NULL,
166 .fs_include_list = NULL,
167 .device_path_exclude_list = NULL,
168
169 // Actual filesystems paths to investigate
170 .path_select_list = filesystem_list_init(),
171
172 .mount_list = NULL,
173 .seen = NULL,
174
175 .display_unit = Humanized,
176 // .unit = MebiBytes,
177
178 .output_format_is_set = false,
179 };
180 return tmp;
181}
182
183char *get_unit_string(byte_unit_enum unit) {
184 switch (unit) {
185 case Bytes:
186 return "Bytes";
187 case KibiBytes:
188 return "KiB";
189 case MebiBytes:
190 return "MiB";
191 case GibiBytes:
192 return "GiB";
193 case TebiBytes:
194 return "TiB";
195 case PebiBytes:
196 return "PiB";
197 case ExbiBytes:
198 return "EiB";
199 case KiloBytes:
200 return "KB";
201 case MegaBytes:
202 return "MB";
203 case GigaBytes:
204 return "GB";
205 case TeraBytes:
206 return "TB";
207 case PetaBytes:
208 return "PB";
209 case ExaBytes:
210 return "EB";
211 default:
212 assert(false);
213 }
214}
215
216measurement_unit measurement_unit_init() {
217 measurement_unit tmp = {
218 .name = NULL,
219 .filesystem_type = NULL,
220 .is_group = false,
221
222 .freeinodes_percent_thresholds = mp_thresholds_init(),
223 .freespace_percent_thresholds = mp_thresholds_init(),
224 .freespace_bytes_thresholds = mp_thresholds_init(),
225
226 .free_bytes = 0,
227 .used_bytes = 0,
228 .total_bytes = 0,
229
230 .inodes_total = 0,
231 .inodes_free = 0,
232 .inodes_free_to_root = 0,
233 .inodes_used = 0,
234 };
235 return tmp;
236}
237
238// Add a given element to the list, memory for the new element is freshly allocated
239// Returns a pointer to new element
240measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem) {
241 // find last element
242 measurement_unit_list *new = NULL;
243 if (list == NULL) {
244 new = calloc(1, sizeof(measurement_unit_list));
245 if (new == NULL) {
246 die(STATE_UNKNOWN, _("allocation failed"));
247 }
248 } else {
249 measurement_unit_list *list_elem = list;
250 while (list_elem->next != NULL) {
251 list_elem = list_elem->next;
252 }
253
254 new = calloc(1, sizeof(measurement_unit_list));
255 if (new == NULL) {
256 die(STATE_UNKNOWN, _("allocation failed"));
257 }
258
259 list_elem->next = new;
260 }
261
262 new->unit = elem;
263 new->next = NULL;
264 return new;
265}
266
267measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem) {
268
269 unit.free_bytes += filesystem.free_bytes;
270 unit.used_bytes += filesystem.used_bytes;
271 unit.total_bytes += filesystem.total_bytes;
272
273 unit.inodes_total += filesystem.inodes_total;
274 unit.inodes_free += filesystem.inodes_free;
275 unit.inodes_free_to_root += filesystem.inodes_free_to_root;
276 unit.inodes_used += filesystem.inodes_used;
277 return unit;
278}
279
280measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp) {
281 measurement_unit result = measurement_unit_init();
282 if (!display_mntp) {
283 result.name = strdup(filesystem.best_match->me_mountdir);
284 } else {
285 result.name = strdup(filesystem.best_match->me_devname);
286 }
287
288 if (filesystem.group) {
289 result.is_group = true;
290 } else {
291 result.is_group = false;
292 if (filesystem.best_match) {
293 result.filesystem_type = filesystem.best_match->me_type;
294 }
295 }
296
297 result.freeinodes_percent_thresholds = filesystem.freeinodes_percent;
298 result.freespace_percent_thresholds = filesystem.freespace_percent;
299 result.freespace_bytes_thresholds = filesystem.freespace_units;
300 result.free_bytes = filesystem.free_bytes;
301 result.total_bytes = filesystem.total_bytes;
302 result.used_bytes = filesystem.used_bytes;
303 result.inodes_total = filesystem.inodes_total;
304 result.inodes_used = filesystem.inodes_used;
305 result.inodes_free = filesystem.inodes_free;
306 result.inodes_free_to_root = filesystem.inodes_free_to_root;
307 return result;
308}
309
310#define RANDOM_STRING_LENGTH 64
311
312char *humanize_byte_value(unsigned long long value, bool use_si_units) {
313 // Idea: A reasonable output should have at most 3 orders of magnitude
314 // before the decimal separator
315 // 353GiB is ok, 2444 GiB should be 2.386 TiB
316 char *result = calloc(RANDOM_STRING_LENGTH, sizeof(char));
317 if (result == NULL) {
318 die(STATE_UNKNOWN, _("allocation failed"));
319 }
320 const byte_unit KibiBytes_factor = 1024;
321 const byte_unit MebiBytes_factor = 1048576;
322 const byte_unit GibiBytes_factor = 1073741824;
323 const byte_unit TebiBytes_factor = 1099511627776;
324 const byte_unit PebiBytes_factor = 1125899906842624;
325 const byte_unit ExbiBytes_factor = 1152921504606846976;
326 const byte_unit KiloBytes_factor = 1000;
327 const byte_unit MegaBytes_factor = 1000000;
328 const byte_unit GigaBytes_factor = 1000000000;
329 const byte_unit TeraBytes_factor = 1000000000000;
330 const byte_unit PetaBytes_factor = 1000000000000000;
331 const byte_unit ExaBytes_factor = 1000000000000000000;
332
333 if (use_si_units) {
334 // SI units, powers of 10
335 if (value < KiloBytes_factor) {
336 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
337 } else if (value < MegaBytes_factor) {
338 snprintf(result, RANDOM_STRING_LENGTH, "%llu KB", value / KiloBytes_factor);
339 } else if (value < GigaBytes_factor) {
340 snprintf(result, RANDOM_STRING_LENGTH, "%llu MB", value / MegaBytes_factor);
341 } else if (value < TeraBytes_factor) {
342 snprintf(result, RANDOM_STRING_LENGTH, "%llu GB", value / GigaBytes_factor);
343 } else if (value < PetaBytes_factor) {
344 snprintf(result, RANDOM_STRING_LENGTH, "%llu TB", value / TeraBytes_factor);
345 } else if (value < ExaBytes_factor) {
346 snprintf(result, RANDOM_STRING_LENGTH, "%llu PB", value / PetaBytes_factor);
347 } else {
348 snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor);
349 }
350 } else {
351 // IEC units, powers of 2 ^ 10
352 if (value < KibiBytes_factor) {
353 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
354 } else if (value < MebiBytes_factor) {
355 snprintf(result, RANDOM_STRING_LENGTH, "%llu KiB", value / KibiBytes_factor);
356 } else if (value < GibiBytes_factor) {
357 snprintf(result, RANDOM_STRING_LENGTH, "%llu MiB", value / MebiBytes_factor);
358 } else if (value < TebiBytes_factor) {
359 snprintf(result, RANDOM_STRING_LENGTH, "%llu GiB", value / GibiBytes_factor);
360 } else if (value < PebiBytes_factor) {
361 snprintf(result, RANDOM_STRING_LENGTH, "%llu TiB", value / TebiBytes_factor);
362 } else if (value < ExbiBytes_factor) {
363 snprintf(result, RANDOM_STRING_LENGTH, "%llu PiB", value / PebiBytes_factor);
364 } else {
365 snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor);
366 }
367 }
368
369 return result;
370}
371
372filesystem_list filesystem_list_init() {
373 filesystem_list tmp = {
374 .length = 0,
375 .first = NULL,
376 };
377 return tmp;
378}
379
380parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name) {
381 parameter_list_elem *current = list->first;
382 parameter_list_elem *new_path = (struct parameter_list *)malloc(sizeof *new_path);
383 *new_path = parameter_list_init(name);
384
385 if (current == NULL) {
386 list->first = new_path;
387 new_path->prev = NULL;
388 list->length = 1;
389 } else {
390 while (current->next) {
391 current = current->next;
392 }
393 current->next = new_path;
394 new_path->prev = current;
395 list->length++;
396 }
397 return new_path;
398}
399
400parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) {
401 if (list.length == 0) {
402 return NULL;
403 }
404
405 for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) {
406 if (!strcmp(temp_list->name, name)) {
407 return temp_list;
408 }
409 }
410
411 return NULL;
412}
413
414parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) {
415 if (list->length == 0) {
416 return NULL;
417 }
418
419 if (item == NULL) {
420 // Got NULL for item, interpret this as "delete first element"
421 // as a kind of compatibility to the old function
422 item = list->first;
423 }
424
425 if (list->first == item) {
426 list->length--;
427
428 list->first = item->next;
429 if (list->first) {
430 list->first->prev = NULL;
431 }
432 return list->first;
433 }
434
435 // Was not the first element, continue
436 parameter_list_elem *prev = list->first;
437 parameter_list_elem *current = list->first->next;
438
439 while (current != item && current != NULL) {
440 prev = current;
441 current = current->next;
442 }
443
444 if (current == NULL) {
445 // didn't find that element ....
446 return NULL;
447 }
448
449 // remove the element
450 parameter_list_elem *next = current->next;
451 prev->next = next;
452 list->length--;
453 if (next) {
454 next->prev = prev;
455 }
456
457 if (item->name) {
458 free(item->name);
459 }
460 free(item);
461
462 return next;
463}
464
465parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) {
466 if (!current) {
467 return NULL;
468 }
469 return current->next;
470}
471
472void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact) {
473 for (parameter_list_elem *elem = list.first; elem; elem = mp_int_fs_list_get_next(elem)) {
474 if (!elem->best_match) {
475 size_t name_len = strlen(elem->name);
476 struct mount_entry *best_match = NULL;
477
478 /* set best match if path name exactly matches a mounted device name */
479 for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
480 if (strcmp(mount_entry->me_devname, elem->name) == 0) {
481 struct fs_usage fsp;
482 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
483 best_match = mount_entry;
484 }
485 }
486 }
487
488 /* set best match by directory name if no match was found by devname */
489 if (!best_match) {
490 size_t best_match_len = 0;
491 for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
492 size_t len = strlen(mount_entry->me_mountdir);
493
494 if ((!exact && (best_match_len <= len && len <= name_len &&
495 (len == 1 || strncmp(mount_entry->me_mountdir, elem->name, len) == 0))) ||
496 (exact && strcmp(mount_entry->me_mountdir, elem->name) == 0)) {
497 struct fs_usage fsp;
498
499 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
500 best_match = mount_entry;
501 best_match_len = len;
502 }
503 }
504 }
505 }
506
507 if (best_match) {
508 elem->best_match = best_match;
509 } else {
510 elem->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
511 }
512
513 // No filesystem without a mount_entry!
514 // assert(elem->best_match != NULL);
515 }
516 }
517}
diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h
new file mode 100644
index 00000000..6831d1fd
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.h
@@ -0,0 +1,157 @@
1#pragma once
2/* Header file for utils_disk */
3
4#include "../../config.h"
5#include "../../gl/mountlist.h"
6#include "../../lib/utils_base.h"
7#include "../../lib/output.h"
8#include "regex.h"
9#include <stdint.h>
10
11typedef unsigned long long byte_unit;
12
13typedef enum {
14 Humanized,
15 Bytes,
16 KibiBytes,
17 MebiBytes,
18 GibiBytes,
19 TebiBytes,
20 PebiBytes,
21 ExbiBytes,
22 KiloBytes,
23 MegaBytes,
24 GigaBytes,
25 TeraBytes,
26 PetaBytes,
27 ExaBytes,
28} byte_unit_enum;
29
30typedef struct name_list string_list;
31struct name_list {
32 char *name;
33 string_list *next;
34};
35
36struct regex_list {
37 regex_t regex;
38 struct regex_list *next;
39};
40
41typedef struct parameter_list parameter_list_elem;
42struct parameter_list {
43 char *name;
44 char *group;
45
46 mp_thresholds freespace_units;
47 mp_thresholds freespace_percent;
48 mp_thresholds freeinodes_percent;
49
50 struct mount_entry *best_match;
51
52 uintmax_t inodes_free_to_root;
53 uintmax_t inodes_free;
54 uintmax_t inodes_used;
55 uintmax_t inodes_total;
56
57 uint64_t used_bytes;
58 uint64_t free_bytes;
59 uint64_t total_bytes;
60
61 parameter_list_elem *next;
62 parameter_list_elem *prev;
63};
64
65typedef struct {
66 size_t length;
67 parameter_list_elem *first;
68} filesystem_list;
69
70filesystem_list filesystem_list_init();
71
72typedef struct {
73 char *name;
74 char *filesystem_type;
75 bool is_group;
76
77 mp_thresholds freespace_bytes_thresholds;
78 mp_thresholds freespace_percent_thresholds;
79 mp_thresholds freeinodes_percent_thresholds;
80
81 uintmax_t inodes_free_to_root;
82 uintmax_t inodes_free;
83 uintmax_t inodes_used;
84 uintmax_t inodes_total;
85
86 uintmax_t used_bytes;
87 uintmax_t free_bytes;
88 uintmax_t total_bytes;
89} measurement_unit;
90
91typedef struct measurement_unit_list measurement_unit_list;
92struct measurement_unit_list {
93 measurement_unit unit;
94 measurement_unit_list *next;
95};
96
97typedef struct {
98 // Output options
99 bool erronly;
100 bool display_mntp;
101 /* show only local filesystems. */
102 bool show_local_fs;
103 /* show only local filesystems but call stat() on remote ones. */
104 bool stat_remote_fs;
105 bool display_inodes_perfdata;
106
107 bool exact_match;
108 bool freespace_ignore_reserved;
109
110 bool ignore_missing;
111 bool path_ignored;
112
113 /* Linked list of filesystem types to omit.
114 If the list is empty, don't exclude any types. */
115 struct regex_list *fs_exclude_list;
116 /* Linked list of filesystem types to check.
117 If the list is empty, include all types. */
118 struct regex_list *fs_include_list;
119 struct name_list *device_path_exclude_list;
120 filesystem_list path_select_list;
121 /* Linked list of mounted filesystems. */
122 struct mount_entry *mount_list;
123 struct name_list *seen;
124
125 byte_unit_enum display_unit;
126 // byte_unit unit;
127
128 bool output_format_is_set;
129 mp_output_format output_format;
130} check_disk_config;
131
132void np_add_name(struct name_list **list, const char *name);
133bool np_find_name(struct name_list *list, const char *name);
134bool np_seen_name(struct name_list *list, const char *name);
135int np_add_regex(struct regex_list **list, const char *regex, int cflags);
136bool np_find_regmatch(struct regex_list *list, const char *name);
137
138parameter_list_elem parameter_list_init(const char *);
139
140parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name);
141parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name);
142parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item);
143parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current);
144void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact);
145
146measurement_unit measurement_unit_init();
147measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem);
148measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem);
149measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp);
150
151int search_parameter_list(parameter_list_elem *list, const char *name);
152bool np_regex_match_mount_entry(struct mount_entry *, regex_t *);
153
154char *get_unit_string(byte_unit_enum);
155check_disk_config check_disk_config_init();
156
157char *humanize_byte_value(unsigned long long value, bool use_si_units);
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
index ec7abb67..8018e06d 100644
--- a/plugins/check_fping.c
+++ b/plugins/check_fping.c
@@ -79,6 +79,24 @@ int main(int argc, char **argv) {
79 server = strscpy(server, config.server_name); 79 server = strscpy(server, config.server_name);
80 80
81 char *option_string = ""; 81 char *option_string = "";
82 char *fping_prog = NULL;
83
84 /* First determine if the target is dualstack or ipv6 only. */
85 bool server_is_inet6_addr = is_inet6_addr(server);
86
87 /*
88 * If the user requested -6 OR the user made no assertion and the address is v6 or dualstack
89 * -> we use ipv6
90 * If the user requested -4 OR the user made no assertion and the address is v4 ONLY
91 * -> we use ipv4
92 */
93 if (address_family == AF_INET6 || (address_family == AF_UNSPEC && server_is_inet6_addr)) {
94 xasprintf(&option_string, "%s-6 ", option_string);
95 } else {
96 xasprintf(&option_string, "%s-4 ", option_string);
97 }
98 fping_prog = strdup(PATH_TO_FPING);
99
82 /* compose the command */ 100 /* compose the command */
83 if (config.target_timeout) { 101 if (config.target_timeout) {
84 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout); 102 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
@@ -99,19 +117,26 @@ int main(int argc, char **argv) {
99 xasprintf(&option_string, "%s-R ", option_string); 117 xasprintf(&option_string, "%s-R ", option_string);
100 } 118 }
101 119
102 char *fping_prog = NULL; 120 if (config.fwmark_set) {
103#ifdef PATH_TO_FPING6 121 xasprintf(&option_string, "%s--fwmark %u ", option_string, config.fwmark);
104 if (address_family != AF_INET && is_inet6_addr(server)) { 122 }
105 fping_prog = strdup(PATH_TO_FPING6); 123
106 } else { 124 if (config.icmp_timestamp) {
107 fping_prog = strdup(PATH_TO_FPING); 125 xasprintf(&option_string, "%s--icmp-timestamp ", option_string);
126 }
127
128 if (config.check_source) {
129 xasprintf(&option_string, "%s--check-source ", option_string);
108 } 130 }
109#else
110 fping_prog = strdup(PATH_TO_FPING);
111#endif
112 131
113 char *command_line = NULL; 132 char *command_line = NULL;
114 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server); 133
134 if (config.icmp_timestamp) {
135 // no packet size settable for ICMP timestamp
136 xasprintf(&command_line, "%s %s -c %d %s", fping_prog, option_string, config.packet_count, server);
137 } else {
138 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server);
139 }
115 140
116 if (verbose) { 141 if (verbose) {
117 printf("%s\n", command_line); 142 printf("%s\n", command_line);
@@ -268,13 +293,38 @@ mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double c
268 293
269/* process command-line arguments */ 294/* process command-line arguments */
270check_fping_config_wrapper process_arguments(int argc, char **argv) { 295check_fping_config_wrapper process_arguments(int argc, char **argv) {
271 static struct option longopts[] = { 296 enum {
272 {"hostname", required_argument, 0, 'H'}, {"sourceip", required_argument, 0, 'S'}, {"sourceif", required_argument, 0, 'I'}, 297 FWMARK_OPT = CHAR_MAX + 1,
273 {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, {"alive", no_argument, 0, 'a'}, 298 ICMP_TIMESTAMP_OPT,
274 {"bytes", required_argument, 0, 'b'}, {"number", required_argument, 0, 'n'}, {"target-timeout", required_argument, 0, 'T'}, 299 CHECK_SOURCE_OPT,
275 {"interval", required_argument, 0, 'i'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, 300 };
276 {"help", no_argument, 0, 'h'}, {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, 301 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
277 {"dontfrag", no_argument, 0, 'M'}, {"random", no_argument, 0, 'R'}, {0, 0, 0, 0}}; 302 {"sourceip", required_argument, 0, 'S'},
303 {"sourceif", required_argument, 0, 'I'},
304 {"critical", required_argument, 0, 'c'},
305 {"warning", required_argument, 0, 'w'},
306 {"alive", no_argument, 0, 'a'},
307 {"bytes", required_argument, 0, 'b'},
308 {"number", required_argument, 0, 'n'},
309 {"target-timeout", required_argument, 0, 'T'},
310 {"interval", required_argument, 0, 'i'},
311 {"verbose", no_argument, 0, 'v'},
312 {"version", no_argument, 0, 'V'},
313 {"help", no_argument, 0, 'h'},
314 {"use-ipv4", no_argument, 0, '4'},
315 {"use-ipv6", no_argument, 0, '6'},
316 {"dontfrag", no_argument, 0, 'M'},
317 {"random", no_argument, 0, 'R'},
318#ifdef FPING_VERSION_5_2_OR_HIGHER
319 // only available with fping version >= 5.2
320 {"fwmark", required_argument, NULL, FWMARK_OPT},
321# ifdef FPING_VERSION_5_3_OR_HIGHER
322 // only available with fping version >= 5.3
323 {"icmp-timestamp", no_argument, NULL, ICMP_TIMESTAMP_OPT},
324 {"check-source", no_argument, NULL, CHECK_SOURCE_OPT},
325# endif
326#endif
327 {0, 0, 0, 0}};
278 328
279 char *rv[2]; 329 char *rv[2];
280 rv[PL] = NULL; 330 rv[PL] = NULL;
@@ -299,7 +349,7 @@ check_fping_config_wrapper process_arguments(int argc, char **argv) {
299 argc--; 349 argc--;
300 } 350 }
301 351
302 while (1) { 352 while (true) {
303 int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option); 353 int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
304 354
305 if (option_index == -1 || option_index == EOF || option_index == 1) { 355 if (option_index == -1 || option_index == EOF || option_index == 1) {
@@ -340,11 +390,7 @@ check_fping_config_wrapper process_arguments(int argc, char **argv) {
340 address_family = AF_INET; 390 address_family = AF_INET;
341 break; 391 break;
342 case '6': /* IPv6 only */ 392 case '6': /* IPv6 only */
343#ifdef USE_IPV6
344 address_family = AF_INET6; 393 address_family = AF_INET6;
345#else
346 usage(_("IPv6 support not available\n"));
347#endif
348 break; 394 break;
349 case 'c': 395 case 'c':
350 get_threshold(optarg, rv); 396 get_threshold(optarg, rv);
@@ -406,6 +452,20 @@ check_fping_config_wrapper process_arguments(int argc, char **argv) {
406 case 'M': 452 case 'M':
407 result.config.dontfrag = true; 453 result.config.dontfrag = true;
408 break; 454 break;
455 case FWMARK_OPT:
456 if (is_intpos(optarg)) {
457 result.config.fwmark = (unsigned int)atol(optarg);
458 result.config.fwmark_set = true;
459 } else {
460 usage(_("fwmark must be a positive integer"));
461 }
462 break;
463 case ICMP_TIMESTAMP_OPT:
464 result.config.icmp_timestamp = true;
465 break;
466 case CHECK_SOURCE_OPT:
467 result.config.check_source = true;
468 break;
409 } 469 }
410 } 470 }
411 471
@@ -493,6 +553,16 @@ void print_help(void) {
493 printf(" %s\n", _("set the Don't Fragment flag")); 553 printf(" %s\n", _("set the Don't Fragment flag"));
494 printf(" %s\n", "-R, --random"); 554 printf(" %s\n", "-R, --random");
495 printf(" %s\n", _("random packet data (to foil link data compression)")); 555 printf(" %s\n", _("random packet data (to foil link data compression)"));
556#ifdef FPING_VERSION_5_2_OR_HIGHER
557 printf(" %s\n", "--fwmark=INTEGER");
558 printf(" %s\n", _("set the routing mark to INTEGER (fping option)"));
559# ifdef FPING_VERSION_5_3_OR_HIGHER
560 printf(" %s\n", "--icmp-timestamp");
561 printf(" %s\n", _("use ICMP Timestamp instead of ICMP Echo (fping option)"));
562 printf(" %s\n", "--check-source");
563 printf(" %s\n", _("discard replies not from target address (fping option)"));
564# endif
565#endif
496 printf(UT_VERBOSE); 566 printf(UT_VERBOSE);
497 printf("\n"); 567 printf("\n");
498 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)")); 568 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
diff --git a/plugins/check_fping.d/config.h b/plugins/check_fping.d/config.h
index a0697bf3..d95e9ded 100644
--- a/plugins/check_fping.d/config.h
+++ b/plugins/check_fping.d/config.h
@@ -29,6 +29,21 @@ typedef struct {
29 bool cpl_p; 29 bool cpl_p;
30 int wpl; 30 int wpl;
31 bool wpl_p; 31 bool wpl_p;
32
33 // only available with fping version >= 5.2
34 // for a given uint _fwmark_ fping sets _fwmark_ as a firewall mark
35 // in the packets
36 unsigned int fwmark;
37 bool fwmark_set;
38
39
40 // only available with fping version >= 5.3
41 // Setting icmp_timestamp tells fping to use ICMP Timestamp (ICMP type 13) instead
42 // of ICMP Echo
43 bool icmp_timestamp;
44
45 // Setting check_source lets fping discard replies which are not from the target address
46 bool check_source;
32} check_fping_config; 47} check_fping_config;
33 48
34check_fping_config check_fping_config_init() { 49check_fping_config check_fping_config_init() {
@@ -53,6 +68,15 @@ check_fping_config check_fping_config_init() {
53 .cpl_p = false, 68 .cpl_p = false,
54 .wpl = 0, 69 .wpl = 0,
55 .wpl_p = false, 70 .wpl_p = false,
71
72 // only available with fping version >= 5.2
73 .fwmark = 0,
74 .fwmark_set = false, // just to be deterministic
75
76 // only available with fping version >= 5.3
77 .icmp_timestamp = false,
78 .check_source = false,
79
56 }; 80 };
57 return tmp; 81 return tmp;
58} 82}
diff --git a/plugins/check_http.c b/plugins/check_http.c
index baff682a..8e0c15ec 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -1724,6 +1724,16 @@ print_help (void)
1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1725 printf ("%s\n", _("certificate expiration times.")); 1725 printf ("%s\n", _("certificate expiration times."));
1726 1726
1727 printf ("\n");
1728 printf ("%s\n", _("ATTENTION!"));
1729 printf ("\n");
1730 printf ("%s\n", _("THIS PLUGIN IS DEPRECATED. The functionality was reimplemented by the"));
1731 printf ("%s\n", _("check_curl plugin, which can be used as a drop-in replacement. You should"));
1732 printf ("%s\n", _("migrate your checks over to check_curl, because check_http is going to be"));
1733 printf ("%s\n", _("removed sooner than later. Just replace check_http with check_curl in your"));
1734 printf ("%s\n", _("check command definitions."));
1735 printf ("%s\n", _("Report issues to: https://github.com/monitoring-plugins/monitoring-plugins/issues"));
1736
1727 printf ("\n\n"); 1737 printf ("\n\n");
1728 1738
1729 print_usage (); 1739 print_usage ();
diff --git a/plugins/check_ide_smart.c b/plugins/check_ide_smart.c
index 9640ef70..16fe3d01 100644
--- a/plugins/check_ide_smart.c
+++ b/plugins/check_ide_smart.c
@@ -56,7 +56,6 @@ void print_usage(void);
56# include <sys/device.h> 56# include <sys/device.h>
57# include <sys/param.h> 57# include <sys/param.h>
58# include <sys/sysctl.h> 58# include <sys/sysctl.h>
59# include <sys/videoio.h> /* for __u8 and friends */
60# include <sys/scsiio.h> 59# include <sys/scsiio.h>
61# include <sys/ataio.h> 60# include <sys/ataio.h>
62# include <dev/ata/atareg.h> 61# include <dev/ata/atareg.h>
@@ -79,48 +78,47 @@ void print_usage(void);
79#define UNKNOWN -1 78#define UNKNOWN -1
80 79
81typedef struct threshold_s { 80typedef struct threshold_s {
82 __u8 id; 81 uint8_t id;
83 __u8 threshold; 82 uint8_t threshold;
84 __u8 reserved[10]; 83 uint8_t reserved[10];
85} __attribute__((packed)) threshold_t; 84} __attribute__((packed)) threshold_t;
86 85
87typedef struct thresholds_s { 86typedef struct thresholds_s {
88 __u16 revision; 87 uint16_t revision;
89 threshold_t thresholds[NR_ATTRIBUTES]; 88 threshold_t thresholds[NR_ATTRIBUTES];
90 __u8 reserved[18]; 89 uint8_t reserved[18];
91 __u8 vendor[131]; 90 uint8_t vendor[131];
92 __u8 checksum; 91 uint8_t checksum;
93} __attribute__((packed)) thresholds_t; 92} __attribute__((packed)) thresholds_t;
94 93
95typedef struct value_s { 94typedef struct value_s {
96 __u8 id; 95 uint8_t id;
97 __u16 status; 96 uint16_t status;
98 __u8 value; 97 uint8_t value;
99 __u8 vendor[8]; 98 uint8_t vendor[8];
100} __attribute__((packed)) value_t; 99} __attribute__((packed)) value_t;
101 100
102typedef struct values_s { 101typedef struct values_s {
103 __u16 revision; 102 uint16_t revision;
104 value_t values[NR_ATTRIBUTES]; 103 value_t values[NR_ATTRIBUTES];
105 __u8 offline_status; 104 uint8_t offline_status;
106 __u8 vendor1; 105 uint8_t vendor1;
107 __u16 offline_timeout; 106 uint16_t offline_timeout;
108 __u8 vendor2; 107 uint8_t vendor2;
109 __u8 offline_capability; 108 uint8_t offline_capability;
110 __u16 smart_capability; 109 uint16_t smart_capability;
111 __u8 reserved[16]; 110 uint8_t reserved[16];
112 __u8 vendor[125]; 111 uint8_t vendor[125];
113 __u8 checksum; 112 uint8_t checksum;
114} __attribute__((packed)) values_t; 113} __attribute__((packed)) values_t;
115 114
116static struct { 115static struct {
117 __u8 value; 116 uint8_t value;
118 char *text; 117 char *text;
119} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"}, 118} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"}, {0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
120 {0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
121 119
122static struct { 120static struct {
123 __u8 value; 121 uint8_t value;
124 char *text; 122 char *text;
125} smart_command[] = {{SMART_ENABLE, "SMART_ENABLE"}, 123} smart_command[] = {{SMART_ENABLE, "SMART_ENABLE"},
126 {SMART_DISABLE, "SMART_DISABLE"}, 124 {SMART_DISABLE, "SMART_DISABLE"},
@@ -140,7 +138,7 @@ static int smart_read_values(int, values_t *);
140static int nagios(values_t *, thresholds_t *); 138static int nagios(values_t *, thresholds_t *);
141static void print_value(value_t *, threshold_t *); 139static void print_value(value_t *, threshold_t *);
142static void print_values(values_t *, thresholds_t *); 140static void print_values(values_t *, thresholds_t *);
143static int smart_cmd_simple(int, enum SmartCommand, __u8, bool); 141static int smart_cmd_simple(int, enum SmartCommand, uint8_t, bool);
144static int smart_read_thresholds(int, thresholds_t *); 142static int smart_read_thresholds(int, thresholds_t *);
145static bool verbose = false; 143static bool verbose = false;
146 144
@@ -175,8 +173,9 @@ int main(int argc, char *argv[]) {
175 173
176 o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex); 174 o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex);
177 175
178 if (o == -1 || o == EOF || o == 1) 176 if (o == -1 || o == EOF || o == 1) {
179 break; 177 break;
178 }
180 179
181 switch (o) { 180 switch (o) {
182 case 'd': 181 case 'd':
@@ -234,8 +233,9 @@ int main(int argc, char *argv[]) {
234 smart_read_values(fd, &values); 233 smart_read_values(fd, &values);
235 smart_read_thresholds(fd, &thresholds); 234 smart_read_thresholds(fd, &thresholds);
236 retval = nagios(&values, &thresholds); 235 retval = nagios(&values, &thresholds);
237 if (verbose) 236 if (verbose) {
238 print_values(&values, &thresholds); 237 print_values(&values, &thresholds);
238 }
239 239
240 close(fd); 240 close(fd);
241 return retval; 241 return retval;
@@ -254,7 +254,7 @@ char *get_offline_text(int status) {
254int smart_read_values(int fd, values_t *values) { 254int smart_read_values(int fd, values_t *values) {
255#ifdef __linux__ 255#ifdef __linux__
256 int e; 256 int e;
257 __u8 args[4 + 512]; 257 uint8_t args[4 + 512];
258 args[0] = WIN_SMART; 258 args[0] = WIN_SMART;
259 args[1] = 0; 259 args[1] = 0;
260 args[2] = SMART_READ_VALUES; 260 args[2] = SMART_READ_VALUES;
@@ -282,8 +282,9 @@ int smart_read_values(int fd, values_t *values) {
282 req.cylinder = WDSMART_CYL; 282 req.cylinder = WDSMART_CYL;
283 283
284 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 284 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
285 if (req.retsts != ATACMD_OK) 285 if (req.retsts != ATACMD_OK) {
286 errno = ENODEV; 286 errno = ENODEV;
287 }
287 } 288 }
288 289
289 if (errno != 0) { 290 if (errno != 0) {
@@ -370,22 +371,24 @@ void print_values(values_t *p, thresholds_t *t) {
370 p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : ""); 371 p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : "");
371} 372}
372 373
373int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_error) { 374int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_error) {
374 int e = STATE_UNKNOWN; 375 int e = STATE_UNKNOWN;
375#ifdef __linux__ 376#ifdef __linux__
376 __u8 args[4]; 377 uint8_t args[4];
377 args[0] = WIN_SMART; 378 args[0] = WIN_SMART;
378 args[1] = val0; 379 args[1] = val0;
379 args[2] = smart_command[command].value; 380 args[2] = smart_command[command].value;
380 args[3] = 0; 381 args[3] = 0;
381 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) { 382 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
382 e = STATE_CRITICAL; 383 e = STATE_CRITICAL;
383 if (show_error) 384 if (show_error) {
384 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); 385 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
386 }
385 } else { 387 } else {
386 e = STATE_OK; 388 e = STATE_OK;
387 if (show_error) 389 if (show_error) {
388 printf(_("OK - Command sent (%s)\n"), smart_command[command].text); 390 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
391 }
389 } 392 }
390 393
391#endif /* __linux__ */ 394#endif /* __linux__ */
@@ -401,20 +404,24 @@ int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_err
401 req.sec_count = val0; 404 req.sec_count = val0;
402 405
403 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 406 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
404 if (req.retsts != ATACMD_OK) 407 if (req.retsts != ATACMD_OK) {
405 errno = ENODEV; 408 errno = ENODEV;
406 if (req.cylinder != WDSMART_CYL) 409 }
410 if (req.cylinder != WDSMART_CYL) {
407 errno = ENODEV; 411 errno = ENODEV;
412 }
408 } 413 }
409 414
410 if (errno != 0) { 415 if (errno != 0) {
411 e = STATE_CRITICAL; 416 e = STATE_CRITICAL;
412 if (show_error) 417 if (show_error) {
413 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); 418 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
419 }
414 } else { 420 } else {
415 e = STATE_OK; 421 e = STATE_OK;
416 if (show_error) 422 if (show_error) {
417 printf(_("OK - Command sent (%s)\n"), smart_command[command].text); 423 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
424 }
418 } 425 }
419 426
420#endif /* __NetBSD__ */ 427#endif /* __NetBSD__ */
@@ -424,7 +431,7 @@ int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_err
424int smart_read_thresholds(int fd, thresholds_t *thresholds) { 431int smart_read_thresholds(int fd, thresholds_t *thresholds) {
425#ifdef __linux__ 432#ifdef __linux__
426 int e; 433 int e;
427 __u8 args[4 + 512]; 434 uint8_t args[4 + 512];
428 args[0] = WIN_SMART; 435 args[0] = WIN_SMART;
429 args[1] = 0; 436 args[1] = 0;
430 args[2] = SMART_READ_THRESHOLDS; 437 args[2] = SMART_READ_THRESHOLDS;
@@ -452,8 +459,9 @@ int smart_read_thresholds(int fd, thresholds_t *thresholds) {
452 req.cylinder = WDSMART_CYL; 459 req.cylinder = WDSMART_CYL;
453 460
454 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 461 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
455 if (req.retsts != ATACMD_OK) 462 if (req.retsts != ATACMD_OK) {
456 errno = ENODEV; 463 errno = ENODEV;
464 }
457 } 465 }
458 466
459 if (errno != 0) { 467 if (errno != 0) {
diff --git a/plugins/check_nwstat.c b/plugins/check_nwstat.c
deleted file mode 100644
index 176dfbc8..00000000
--- a/plugins/check_nwstat.c
+++ /dev/null
@@ -1,1527 +0,0 @@
1/*****************************************************************************
2 *
3 * Monitoring check_nwstat plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_nwstat plugin
11 *
12 * This plugin attempts to contact the MRTGEXT NLM running on a
13 * Novell server to gather the requested system information.
14 *
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 *
29 *
30 *****************************************************************************/
31
32const char *progname = "check_nwstat";
33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "common.h"
37#include "netutils.h"
38#include "utils.h"
39
40enum checkvar {
41 NONE,
42 LOAD1, /* check 1 minute CPU load */
43 LOAD5, /* check 5 minute CPU load */
44 LOAD15, /* check 15 minute CPU load */
45 CONNS, /* check number of connections */
46 VPF, /* check % free space on volume */
47 VMF, /* check MB free space on volume */
48 VMU, /* check MB used space on volume */
49 VPU, /* check % used space on volume */
50 VMP, /* check MB purgeable space on volume */
51 VKF, /* check KB free space on volume */
52 LTCH, /* check long-term cache hit percentage */
53 CBUFF, /* check total cache buffers */
54 CDBUFF, /* check dirty cache buffers */
55 LRUM, /* check LRU sitting time in minutes */
56 DSDB, /* check to see if DS Database is open */
57 LOGINS, /* check to see if logins are enabled */
58 NRMH, /* check to see NRM Health Status */
59 PUPRB, /* check % of used packet receive buffers */
60 UPRB, /* check used packet receive buffers */
61 SAPENTRIES, /* check SAP entries */
62 OFILES, /* check number of open files */
63 VKP, /* check KB purgeable space on volume */
64 VPP, /* check % purgeable space on volume */
65 VKNP, /* check KB not yet purgeable space on volume */
66 VPNP, /* check % not yet purgeable space on volume */
67 ABENDS, /* check abended thread count */
68 CSPROCS, /* check number of current service processes */
69 TSYNC, /* check timesync status 0=no 1=yes in sync to the network */
70 LRUS, /* check LRU sitting time in seconds */
71 DCB, /* check dirty cache buffers as a percentage of the total */
72 TCB, /* check total cache buffers as a percentage of the original */
73 DSVER, /* check NDS version */
74 UPTIME, /* check server uptime */
75 NLM, /* check NLM loaded */
76 NRMP, /* check NRM Process Values */
77 NRMM, /* check NRM Memory Values */
78 NRMS, /* check NRM Values */
79 NSS1, /* check Statistics from _Admin:Manage_NSS\GeneralStats.xml */
80 NSS2, /* check Statistics from _Admin:Manage_NSS\BufferCache.xml */
81 NSS3, /* check statistics from _Admin:Manage_NSS\NameCache.xml */
82 NSS4, /* check statistics from _Admin:Manage_NSS\FileStats.xml */
83 NSS5, /* check statistics from _Admin:Manage_NSS\ObjectCache.xml */
84 NSS6, /* check statistics from _Admin:Manage_NSS\Thread.xml */
85 NSS7 /* check statistics from _Admin:Manage_NSS\AuthorizationCache.xml */
86};
87
88enum {
89 PORT = 9999
90};
91
92static char *server_address = NULL;
93static char *volume_name = NULL;
94static char *nlm_name = NULL;
95static char *nrmp_name = NULL;
96static char *nrmm_name = NULL;
97static char *nrms_name = NULL;
98static char *nss1_name = NULL;
99static char *nss2_name = NULL;
100static char *nss3_name = NULL;
101static char *nss4_name = NULL;
102static char *nss5_name = NULL;
103static char *nss6_name = NULL;
104static char *nss7_name = NULL;
105static int server_port = PORT;
106static unsigned long warning_value = 0L;
107static unsigned long critical_value = 0L;
108static bool check_warning_value = false;
109static bool check_critical_value = false;
110static bool check_netware_version = false;
111static enum checkvar vars_to_check = NONE;
112static int sap_number = -1;
113
114static int process_arguments(int /*argc*/, char ** /*argv*/);
115static void print_help(void);
116void print_usage(void);
117
118int main(int argc, char **argv) {
119 int result = STATE_UNKNOWN;
120 int sd;
121 char *send_buffer = NULL;
122 char recv_buffer[MAX_INPUT_BUFFER];
123 char *output_message = NULL;
124 char *temp_buffer = NULL;
125 char *netware_version = NULL;
126
127 int time_sync_status = 0;
128 int nrm_health_status = 0;
129 unsigned long total_cache_buffers = 0;
130 unsigned long dirty_cache_buffers = 0;
131 unsigned long open_files = 0;
132 unsigned long abended_threads = 0;
133 unsigned long max_service_processes = 0;
134 unsigned long current_service_processes = 0;
135 unsigned long free_disk_space = 0L;
136 unsigned long nrmp_value = 0L;
137 unsigned long nrmm_value = 0L;
138 unsigned long nrms_value = 0L;
139 unsigned long nss1_value = 0L;
140 unsigned long nss2_value = 0L;
141 unsigned long nss3_value = 0L;
142 unsigned long nss4_value = 0L;
143 unsigned long nss5_value = 0L;
144 unsigned long nss6_value = 0L;
145 unsigned long nss7_value = 0L;
146 unsigned long total_disk_space = 0L;
147 unsigned long used_disk_space = 0L;
148 unsigned long percent_used_disk_space = 0L;
149 unsigned long purgeable_disk_space = 0L;
150 unsigned long non_purgeable_disk_space = 0L;
151 unsigned long percent_free_space = 0;
152 unsigned long percent_purgeable_space = 0;
153 unsigned long percent_non_purgeable_space = 0;
154 unsigned long current_connections = 0L;
155 unsigned long utilization = 0L;
156 unsigned long cache_hits = 0;
157 unsigned long cache_buffers = 0L;
158 unsigned long lru_time = 0L;
159 unsigned long max_packet_receive_buffers = 0;
160 unsigned long used_packet_receive_buffers = 0;
161 unsigned long percent_used_packet_receive_buffers = 0L;
162 unsigned long sap_entries = 0;
163 char uptime[MAX_INPUT_BUFFER];
164
165 setlocale(LC_ALL, "");
166 bindtextdomain(PACKAGE, LOCALEDIR);
167 textdomain(PACKAGE);
168
169 /* Parse extra opts if any */
170 argv = np_extra_opts(&argc, argv, progname);
171
172 if (process_arguments(argc, argv) == ERROR)
173 usage4(_("Could not parse arguments"));
174
175 /* initialize alarm signal handling */
176 signal(SIGALRM, socket_timeout_alarm_handler);
177
178 /* set socket timeout */
179 alarm(socket_timeout);
180
181 /* open connection */
182 my_tcp_connect(server_address, server_port, &sd);
183
184 /* get OS version string */
185 if (check_netware_version) {
186 send_buffer = strdup("S19\r\n");
187 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
188 if (result != STATE_OK)
189 return result;
190 if (!strcmp(recv_buffer, "-1\n"))
191 netware_version = strdup("");
192 else {
193 recv_buffer[strlen(recv_buffer) - 1] = 0;
194 xasprintf(&netware_version, _("NetWare %s: "), recv_buffer);
195 }
196 } else
197 netware_version = strdup("");
198
199 /* check CPU load */
200 if (vars_to_check == LOAD1 || vars_to_check == LOAD5 || vars_to_check == LOAD15) {
201
202 switch (vars_to_check) {
203 case LOAD1:
204 temp_buffer = strdup("1");
205 break;
206 case LOAD5:
207 temp_buffer = strdup("5");
208 break;
209 default:
210 temp_buffer = strdup("15");
211 break;
212 }
213
214 close(sd);
215 my_tcp_connect(server_address, server_port, &sd);
216
217 xasprintf(&send_buffer, "UTIL%s\r\n", temp_buffer);
218 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
219 if (result != STATE_OK)
220 return result;
221 utilization = strtoul(recv_buffer, NULL, 10);
222
223 close(sd);
224 my_tcp_connect(server_address, server_port, &sd);
225
226 send_buffer = strdup("UPTIME\r\n");
227 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
228 if (result != STATE_OK)
229 return result;
230 recv_buffer[strlen(recv_buffer) - 1] = 0;
231 sprintf(uptime, _("Up %s,"), recv_buffer);
232
233 if (check_critical_value && utilization >= critical_value)
234 result = STATE_CRITICAL;
235 else if (check_warning_value && utilization >= warning_value)
236 result = STATE_WARNING;
237
238 xasprintf(&output_message, _("Load %s - %s %s-min load average = %lu%%|load%s=%lu;%lu;%lu;0;100"), state_text(result), uptime,
239 temp_buffer, utilization, temp_buffer, utilization, warning_value, critical_value);
240
241 /* check number of user connections */
242 } else if (vars_to_check == CONNS) {
243
244 close(sd);
245 my_tcp_connect(server_address, server_port, &sd);
246
247 send_buffer = strdup("CONNECT\r\n");
248 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
249 if (result != STATE_OK)
250 return result;
251 current_connections = strtoul(recv_buffer, NULL, 10);
252
253 if (check_critical_value && current_connections >= critical_value)
254 result = STATE_CRITICAL;
255 else if (check_warning_value && current_connections >= warning_value)
256 result = STATE_WARNING;
257
258 xasprintf(&output_message, _("Conns %s - %lu current connections|Conns=%lu;%lu;%lu;;"), state_text(result), current_connections,
259 current_connections, warning_value, critical_value);
260
261 /* check % long term cache hits */
262 } else if (vars_to_check == LTCH) {
263
264 close(sd);
265 my_tcp_connect(server_address, server_port, &sd);
266
267 send_buffer = strdup("S1\r\n");
268 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
269 if (result != STATE_OK)
270 return result;
271 cache_hits = atoi(recv_buffer);
272
273 if (check_critical_value && cache_hits <= critical_value)
274 result = STATE_CRITICAL;
275 else if (check_warning_value && cache_hits <= warning_value)
276 result = STATE_WARNING;
277
278 xasprintf(&output_message, _("%s: Long term cache hits = %lu%%"), state_text(result), cache_hits);
279
280 /* check cache buffers */
281 } else if (vars_to_check == CBUFF) {
282
283 close(sd);
284 my_tcp_connect(server_address, server_port, &sd);
285
286 send_buffer = strdup("S2\r\n");
287 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
288 if (result != STATE_OK)
289 return result;
290 cache_buffers = strtoul(recv_buffer, NULL, 10);
291
292 if (check_critical_value && cache_buffers <= critical_value)
293 result = STATE_CRITICAL;
294 else if (check_warning_value && cache_buffers <= warning_value)
295 result = STATE_WARNING;
296
297 xasprintf(&output_message, _("%s: Total cache buffers = %lu|Cachebuffers=%lu;%lu;%lu;;"), state_text(result), cache_buffers,
298 cache_buffers, warning_value, critical_value);
299
300 /* check dirty cache buffers */
301 } else if (vars_to_check == CDBUFF) {
302
303 close(sd);
304 my_tcp_connect(server_address, server_port, &sd);
305
306 send_buffer = strdup("S3\r\n");
307 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
308 if (result != STATE_OK)
309 return result;
310 cache_buffers = strtoul(recv_buffer, NULL, 10);
311
312 if (check_critical_value && cache_buffers >= critical_value)
313 result = STATE_CRITICAL;
314 else if (check_warning_value && cache_buffers >= warning_value)
315 result = STATE_WARNING;
316
317 xasprintf(&output_message, _("%s: Dirty cache buffers = %lu|Dirty-Cache-Buffers=%lu;%lu;%lu;;"), state_text(result), cache_buffers,
318 cache_buffers, warning_value, critical_value);
319
320 /* check LRU sitting time in minutes */
321 } else if (vars_to_check == LRUM) {
322
323 close(sd);
324 my_tcp_connect(server_address, server_port, &sd);
325
326 send_buffer = strdup("S5\r\n");
327 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
328 if (result != STATE_OK)
329 return result;
330 lru_time = strtoul(recv_buffer, NULL, 10);
331
332 if (check_critical_value && lru_time <= critical_value)
333 result = STATE_CRITICAL;
334 else if (check_warning_value && lru_time <= warning_value)
335 result = STATE_WARNING;
336
337 xasprintf(&output_message, _("%s: LRU sitting time = %lu minutes"), state_text(result), lru_time);
338
339 /* check KB free space on volume */
340 } else if (vars_to_check == VKF) {
341
342 close(sd);
343 my_tcp_connect(server_address, server_port, &sd);
344
345 xasprintf(&send_buffer, "VKF%s\r\n", volume_name);
346 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
347 if (result != STATE_OK)
348 return result;
349
350 if (!strcmp(recv_buffer, "-1\n")) {
351 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
352 result = STATE_CRITICAL;
353 } else {
354 free_disk_space = strtoul(recv_buffer, NULL, 10);
355 if (check_critical_value && free_disk_space <= critical_value)
356 result = STATE_CRITICAL;
357 else if (check_warning_value && free_disk_space <= warning_value)
358 result = STATE_WARNING;
359 xasprintf(&output_message, _("%s%lu KB free on volume %s|KBFree%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
360 free_disk_space, volume_name, volume_name, free_disk_space, warning_value, critical_value);
361 }
362
363 /* check MB free space on volume */
364 } else if (vars_to_check == VMF) {
365
366 xasprintf(&send_buffer, "VMF%s\r\n", volume_name);
367 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
368 if (result != STATE_OK)
369 return result;
370
371 if (!strcmp(recv_buffer, "-1\n")) {
372 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
373 result = STATE_CRITICAL;
374 } else {
375 free_disk_space = strtoul(recv_buffer, NULL, 10);
376 if (check_critical_value && free_disk_space <= critical_value)
377 result = STATE_CRITICAL;
378 else if (check_warning_value && free_disk_space <= warning_value)
379 result = STATE_WARNING;
380 xasprintf(&output_message, _("%s%lu MB free on volume %s|MBFree%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
381 free_disk_space, volume_name, volume_name, free_disk_space, warning_value, critical_value);
382 }
383 /* check MB used space on volume */
384 } else if (vars_to_check == VMU) {
385
386 xasprintf(&send_buffer, "VMU%s\r\n", volume_name);
387 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
388 if (result != STATE_OK)
389 return result;
390
391 if (!strcmp(recv_buffer, "-1\n")) {
392 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
393 result = STATE_CRITICAL;
394 } else {
395 free_disk_space = strtoul(recv_buffer, NULL, 10);
396 if (check_critical_value && free_disk_space <= critical_value)
397 result = STATE_CRITICAL;
398 else if (check_warning_value && free_disk_space <= warning_value)
399 result = STATE_WARNING;
400 xasprintf(&output_message, _("%s%lu MB used on volume %s|MBUsed%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
401 free_disk_space, volume_name, volume_name, free_disk_space, warning_value, critical_value);
402 }
403 /* check % used space on volume */
404 } else if (vars_to_check == VPU) {
405 close(sd);
406 my_tcp_connect(server_address, server_port, &sd);
407
408 asprintf(&send_buffer, "VMU%s\r\n", volume_name);
409 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
410
411 if (result != STATE_OK)
412 return result;
413
414 if (!strcmp(recv_buffer, "-1\n")) {
415 asprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
416 result = STATE_CRITICAL;
417
418 } else {
419 used_disk_space = strtoul(recv_buffer, NULL, 10);
420 close(sd);
421 my_tcp_connect(server_address, server_port, &sd);
422 /* get total volume in MB */
423 asprintf(&send_buffer, "VMS%s\r\n", volume_name);
424 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
425 if (result != STATE_OK)
426 return result;
427 total_disk_space = strtoul(recv_buffer, NULL, 10);
428 /* calculate percent used on volume */
429 percent_used_disk_space = (unsigned long)(((double)used_disk_space / (double)total_disk_space) * 100.0);
430
431 if (check_critical_value && percent_used_disk_space >= critical_value)
432 result = STATE_CRITICAL;
433 else if (check_warning_value && percent_used_disk_space >= warning_value)
434 result = STATE_WARNING;
435
436 asprintf(&output_message, _("%lu MB (%lu%%) used on volume %s - total %lu MB|Used space in percent on %s=%lu;%lu;%lu;0;100"),
437 used_disk_space, percent_used_disk_space, volume_name, total_disk_space, volume_name, percent_used_disk_space,
438 warning_value, critical_value);
439 }
440
441 /* check % free space on volume */
442 } else if (vars_to_check == VPF) {
443
444 close(sd);
445 my_tcp_connect(server_address, server_port, &sd);
446
447 xasprintf(&send_buffer, "VKF%s\r\n", volume_name);
448 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
449 if (result != STATE_OK)
450 return result;
451
452 if (!strcmp(recv_buffer, "-1\n")) {
453
454 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
455 result = STATE_CRITICAL;
456
457 } else {
458
459 free_disk_space = strtoul(recv_buffer, NULL, 10);
460
461 close(sd);
462 my_tcp_connect(server_address, server_port, &sd);
463
464 xasprintf(&send_buffer, "VKS%s\r\n", volume_name);
465 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
466 if (result != STATE_OK)
467 return result;
468 total_disk_space = strtoul(recv_buffer, NULL, 10);
469
470 percent_free_space = (unsigned long)(((double)free_disk_space / (double)total_disk_space) * 100.0);
471
472 if (check_critical_value && percent_free_space <= critical_value)
473 result = STATE_CRITICAL;
474 else if (check_warning_value && percent_free_space <= warning_value)
475 result = STATE_WARNING;
476 free_disk_space /= 1024;
477 total_disk_space /= 1024;
478 xasprintf(&output_message, _("%lu MB (%lu%%) free on volume %s - total %lu MB|FreeMB%s=%lu;%lu;%lu;0;100"), free_disk_space,
479 percent_free_space, volume_name, total_disk_space, volume_name, percent_free_space, warning_value, critical_value);
480 }
481
482 /* check to see if DS Database is open or closed */
483 } else if (vars_to_check == DSDB) {
484
485 close(sd);
486 my_tcp_connect(server_address, server_port, &sd);
487
488 send_buffer = strdup("S11\r\n");
489 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
490 if (result != STATE_OK)
491 return result;
492 if (atoi(recv_buffer) == 1)
493 result = STATE_OK;
494 else
495 result = STATE_WARNING;
496
497 close(sd);
498 my_tcp_connect(server_address, server_port, &sd);
499
500 send_buffer = strdup("S13\r\n");
501 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
502 temp_buffer = strtok(recv_buffer, "\r\n");
503
504 xasprintf(&output_message, _("Directory Services Database is %s (DS version %s)"), (result == STATE_OK) ? "open" : "closed",
505 temp_buffer);
506
507 /* check to see if logins are enabled */
508 } else if (vars_to_check == LOGINS) {
509
510 close(sd);
511 my_tcp_connect(server_address, server_port, &sd);
512
513 send_buffer = strdup("S12\r\n");
514 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
515 if (result != STATE_OK)
516 return result;
517 if (atoi(recv_buffer) == 1)
518 result = STATE_OK;
519 else
520 result = STATE_WARNING;
521
522 xasprintf(&output_message, _("Logins are %s"), (result == STATE_OK) ? _("enabled") : _("disabled"));
523
524 /* check NRM Health Status Summary*/
525 } else if (vars_to_check == NRMH) {
526
527 xasprintf(&send_buffer, "NRMH\r\n");
528 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
529 if (result != STATE_OK)
530 return result;
531
532 nrm_health_status = atoi(recv_buffer);
533
534 if (nrm_health_status == 2) {
535 result = STATE_OK;
536 xasprintf(&output_message, _("CRITICAL - NRM Status is bad!"));
537 } else {
538 if (nrm_health_status == 1) {
539 result = STATE_WARNING;
540 xasprintf(&output_message, _("Warning - NRM Status is suspect!"));
541 }
542
543 xasprintf(&output_message, _("OK - NRM Status is good!"));
544 }
545
546 /* check packet receive buffers */
547 } else if (vars_to_check == UPRB || vars_to_check == PUPRB) {
548
549 close(sd);
550 my_tcp_connect(server_address, server_port, &sd);
551
552 xasprintf(&send_buffer, "S15\r\n");
553 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
554 if (result != STATE_OK)
555 return result;
556
557 used_packet_receive_buffers = atoi(recv_buffer);
558
559 close(sd);
560 my_tcp_connect(server_address, server_port, &sd);
561
562 xasprintf(&send_buffer, "S16\r\n");
563 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
564 if (result != STATE_OK)
565 return result;
566
567 max_packet_receive_buffers = atoi(recv_buffer);
568
569 percent_used_packet_receive_buffers =
570 (unsigned long)(((double)used_packet_receive_buffers / (double)max_packet_receive_buffers) * 100.0);
571
572 if (vars_to_check == UPRB) {
573 if (check_critical_value && used_packet_receive_buffers >= critical_value)
574 result = STATE_CRITICAL;
575 else if (check_warning_value && used_packet_receive_buffers >= warning_value)
576 result = STATE_WARNING;
577 } else {
578 if (check_critical_value && percent_used_packet_receive_buffers >= critical_value)
579 result = STATE_CRITICAL;
580 else if (check_warning_value && percent_used_packet_receive_buffers >= warning_value)
581 result = STATE_WARNING;
582 }
583
584 xasprintf(&output_message, _("%lu of %lu (%lu%%) packet receive buffers used"), used_packet_receive_buffers,
585 max_packet_receive_buffers, percent_used_packet_receive_buffers);
586
587 /* check SAP table entries */
588 } else if (vars_to_check == SAPENTRIES) {
589
590 close(sd);
591 my_tcp_connect(server_address, server_port, &sd);
592
593 if (sap_number == -1)
594 xasprintf(&send_buffer, "S9\r\n");
595 else
596 xasprintf(&send_buffer, "S9.%d\r\n", sap_number);
597 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
598 if (result != STATE_OK)
599 return result;
600
601 sap_entries = atoi(recv_buffer);
602
603 if (check_critical_value && sap_entries >= critical_value)
604 result = STATE_CRITICAL;
605 else if (check_warning_value && sap_entries >= warning_value)
606 result = STATE_WARNING;
607
608 if (sap_number == -1)
609 xasprintf(&output_message, _("%lu entries in SAP table"), sap_entries);
610 else
611 xasprintf(&output_message, _("%lu entries in SAP table for SAP type %d"), sap_entries, sap_number);
612
613 /* check KB purgeable space on volume */
614 } else if (vars_to_check == VKP) {
615
616 close(sd);
617 my_tcp_connect(server_address, server_port, &sd);
618
619 xasprintf(&send_buffer, "VKP%s\r\n", volume_name);
620 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
621 if (result != STATE_OK)
622 return result;
623
624 if (!strcmp(recv_buffer, "-1\n")) {
625 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
626 result = STATE_CRITICAL;
627 } else {
628 purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
629 if (check_critical_value && purgeable_disk_space >= critical_value)
630 result = STATE_CRITICAL;
631 else if (check_warning_value && purgeable_disk_space >= warning_value)
632 result = STATE_WARNING;
633 xasprintf(&output_message, _("%s%lu KB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
634 purgeable_disk_space, volume_name, volume_name, purgeable_disk_space, warning_value, critical_value);
635 }
636 /* check MB purgeable space on volume */
637 } else if (vars_to_check == VMP) {
638
639 xasprintf(&send_buffer, "VMP%s\r\n", volume_name);
640 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
641 if (result != STATE_OK)
642 return result;
643
644 if (!strcmp(recv_buffer, "-1\n")) {
645 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
646 result = STATE_CRITICAL;
647 } else {
648 purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
649 if (check_critical_value && purgeable_disk_space >= critical_value)
650 result = STATE_CRITICAL;
651 else if (check_warning_value && purgeable_disk_space >= warning_value)
652 result = STATE_WARNING;
653 xasprintf(&output_message, _("%s%lu MB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"), (result == STATE_OK) ? "" : _("Only "),
654 purgeable_disk_space, volume_name, volume_name, purgeable_disk_space, warning_value, critical_value);
655 }
656
657 /* check % purgeable space on volume */
658 } else if (vars_to_check == VPP) {
659
660 close(sd);
661 my_tcp_connect(server_address, server_port, &sd);
662
663 xasprintf(&send_buffer, "VKP%s\r\n", volume_name);
664 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
665 if (result != STATE_OK)
666 return result;
667
668 if (!strcmp(recv_buffer, "-1\n")) {
669
670 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
671 result = STATE_CRITICAL;
672
673 } else {
674
675 purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
676
677 close(sd);
678 my_tcp_connect(server_address, server_port, &sd);
679
680 xasprintf(&send_buffer, "VKS%s\r\n", volume_name);
681 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
682 if (result != STATE_OK)
683 return result;
684 total_disk_space = strtoul(recv_buffer, NULL, 10);
685
686 percent_purgeable_space = (unsigned long)(((double)purgeable_disk_space / (double)total_disk_space) * 100.0);
687
688 if (check_critical_value && percent_purgeable_space >= critical_value)
689 result = STATE_CRITICAL;
690 else if (check_warning_value && percent_purgeable_space >= warning_value)
691 result = STATE_WARNING;
692 purgeable_disk_space /= 1024;
693 xasprintf(&output_message, _("%lu MB (%lu%%) purgeable on volume %s|Purgeable%s=%lu;%lu;%lu;0;100"), purgeable_disk_space,
694 percent_purgeable_space, volume_name, volume_name, percent_purgeable_space, warning_value, critical_value);
695 }
696
697 /* check KB not yet purgeable space on volume */
698 } else if (vars_to_check == VKNP) {
699
700 close(sd);
701 my_tcp_connect(server_address, server_port, &sd);
702
703 xasprintf(&send_buffer, "VKNP%s\r\n", volume_name);
704 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
705 if (result != STATE_OK)
706 return result;
707
708 if (!strcmp(recv_buffer, "-1\n")) {
709 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
710 result = STATE_CRITICAL;
711 } else {
712 non_purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
713 if (check_critical_value && non_purgeable_disk_space >= critical_value)
714 result = STATE_CRITICAL;
715 else if (check_warning_value && non_purgeable_disk_space >= warning_value)
716 result = STATE_WARNING;
717 xasprintf(&output_message, _("%s%lu KB not yet purgeable on volume %s"), (result == STATE_OK) ? "" : _("Only "),
718 non_purgeable_disk_space, volume_name);
719 }
720
721 /* check % not yet purgeable space on volume */
722 } else if (vars_to_check == VPNP) {
723
724 close(sd);
725 my_tcp_connect(server_address, server_port, &sd);
726
727 xasprintf(&send_buffer, "VKNP%s\r\n", volume_name);
728 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
729 if (result != STATE_OK)
730 return result;
731
732 if (!strcmp(recv_buffer, "-1\n")) {
733
734 xasprintf(&output_message, _("CRITICAL - Volume '%s' does not exist!"), volume_name);
735 result = STATE_CRITICAL;
736
737 } else {
738
739 non_purgeable_disk_space = strtoul(recv_buffer, NULL, 10);
740
741 close(sd);
742 my_tcp_connect(server_address, server_port, &sd);
743
744 xasprintf(&send_buffer, "VKS%s\r\n", volume_name);
745 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
746 if (result != STATE_OK)
747 return result;
748 total_disk_space = strtoul(recv_buffer, NULL, 10);
749
750 percent_non_purgeable_space = (unsigned long)(((double)non_purgeable_disk_space / (double)total_disk_space) * 100.0);
751
752 if (check_critical_value && percent_non_purgeable_space >= critical_value)
753 result = STATE_CRITICAL;
754 else if (check_warning_value && percent_non_purgeable_space >= warning_value)
755 result = STATE_WARNING;
756 purgeable_disk_space /= 1024;
757 xasprintf(&output_message, _("%lu MB (%lu%%) not yet purgeable on volume %s"), non_purgeable_disk_space,
758 percent_non_purgeable_space, volume_name);
759 }
760
761 /* check # of open files */
762 } else if (vars_to_check == OFILES) {
763
764 close(sd);
765 my_tcp_connect(server_address, server_port, &sd);
766
767 xasprintf(&send_buffer, "S18\r\n");
768 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
769 if (result != STATE_OK)
770 return result;
771
772 open_files = atoi(recv_buffer);
773
774 if (check_critical_value && open_files >= critical_value)
775 result = STATE_CRITICAL;
776 else if (check_warning_value && open_files >= warning_value)
777 result = STATE_WARNING;
778
779 xasprintf(&output_message, _("%lu open files|Openfiles=%lu;%lu;%lu;0,0"), open_files, open_files, warning_value, critical_value);
780
781 /* check # of abended threads (Netware > 5.x only) */
782 } else if (vars_to_check == ABENDS) {
783
784 close(sd);
785 my_tcp_connect(server_address, server_port, &sd);
786
787 xasprintf(&send_buffer, "S17\r\n");
788 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
789 if (result != STATE_OK)
790 return result;
791
792 abended_threads = atoi(recv_buffer);
793
794 if (check_critical_value && abended_threads >= critical_value)
795 result = STATE_CRITICAL;
796 else if (check_warning_value && abended_threads >= warning_value)
797 result = STATE_WARNING;
798
799 xasprintf(&output_message, _("%lu abended threads|Abends=%lu;%lu;%lu;;"), abended_threads, abended_threads, warning_value,
800 critical_value);
801
802 /* check # of current service processes (Netware 5.x only) */
803 } else if (vars_to_check == CSPROCS) {
804
805 close(sd);
806 my_tcp_connect(server_address, server_port, &sd);
807
808 xasprintf(&send_buffer, "S20\r\n");
809 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
810 if (result != STATE_OK)
811 return result;
812
813 max_service_processes = atoi(recv_buffer);
814
815 close(sd);
816 my_tcp_connect(server_address, server_port, &sd);
817
818 xasprintf(&send_buffer, "S21\r\n");
819 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
820 if (result != STATE_OK)
821 return result;
822
823 current_service_processes = atoi(recv_buffer);
824
825 if (check_critical_value && current_service_processes >= critical_value)
826 result = STATE_CRITICAL;
827 else if (check_warning_value && current_service_processes >= warning_value)
828 result = STATE_WARNING;
829
830 xasprintf(&output_message, _("%lu current service processes (%lu max)|Processes=%lu;%lu;%lu;0;%lu"), current_service_processes,
831 max_service_processes, current_service_processes, warning_value, critical_value, max_service_processes);
832
833 /* check # Timesync Status */
834 } else if (vars_to_check == TSYNC) {
835
836 close(sd);
837 my_tcp_connect(server_address, server_port, &sd);
838
839 xasprintf(&send_buffer, "S22\r\n");
840 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
841 if (result != STATE_OK)
842 return result;
843
844 time_sync_status = atoi(recv_buffer);
845
846 if (time_sync_status == 0) {
847 result = STATE_CRITICAL;
848 xasprintf(&output_message, _("CRITICAL - Time not in sync with network!"));
849 } else {
850 xasprintf(&output_message, _("OK - Time in sync with network!"));
851 }
852
853 /* check LRU sitting time in secondss */
854 } else if (vars_to_check == LRUS) {
855
856 close(sd);
857 my_tcp_connect(server_address, server_port, &sd);
858
859 send_buffer = strdup("S4\r\n");
860 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
861 if (result != STATE_OK)
862 return result;
863 lru_time = strtoul(recv_buffer, NULL, 10);
864
865 if (check_critical_value && lru_time <= critical_value)
866 result = STATE_CRITICAL;
867 else if (check_warning_value && lru_time <= warning_value)
868 result = STATE_WARNING;
869 xasprintf(&output_message, _("LRU sitting time = %lu seconds"), lru_time);
870
871 /* check % dirty cacheobuffers as a percentage of the total*/
872 } else if (vars_to_check == DCB) {
873
874 close(sd);
875 my_tcp_connect(server_address, server_port, &sd);
876
877 send_buffer = strdup("S6\r\n");
878 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
879 if (result != STATE_OK)
880 return result;
881 dirty_cache_buffers = atoi(recv_buffer);
882
883 if (check_critical_value && dirty_cache_buffers <= critical_value)
884 result = STATE_CRITICAL;
885 else if (check_warning_value && dirty_cache_buffers <= warning_value)
886 result = STATE_WARNING;
887 xasprintf(&output_message, _("Dirty cache buffers = %lu%% of the total|DCB=%lu;%lu;%lu;0;100"), dirty_cache_buffers,
888 dirty_cache_buffers, warning_value, critical_value);
889
890 /* check % total cache buffers as a percentage of the original*/
891 } else if (vars_to_check == TCB) {
892
893 close(sd);
894 my_tcp_connect(server_address, server_port, &sd);
895
896 send_buffer = strdup("S7\r\n");
897 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
898 if (result != STATE_OK)
899 return result;
900 total_cache_buffers = atoi(recv_buffer);
901
902 if (check_critical_value && total_cache_buffers <= critical_value)
903 result = STATE_CRITICAL;
904 else if (check_warning_value && total_cache_buffers <= warning_value)
905 result = STATE_WARNING;
906 xasprintf(&output_message, _("Total cache buffers = %lu%% of the original|TCB=%lu;%lu;%lu;0;100"), total_cache_buffers,
907 total_cache_buffers, warning_value, critical_value);
908
909 } else if (vars_to_check == DSVER) {
910
911 close(sd);
912 my_tcp_connect(server_address, server_port, &sd);
913
914 xasprintf(&send_buffer, "S13\r\n");
915 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
916 if (result != STATE_OK)
917 return result;
918
919 recv_buffer[strlen(recv_buffer) - 1] = 0;
920
921 xasprintf(&output_message, _("NDS Version %s"), recv_buffer);
922
923 } else if (vars_to_check == UPTIME) {
924
925 close(sd);
926 my_tcp_connect(server_address, server_port, &sd);
927
928 xasprintf(&send_buffer, "UPTIME\r\n");
929 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
930 if (result != STATE_OK)
931 return result;
932
933 recv_buffer[sizeof(recv_buffer) - 1] = 0;
934 recv_buffer[strlen(recv_buffer) - 1] = 0;
935
936 xasprintf(&output_message, _("Up %s"), recv_buffer);
937
938 } else if (vars_to_check == NLM) {
939
940 close(sd);
941 my_tcp_connect(server_address, server_port, &sd);
942
943 xasprintf(&send_buffer, "S24:%s\r\n", nlm_name);
944 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
945 if (result != STATE_OK)
946 return result;
947
948 recv_buffer[strlen(recv_buffer) - 1] = 0;
949 if (strcmp(recv_buffer, "-1")) {
950 xasprintf(&output_message, _("Module %s version %s is loaded"), nlm_name, recv_buffer);
951 } else {
952 result = STATE_CRITICAL;
953 xasprintf(&output_message, _("Module %s is not loaded"), nlm_name);
954 }
955 } else if (vars_to_check == NRMP) {
956
957 xasprintf(&send_buffer, "NRMP:%s\r\n", nrmp_name);
958 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
959 if (result != STATE_OK)
960 return result;
961
962 if (!strcmp(recv_buffer, "-1\n")) {
963 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nrmp_name);
964 result = STATE_CRITICAL;
965 } else {
966 nrmp_value = strtoul(recv_buffer, NULL, 10);
967 if (check_critical_value && nrmp_value <= critical_value)
968 result = STATE_CRITICAL;
969 else if (check_warning_value && nrmp_value <= warning_value)
970 result = STATE_WARNING;
971 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nrmp_name, nrmp_value, nrmp_name, nrmp_value, warning_value,
972 critical_value);
973 }
974
975 } else if (vars_to_check == NRMM) {
976
977 xasprintf(&send_buffer, "NRMM:%s\r\n", nrmm_name);
978 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
979 if (result != STATE_OK)
980 return result;
981
982 if (!strcmp(recv_buffer, "-1\n")) {
983 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nrmm_name);
984 result = STATE_CRITICAL;
985 } else {
986 nrmm_value = strtoul(recv_buffer, NULL, 10);
987 if (check_critical_value && nrmm_value <= critical_value)
988 result = STATE_CRITICAL;
989 else if (check_warning_value && nrmm_value <= warning_value)
990 result = STATE_WARNING;
991 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nrmm_name, nrmm_value, nrmm_name, nrmm_value, warning_value,
992 critical_value);
993 }
994
995 } else if (vars_to_check == NRMS) {
996
997 xasprintf(&send_buffer, "NRMS:%s\r\n", nrms_name);
998 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
999 if (result != STATE_OK)
1000 return result;
1001
1002 if (!strcmp(recv_buffer, "-1\n")) {
1003 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nrms_name);
1004 result = STATE_CRITICAL;
1005 } else {
1006 nrms_value = strtoul(recv_buffer, NULL, 10);
1007 if (check_critical_value && nrms_value >= critical_value)
1008 result = STATE_CRITICAL;
1009 else if (check_warning_value && nrms_value >= warning_value)
1010 result = STATE_WARNING;
1011 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nrms_name, nrms_value, nrms_name, nrms_value, warning_value,
1012 critical_value);
1013 }
1014
1015 } else if (vars_to_check == NSS1) {
1016
1017 xasprintf(&send_buffer, "NSS1:%s\r\n", nss1_name);
1018 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1019 if (result != STATE_OK)
1020 return result;
1021
1022 if (!strcmp(recv_buffer, "-1\n")) {
1023 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss1_name);
1024 result = STATE_CRITICAL;
1025 } else {
1026 nss1_value = strtoul(recv_buffer, NULL, 10);
1027 if (check_critical_value && nss1_value >= critical_value)
1028 result = STATE_CRITICAL;
1029 else if (check_warning_value && nss1_value >= warning_value)
1030 result = STATE_WARNING;
1031 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss1_name, nss1_value, nss1_name, nss1_value, warning_value,
1032 critical_value);
1033 }
1034
1035 } else if (vars_to_check == NSS2) {
1036
1037 xasprintf(&send_buffer, "NSS2:%s\r\n", nss2_name);
1038 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1039 if (result != STATE_OK)
1040 return result;
1041
1042 if (!strcmp(recv_buffer, "-1\n")) {
1043 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss2_name);
1044 result = STATE_CRITICAL;
1045 } else {
1046 nss2_value = strtoul(recv_buffer, NULL, 10);
1047 if (check_critical_value && nss2_value >= critical_value)
1048 result = STATE_CRITICAL;
1049 else if (check_warning_value && nss2_value >= warning_value)
1050 result = STATE_WARNING;
1051 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss2_name, nss2_value, nss2_name, nss2_value, warning_value,
1052 critical_value);
1053 }
1054
1055 } else if (vars_to_check == NSS3) {
1056
1057 xasprintf(&send_buffer, "NSS3:%s\r\n", nss3_name);
1058 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1059 if (result != STATE_OK)
1060 return result;
1061
1062 if (!strcmp(recv_buffer, "-1\n")) {
1063 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss3_name);
1064 result = STATE_CRITICAL;
1065 } else {
1066 nss3_value = strtoul(recv_buffer, NULL, 10);
1067 if (check_critical_value && nss3_value >= critical_value)
1068 result = STATE_CRITICAL;
1069 else if (check_warning_value && nss3_value >= warning_value)
1070 result = STATE_WARNING;
1071 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss3_name, nss3_value, nss3_name, nss3_value, warning_value,
1072 critical_value);
1073 }
1074
1075 } else if (vars_to_check == NSS4) {
1076
1077 xasprintf(&send_buffer, "NSS4:%s\r\n", nss4_name);
1078 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1079 if (result != STATE_OK)
1080 return result;
1081
1082 if (!strcmp(recv_buffer, "-1\n")) {
1083 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss4_name);
1084 result = STATE_CRITICAL;
1085 } else {
1086 nss4_value = strtoul(recv_buffer, NULL, 10);
1087 if (check_critical_value && nss4_value >= critical_value)
1088 result = STATE_CRITICAL;
1089 else if (check_warning_value && nss4_value >= warning_value)
1090 result = STATE_WARNING;
1091 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss4_name, nss4_value, nss4_name, nss4_value, warning_value,
1092 critical_value);
1093 }
1094
1095 } else if (vars_to_check == NSS5) {
1096
1097 xasprintf(&send_buffer, "NSS5:%s\r\n", nss5_name);
1098 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1099 if (result != STATE_OK)
1100 return result;
1101
1102 if (!strcmp(recv_buffer, "-1\n")) {
1103 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss5_name);
1104 result = STATE_CRITICAL;
1105 } else {
1106 nss5_value = strtoul(recv_buffer, NULL, 10);
1107 if (check_critical_value && nss5_value >= critical_value)
1108 result = STATE_CRITICAL;
1109 else if (check_warning_value && nss5_value >= warning_value)
1110 result = STATE_WARNING;
1111 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss5_name, nss5_value, nss5_name, nss5_value, warning_value,
1112 critical_value);
1113 }
1114
1115 } else if (vars_to_check == NSS6) {
1116
1117 xasprintf(&send_buffer, "NSS6:%s\r\n", nss6_name);
1118 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1119 if (result != STATE_OK)
1120 return result;
1121
1122 if (!strcmp(recv_buffer, "-1\n")) {
1123 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss6_name);
1124 result = STATE_CRITICAL;
1125 } else {
1126 nss6_value = strtoul(recv_buffer, NULL, 10);
1127 if (check_critical_value && nss6_value >= critical_value)
1128 result = STATE_CRITICAL;
1129 else if (check_warning_value && nss6_value >= warning_value)
1130 result = STATE_WARNING;
1131 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss6_name, nss6_value, nss6_name, nss6_value, warning_value,
1132 critical_value);
1133 }
1134
1135 } else if (vars_to_check == NSS7) {
1136
1137 xasprintf(&send_buffer, "NSS7:%s\r\n", nss7_name);
1138 result = send_tcp_request(sd, send_buffer, recv_buffer, sizeof(recv_buffer));
1139 if (result != STATE_OK)
1140 return result;
1141
1142 if (!strcmp(recv_buffer, "-1\n")) {
1143 xasprintf(&output_message, _("CRITICAL - Value '%s' does not exist!"), nss7_name);
1144 result = STATE_CRITICAL;
1145 } else {
1146 nss7_value = strtoul(recv_buffer, NULL, 10);
1147 if (check_critical_value && nss7_value >= critical_value)
1148 result = STATE_CRITICAL;
1149 else if (check_warning_value && nss7_value >= warning_value)
1150 result = STATE_WARNING;
1151 xasprintf(&output_message, _("%s is %lu|%s=%lu;%lu;%lu;;"), nss7_name, nss7_value, nss7_name, nss7_value, warning_value,
1152 critical_value);
1153 }
1154
1155 } else {
1156
1157 output_message = strdup(_("Nothing to check!\n"));
1158 result = STATE_UNKNOWN;
1159 }
1160
1161 close(sd);
1162
1163 /* reset timeout */
1164 alarm(0);
1165
1166 printf("%s%s\n", netware_version, output_message);
1167
1168 return result;
1169}
1170
1171/* process command-line arguments */
1172int process_arguments(int argc, char **argv) {
1173 int c;
1174
1175 int option = 0;
1176 static struct option longopts[] = {{"port", required_argument, 0, 'p'}, {"timeout", required_argument, 0, 't'},
1177 {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'},
1178 {"variable", required_argument, 0, 'v'}, {"hostname", required_argument, 0, 'H'},
1179 {"osversion", no_argument, 0, 'o'}, {"version", no_argument, 0, 'V'},
1180 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
1181
1182 /* no options were supplied */
1183 if (argc < 2)
1184 return ERROR;
1185
1186 /* backwards compatibility */
1187 if (!is_option(argv[1])) {
1188 server_address = argv[1];
1189 argv[1] = argv[0];
1190 argv = &argv[1];
1191 argc--;
1192 }
1193
1194 for (c = 1; c < argc; c++) {
1195 if (strcmp("-to", argv[c]) == 0)
1196 strcpy(argv[c], "-t");
1197 else if (strcmp("-wv", argv[c]) == 0)
1198 strcpy(argv[c], "-w");
1199 else if (strcmp("-cv", argv[c]) == 0)
1200 strcpy(argv[c], "-c");
1201 }
1202
1203 while (1) {
1204 c = getopt_long(argc, argv, "+hoVH:t:c:w:p:v:", longopts, &option);
1205
1206 if (c == -1 || c == EOF || c == 1)
1207 break;
1208
1209 switch (c) {
1210 case '?': /* print short usage statement if args not parsable */
1211 usage5();
1212 case 'h': /* help */
1213 print_help();
1214 exit(STATE_UNKNOWN);
1215 case 'V': /* version */
1216 print_revision(progname, NP_VERSION);
1217 exit(STATE_UNKNOWN);
1218 case 'H': /* hostname */
1219 server_address = optarg;
1220 break;
1221 case 'o': /* display nos version */
1222 check_netware_version = true;
1223 break;
1224 case 'p': /* port */
1225 if (is_intnonneg(optarg))
1226 server_port = atoi(optarg);
1227 else
1228 die(STATE_UNKNOWN, _("Server port an integer\n"));
1229 break;
1230 case 'v':
1231 if (strlen(optarg) < 3)
1232 return ERROR;
1233 if (!strcmp(optarg, "LOAD1"))
1234 vars_to_check = LOAD1;
1235 else if (!strcmp(optarg, "LOAD5"))
1236 vars_to_check = LOAD5;
1237 else if (!strcmp(optarg, "LOAD15"))
1238 vars_to_check = LOAD15;
1239 else if (!strcmp(optarg, "CONNS"))
1240 vars_to_check = CONNS;
1241 else if (!strcmp(optarg, "LTCH"))
1242 vars_to_check = LTCH;
1243 else if (!strcmp(optarg, "DCB"))
1244 vars_to_check = DCB;
1245 else if (!strcmp(optarg, "TCB"))
1246 vars_to_check = TCB;
1247 else if (!strcmp(optarg, "CBUFF"))
1248 vars_to_check = CBUFF;
1249 else if (!strcmp(optarg, "CDBUFF"))
1250 vars_to_check = CDBUFF;
1251 else if (!strcmp(optarg, "LRUM"))
1252 vars_to_check = LRUM;
1253 else if (!strcmp(optarg, "LRUS"))
1254 vars_to_check = LRUS;
1255 else if (strncmp(optarg, "VPF", 3) == 0) {
1256 vars_to_check = VPF;
1257 volume_name = strdup(optarg + 3);
1258 if (!strcmp(volume_name, ""))
1259 volume_name = strdup("SYS");
1260 } else if (strncmp(optarg, "VKF", 3) == 0) {
1261 vars_to_check = VKF;
1262 volume_name = strdup(optarg + 3);
1263 if (!strcmp(volume_name, ""))
1264 volume_name = strdup("SYS");
1265 } else if (strncmp(optarg, "VMF", 3) == 0) {
1266 vars_to_check = VMF;
1267 volume_name = strdup(optarg + 3);
1268 if (!strcmp(volume_name, ""))
1269 volume_name = strdup("SYS");
1270 } else if (!strcmp(optarg, "DSDB"))
1271 vars_to_check = DSDB;
1272 else if (!strcmp(optarg, "LOGINS"))
1273 vars_to_check = LOGINS;
1274 else if (!strcmp(optarg, "NRMH"))
1275 vars_to_check = NRMH;
1276 else if (!strcmp(optarg, "UPRB"))
1277 vars_to_check = UPRB;
1278 else if (!strcmp(optarg, "PUPRB"))
1279 vars_to_check = PUPRB;
1280 else if (!strncmp(optarg, "SAPENTRIES", 10)) {
1281 vars_to_check = SAPENTRIES;
1282 if (strlen(optarg) > 10)
1283 sap_number = atoi(optarg + 10);
1284 else
1285 sap_number = -1;
1286 } else if (!strcmp(optarg, "OFILES"))
1287 vars_to_check = OFILES;
1288 else if (strncmp(optarg, "VKP", 3) == 0) {
1289 vars_to_check = VKP;
1290 volume_name = strdup(optarg + 3);
1291 if (!strcmp(volume_name, ""))
1292 volume_name = strdup("SYS");
1293 } else if (strncmp(optarg, "VMP", 3) == 0) {
1294 vars_to_check = VMP;
1295 volume_name = strdup(optarg + 3);
1296 if (!strcmp(volume_name, ""))
1297 volume_name = strdup("SYS");
1298 } else if (strncmp(optarg, "VMU", 3) == 0) {
1299 vars_to_check = VMU;
1300 volume_name = strdup(optarg + 3);
1301 if (!strcmp(volume_name, ""))
1302 volume_name = strdup("SYS");
1303 } else if (strncmp(optarg, "VPU", 3) == 0) {
1304 vars_to_check = VPU;
1305 volume_name = strdup(optarg + 3);
1306 if (!strcmp(volume_name, ""))
1307 volume_name = strdup("SYS");
1308 } else if (strncmp(optarg, "VPP", 3) == 0) {
1309 vars_to_check = VPP;
1310 volume_name = strdup(optarg + 3);
1311 if (!strcmp(volume_name, ""))
1312 volume_name = strdup("SYS");
1313 } else if (strncmp(optarg, "VKNP", 4) == 0) {
1314 vars_to_check = VKNP;
1315 volume_name = strdup(optarg + 4);
1316 if (!strcmp(volume_name, ""))
1317 volume_name = strdup("SYS");
1318 } else if (strncmp(optarg, "VPNP", 4) == 0) {
1319 vars_to_check = VPNP;
1320 volume_name = strdup(optarg + 4);
1321 if (!strcmp(volume_name, ""))
1322 volume_name = strdup("SYS");
1323 } else if (!strcmp(optarg, "ABENDS"))
1324 vars_to_check = ABENDS;
1325 else if (!strcmp(optarg, "CSPROCS"))
1326 vars_to_check = CSPROCS;
1327 else if (!strcmp(optarg, "TSYNC"))
1328 vars_to_check = TSYNC;
1329 else if (!strcmp(optarg, "DSVER"))
1330 vars_to_check = DSVER;
1331 else if (!strcmp(optarg, "UPTIME")) {
1332 vars_to_check = UPTIME;
1333 } else if (strncmp(optarg, "NLM:", 4) == 0) {
1334 vars_to_check = NLM;
1335 nlm_name = strdup(optarg + 4);
1336 } else if (strncmp(optarg, "NRMP", 4) == 0) {
1337 vars_to_check = NRMP;
1338 nrmp_name = strdup(optarg + 4);
1339 if (!strcmp(nrmp_name, ""))
1340 nrmp_name = strdup("AVAILABLE_MEMORY");
1341 } else if (strncmp(optarg, "NRMM", 4) == 0) {
1342 vars_to_check = NRMM;
1343 nrmm_name = strdup(optarg + 4);
1344 if (!strcmp(nrmm_name, ""))
1345 nrmm_name = strdup("AVAILABLE_CACHE_MEMORY");
1346
1347 }
1348
1349 else if (strncmp(optarg, "NRMS", 4) == 0) {
1350 vars_to_check = NRMS;
1351 nrms_name = strdup(optarg + 4);
1352 if (!strcmp(nrms_name, ""))
1353 nrms_name = strdup("USED_SWAP_SPACE");
1354
1355 }
1356
1357 else if (strncmp(optarg, "NSS1", 4) == 0) {
1358 vars_to_check = NSS1;
1359 nss1_name = strdup(optarg + 4);
1360 if (!strcmp(nss1_name, ""))
1361 nss1_name = strdup("CURRENTBUFFERCACHESIZE");
1362
1363 }
1364
1365 else if (strncmp(optarg, "NSS2", 4) == 0) {
1366 vars_to_check = NSS2;
1367 nss2_name = strdup(optarg + 4);
1368 if (!strcmp(nss2_name, ""))
1369 nss2_name = strdup("CACHEHITS");
1370
1371 }
1372
1373 else if (strncmp(optarg, "NSS3", 4) == 0) {
1374 vars_to_check = NSS3;
1375 nss3_name = strdup(optarg + 4);
1376 if (!strcmp(nss3_name, ""))
1377 nss3_name = strdup("CACHEGITPERCENT");
1378
1379 }
1380
1381 else if (strncmp(optarg, "NSS4", 4) == 0) {
1382 vars_to_check = NSS4;
1383 nss4_name = strdup(optarg + 4);
1384 if (!strcmp(nss4_name, ""))
1385 nss4_name = strdup("CURRENTOPENCOUNT");
1386
1387 }
1388
1389 else if (strncmp(optarg, "NSS5", 4) == 0) {
1390 vars_to_check = NSS5;
1391 nss5_name = strdup(optarg + 4);
1392 if (!strcmp(nss5_name, ""))
1393 nss5_name = strdup("CACHEMISSES");
1394
1395 }
1396
1397 else if (strncmp(optarg, "NSS6", 4) == 0) {
1398 vars_to_check = NSS6;
1399 nss6_name = strdup(optarg + 4);
1400 if (!strcmp(nss6_name, ""))
1401 nss6_name = strdup("PENDINGWORKSCOUNT");
1402
1403 }
1404
1405 else if (strncmp(optarg, "NSS7", 4) == 0) {
1406 vars_to_check = NSS7;
1407 nss7_name = strdup(optarg + 4);
1408 if (!strcmp(nss7_name, ""))
1409 nss7_name = strdup("CACHESIZE");
1410
1411 }
1412
1413 else
1414 return ERROR;
1415 break;
1416 case 'w': /* warning threshold */
1417 warning_value = strtoul(optarg, NULL, 10);
1418 check_warning_value = true;
1419 break;
1420 case 'c': /* critical threshold */
1421 critical_value = strtoul(optarg, NULL, 10);
1422 check_critical_value = true;
1423 break;
1424 case 't': /* timeout */
1425 socket_timeout = atoi(optarg);
1426 if (socket_timeout <= 0)
1427 return ERROR;
1428 }
1429 }
1430
1431 return OK;
1432}
1433
1434void print_help(void) {
1435 char *myport;
1436 xasprintf(&myport, "%d", PORT);
1437
1438 print_revision(progname, NP_VERSION);
1439
1440 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1441 printf(COPYRIGHT, copyright, email);
1442
1443 printf("%s\n", _("This plugin attempts to contact the MRTGEXT NLM running on a"));
1444 printf("%s\n", _("Novell server to gather the requested system information."));
1445
1446 printf("\n\n");
1447
1448 print_usage();
1449
1450 printf(UT_HELP_VRSN);
1451 printf(UT_EXTRA_OPTS);
1452
1453 printf(UT_HOST_PORT, 'p', myport);
1454
1455 printf(" %s\n", "-v, --variable=STRING");
1456 printf(" %s\n", _("Variable to check. Valid variables include:"));
1457 printf(" %s\n", _("LOAD1 = 1 minute average CPU load"));
1458 printf(" %s\n", _("LOAD5 = 5 minute average CPU load"));
1459 printf(" %s\n", _("LOAD15 = 15 minute average CPU load"));
1460 printf(" %s\n", _("CSPROCS = number of current service processes (NW 5.x only)"));
1461 printf(" %s\n", _("ABENDS = number of abended threads (NW 5.x only)"));
1462 printf(" %s\n", _("UPTIME = server uptime"));
1463 printf(" %s\n", _("LTCH = percent long term cache hits"));
1464 printf(" %s\n", _("CBUFF = current number of cache buffers"));
1465 printf(" %s\n", _("CDBUFF = current number of dirty cache buffers"));
1466 printf(" %s\n", _("DCB = dirty cache buffers as a percentage of the total"));
1467 printf(" %s\n", _("TCB = dirty cache buffers as a percentage of the original"));
1468 printf(" %s\n", _("OFILES = number of open files"));
1469 printf(" %s\n", _(" VMF<vol> = MB of free space on Volume <vol>"));
1470 printf(" %s\n", _(" VMU<vol> = MB used space on Volume <vol>"));
1471 printf(" %s\n", _(" VPU<vol> = percent used space on Volume <vol>"));
1472 printf(" %s\n", _(" VMP<vol> = MB of purgeable space on Volume <vol>"));
1473 printf(" %s\n", _(" VPF<vol> = percent free space on volume <vol>"));
1474 printf(" %s\n", _(" VKF<vol> = KB of free space on volume <vol>"));
1475 printf(" %s\n", _(" VPP<vol> = percent purgeable space on volume <vol>"));
1476 printf(" %s\n", _(" VKP<vol> = KB of purgeable space on volume <vol>"));
1477 printf(" %s\n", _(" VPNP<vol> = percent not yet purgeable space on volume <vol>"));
1478 printf(" %s\n", _(" VKNP<vol> = KB of not yet purgeable space on volume <vol>"));
1479 printf(" %s\n", _(" LRUM = LRU sitting time in minutes"));
1480 printf(" %s\n", _(" LRUS = LRU sitting time in seconds"));
1481 printf(" %s\n", _(" DSDB = check to see if DS Database is open"));
1482 printf(" %s\n", _(" DSVER = NDS version"));
1483 printf(" %s\n", _(" UPRB = used packet receive buffers"));
1484 printf(" %s\n", _(" PUPRB = percent (of max) used packet receive buffers"));
1485 printf(" %s\n", _(" SAPENTRIES = number of entries in the SAP table"));
1486 printf(" %s\n", _(" SAPENTRIES<n> = number of entries in the SAP table for SAP type <n>"));
1487 printf(" %s\n", _(" TSYNC = timesync status"));
1488 printf(" %s\n", _(" LOGINS = check to see if logins are enabled"));
1489 printf(" %s\n", _(" CONNS = number of currently licensed connections"));
1490 printf(" %s\n", _(" NRMH = NRM Summary Status"));
1491 printf(" %s\n", _(" NRMP<stat> = Returns the current value for a NRM health item"));
1492 printf(" %s\n", _(" NRMM<stat> = Returns the current memory stats from NRM"));
1493 printf(" %s\n", _(" NRMS<stat> = Returns the current Swapfile stats from NRM"));
1494 printf(" %s\n", _(" NSS1<stat> = Statistics from _Admin:Manage_NSS\\GeneralStats.xml"));
1495 printf(" %s\n", _(" NSS3<stat> = Statistics from _Admin:Manage_NSS\\NameCache.xml"));
1496 printf(" %s\n", _(" NSS4<stat> = Statistics from _Admin:Manage_NSS\\FileStats.xml"));
1497 printf(" %s\n", _(" NSS5<stat> = Statistics from _Admin:Manage_NSS\\ObjectCache.xml"));
1498 printf(" %s\n", _(" NSS6<stat> = Statistics from _Admin:Manage_NSS\\Thread.xml"));
1499 printf(" %s\n", _(" NSS7<stat> = Statistics from _Admin:Manage_NSS\\AuthorizationCache.xml"));
1500 printf(" %s\n", _(" NLM:<nlm> = check if NLM is loaded and report version"));
1501 printf(" %s\n", _(" (e.g. NLM:TSANDS.NLM)"));
1502 printf("\n");
1503 printf(" %s\n", "-w, --warning=INTEGER");
1504 printf(" %s\n", _("Threshold which will result in a warning status"));
1505 printf(" %s\n", "-c, --critical=INTEGER");
1506 printf(" %s\n", _("Threshold which will result in a critical status"));
1507 printf(" %s\n", "-o, --osversion");
1508 printf(" %s\n", _("Include server version string in results"));
1509
1510 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1511
1512 printf("\n");
1513 printf("%s\n", _("Notes:"));
1514 printf(" %s\n", _("- This plugin requires that the MRTGEXT.NLM file from James Drews' MRTG"));
1515 printf(" %s\n", _(" extension for NetWare be loaded on the Novell servers you wish to check."));
1516 printf(" %s\n", _(" (available from http://www.engr.wisc.edu/~drews/mrtg/)"));
1517 printf(" %s\n", _("- Values for critical thresholds should be lower than warning thresholds"));
1518 printf(" %s\n", _(" when the following variables are checked: VPF, VKF, LTCH, CBUFF, DCB, "));
1519 printf(" %s\n", _(" TCB, LRUS and LRUM."));
1520
1521 printf(UT_SUPPORT);
1522}
1523
1524void print_usage(void) {
1525 printf("%s\n", _("Usage:"));
1526 printf("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n", progname);
1527}
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
index 940b9475..6bcdeaad 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -116,10 +116,10 @@ int main(int argc, char **argv) {
116# ifdef PING_HAS_TIMEOUT 116# ifdef PING_HAS_TIMEOUT
117 xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]); 117 xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]);
118# else 118# else
119 xasprintf(&cmd, rawcmd, config.max_packets, addresses[i]); 119 xasprintf(&cmd, rawcmd, config.max_packets, config.addresses[i]);
120# endif 120# endif
121#else 121#else
122 xasprintf(&cmd, rawcmd, addresses[i], config.max_packets); 122 xasprintf(&cmd, rawcmd, config.addresses[i], config.max_packets);
123#endif 123#endif
124 124
125 if (verbose >= 2) { 125 if (verbose >= 2) {
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
index 1d78ccee..83e6864e 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -1,41 +1,41 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_procs plugin 3 * Monitoring check_procs plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2024 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_procs plugin 10 * This file contains the check_procs plugin
11* 11 *
12* Checks all processes and generates WARNING or CRITICAL states if the 12 * Checks all processes and generates WARNING or CRITICAL states if the
13* specified metric is outside the required threshold ranges. The metric 13 * specified metric is outside the required threshold ranges. The metric
14* defaults to number of processes. Search filters can be applied to limit 14 * defaults to number of processes. Search filters can be applied to limit
15* the processes to check. 15 * the processes to check.
16* 16 *
17* The parent process, check_procs itself and any child process of 17 * The parent process, check_procs itself and any child process of
18* check_procs (ps) are excluded from any checks to prevent false positives. 18 * check_procs (ps) are excluded from any checks to prevent false positives.
19* 19 *
20* 20 *
21* This program is free software: you can redistribute it and/or modify 21 * This program is free software: you can redistribute it and/or modify
22* it under the terms of the GNU General Public License as published by 22 * it under the terms of the GNU General Public License as published by
23* the Free Software Foundation, either version 3 of the License, or 23 * the Free Software Foundation, either version 3 of the License, or
24* (at your option) any later version. 24 * (at your option) any later version.
25* 25 *
26* This program is distributed in the hope that it will be useful, 26 * This program is distributed in the hope that it will be useful,
27* but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29* GNU General Public License for more details. 29 * GNU General Public License for more details.
30* 30 *
31* You should have received a copy of the GNU General Public License 31 * You should have received a copy of the GNU General Public License
32* along with this program. If not, see <http://www.gnu.org/licenses/>. 32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33* 33 *
34* 34 *
35*****************************************************************************/ 35 *****************************************************************************/
36 36
37const char *progname = "check_procs"; 37const char *progname = "check_procs";
38const char *program_name = "check_procs"; /* Required for coreutils libs */ 38const char *program_name = "check_procs"; /* Required for coreutils libs */
39const char *copyright = "2000-2024"; 39const char *copyright = "2000-2024";
40const char *email = "devel@monitoring-plugins.org"; 40const char *email = "devel@monitoring-plugins.org";
41 41
@@ -43,313 +43,288 @@ const char *email = "devel@monitoring-plugins.org";
43#include "utils.h" 43#include "utils.h"
44#include "utils_cmd.h" 44#include "utils_cmd.h"
45#include "regex.h" 45#include "regex.h"
46#include "states.h"
47#include "check_procs.d/config.h"
46 48
47#include <pwd.h> 49#include <pwd.h>
48#include <errno.h> 50#include <errno.h>
49 51
50#ifdef HAVE_SYS_STAT_H 52#ifdef HAVE_SYS_STAT_H
51#include <sys/stat.h> 53# include <sys/stat.h>
52#endif 54#endif
53 55
54static int process_arguments (int /*argc*/, char ** /*argv*/); 56typedef struct {
55static int validate_arguments (void); 57 int errorcode;
56static int convert_to_seconds (char * /*etime*/); 58 check_procs_config config;
57static void print_help (void); 59} check_procs_config_wrapper;
58void print_usage (void); 60static check_procs_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
59 61static check_procs_config_wrapper validate_arguments(check_procs_config_wrapper /*config_wrapper*/);
60static char *warning_range = NULL; 62
61static char *critical_range = NULL; 63static int convert_to_seconds(char * /*etime*/, enum metric /*metric*/);
62static thresholds *procs_thresholds = NULL; 64static void print_help(void);
63 65void print_usage(void);
64static int options = 0; /* bitmask of filter criteria to test against */ 66
65#define ALL 1 67#define ALL 1
66#define STAT 2 68#define STAT 2
67#define PPID 4 69#define PPID 4
68#define USER 8 70#define USER 8
69#define PROG 16 71#define PROG 16
70#define ARGS 32 72#define ARGS 32
71#define VSZ 64 73#define VSZ 64
72#define RSS 128 74#define RSS 128
73#define PCPU 256 75#define PCPU 256
74#define ELAPSED 512 76#define ELAPSED 512
75#define EREG_ARGS 1024 77#define EREG_ARGS 1024
76#define EXCLUDE_PROGS 2048 78#define EXCLUDE_PROGS 2048
77 79
78#define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads: 80#define KTHREAD_PARENT \
79 ppid of procs are compared to pid of this proc*/ 81 "kthreadd" /* the parent process of kernel threads: \
80 82 ppid of procs are compared to pid of this proc*/
81/* Different metrics */
82char *metric_name;
83enum metric {
84 METRIC_PROCS,
85 METRIC_VSZ,
86 METRIC_RSS,
87 METRIC_CPU,
88 METRIC_ELAPSED
89};
90enum metric metric = METRIC_PROCS;
91 83
92static int verbose = 0; 84static int verbose = 0;
93static int uid; 85
94static pid_t ppid; 86static int stat_exe(const pid_t pid, struct stat *buf) {
95static int vsz;
96static int rss;
97static float pcpu;
98static char *statopts;
99static char *prog;
100static char *exclude_progs;
101static char **exclude_progs_arr = NULL;
102static char exclude_progs_counter = 0;
103static char *args;
104static char *input_filename = NULL;
105static regex_t re_args;
106static char *fmt;
107static char *fails;
108static char tmp[MAX_INPUT_BUFFER];
109static int kthread_filter = 0;
110static int usepid = 0; /* whether to test for pid or /proc/pid/exe */
111
112static int
113stat_exe (const pid_t pid, struct stat *buf) {
114 char *path; 87 char *path;
115 int ret;
116 xasprintf(&path, "/proc/%d/exe", pid); 88 xasprintf(&path, "/proc/%d/exe", pid);
117 ret = stat(path, buf); 89 int ret = stat(path, buf);
118 free(path); 90 free(path);
119 return ret; 91 return ret;
120} 92}
121 93
122 94int main(int argc, char **argv) {
123int 95 setlocale(LC_ALL, "");
124main (int argc, char **argv)
125{
126 char *input_buffer;
127 char *input_line;
128 char *procprog;
129
130 pid_t mypid = 0;
131 pid_t myppid = 0;
132 struct stat statbuf;
133 dev_t mydev = 0;
134 ino_t myino = 0;
135 int procuid = 0;
136 pid_t procpid = 0;
137 pid_t procppid = 0;
138 pid_t kthread_ppid = 0;
139 int procvsz = 0;
140 int procrss = 0;
141 int procseconds = 0;
142 float procpcpu = 0;
143 char procstat[8];
144 char procetime[MAX_INPUT_BUFFER] = { '\0' };
145 char *procargs;
146
147 const char *zombie = "Z";
148
149 int resultsum = 0; /* bitmask of the filter criteria met by a process */
150 int found = 0; /* counter for number of lines returned in `ps` output */
151 int procs = 0; /* counter for number of processes meeting filter criteria */
152 int pos; /* number of spaces before 'args' in `ps` output */
153 int cols; /* number of columns in ps output */
154 int expected_cols = PS_COLS - 1;
155 int warn = 0; /* number of processes in warn state */
156 int crit = 0; /* number of processes in crit state */
157 int i = 0;
158 int result = STATE_UNKNOWN;
159 int ret = 0;
160 output chld_out, chld_err;
161
162 setlocale (LC_ALL, "");
163 bindtextdomain (PACKAGE, LOCALEDIR);
164 textdomain (PACKAGE);
165 setlocale(LC_NUMERIC, "POSIX"); 96 setlocale(LC_NUMERIC, "POSIX");
166 97 bindtextdomain(PACKAGE, LOCALEDIR);
167 input_buffer = malloc (MAX_INPUT_BUFFER); 98 textdomain(PACKAGE);
168 procprog = malloc (MAX_INPUT_BUFFER);
169
170 xasprintf (&metric_name, "PROCS");
171 metric = METRIC_PROCS;
172 99
173 /* Parse extra opts if any */ 100 /* Parse extra opts if any */
174 argv=np_extra_opts (&argc, argv, progname); 101 argv = np_extra_opts(&argc, argv, progname);
102
103 check_procs_config_wrapper tmp_config = process_arguments(argc, argv);
104 if (tmp_config.errorcode == ERROR) {
105 usage4(_("Could not parse arguments"));
106 }
175 107
176 if (process_arguments (argc, argv) == ERROR) 108 check_procs_config config = tmp_config.config;
177 usage4 (_("Could not parse arguments"));
178 109
179 /* find ourself */ 110 /* find ourself */
180 mypid = getpid(); 111 pid_t mypid = getpid();
181 myppid = getppid(); 112 pid_t myppid = getppid();
182 if (usepid || stat_exe(mypid, &statbuf) == -1) { 113 dev_t mydev = 0;
114 ino_t myino = 0;
115 struct stat statbuf;
116 if (config.usepid || stat_exe(mypid, &statbuf) == -1) {
183 /* usepid might have been set by -T */ 117 /* usepid might have been set by -T */
184 usepid = 1; 118 config.usepid = true;
185 } else { 119 } else {
186 usepid = 0; 120 config.usepid = false;
187 mydev = statbuf.st_dev; 121 mydev = statbuf.st_dev;
188 myino = statbuf.st_ino; 122 myino = statbuf.st_ino;
189 } 123 }
190 124
191 /* Set signal handling and alarm timeout */ 125 /* Set signal handling and alarm timeout */
192 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 126 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
193 die (STATE_UNKNOWN, _("Cannot catch SIGALRM")); 127 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
194 } 128 }
195 (void) alarm ((unsigned) timeout_interval); 129 (void)alarm(timeout_interval);
196 130
197 if (verbose >= 2) 131 if (verbose >= 2) {
198 printf (_("CMD: %s\n"), PS_COMMAND); 132 printf(_("CMD: %s\n"), PS_COMMAND);
133 }
199 134
200 if (input_filename == NULL) { 135 output chld_out;
201 result = cmd_run( PS_COMMAND, &chld_out, &chld_err, 0); 136 output chld_err;
137 mp_state_enum result = STATE_UNKNOWN;
138 if (config.input_filename == NULL) {
139 result = cmd_run(PS_COMMAND, &chld_out, &chld_err, 0);
202 if (chld_err.lines > 0) { 140 if (chld_err.lines > 0) {
203 printf ("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]); 141 printf("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]);
204 exit(STATE_WARNING); 142 exit(STATE_WARNING);
205 } 143 }
206 } else { 144 } else {
207 result = cmd_file_read( input_filename, &chld_out, 0); 145 result = cmd_file_read(config.input_filename, &chld_out, 0);
208 } 146 }
209 147
148 int pos; /* number of spaces before 'args' in `ps` output */
149 uid_t procuid = 0;
150 pid_t procpid = 0;
151 pid_t procppid = 0;
152 pid_t kthread_ppid = 0;
153 int warn = 0; /* number of processes in warn state */
154 int crit = 0; /* number of processes in crit state */
155 int procvsz = 0;
156 int procrss = 0;
157 int procseconds = 0;
158 float procpcpu = 0;
159 char procstat[8];
160 char procetime[MAX_INPUT_BUFFER] = {'\0'};
161 int resultsum = 0; /* bitmask of the filter criteria met by a process */
162 int found = 0; /* counter for number of lines returned in `ps` output */
163 int procs = 0; /* counter for number of processes meeting filter criteria */
164 char *input_buffer = malloc(MAX_INPUT_BUFFER);
165 char *procprog = malloc(MAX_INPUT_BUFFER);
166 const int expected_cols = PS_COLS - 1;
167
210 /* flush first line: j starts at 1 */ 168 /* flush first line: j starts at 1 */
211 for (size_t j = 1; j < chld_out.lines; j++) { 169 for (size_t j = 1; j < chld_out.lines; j++) {
212 input_line = chld_out.line[j]; 170 char *input_line = chld_out.line[j];
213 171
214 if (verbose >= 3) 172 if (verbose >= 3) {
215 printf ("%s", input_line); 173 printf("%s", input_line);
174 }
216 175
217 strcpy (procprog, ""); 176 strcpy(procprog, "");
218 xasprintf (&procargs, "%s", ""); 177 char *procargs;
178 xasprintf(&procargs, "%s", "");
219 179
220 cols = sscanf (input_line, PS_FORMAT, PS_VARLIST); 180 /* number of columns in ps output */
181 int cols = sscanf(input_line, PS_FORMAT, PS_VARLIST);
221 182
222 /* Zombie processes do not give a procprog command */ 183 /* Zombie processes do not give a procprog command */
223 if ( cols < expected_cols && strstr(procstat, zombie) ) { 184 const char *zombie = "Z";
185 if (cols < expected_cols && strstr(procstat, zombie)) {
224 cols = expected_cols; 186 cols = expected_cols;
225 } 187 }
226 if ( cols >= expected_cols ) { 188 if (cols >= expected_cols) {
227 resultsum = 0; 189 resultsum = 0;
228 xasprintf (&procargs, "%s", input_line + pos); 190 xasprintf(&procargs, "%s", input_line + pos);
229 strip (procargs); 191 strip(procargs);
230 192
231 /* Some ps return full pathname for command. This removes path */ 193 /* Some ps return full pathname for command. This removes path */
232 strcpy(procprog, base_name(procprog)); 194 strcpy(procprog, base_name(procprog));
233 195
234 /* we need to convert the elapsed time to seconds */ 196 /* we need to convert the elapsed time to seconds */
235 procseconds = convert_to_seconds(procetime); 197 procseconds = convert_to_seconds(procetime, config.metric);
236 198
237 if (verbose >= 3) 199 if (verbose >= 3) {
238 printf ("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 200 printf("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", procs, procuid, procvsz,
239 procs, procuid, procvsz, procrss, 201 procrss, procpid, procppid, procpcpu, procstat, procetime, procprog, procargs);
240 procpid, procppid, procpcpu, procstat, 202 }
241 procetime, procprog, procargs);
242 203
243 /* Ignore self */ 204 /* Ignore self */
244 if ((usepid && mypid == procpid) || 205 int ret = 0;
245 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) || 206 if ((config.usepid && mypid == procpid) ||
246 (ret == -1 && errno == ENOENT)) 207 (((!config.usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
247 ) { 208 (ret == -1 && errno == ENOENT))) {
248 if (verbose >= 3) 209 if (verbose >= 3) {
249 printf("not considering - is myself or gone\n"); 210 printf("not considering - is myself or gone\n");
211 }
250 continue; 212 continue;
251 } 213 }
252 /* Ignore parent*/ 214 /* Ignore parent*/
253 else if (myppid == procpid) { 215 if (myppid == procpid) {
254 if (verbose >= 3) 216 if (verbose >= 3) {
255 printf("not considering - is parent\n"); 217 printf("not considering - is parent\n");
218 }
256 continue; 219 continue;
257 } 220 }
258 221
259 /* Ignore our own children */ 222 /* Ignore our own children */
260 if (procppid == mypid) { 223 if (procppid == mypid) {
261 if (verbose >= 3) 224 if (verbose >= 3) {
262 printf("not considering - is our child\n"); 225 printf("not considering - is our child\n");
226 }
263 continue; 227 continue;
264 } 228 }
265 229
266 /* Ignore excluded processes by name */ 230 /* Ignore excluded processes by name */
267 if(options & EXCLUDE_PROGS) { 231 if (config.options & EXCLUDE_PROGS) {
268 int found = 0; 232 bool found = false;
269 int i = 0; 233 for (int i = 0; i < (config.exclude_progs_counter); i++) {
270 234 if (!strcmp(procprog, config.exclude_progs_arr[i])) {
271 for(i=0; i < (exclude_progs_counter); i++) { 235 found = true;
272 if(!strcmp(procprog, exclude_progs_arr[i])) { 236 }
273 found = 1; 237 }
274 } 238 if (!found) {
275 } 239 resultsum |= EXCLUDE_PROGS;
276 if(found == 0) { 240 } else {
277 resultsum |= EXCLUDE_PROGS; 241 if (verbose >= 3) {
278 } else 242 printf("excluding - by ignorelist\n");
279 { 243 }
280 if(verbose >= 3) 244 }
281 printf("excluding - by ignorelist\n");
282 }
283 } 245 }
284 246
285 /* filter kernel threads (children of KTHREAD_PARENT)*/ 247 /* filter kernel threads (children of KTHREAD_PARENT)*/
286 /* TODO adapt for other OSes than GNU/Linux 248 /* TODO adapt for other OSes than GNU/Linux
287 sorry for not doing that, but I've no other OSes to test :-( */ 249 sorry for not doing that, but I've no other OSes to test :-( */
288 if (kthread_filter == 1) { 250 if (config.kthread_filter) {
289 /* get pid KTHREAD_PARENT */ 251 /* get pid KTHREAD_PARENT */
290 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) 252 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT)) {
291 kthread_ppid = procpid; 253 kthread_ppid = procpid;
254 }
292 255
293 if (kthread_ppid == procppid) { 256 if (kthread_ppid == procppid) {
294 if (verbose >= 2) 257 if (verbose >= 2) {
295 printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs); 258 printf("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs);
259 }
296 continue; 260 continue;
297 } 261 }
298 } 262 }
299 263
300 if ((options & STAT) && (strstr (procstat, statopts))) 264 if ((config.options & STAT) && (strstr(procstat, config.statopts))) {
301 resultsum |= STAT; 265 resultsum |= STAT;
302 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 266 }
267 if ((config.options & ARGS) && procargs && (strstr(procargs, config.args) != NULL)) {
303 resultsum |= ARGS; 268 resultsum |= ARGS;
304 if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0)) 269 }
270 if ((config.options & EREG_ARGS) && procargs && (regexec(&config.re_args, procargs, (size_t)0, NULL, 0) == 0)) {
305 resultsum |= EREG_ARGS; 271 resultsum |= EREG_ARGS;
306 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0)) 272 }
273 if ((config.options & PROG) && procprog && (strcmp(config.prog, procprog) == 0)) {
307 resultsum |= PROG; 274 resultsum |= PROG;
308 if ((options & PPID) && (procppid == ppid)) 275 }
276 if ((config.options & PPID) && (procppid == config.ppid)) {
309 resultsum |= PPID; 277 resultsum |= PPID;
310 if ((options & USER) && (procuid == uid)) 278 }
279 if ((config.options & USER) && (procuid == config.uid)) {
311 resultsum |= USER; 280 resultsum |= USER;
312 if ((options & VSZ) && (procvsz >= vsz)) 281 }
282 if ((config.options & VSZ) && (procvsz >= config.vsz)) {
313 resultsum |= VSZ; 283 resultsum |= VSZ;
314 if ((options & RSS) && (procrss >= rss)) 284 }
285 if ((config.options & RSS) && (procrss >= config.rss)) {
315 resultsum |= RSS; 286 resultsum |= RSS;
316 if ((options & PCPU) && (procpcpu >= pcpu)) 287 }
288 if ((config.options & PCPU) && (procpcpu >= config.pcpu)) {
317 resultsum |= PCPU; 289 resultsum |= PCPU;
290 }
318 291
319 found++; 292 found++;
320 293
321 /* Next line if filters not matched */ 294 /* Next line if filters not matched */
322 if (!(options == resultsum || options == ALL)) 295 if (!(config.options == resultsum || config.options == ALL)) {
323 continue; 296 continue;
297 }
324 298
325 procs++; 299 procs++;
326 if (verbose >= 2) { 300 if (verbose >= 2) {
327 printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 301 printf("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", procuid, procvsz,
328 procuid, procvsz, procrss, 302 procrss, procpid, procppid, procpcpu, procstat, procetime, procprog, procargs);
329 procpid, procppid, procpcpu, procstat,
330 procetime, procprog, procargs);
331 } 303 }
332 304
333 if (metric == METRIC_VSZ) 305 mp_state_enum temporary_result = STATE_OK;
334 i = get_status ((double)procvsz, procs_thresholds); 306 if (config.metric == METRIC_VSZ) {
335 else if (metric == METRIC_RSS) 307 temporary_result = get_status((double)procvsz, config.procs_thresholds);
336 i = get_status ((double)procrss, procs_thresholds); 308 } else if (config.metric == METRIC_RSS) {
309 temporary_result = get_status((double)procrss, config.procs_thresholds);
310 }
337 /* TODO? float thresholds for --metric=CPU */ 311 /* TODO? float thresholds for --metric=CPU */
338 else if (metric == METRIC_CPU) 312 else if (config.metric == METRIC_CPU) {
339 i = get_status (procpcpu, procs_thresholds); 313 temporary_result = get_status(procpcpu, config.procs_thresholds);
340 else if (metric == METRIC_ELAPSED) 314 } else if (config.metric == METRIC_ELAPSED) {
341 i = get_status ((double)procseconds, procs_thresholds); 315 temporary_result = get_status((double)procseconds, config.procs_thresholds);
316 }
342 317
343 if (metric != METRIC_PROCS) { 318 if (config.metric != METRIC_PROCS) {
344 if (i == STATE_WARNING) { 319 if (temporary_result == STATE_WARNING) {
345 warn++; 320 warn++;
346 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 321 xasprintf(&config.fails, "%s%s%s", config.fails, (strcmp(config.fails, "") ? ", " : ""), procprog);
347 result = max_state (result, i); 322 result = max_state(result, temporary_result);
348 } 323 }
349 if (i == STATE_CRITICAL) { 324 if (temporary_result == STATE_CRITICAL) {
350 crit++; 325 crit++;
351 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 326 xasprintf(&config.fails, "%s%s%s", config.fails, (strcmp(config.fails, "") ? ", " : ""), procprog);
352 result = max_state (result, i); 327 result = max_state(result, temporary_result);
353 } 328 }
354 } 329 }
355 } 330 }
@@ -359,339 +334,350 @@ main (int argc, char **argv)
359 } 334 }
360 } 335 }
361 336
362 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */ 337 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
363 printf (_("Unable to read output\n")); 338 printf(_("Unable to read output\n"));
364 return STATE_UNKNOWN; 339 return STATE_UNKNOWN;
365 } 340 }
366 341
367 if ( result == STATE_UNKNOWN ) 342 if (result == STATE_UNKNOWN) {
368 result = STATE_OK; 343 result = STATE_OK;
344 }
369 345
370 /* Needed if procs found, but none match filter */ 346 /* Needed if procs found, but none match filter */
371 if ( metric == METRIC_PROCS ) { 347 if (config.metric == METRIC_PROCS) {
372 result = max_state (result, get_status ((double)procs, procs_thresholds) ); 348 result = max_state(result, get_status((double)procs, config.procs_thresholds));
373 } 349 }
374 350
375 if ( result == STATE_OK ) { 351 if (result == STATE_OK) {
376 printf ("%s %s: ", metric_name, _("OK")); 352 printf("%s %s: ", config.metric_name, _("OK"));
377 } else if (result == STATE_WARNING) { 353 } else if (result == STATE_WARNING) {
378 printf ("%s %s: ", metric_name, _("WARNING")); 354 printf("%s %s: ", config.metric_name, _("WARNING"));
379 if ( metric != METRIC_PROCS ) { 355 if (config.metric != METRIC_PROCS) {
380 printf (_("%d warn out of "), warn); 356 printf(_("%d warn out of "), warn);
381 } 357 }
382 } else if (result == STATE_CRITICAL) { 358 } else if (result == STATE_CRITICAL) {
383 printf ("%s %s: ", metric_name, _("CRITICAL")); 359 printf("%s %s: ", config.metric_name, _("CRITICAL"));
384 if (metric != METRIC_PROCS) { 360 if (config.metric != METRIC_PROCS) {
385 printf (_("%d crit, %d warn out of "), crit, warn); 361 printf(_("%d crit, %d warn out of "), crit, warn);
386 } 362 }
387 } 363 }
388 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 364 printf(ngettext("%d process", "%d processes", (unsigned long)procs), procs);
389 365
390 if (strcmp(fmt,"") != 0) { 366 if (strcmp(config.fmt, "") != 0) {
391 printf (_(" with %s"), fmt); 367 printf(_(" with %s"), config.fmt);
392 } 368 }
393 369
394 if ( verbose >= 1 && strcmp(fails,"") ) 370 if (verbose >= 1 && strcmp(config.fails, "")) {
395 printf (" [%s]", fails); 371 printf(" [%s]", config.fails);
372 }
396 373
397 if (metric == METRIC_PROCS) 374 if (config.metric == METRIC_PROCS) {
398 printf (" | procs=%d;%s;%s;0;", procs, 375 printf(" | procs=%d;%s;%s;0;", procs, config.warning_range ? config.warning_range : "",
399 warning_range ? warning_range : "", 376 config.critical_range ? config.critical_range : "");
400 critical_range ? critical_range : ""); 377 } else {
401 else 378 printf(" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
402 printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit); 379 }
403 380
404 printf ("\n"); 381 printf("\n");
405 return result; 382 exit(result);
406} 383}
407 384
408
409
410/* process command-line arguments */ 385/* process command-line arguments */
411int 386check_procs_config_wrapper process_arguments(int argc, char **argv) {
412process_arguments (int argc, char **argv) 387 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
413{ 388 {"critical", required_argument, 0, 'c'},
414 int c = 1; 389 {"metric", required_argument, 0, 'm'},
415 char *user; 390 {"timeout", required_argument, 0, 't'},
416 struct passwd *pw; 391 {"status", required_argument, 0, 's'},
417 int option = 0; 392 {"ppid", required_argument, 0, 'p'},
418 int err; 393 {"user", required_argument, 0, 'u'},
419 int cflags = REG_NOSUB | REG_EXTENDED; 394 {"command", required_argument, 0, 'C'},
420 char errbuf[MAX_INPUT_BUFFER]; 395 {"vsz", required_argument, 0, 'z'},
421 char *temp_string; 396 {"rss", required_argument, 0, 'r'},
422 int i=0; 397 {"pcpu", required_argument, 0, 'P'},
423 static struct option longopts[] = { 398 {"elapsed", required_argument, 0, 'e'},
424 {"warning", required_argument, 0, 'w'}, 399 {"argument-array", required_argument, 0, 'a'},
425 {"critical", required_argument, 0, 'c'}, 400 {"help", no_argument, 0, 'h'},
426 {"metric", required_argument, 0, 'm'}, 401 {"version", no_argument, 0, 'V'},
427 {"timeout", required_argument, 0, 't'}, 402 {"verbose", no_argument, 0, 'v'},
428 {"status", required_argument, 0, 's'}, 403 {"ereg-argument-array", required_argument, 0, CHAR_MAX + 1},
429 {"ppid", required_argument, 0, 'p'}, 404 {"input-file", required_argument, 0, CHAR_MAX + 2},
430 {"user", required_argument, 0, 'u'}, 405 {"no-kthreads", required_argument, 0, 'k'},
431 {"command", required_argument, 0, 'C'}, 406 {"traditional-filter", no_argument, 0, 'T'},
432 {"vsz", required_argument, 0, 'z'}, 407 {"exclude-process", required_argument, 0, 'X'},
433 {"rss", required_argument, 0, 'r'}, 408 {0, 0, 0, 0}};
434 {"pcpu", required_argument, 0, 'P'}, 409
435 {"elapsed", required_argument, 0, 'e'}, 410 for (int index = 1; index < argc; index++) {
436 {"argument-array", required_argument, 0, 'a'}, 411 if (strcmp("-to", argv[index]) == 0) {
437 {"help", no_argument, 0, 'h'}, 412 strcpy(argv[index], "-t");
438 {"version", no_argument, 0, 'V'}, 413 }
439 {"verbose", no_argument, 0, 'v'}, 414 }
440 {"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
441 {"input-file", required_argument, 0, CHAR_MAX+2},
442 {"no-kthreads", required_argument, 0, 'k'},
443 {"traditional-filter", no_argument, 0, 'T'},
444 {"exclude-process", required_argument, 0, 'X'},
445 {0, 0, 0, 0}
446 };
447 415
448 for (c = 1; c < argc; c++) 416 check_procs_config_wrapper result = {
449 if (strcmp ("-to", argv[c]) == 0) 417 .errorcode = OK,
450 strcpy (argv[c], "-t"); 418 .config = check_procs_config_init(),
419 };
451 420
452 while (1) { 421 while (true) {
453 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", 422 int option = 0;
454 longopts, &option); 423 int option_index = getopt_long(argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", longopts, &option);
455 424
456 if (c == -1 || c == EOF) 425 if (option_index == -1 || option_index == EOF) {
457 break; 426 break;
427 }
458 428
459 switch (c) { 429 switch (option_index) {
460 case '?': /* help */ 430 case '?': /* help */
461 usage5 (); 431 usage5();
462 case 'h': /* help */ 432 case 'h': /* help */
463 print_help (); 433 print_help();
464 exit (STATE_UNKNOWN); 434 exit(STATE_UNKNOWN);
465 case 'V': /* version */ 435 case 'V': /* version */
466 print_revision (progname, NP_VERSION); 436 print_revision(progname, NP_VERSION);
467 exit (STATE_UNKNOWN); 437 exit(STATE_UNKNOWN);
468 case 't': /* timeout period */ 438 case 't': /* timeout period */
469 if (!is_integer (optarg)) 439 if (!is_integer(optarg)) {
470 usage2 (_("Timeout interval must be a positive integer"), optarg); 440 usage2(_("Timeout interval must be a positive integer"), optarg);
471 else 441 } else {
472 timeout_interval = atoi (optarg); 442 timeout_interval = atoi(optarg);
443 }
473 break; 444 break;
474 case 'c': /* critical threshold */ 445 case 'c': /* critical threshold */
475 critical_range = optarg; 446 result.config.critical_range = optarg;
476 break; 447 break;
477 case 'w': /* warning threshold */ 448 case 'w': /* warning threshold */
478 warning_range = optarg; 449 result.config.warning_range = optarg;
479 break; 450 break;
480 case 'p': /* process id */ 451 case 'p': { /* process id */
481 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { 452 static char tmp[MAX_INPUT_BUFFER];
482 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid); 453 if (sscanf(optarg, "%d%[^0-9]", &result.config.ppid, tmp) == 1) {
483 options |= PPID; 454 xasprintf(&result.config.fmt, "%s%sPPID = %d", (result.config.fmt ? result.config.fmt : ""),
455 (result.config.options ? ", " : ""), result.config.ppid);
456 result.config.options |= PPID;
484 break; 457 break;
485 } 458 }
486 usage4 (_("Parent Process ID must be an integer!")); 459 usage4(_("Parent Process ID must be an integer!"));
487 case 's': /* status */ 460 }
488 if (statopts) 461 case 's': /* status */
462 if (result.config.statopts) {
489 break; 463 break;
490 else 464 } else {
491 statopts = optarg; 465 result.config.statopts = optarg;
492 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 466 }
493 options |= STAT; 467 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"), (result.config.fmt ? result.config.fmt : ""),
468 (result.config.options ? ", " : ""), result.config.statopts);
469 result.config.options |= STAT;
494 break; 470 break;
495 case 'u': /* user or user id */ 471 case 'u': /* user or user id */ {
496 if (is_integer (optarg)) { 472 struct passwd *pw;
497 uid = atoi (optarg); 473 if (is_integer(optarg)) {
498 pw = getpwuid ((uid_t) uid); 474 result.config.uid = atoi(optarg);
475 pw = getpwuid(result.config.uid);
499 /* check to be sure user exists */ 476 /* check to be sure user exists */
500 if (pw == NULL) 477 if (pw == NULL) {
501 usage2 (_("UID was not found"), optarg); 478 usage2(_("UID was not found"), optarg);
502 } 479 }
503 else { 480 } else {
504 pw = getpwnam (optarg); 481 pw = getpwnam(optarg);
505 /* check to be sure user exists */ 482 /* check to be sure user exists */
506 if (pw == NULL) 483 if (pw == NULL) {
507 usage2 (_("User name was not found"), optarg); 484 usage2(_("User name was not found"), optarg);
485 }
508 /* then get uid */ 486 /* then get uid */
509 uid = pw->pw_uid; 487 result.config.uid = pw->pw_uid;
510 } 488 }
511 user = pw->pw_name; 489
512 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""), 490 char *user = pw->pw_name;
513 uid, user); 491 xasprintf(&result.config.fmt, "%s%sUID = %d (%s)", (result.config.fmt ? result.config.fmt : ""),
514 options |= USER; 492 (result.config.options ? ", " : ""), result.config.uid, user);
515 break; 493 result.config.options |= USER;
516 case 'C': /* command */ 494 } break;
495 case 'C': /* command */
517 /* TODO: allow this to be passed in with --metric */ 496 /* TODO: allow this to be passed in with --metric */
518 if (prog) 497 if (result.config.prog) {
519 break; 498 break;
520 else 499 } else {
521 prog = optarg; 500 result.config.prog = optarg;
522 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 501 }
523 prog); 502 xasprintf(&result.config.fmt, _("%s%scommand name '%s'"), (result.config.fmt ? result.config.fmt : ""),
524 options |= PROG; 503 (result.config.options ? ", " : ""), result.config.prog);
504 result.config.options |= PROG;
525 break; 505 break;
526 case 'X': 506 case 'X':
527 if(exclude_progs) 507 if (result.config.exclude_progs) {
528 break; 508 break;
529 else 509 } else {
530 exclude_progs = optarg; 510 result.config.exclude_progs = optarg;
531 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 511 }
532 exclude_progs); 512 xasprintf(&result.config.fmt, _("%s%sexclude progs '%s'"), (result.config.fmt ? result.config.fmt : ""),
533 char *p = strtok(exclude_progs, ","); 513 (result.config.options ? ", " : ""), result.config.exclude_progs);
534 514 char *tmp_pointer = strtok(result.config.exclude_progs, ",");
535 while(p){ 515
536 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter); 516 while (tmp_pointer) {
537 exclude_progs_arr[exclude_progs_counter-1] = p; 517 result.config.exclude_progs_arr =
538 p = strtok(NULL, ","); 518 realloc(result.config.exclude_progs_arr, sizeof(char *) * ++result.config.exclude_progs_counter);
519 result.config.exclude_progs_arr[result.config.exclude_progs_counter - 1] = tmp_pointer;
520 tmp_pointer = strtok(NULL, ",");
539 } 521 }
540 522
541 options |= EXCLUDE_PROGS; 523 result.config.options |= EXCLUDE_PROGS;
542 break; 524 break;
543 case 'a': /* args (full path name with args) */ 525 case 'a': /* args (full path name with args) */
544 /* TODO: allow this to be passed in with --metric */ 526 /* TODO: allow this to be passed in with --metric */
545 if (args) 527 if (result.config.args) {
546 break; 528 break;
547 else 529 } else {
548 args = optarg; 530 result.config.args = optarg;
549 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args); 531 }
550 options |= ARGS; 532 xasprintf(&result.config.fmt, "%s%sargs '%s'", (result.config.fmt ? result.config.fmt : ""),
533 (result.config.options ? ", " : ""), result.config.args);
534 result.config.options |= ARGS;
551 break; 535 break;
552 case CHAR_MAX+1: 536 case CHAR_MAX + 1: {
553 err = regcomp(&re_args, optarg, cflags); 537 int cflags = REG_NOSUB | REG_EXTENDED;
538 int err = regcomp(&result.config.re_args, optarg, cflags);
554 if (err != 0) { 539 if (err != 0) {
555 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER); 540 char errbuf[MAX_INPUT_BUFFER];
556 die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 541 regerror(err, &result.config.re_args, errbuf, MAX_INPUT_BUFFER);
542 die(STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
557 } 543 }
558 /* Strip off any | within the regex optarg */ 544 /* Strip off any | within the regex optarg */
559 temp_string = strdup(optarg); 545 char *temp_string = strdup(optarg);
560 while(temp_string[i]!='\0'){ 546 int index = 0;
561 if(temp_string[i]=='|') 547 while (temp_string[index] != '\0') {
562 temp_string[i]=','; 548 if (temp_string[index] == '|') {
563 i++; 549 temp_string[index] = ',';
564 } 550 }
565 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string); 551 index++;
566 options |= EREG_ARGS; 552 }
567 break; 553 xasprintf(&result.config.fmt, "%s%sregex args '%s'", (result.config.fmt ? result.config.fmt : ""),
568 case 'r': /* RSS */ 554 (result.config.options ? ", " : ""), temp_string);
569 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) { 555 result.config.options |= EREG_ARGS;
570 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss); 556 } break;
571 options |= RSS; 557 case 'r': { /* RSS */
558 static char tmp[MAX_INPUT_BUFFER];
559 if (sscanf(optarg, "%d%[^0-9]", &result.config.rss, tmp) == 1) {
560 xasprintf(&result.config.fmt, "%s%sRSS >= %d", (result.config.fmt ? result.config.fmt : ""),
561 (result.config.options ? ", " : ""), result.config.rss);
562 result.config.options |= RSS;
572 break; 563 break;
573 } 564 }
574 usage4 (_("RSS must be an integer!")); 565 usage4(_("RSS must be an integer!"));
575 case 'z': /* VSZ */ 566 }
576 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) { 567 case 'z': { /* VSZ */
577 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz); 568 static char tmp[MAX_INPUT_BUFFER];
578 options |= VSZ; 569 if (sscanf(optarg, "%d%[^0-9]", &result.config.vsz, tmp) == 1) {
570 xasprintf(&result.config.fmt, "%s%sVSZ >= %d", (result.config.fmt ? result.config.fmt : ""),
571 (result.config.options ? ", " : ""), result.config.vsz);
572 result.config.options |= VSZ;
579 break; 573 break;
580 } 574 }
581 usage4 (_("VSZ must be an integer!")); 575 usage4(_("VSZ must be an integer!"));
582 case 'P': /* PCPU */ 576 }
577 case 'P': { /* PCPU */
583 /* TODO: -P 1.5.5 is accepted */ 578 /* TODO: -P 1.5.5 is accepted */
584 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) { 579 static char tmp[MAX_INPUT_BUFFER];
585 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu); 580 if (sscanf(optarg, "%f%[^0-9.]", &result.config.pcpu, tmp) == 1) {
586 options |= PCPU; 581 xasprintf(&result.config.fmt, "%s%sPCPU >= %.2f", (result.config.fmt ? result.config.fmt : ""),
582 (result.config.options ? ", " : ""), result.config.pcpu);
583 result.config.options |= PCPU;
587 break; 584 break;
588 } 585 }
589 usage4 (_("PCPU must be a float!")); 586 usage4(_("PCPU must be a float!"));
587 }
590 case 'm': 588 case 'm':
591 xasprintf (&metric_name, "%s", optarg); 589 xasprintf(&result.config.metric_name, "%s", optarg);
592 if ( strcmp(optarg, "PROCS") == 0) { 590 if (strcmp(optarg, "PROCS") == 0) {
593 metric = METRIC_PROCS; 591 result.config.metric = METRIC_PROCS;
594 break; 592 break;
595 } 593 }
596 else if ( strcmp(optarg, "VSZ") == 0) { 594 if (strcmp(optarg, "VSZ") == 0) {
597 metric = METRIC_VSZ; 595 result.config.metric = METRIC_VSZ;
598 break; 596 break;
599 } 597 }
600 else if ( strcmp(optarg, "RSS") == 0 ) { 598 if (strcmp(optarg, "RSS") == 0) {
601 metric = METRIC_RSS; 599 result.config.metric = METRIC_RSS;
602 break; 600 break;
603 } 601 }
604 else if ( strcmp(optarg, "CPU") == 0 ) { 602 if (strcmp(optarg, "CPU") == 0) {
605 metric = METRIC_CPU; 603 result.config.metric = METRIC_CPU;
606 break; 604 break;
607 } 605 }
608 else if ( strcmp(optarg, "ELAPSED") == 0) { 606 if (strcmp(optarg, "ELAPSED") == 0) {
609 metric = METRIC_ELAPSED; 607 result.config.metric = METRIC_ELAPSED;
610 break; 608 break;
611 } 609 }
612 610
613 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 611 usage4(_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
614 case 'k': /* linux kernel thread filter */ 612 case 'k': /* linux kernel thread filter */
615 kthread_filter = 1; 613 result.config.kthread_filter = true;
616 break; 614 break;
617 case 'v': /* command */ 615 case 'v': /* command */
618 verbose++; 616 verbose++;
619 break; 617 break;
620 case 'T': 618 case 'T':
621 usepid = 1; 619 result.config.usepid = true;
622 break; 620 break;
623 case CHAR_MAX+2: 621 case CHAR_MAX + 2:
624 input_filename = optarg; 622 result.config.input_filename = optarg;
625 break; 623 break;
626 } 624 }
627 } 625 }
628 626
629 c = optind; 627 int index = optind;
630 if ((! warning_range) && argv[c]) 628 if ((!result.config.warning_range) && argv[index]) {
631 warning_range = argv[c++]; 629 result.config.warning_range = argv[index++];
632 if ((! critical_range) && argv[c]) 630 }
633 critical_range = argv[c++]; 631 if ((!result.config.critical_range) && argv[index]) {
634 if (statopts == NULL && argv[c]) { 632 result.config.critical_range = argv[index++];
635 xasprintf (&statopts, "%s", argv[c++]); 633 }
636 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 634 if (result.config.statopts == NULL && argv[index]) {
637 options |= STAT; 635 xasprintf(&result.config.statopts, "%s", argv[index++]);
636 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"), (result.config.fmt ? result.config.fmt : ""),
637 (result.config.options ? ", " : ""), result.config.statopts);
638 result.config.options |= STAT;
638 } 639 }
639 640
640 /* this will abort in case of invalid ranges */ 641 /* this will abort in case of invalid ranges */
641 set_thresholds (&procs_thresholds, warning_range, critical_range); 642 set_thresholds(&result.config.procs_thresholds, result.config.warning_range, result.config.critical_range);
642 643
643 return validate_arguments (); 644 return validate_arguments(result);
644} 645}
645 646
647check_procs_config_wrapper validate_arguments(check_procs_config_wrapper config_wrapper) {
648 if (config_wrapper.config.options == 0) {
649 config_wrapper.config.options = ALL;
650 }
646 651
652 if (config_wrapper.config.statopts == NULL) {
653 config_wrapper.config.statopts = strdup("");
654 }
647 655
648int 656 if (config_wrapper.config.prog == NULL) {
649validate_arguments () 657 config_wrapper.config.prog = strdup("");
650{ 658 }
651 if (options == 0)
652 options = ALL;
653
654 if (statopts==NULL)
655 statopts = strdup("");
656
657 if (prog==NULL)
658 prog = strdup("");
659 659
660 if (args==NULL) 660 if (config_wrapper.config.args == NULL) {
661 args = strdup(""); 661 config_wrapper.config.args = strdup("");
662 }
662 663
663 if (fmt==NULL) 664 if (config_wrapper.config.fmt == NULL) {
664 fmt = strdup(""); 665 config_wrapper.config.fmt = strdup("");
666 }
665 667
666 if (fails==NULL) 668 if (config_wrapper.config.fails == NULL) {
667 fails = strdup(""); 669 config_wrapper.config.fails = strdup("");
670 }
668 671
669 return options; 672 // return options;
673 return config_wrapper;
670} 674}
671 675
672
673/* convert the elapsed time to seconds */ 676/* convert the elapsed time to seconds */
674int 677int convert_to_seconds(char *etime, enum metric metric) {
675convert_to_seconds(char *etime) { 678 int hyphcnt = 0;
676 679 int coloncnt = 0;
677 char *ptr; 680 for (char *ptr = etime; *ptr != '\0'; ptr++) {
678 int total;
679
680 int hyphcnt;
681 int coloncnt;
682 int days;
683 int hours;
684 int minutes;
685 int seconds;
686
687 hyphcnt = 0;
688 coloncnt = 0;
689 days = 0;
690 hours = 0;
691 minutes = 0;
692 seconds = 0;
693
694 for (ptr = etime; *ptr != '\0'; ptr++) {
695 681
696 if (*ptr == '-') { 682 if (*ptr == '-') {
697 hyphcnt++; 683 hyphcnt++;
@@ -703,9 +689,12 @@ convert_to_seconds(char *etime) {
703 } 689 }
704 } 690 }
705 691
692 int days = 0;
693 int hours = 0;
694 int minutes = 0;
695 int seconds = 0;
706 if (hyphcnt > 0) { 696 if (hyphcnt > 0) {
707 sscanf(etime, "%d-%d:%d:%d", 697 sscanf(etime, "%d-%d:%d:%d", &days, &hours, &minutes, &seconds);
708 &days, &hours, &minutes, &seconds);
709 /* linux 2.6.5/2.6.6 reporting some processes with infinite 698 /* linux 2.6.5/2.6.6 reporting some processes with infinite
710 * elapsed times for some reason */ 699 * elapsed times for some reason */
711 if (days == 49710) { 700 if (days == 49710) {
@@ -713,135 +702,125 @@ convert_to_seconds(char *etime) {
713 } 702 }
714 } else { 703 } else {
715 if (coloncnt == 2) { 704 if (coloncnt == 2) {
716 sscanf(etime, "%d:%d:%d", 705 sscanf(etime, "%d:%d:%d", &hours, &minutes, &seconds);
717 &hours, &minutes, &seconds);
718 } else if (coloncnt == 1) { 706 } else if (coloncnt == 1) {
719 sscanf(etime, "%d:%d", 707 sscanf(etime, "%d:%d", &minutes, &seconds);
720 &minutes, &seconds);
721 } 708 }
722 } 709 }
723 710
724 total = (days * 86400) + 711 int total = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
725 (hours * 3600) +
726 (minutes * 60) +
727 seconds;
728 712
729 if (verbose >= 3 && metric == METRIC_ELAPSED) { 713 if (verbose >= 3 && metric == METRIC_ELAPSED) {
730 printf("seconds: %d\n", total); 714 printf("seconds: %d\n", total);
731 } 715 }
732 return total; 716 return total;
733} 717}
734 718
719void print_help(void) {
720 print_revision(progname, NP_VERSION);
735 721
736void 722 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
737print_help (void) 723 printf(COPYRIGHT, copyright, email);
738{
739 print_revision (progname, NP_VERSION);
740
741 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
742 printf (COPYRIGHT, copyright, email);
743 724
744 printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified")); 725 printf("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
745 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number")); 726 printf("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number"));
746 printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check.")); 727 printf("%s\n", _("of processes. Search filters can be applied to limit the processes to check."));
747 728
748 printf ("\n\n"); 729 printf("\n\n");
749 730
750 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)")); 731 printf("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)"));
751 printf ("%s\n", _("are excluded from any checks to prevent false positives.")); 732 printf("%s\n", _("are excluded from any checks to prevent false positives."));
752 733
753 printf ("\n\n"); 734 printf("\n\n");
754 735
755 print_usage (); 736 print_usage();
756 737
757 printf (UT_HELP_VRSN); 738 printf(UT_HELP_VRSN);
758 printf (UT_EXTRA_OPTS); 739 printf(UT_EXTRA_OPTS);
759 printf (" %s\n", "-w, --warning=RANGE"); 740 printf(" %s\n", "-w, --warning=RANGE");
760 printf (" %s\n", _("Generate warning state if metric is outside this range")); 741 printf(" %s\n", _("Generate warning state if metric is outside this range"));
761 printf (" %s\n", "-c, --critical=RANGE"); 742 printf(" %s\n", "-c, --critical=RANGE");
762 printf (" %s\n", _("Generate critical state if metric is outside this range")); 743 printf(" %s\n", _("Generate critical state if metric is outside this range"));
763 printf (" %s\n", "-m, --metric=TYPE"); 744 printf(" %s\n", "-m, --metric=TYPE");
764 printf (" %s\n", _("Check thresholds against metric. Valid types:")); 745 printf(" %s\n", _("Check thresholds against metric. Valid types:"));
765 printf (" %s\n", _("PROCS - number of processes (default)")); 746 printf(" %s\n", _("PROCS - number of processes (default)"));
766 printf (" %s\n", _("VSZ - virtual memory size")); 747 printf(" %s\n", _("VSZ - virtual memory size"));
767 printf (" %s\n", _("RSS - resident set memory size")); 748 printf(" %s\n", _("RSS - resident set memory size"));
768 printf (" %s\n", _("CPU - percentage CPU")); 749 printf(" %s\n", _("CPU - percentage CPU"));
769/* only linux etime is support currently */ 750/* only linux etime is support currently */
770#if defined( __linux__ ) 751#if defined(__linux__)
771 printf (" %s\n", _("ELAPSED - time elapsed in seconds")); 752 printf(" %s\n", _("ELAPSED - time elapsed in seconds"));
772#endif /* defined(__linux__) */ 753#endif /* defined(__linux__) */
773 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 754 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
774 755
775 printf (" %s\n", "-v, --verbose"); 756 printf(" %s\n", "-v, --verbose");
776 printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); 757 printf(" %s\n", _("Extra information. Up to 3 verbosity levels"));
777 758
778 printf (" %s\n", "-T, --traditional"); 759 printf(" %s\n", "-T, --traditional");
779 printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe")); 760 printf(" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
780 761
781 printf ("\n"); 762 printf("\n");
782 printf ("%s\n", "Filters:"); 763 printf("%s\n", "Filters:");
783 printf (" %s\n", "-s, --state=STATUSFLAGS"); 764 printf(" %s\n", "-s, --state=STATUSFLAGS");
784 printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or")); 765 printf(" %s\n", _("Only scan for processes that have, in the output of `ps`, one or"));
785 printf (" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,")); 766 printf(" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,"));
786 printf (" %s\n", _("RSZDT, plus others based on the output of your 'ps' command).")); 767 printf(" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
787 printf (" %s\n", "-p, --ppid=PPID"); 768 printf(" %s\n", "-p, --ppid=PPID");
788 printf (" %s\n", _("Only scan for children of the parent process ID indicated.")); 769 printf(" %s\n", _("Only scan for children of the parent process ID indicated."));
789 printf (" %s\n", "-z, --vsz=VSZ"); 770 printf(" %s\n", "-z, --vsz=VSZ");
790 printf (" %s\n", _("Only scan for processes with VSZ higher than indicated.")); 771 printf(" %s\n", _("Only scan for processes with VSZ higher than indicated."));
791 printf (" %s\n", "-r, --rss=RSS"); 772 printf(" %s\n", "-r, --rss=RSS");
792 printf (" %s\n", _("Only scan for processes with RSS higher than indicated.")); 773 printf(" %s\n", _("Only scan for processes with RSS higher than indicated."));
793 printf (" %s\n", "-P, --pcpu=PCPU"); 774 printf(" %s\n", "-P, --pcpu=PCPU");
794 printf (" %s\n", _("Only scan for processes with PCPU higher than indicated.")); 775 printf(" %s\n", _("Only scan for processes with PCPU higher than indicated."));
795 printf (" %s\n", "-u, --user=USER"); 776 printf(" %s\n", "-u, --user=USER");
796 printf (" %s\n", _("Only scan for processes with user name or ID indicated.")); 777 printf(" %s\n", _("Only scan for processes with user name or ID indicated."));
797 printf (" %s\n", "-a, --argument-array=STRING"); 778 printf(" %s\n", "-a, --argument-array=STRING");
798 printf (" %s\n", _("Only scan for processes with args that contain STRING.")); 779 printf(" %s\n", _("Only scan for processes with args that contain STRING."));
799 printf (" %s\n", "--ereg-argument-array=STRING"); 780 printf(" %s\n", "--ereg-argument-array=STRING");
800 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); 781 printf(" %s\n", _("Only scan for processes with args that contain the regex STRING."));
801 printf (" %s\n", "-C, --command=COMMAND"); 782 printf(" %s\n", "-C, --command=COMMAND");
802 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); 783 printf(" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
803 printf (" %s\n", "-X, --exclude-process"); 784 printf(" %s\n", "-X, --exclude-process");
804 printf (" %s\n", _("Exclude processes which match this comma separated list")); 785 printf(" %s\n", _("Exclude processes which match this comma separated list"));
805 printf (" %s\n", "-k, --no-kthreads"); 786 printf(" %s\n", "-k, --no-kthreads");
806 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); 787 printf(" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
807 788
808 printf(_("\n\ 789 printf(_("\n\
809RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ 790RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
810specified 'max:min', a warning status will be generated if the\n\ 791specified 'max:min', a warning status will be generated if the\n\
811count is inside the specified range\n\n")); 792count is inside the specified range\n\n"));
812 793
813 printf(_("\ 794 printf(_("\
814This plugin checks the number of currently running processes and\n\ 795This plugin checks the number of currently running processes and\n\
815generates WARNING or CRITICAL states if the process count is outside\n\ 796generates WARNING or CRITICAL states if the process count is outside\n\
816the specified threshold ranges. The process count can be filtered by\n\ 797the specified threshold ranges. The process count can be filtered by\n\
817process owner, parent process PID, current state (e.g., 'Z'), or may\n\ 798process owner, parent process PID, current state (e.g., 'Z'), or may\n\
818be the total number of running processes\n\n")); 799be the total number of running processes\n\n"));
819 800
820 printf ("%s\n", _("Examples:")); 801 printf("%s\n", _("Examples:"));
821 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry"); 802 printf(" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
822 printf (" %s\n", _("Warning if not two processes with command name portsentry.")); 803 printf(" %s\n", _("Warning if not two processes with command name portsentry."));
823 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 804 printf(" %s\n\n", _("Critical if < 2 or > 1024 processes"));
824 printf (" %s\n", "check_procs -c 1: -C sshd"); 805 printf(" %s\n", "check_procs -c 1: -C sshd");
825 printf (" %s\n", _("Critical if not at least 1 process with command sshd")); 806 printf(" %s\n", _("Critical if not at least 1 process with command sshd"));
826 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd"); 807 printf(" %s\n", "check_procs -w 1024 -c 1: -C sshd");
827 printf (" %s\n", _("Warning if > 1024 processes with command name sshd.")); 808 printf(" %s\n", _("Warning if > 1024 processes with command name sshd."));
828 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd.")); 809 printf(" %s\n\n", _("Critical if < 1 processes with command name sshd."));
829 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root"); 810 printf(" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
830 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing")); 811 printf(" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
831 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root")); 812 printf(" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
832 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 813 printf(" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
833 printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K")); 814 printf(" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K"));
834 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU"); 815 printf(" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
835 printf (" %s\n", _("Alert if CPU of any processes over 10%% or 20%%")); 816 printf(" %s\n", _("Alert if CPU of any processes over 10%% or 20%%"));
836 817
837 printf (UT_SUPPORT); 818 printf(UT_SUPPORT);
838} 819}
839 820
840void 821void print_usage(void) {
841print_usage (void) 822 printf("%s\n", _("Usage:"));
842{ 823 printf("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
843 printf ("%s\n", _("Usage:")); 824 printf(" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
844 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname); 825 printf(" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
845 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
846 printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
847} 826}
diff --git a/plugins/check_procs.d/config.h b/plugins/check_procs.d/config.h
new file mode 100644
index 00000000..e32ca066
--- /dev/null
+++ b/plugins/check_procs.d/config.h
@@ -0,0 +1,75 @@
1#pragma once
2
3#include "../../config.h"
4#include "regex.h"
5#include "thresholds.h"
6#include <stddef.h>
7#include <string.h>
8#include <sys/types.h>
9
10enum metric {
11 METRIC_PROCS,
12 METRIC_VSZ,
13 METRIC_RSS,
14 METRIC_CPU,
15 METRIC_ELAPSED
16};
17
18typedef struct {
19 int options; /* bitmask of filter criteria to test against */
20 enum metric metric;
21 char *metric_name;
22 char *input_filename;
23 char *prog;
24 char *args;
25 char *fmt;
26 char *fails;
27 char *exclude_progs;
28 char **exclude_progs_arr;
29 char exclude_progs_counter;
30 regex_t re_args;
31
32 bool kthread_filter;
33 bool usepid; /* whether to test for pid or /proc/pid/exe */
34 uid_t uid;
35 pid_t ppid;
36 int vsz;
37 int rss;
38 float pcpu;
39 char *statopts;
40
41 char *warning_range;
42 char *critical_range;
43 thresholds *procs_thresholds;
44} check_procs_config;
45
46check_procs_config check_procs_config_init() {
47 check_procs_config tmp = {
48 .options = 0,
49 .metric = METRIC_PROCS,
50 .metric_name = strdup("PROCS"),
51 .input_filename = NULL,
52 .prog = NULL,
53 .args = NULL,
54 .fmt = NULL,
55 .fails = NULL,
56 .exclude_progs = NULL,
57 .exclude_progs_arr = NULL,
58 .exclude_progs_counter = 0,
59 .re_args = {0},
60
61 .kthread_filter = false,
62 .usepid = false,
63 .uid = 0,
64 .ppid = 0,
65 .vsz = 0,
66 .rss = 0,
67 .pcpu = 0,
68 .statopts = NULL,
69
70 .warning_range = NULL,
71 .critical_range = NULL,
72 .procs_thresholds = NULL,
73 };
74 return tmp;
75}
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index cb95949a..435a104e 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -90,6 +90,14 @@ int main(int argc, char **argv) {
90 exit(STATE_UNKNOWN); 90 exit(STATE_UNKNOWN);
91 } 91 }
92 92
93 if (verbose) {
94 printf("Swap retrieval result:\n"
95 "\tFree: %llu\n"
96 "\tUsed: %llu\n"
97 "\tTotal: %llu\n",
98 data.metrics.free, data.metrics.used, data.metrics.total);
99 }
100
93 double percent_used; 101 double percent_used;
94 mp_check overall = mp_check_init(); 102 mp_check overall = mp_check_init();
95 if (config.output_format_is_set) { 103 if (config.output_format_is_set) {
diff --git a/plugins/check_swap.d/check_swap.h b/plugins/check_swap.d/check_swap.h
index 1000fc9e..da08d65a 100644
--- a/plugins/check_swap.d/check_swap.h
+++ b/plugins/check_swap.d/check_swap.h
@@ -1,7 +1,8 @@
1#pragma once 1#pragma once
2 2
3#include "../common.h" 3#include "../common.h"
4#include "output.h" 4#include "../../lib/output.h"
5#include "../../lib/states.h"
5 6
6#ifndef SWAP_CONVERSION 7#ifndef SWAP_CONVERSION
7# define SWAP_CONVERSION 1 8# define SWAP_CONVERSION 1
@@ -26,7 +27,7 @@ typedef struct {
26 27
27typedef struct { 28typedef struct {
28 bool allswaps; 29 bool allswaps;
29 int no_swap_state; 30 mp_state_enum no_swap_state;
30 bool warn_is_set; 31 bool warn_is_set;
31 check_swap_threshold warn; 32 check_swap_threshold warn;
32 bool crit_is_set; 33 bool crit_is_set;
diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c
index 180d5037..634f80d9 100644
--- a/plugins/check_swap.d/swap.c
+++ b/plugins/check_swap.d/swap.c
@@ -68,7 +68,7 @@ swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
68 FILE *meminfo_file_ptr; 68 FILE *meminfo_file_ptr;
69 meminfo_file_ptr = fopen(proc_meminfo, "r"); 69 meminfo_file_ptr = fopen(proc_meminfo, "r");
70 70
71 swap_result result = {0}; 71 swap_result result = {};
72 result.errorcode = STATE_UNKNOWN; 72 result.errorcode = STATE_UNKNOWN;
73 73
74 if (meminfo_file_ptr == NULL) { 74 if (meminfo_file_ptr == NULL) {
@@ -78,83 +78,71 @@ swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
78 return result; 78 return result;
79 } 79 }
80 80
81 uint64_t swap_total = 0; 81 unsigned long swap_total = 0;
82 uint64_t swap_used = 0; 82 unsigned long swap_used = 0;
83 uint64_t swap_free = 0; 83 unsigned long swap_free = 0;
84 84
85 bool found_total = false; 85 bool found_total = false;
86 bool found_used = false;
87 bool found_free = false; 86 bool found_free = false;
88 87
89 char input_buffer[MAX_INPUT_BUFFER]; 88 char input_buffer[MAX_INPUT_BUFFER];
90 char str[32]; 89 char str[32];
91 90
92 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) { 91 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) {
93 uint64_t tmp_KB = 0;
94 92
95 /* 93 /*
96 * The following sscanf call looks for a line looking like: "Swap: 123 94 * The following sscanf call looks for a line looking like: "Swap: 123
97 * 123 123" On which kind of system this format exists, I can not say, 95 * 123 123" which exists on NetBSD (at least),
98 * but I wanted to document this for people who are not adapt with 96 * The unit should be Bytes
99 * sscanf anymore, like me
100 * Also the units used here are unclear and probably wrong
101 */ 97 */
102 if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) { 98 if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) {
103
104 result.metrics.total += swap_total;
105 result.metrics.used += swap_used;
106 result.metrics.free += swap_free;
107
108 found_total = true; 99 found_total = true;
109 found_free = true; 100 found_free = true;
110 found_used = true;
111
112 // Set error 101 // Set error
113 result.errorcode = STATE_OK; 102 result.errorcode = STATE_OK;
103 // Break out of fgets here, since both scanf expressions might match (NetBSD for example)
104 break;
105 }
106
107 /*
108 * The following sscanf call looks for lines looking like:
109 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least
110 * on Debian Linux with a 5.* kernel
111 */
112 unsigned long tmp_KB = 0;
113 int sscanf_result = sscanf(input_buffer,
114 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
115 "%*[k]%*[B]",
116 str, &tmp_KB);
117
118 if (sscanf_result == 2) {
119
120 if (verbose >= 3) {
121 printf("Got %s with %lu\n", str, tmp_KB);
122 }
114 123
115 /* 124 /* I think this part is always in Kb, so convert to bytes */
116 * The following sscanf call looks for lines looking like: 125 if (strcmp("Total", str) == 0) {
117 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least 126 swap_total = tmp_KB * 1000;
118 * on Debian Linux with a 5.* kernel 127 found_total = true;
119 */ 128 } else if (strcmp("Free", str) == 0) {
120 } else { 129 swap_free += tmp_KB * 1000;
121 int sscanf_result = sscanf(input_buffer, 130 found_free = true;
122 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu " 131 } else if (strcmp("Cached", str) == 0) {
123 "%*[k]%*[B]", 132 swap_free += tmp_KB * 1000;
124 str, &tmp_KB);
125
126 if (sscanf_result == 2) {
127
128 if (verbose >= 3) {
129 printf("Got %s with %lu\n", str, tmp_KB);
130 }
131
132 /* I think this part is always in Kb, so convert to bytes */
133 if (strcmp("Total", str) == 0) {
134 swap_total = tmp_KB * 1000;
135 found_total = true;
136 } else if (strcmp("Free", str) == 0) {
137 swap_free = swap_free + tmp_KB * 1000;
138 found_free = true;
139 found_used = true; // No explicit used metric available
140 } else if (strcmp("Cached", str) == 0) {
141 swap_free = swap_free + tmp_KB * 1000;
142 found_free = true;
143 found_used = true; // No explicit used metric available
144 }
145
146 result.errorcode = STATE_OK;
147 } 133 }
134
135 result.errorcode = STATE_OK;
148 } 136 }
149 } 137 }
150 138
151 fclose(meminfo_file_ptr); 139 fclose(meminfo_file_ptr);
152 140
153 result.metrics.total = swap_total; 141 result.metrics.total = swap_total;
154 result.metrics.used = swap_total - swap_free;
155 result.metrics.free = swap_free; 142 result.metrics.free = swap_free;
143 result.metrics.used = swap_total - swap_free;
156 144
157 if (!found_free || !found_total || !found_used) { 145 if (!found_free || !found_total) {
158 result.errorcode = STATE_UNKNOWN; 146 result.errorcode = STATE_UNKNOWN;
159 } 147 }
160 148
@@ -297,8 +285,14 @@ struct swapent {
297}; 285};
298 286
299#else 287#else
288
289// Includes for NetBSD
290# include <unistd.h>
291# include <sys/swap.h>
292
300# define bsd_swapctl swapctl 293# define bsd_swapctl swapctl
301#endif 294
295#endif // CHECK_SWAP_SWAPCTL_BSD
302 296
303swap_result getSwapFromSwapctl_BSD(swap_config config) { 297swap_result getSwapFromSwapctl_BSD(swap_config config) {
304 /* get the number of active swap devices */ 298 /* get the number of active swap devices */
@@ -322,8 +316,8 @@ swap_result getSwapFromSwapctl_BSD(swap_config config) {
322 unsigned long long used_swap_mb = 0; 316 unsigned long long used_swap_mb = 0;
323 317
324 for (int i = 0; i < nswaps; i++) { 318 for (int i = 0; i < nswaps; i++) {
325 dsktotal_mb = (float)ent[i].se_nblks / (float)config.conversion_factor; 319 dsktotal_mb = (double)ent[i].se_nblks / (double)config.conversion_factor;
326 dskused_mb = (float)ent[i].se_inuse / (float)config.conversion_factor; 320 dskused_mb = (double)ent[i].se_inuse / (double)config.conversion_factor;
327 dskfree_mb = (dsktotal_mb - dskused_mb); 321 dskfree_mb = (dsktotal_mb - dskused_mb);
328 322
329 if (config.allswaps && dsktotal_mb > 0) { 323 if (config.allswaps && dsktotal_mb > 0) {
diff --git a/plugins/common.h b/plugins/common.h
index 603bae55..35d1e549 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -31,7 +31,7 @@
31#ifndef _COMMON_H_ 31#ifndef _COMMON_H_
32#define _COMMON_H_ 32#define _COMMON_H_
33 33
34#include "config.h" 34#include "../config.h"
35#include "../lib/monitoringplug.h" 35#include "../lib/monitoringplug.h"
36 36
37#ifdef HAVE_FEATURES_H 37#ifdef HAVE_FEATURES_H
@@ -110,7 +110,7 @@
110 110
111/* GNU Libraries */ 111/* GNU Libraries */
112#include <getopt.h> 112#include <getopt.h>
113#include "dirname.h" 113#include "../gl/dirname.h"
114 114
115#include <locale.h> 115#include <locale.h>
116 116
@@ -190,7 +190,7 @@ enum {
190 * Internationalization 190 * Internationalization
191 * 191 *
192 */ 192 */
193#include "gettext.h" 193#include "../gl/gettext.h"
194#define _(String) gettext (String) 194#define _(String) gettext (String)
195#if ! ENABLE_NLS 195#if ! ENABLE_NLS
196# undef textdomain 196# undef textdomain
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
index 719de575..96740b3a 100644
--- a/plugins/sslutils.c
+++ b/plugins/sslutils.c
@@ -201,7 +201,7 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
201 time_t tm_t; 201 time_t tm_t;
202 202
203 if (!certificate) { 203 if (!certificate) {
204 printf("%s\n", _("CRITICAL - Cannot retrieve server certificate.")); 204 printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
205 return STATE_CRITICAL; 205 return STATE_CRITICAL;
206 } 206 }
207 207
diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t
index 9eb77ce4..0f62fb2b 100644
--- a/plugins/t/check_disk.t
+++ b/plugins/t/check_disk.t
@@ -10,6 +10,7 @@ use strict;
10use Test::More; 10use Test::More;
11use NPTest; 11use NPTest;
12use POSIX qw(ceil floor); 12use POSIX qw(ceil floor);
13use Data::Dumper;
13 14
14my $successOutput = '/^DISK OK/'; 15my $successOutput = '/^DISK OK/';
15my $failureOutput = '/^DISK CRITICAL/'; 16my $failureOutput = '/^DISK CRITICAL/';
@@ -20,173 +21,216 @@ my $result;
20my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/"); 21my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/");
21my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var"); 22my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var");
22 23
24my $output_format = "--output-format mp-test-json";
25
23if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") { 26if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") {
24 plan skip_all => "Need 2 mountpoints to test"; 27 plan skip_all => "Need 2 mountpoints to test";
25} else { 28} else {
26 plan tests => 94; 29 plan tests => 97;
27} 30}
28 31
29$result = NPTest->testCmd( 32$result = NPTest->testCmd(
30 "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -p $mountpoint2_valid" 33 "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -P -p $mountpoint2_valid $output_format"
31 ); 34 );
32cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)"); 35cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)");
33my $c = 0;
34$_ = $result->output;
35$c++ while /\(/g; # counts number of "(" - should be two
36cmp_ok( $c, '==', 2, "Got two mountpoints in output");
37 36
37like($result->{'mp_test_result'}->{'state'}, "/OK/", "Main result is OK");
38like($result->{'mp_test_result'}->{'checks'}->[0]->{'state'}, "/OK/", "First sub result is OK");
39like($result->{'mp_test_result'}->{'checks'}->[1]->{'state'}, "/OK/", "Second sub result is OK");
40
41my $absolut_space_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
42# print("absolute space on mp1: ". $absolut_space_mp1 . "\n");
43
44my $free_percent_on_mp1 = ($result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / ($absolut_space_mp1/100));
45print("free percent on mp1: ". $free_percent_on_mp1 . "\n");
46
47my $absolut_space_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
48# print("absolute space on mp2: ". $absolut_space_mp2 . "\n");
49
50my $free_percent_on_mp2 = ($result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ ($absolut_space_mp2/100));
51print("free percent on mp2: ". $free_percent_on_mp2 . "\n");
38 52
39# Get perf data 53my @perfdata;
40# Should use Monitoring::Plugin 54@perfdata[0] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
41my @perf_data = sort(split(/ /, $result->perf_output)); 55@perfdata[1] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
42 56
57# Decrease precision of numbers since the the fs might be modified between the two runs
58$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000);
59$perfdata[1]->{'value'}->{'value'} = int($perfdata[1]->{'value'}->{'value'} / 1000000);
43 60
44# Calculate avg_free free on mountpoint1 and mountpoint2 61# Calculate avg_free free on mountpoint1 and mountpoint2
45# because if you check in the middle, you should get different errors 62# because if you check in the middle, you should get different errors
46$_ = $result->output; 63my $avg_free_percent = ceil(($free_percent_on_mp1+$free_percent_on_mp2)/2);
47my ($free_on_mp1, $free_on_mp2) = (m/\((\d+\.\d+)%.*\((\d+\.\d+)%/); 64# print("avg_free: " . $avg_free_percent . "\n");
48die "Cannot parse output: $_" unless ($free_on_mp1 && $free_on_mp2);
49my $avg_free = ceil(($free_on_mp1+$free_on_mp2)/2);
50my ($more_free, $less_free); 65my ($more_free, $less_free);
51if ($free_on_mp1 > $free_on_mp2) { 66if ($free_percent_on_mp1 > $free_percent_on_mp2) {
52 $more_free = $mountpoint_valid; 67 $more_free = $mountpoint_valid;
53 $less_free = $mountpoint2_valid; 68 $less_free = $mountpoint2_valid;
54} elsif ($free_on_mp1 < $free_on_mp2) { 69} elsif ($free_percent_on_mp1 < $free_percent_on_mp2) {
55 $more_free = $mountpoint2_valid; 70 $more_free = $mountpoint2_valid;
56 $less_free = $mountpoint_valid; 71 $less_free = $mountpoint_valid;
57} else { 72} else {
58 die "Two mountpoints are the same - cannot do rest of test"; 73 die "Two mountpoints are the same - cannot do rest of test";
59} 74}
60if($free_on_mp1 == $avg_free || $free_on_mp2 == $avg_free) { 75
76print("less free: " . $less_free . "\n");
77print("more free: " . $more_free . "\n");
78
79if($free_percent_on_mp1 == $avg_free_percent || $free_percent_on_mp2 == $avg_free_percent) {
61 die "One mountpoints has average space free - cannot do rest of test"; 80 die "One mountpoints has average space free - cannot do rest of test";
62} 81}
63 82
83my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
84my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
85my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100);
64 86
65# Do same for inodes 87my $free_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
66$_ = $result->output; 88my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
67my ($free_inode_on_mp1, $free_inode_on_mp2) = (m/inode=(\d+)%.*inode=(\d+)%/); 89my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100);
68die "Cannot parse free inodes: $_" unless ($free_inode_on_mp1 && $free_inode_on_mp2); 90
69my $avg_inode_free = ceil(($free_inode_on_mp1 + $free_inode_on_mp2)/2); 91my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2);
70my ($more_inode_free, $less_inode_free); 92my ($more_inode_free, $less_inode_free);
71if ($free_inode_on_mp1 > $free_inode_on_mp2) { 93if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) {
72 $more_inode_free = $mountpoint_valid; 94 $more_inode_free = $mountpoint_valid;
73 $less_inode_free = $mountpoint2_valid; 95 $less_inode_free = $mountpoint2_valid;
74} elsif ($free_inode_on_mp1 < $free_inode_on_mp2) { 96} elsif ($free_inode_percentage_on_mp1 < $free_inode_percentage_on_mp2) {
75 $more_inode_free = $mountpoint2_valid; 97 $more_inode_free = $mountpoint2_valid;
76 $less_inode_free = $mountpoint_valid; 98 $less_inode_free = $mountpoint_valid;
77} else { 99} else {
78 die "Two mountpoints with same inodes free - cannot do rest of test"; 100 die "Two mountpoints with same inodes free - cannot do rest of test";
79} 101}
80if($free_inode_on_mp1 == $avg_inode_free || $free_inode_on_mp2 == $avg_inode_free) { 102if($free_inode_percentage_on_mp1 == $avg_inode_free_percentage || $free_inode_percentage_on_mp2 == $avg_inode_free_percentage) {
81 die "One mountpoints has average inodes free - cannot do rest of test"; 103 die "One mountpoints has average inodes free - cannot do rest of test";
82} 104}
83 105
84# Verify performance data 106# Verify performance data
85# First check absolute thresholds... 107# First check absolute thresholds...
86$result = NPTest->testCmd( 108$result = NPTest->testCmd(
87 "./check_disk -w 20 -c 10 -p $mountpoint_valid" 109 "./check_disk -w 20 -c 10 -p $mountpoint_valid $output_format"
88 ); 110 );
89$_ = $result->perf_output; 111
90my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); 112cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
91# default unit is MiB, but perfdata is always bytes 113
92is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds"); 114my $warn_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
93is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds"); 115my $crit_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
116my $total_absth_data= $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
117
118# print("warn: " .$warn_absth_data . "\n");
119# print("crit: " .$crit_absth_data . "\n");
120# print("total: " .$total_absth_data . "\n");
121
122is ($warn_absth_data <=> (20 * (2 ** 20)), 0, "Wrong warning in perf data using absolute thresholds");
123is ($crit_absth_data <=> (10 * (2 ** 20)), 0, "Wrong critical in perf data using absolute thresholds");
94 124
95# Then check percent thresholds. 125# Then check percent thresholds.
96$result = NPTest->testCmd( 126$result = NPTest->testCmd(
97 "./check_disk -w 20% -c 10% -p $mountpoint_valid" 127 "./check_disk -w 20% -c 10% -p $mountpoint_valid $output_format"
98 ); 128 );
99$_ = $result->perf_output; 129
100my ($warn_percth_data, $crit_percth_data, $total_percth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); 130cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
101is ($warn_percth_data, int((1-20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds"); 131
102is ($crit_percth_data, int((1-10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds"); 132my $warn_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
133my $crit_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
134my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
135
136print("warn_percth_data: " . $warn_percth_data . "\n");
137print("crit_percth_data: " . $crit_percth_data . "\n");
138
139is (int($warn_percth_data), int((20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds. Got " . $warn_percth_data . " with total " . $total_percth_data);
140is (int($crit_percth_data), int((10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds. Got " . $crit_percth_data . " with total " . $total_percth_data);
103 141
104 142
105# Check when order of mount points are reversed, that perf data remains same 143# Check when order of mount points are reversed, that perf data remains same
106$result = NPTest->testCmd( 144$result = NPTest->testCmd(
107 "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid" 145 "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid $output_format"
108 ); 146 );
109@_ = sort(split(/ /, $result->perf_output)); 147cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
110is_deeply( \@perf_data, \@_, "perf data for both filesystems same when reversed");
111 148
149# write comparison set for perfdata here, but in reversed order, maybe there is a smarter way
150my @perfdata2;
151@perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
152@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
153# Decrease precision of numbers since the the fs might be modified between the two runs
154$perfdata2[0]->{'value'}->{'value'} = int($perfdata2[0]->{'value'}->{'value'} / 1000000);
155$perfdata2[1]->{'value'}->{'value'} = int($perfdata2[1]->{'value'}->{'value'} / 1000000);
156is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed");
112 157
113# Basic filesystem checks for sizes 158# Basic filesystem checks for sizes
114$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free" ); 159$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free $output_format");
115cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free"); 160cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
116like ( $result->output, $successOutput, "OK output" ); 161like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free");
117like ( $result->only_output, qr/free space/, "Have free space text");
118like ( $result->only_output, qr/$more_free/, "Have disk name in text");
119 162
120$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" ); 163$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free $output_format" );
121cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free"); 164cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
165like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free and $less_free");
122 166
123$_ = $result->output; 167my $free_mb_on_mp1 =$result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / (1024 * 1024);
124 168my $free_mb_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ (1024 * 1024);
125my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g);
126die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2); 169die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2);
127 170
128my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2; 171my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2;
129 172
130 173
174$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free $output_format" );
175cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
131 176
132$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free" ); 177$result = NPTest->testCmd( "./check_disk 101 101 $more_free" );
133is( $result->only_output, "DISK OK", "No print out of disks with -e for OKs"); 178like($result->output, "/OK/", "OK in Output");
134 179cmp_ok( $result->return_code, '==', 0, "Old syntax okay, output was: ". $result->output . "\n" );
135$result = NPTest->testCmd( "./check_disk 100 100 $more_free" );
136cmp_ok( $result->return_code, '==', 0, "Old syntax okay" );
137 180
138$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" ); 181$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" );
139cmp_ok( $result->return_code, "==", 0, "At least 1% free" ); 182cmp_ok( $result->return_code, "==", 0, "At least 1% free" );
140 183
141$result = NPTest->testCmd( 184$result = NPTest->testCmd(
142 "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free" 185 "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free $output_format"
143 ); 186 );
144cmp_ok( $result->return_code, "==", 2, "Get critical on less_free mountpoint $less_free" ); 187cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
145like( $result->output, $failureOutput, "Right output" ); 188like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Get critical on less_free mountpoint $less_free");
146 189
147 190
148$result = NPTest->testCmd( 191$result = NPTest->testCmd(
149 "./check_disk -w $avg_free% -c 0% -p $less_free" 192 "./check_disk -w $avg_free_percent% -c 0% -p $less_free $output_format"
150 ); 193 );
151cmp_ok( $result->return_code, '==', 1, "Get warning on less_free mountpoint, when checking avg_free"); 194cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
195like($result->{'mp_test_result'}->{'state'}, "/WARNING/", "Get warning on less_free mountpoint, when checking avg_free");
152 196
153$result = NPTest->testCmd( 197$result = NPTest->testCmd(
154 "./check_disk -w $avg_free% -c $avg_free% -p $more_free" 198 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
155 ); 199 );
156cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free"); 200cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free");
157 201
158$result = NPTest->testCmd( 202$result = NPTest->testCmd(
159 "./check_disk -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" 203 "./check_disk -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
160 ); 204 );
161cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning"); 205cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning");
162my $all_disks = $result->output; 206my $all_disks = $result->output;
163 207
164$result = NPTest->testCmd( 208$result = NPTest->testCmd(
165 "./check_disk -e -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" 209 "./check_disk -e -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
166 ); 210 );
167isnt( $result->output, $all_disks, "-e gives different output"); 211isnt( $result->output, $all_disks, "-e gives different output");
168 212
169# Need spaces around filesystem name in case less_free and more_free are nested 213# Need spaces around filesystem name in case less_free and more_free are nested
170like( $result->output, qr/ $less_free /, "Found problem $less_free"); 214like( $result->output, qr/ $less_free /, "Found problem $less_free");
171unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem"); 215unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem");
172like( $result->perf_output, qr/ $more_free=/, "But $more_free is still in perf data"); 216like( $result->perf_output, qr/'$more_free'=/, "But $more_free is still in perf data");
173 217
174$result = NPTest->testCmd( 218$result = NPTest->testCmd(
175 "./check_disk -w $avg_free% -c 0% -p $more_free" 219 "./check_disk -w $avg_free_percent% -c 0% -p $more_free"
176 ); 220 );
177cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free"); 221cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free");
178 222
179$result = NPTest->testCmd( 223$result = NPTest->testCmd(
180 "./check_disk -w $avg_free% -c $avg_free% -p $less_free" 224 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
181 ); 225 );
182cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free"); 226cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free");
183$result = NPTest->testCmd( 227$result = NPTest->testCmd(
184 "./check_disk -w $avg_free% -c 0% -p $more_free -w $avg_free% -c $avg_free% -p $less_free" 228 "./check_disk -w $avg_free_percent% -c 0% -p $more_free -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
185 ); 229 );
186cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical"); 230cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical");
187 231
188$result = NPTest->testCmd( 232$result = NPTest->testCmd(
189 "./check_disk -w $avg_free% -c $avg_free% -p $less_free -w $avg_free% -c 0% -p $more_free" 233 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free -w $avg_free_percent% -c 0% -p $more_free"
190 ); 234 );
191cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); 235cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
192 236
@@ -203,32 +247,32 @@ is( $result->return_code, 2, "Critical requesting 100% free inodes for both moun
203$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" ); 247$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" );
204is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free"); 248is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free");
205 249
206$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free" ); 250$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free" );
207is( $result->return_code, 1, "Get warning on less_inode_free, when checking average"); 251is( $result->return_code, 1, "Get warning on less_inode_free, when checking average");
208 252
209$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free "); 253$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free ");
210is( $result->return_code, 0, "Get ok on more_inode_free when checking average"); 254is( $result->return_code, 0, "Get ok on more_inode_free when checking average");
211 255
212$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); 256$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
213is ($result->return_code, 1, "Combine above two tests, get warning"); 257is ($result->return_code, 1, "Combine above two tests, get warning");
214$all_disks = $result->output; 258$all_disks = $result->output;
215 259
216$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); 260$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
217isnt( $result->output, $all_disks, "-e gives different output"); 261isnt( $result->output, $all_disks, "-e gives different output");
218like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free"); 262like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free");
219unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem"); 263unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem");
220like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data"); 264like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data");
221 265
222$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free" ); 266$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
223is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average"); 267is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average");
224 268
225$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); 269$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
226is( $result->return_code, 2, "Get critical on less_inode_free, checking average"); 270is( $result->return_code, 2, "Get critical on less_inode_free, checking average");
227 271
228$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); 272$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
229is( $result->return_code, 2, "Combining above two tests, get critical"); 273is( $result->return_code, 2, "Combining above two tests, get critical");
230 274
231$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free -W $avg_inode_free% -K 0% -p $more_inode_free" ); 275$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
232cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); 276cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
233 277
234 278
@@ -249,9 +293,9 @@ $result = NPTest->testCmd(
249 ); 293 );
250cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" ); 294cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" );
251 295
252$result = NPTest->testCmd( "./check_disk -w 100% -c 100% ".${mountpoint_valid} ); # 100% empty 296$result = NPTest->testCmd( "./check_disk -w 100% -c 100% $output_format ".${mountpoint_valid} ); # 100% empty
253cmp_ok( $result->return_code, "==", 2, "100% empty" ); 297cmp_ok( $result->return_code, "==", 0, "100% empty" );
254like( $result->output, $failureOutput, "Right output" ); 298like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "100% empty");
255 299
256$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" ); 300$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" );
257cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" ); 301cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" );
@@ -263,7 +307,8 @@ cmp_ok( $result->return_code, "==", 2, "100 TB empty" );
263# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds 307# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds
264$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} ); 308$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} );
265cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used"); 309cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used");
266like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments"); 310# like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
311# TODO not sure what the above should test, taking it out
267 312
268$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" ); 313$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" );
269cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" ); 314cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" );
@@ -311,8 +356,9 @@ $result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /" );
311unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice"); 356unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice");
312 357
313# are partitions added if -C is given without path selection -p ? 358# are partitions added if -C is given without path selection -p ?
314$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid" ); 359$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid $output_format" );
315like( $result->output, '/;.*;\|/', "-C selects partitions if -p is not given"); 360cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
361cmp_ok(scalar $result->{'mp_test_result'}->{'checks'}, '>', 1, "-C invokes matchall logic again");
316 362
317# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit 363# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit
318$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" ); 364$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" );
@@ -359,39 +405,37 @@ like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mo
359# ignore-missing: exit okay, when fs is not accessible 405# ignore-missing: exit okay, when fs is not accessible
360$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob"); 406$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob");
361cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob"); 407cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob");
362like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /bob;.*$/', 'Output OK'); 408like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
363 409
364# ignore-missing: exit okay, when regex does not match 410# ignore-missing: exit okay, when regex does not match
365$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob"); 411$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob");
366cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 412cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
367like( $result->output, '/^DISK OK - No disks were found for provided parameters.*$/', 'Output OK'); 413like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
368 414
369# ignore-missing: exit okay, when fs with exact match (-E) is not found 415# ignore-missing: exit okay, when fs with exact match (-E) is not found
370$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc"); 416$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc");
371cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs"); 417cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs");
372like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /etc;.*$/', 'Output OK'); 418like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
373 419
374# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex) 420# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex)
375$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'"); 421$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'");
376cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 422cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
377like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK');
378 423
379# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path) 424# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path)
380$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'"); 425$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'");
381cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 426cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
382like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK'); 427# like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK');
383 428
384# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored 429# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored
385$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2"); 430$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2");
386cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 431cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
387like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); 432like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
388 433
389# ignore-missing: exit okay, when regex match does not find anything 434# ignore-missing: exit okay, when regex match does not find anything
390$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); 435$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
391cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 436cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
392like( $result->output, '/^DISK OK\|$/', 'Output OK');
393 437
394# ignore-missing: exit okay, when regex match does not find anything 438# ignore-missing: exit okay, when regex match does not find anything
395$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); 439$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
396cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 440cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
397like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); 441like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
diff --git a/plugins/tests/test_check_disk.c b/plugins/tests/test_check_disk.c
new file mode 100644
index 00000000..35c57bce
--- /dev/null
+++ b/plugins/tests/test_check_disk.c
@@ -0,0 +1,197 @@
1/*****************************************************************************
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 *
17 *****************************************************************************/
18
19#include "common.h"
20#include "../check_disk.d/utils_disk.h"
21#include "../../tap/tap.h"
22#include "regex.h"
23
24void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc);
25
26int main(int argc, char **argv) {
27 plan_tests(35);
28
29 struct name_list *exclude_filesystem = NULL;
30 ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
31 np_add_name(&exclude_filesystem, "/var/log");
32 ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
33 ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list");
34 np_add_name(&exclude_filesystem, "/home");
35 ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
36 ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
37
38 struct name_list *exclude_fstype = NULL;
39 ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
40 np_add_name(&exclude_fstype, "iso9660");
41 ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
42
43 ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables");
44
45 /*
46 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) {
47 printf("Name: %s\n", temp_name->name);
48 }
49 */
50
51 struct mount_entry *dummy_mount_list;
52 struct mount_entry **mtail = &dummy_mount_list;
53 struct mount_entry *me = (struct mount_entry *)malloc(sizeof *me);
54 me->me_devname = strdup("/dev/c0t0d0s0");
55 me->me_mountdir = strdup("/");
56 *mtail = me;
57 mtail = &me->me_next;
58
59 me = (struct mount_entry *)malloc(sizeof *me);
60 me->me_devname = strdup("/dev/c1t0d1s0");
61 me->me_mountdir = strdup("/var");
62 *mtail = me;
63 mtail = &me->me_next;
64
65 me = (struct mount_entry *)malloc(sizeof *me);
66 me->me_devname = strdup("/dev/c2t0d0s0");
67 me->me_mountdir = strdup("/home");
68 *mtail = me;
69 mtail = &me->me_next;
70
71 int cflags = REG_NOSUB | REG_EXTENDED;
72 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
73 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3, strdup("regex on dev names:"));
74 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0, strdup("regex on non existent dev/path:"));
75 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0, strdup("regi on non existent dev/path:"));
76 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3, strdup("partial devname regex match:"));
77 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1, strdup("partial devname regex match:"));
78 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:"));
79 np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1, strdup("partial pathname regex match:"));
80 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:"));
81 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:"));
82 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:"));
83
84 filesystem_list test_paths = filesystem_list_init();
85 mp_int_fs_list_append(&test_paths, "/home/groups");
86 mp_int_fs_list_append(&test_paths, "/var");
87 mp_int_fs_list_append(&test_paths, "/tmp");
88 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
89 mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0");
90 ok(test_paths.length == 5, "List counter works correctly with appends");
91
92 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false);
93 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
94 struct mount_entry *temp_me;
95 temp_me = p->best_match;
96 if (!strcmp(p->name, "/home/groups")) {
97 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home");
98 } else if (!strcmp(p->name, "/var")) {
99 ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
100 } else if (!strcmp(p->name, "/tmp")) {
101 ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
102 } else if (!strcmp(p->name, "/home/tonvoon")) {
103 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home");
104 } else if (!strcmp(p->name, "/dev/c2t0d0s0")) {
105 ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0");
106 }
107 }
108
109 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
110 mp_int_fs_list_del(&test_paths, p);
111 }
112 ok(test_paths.length == 0, "List delete sets counter properly");
113
114 mp_int_fs_list_append(&test_paths, "/home/groups");
115 mp_int_fs_list_append(&test_paths, "/var");
116 mp_int_fs_list_append(&test_paths, "/tmp");
117 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
118 mp_int_fs_list_append(&test_paths, "/home");
119
120 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true);
121 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
122 if (!strcmp(p->name, "/home/groups")) {
123 ok(!p->best_match, "/home/groups correctly not found");
124 } else if (!strcmp(p->name, "/var")) {
125 ok(p->best_match, "/var found");
126 } else if (!strcmp(p->name, "/tmp")) {
127 ok(!p->best_match, "/tmp correctly not found");
128 } else if (!strcmp(p->name, "/home/tonvoon")) {
129 ok(!p->best_match, "/home/tonvoon not found");
130 } else if (!strcmp(p->name, "/home")) {
131 ok(p->best_match, "/home found");
132 }
133 }
134
135 bool found = false;
136 /* test deleting first element in paths */
137 mp_int_fs_list_del(&test_paths, NULL);
138 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
139 if (!strcmp(p->name, "/home/groups")) {
140 found = true;
141 }
142 }
143 ok(!found, "first element successfully deleted");
144 found = false;
145
146 parameter_list_elem *prev = NULL;
147 parameter_list_elem *p = NULL;
148 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
149 if (!strcmp(path->name, "/tmp")) {
150 mp_int_fs_list_del(&test_paths, path);
151 }
152 p = path;
153 }
154
155 parameter_list_elem *last = NULL;
156 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
157 if (!strcmp(path->name, "/tmp")) {
158 found = true;
159 }
160 if (path->next) {
161 prev = path;
162 } else {
163 last = path;
164 }
165 }
166 ok(!found, "/tmp element successfully deleted");
167
168 int count = 0;
169 mp_int_fs_list_del(&test_paths, p);
170 for (p = test_paths.first; p; p = p->next) {
171 if (!strcmp(p->name, "/home")) {
172 found = true;
173 }
174 last = p;
175 count++;
176 }
177 ok(!found, "last (/home) element successfully deleted");
178 ok(count == 2, "two elements remaining");
179
180 return exit_status();
181}
182
183void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) {
184 regex_t regex;
185 if (regcomp(&regex, regstr, cflags) == 0) {
186 int matches = 0;
187 for (struct mount_entry *me = dummy_mount_list; me; me = me->me_next) {
188 if (np_regex_match_mount_entry(me, &regex)) {
189 matches++;
190 }
191 }
192 ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches);
193
194 } else {
195 ok(false, "regex '%s' not compilable", regstr);
196 }
197}
diff --git a/plugins/tests/test_check_disk.t b/plugins/tests/test_check_disk.t
new file mode 100755
index 00000000..56354650
--- /dev/null
+++ b/plugins/tests/test_check_disk.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_disk") {
4 plan skip_all => "./test_check_disk not compiled - please enable libtap library to test";
5}
6exec "./test_check_disk";
diff --git a/plugins/utils.h b/plugins/utils.h
index 92a6c115..1d3c153c 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -76,7 +76,7 @@ char *strnl(char *);
76char *strpcpy(char *, const char *, const char *); 76char *strpcpy(char *, const char *, const char *);
77char *strpcat(char *, const char *, const char *); 77char *strpcat(char *, const char *, const char *);
78int xvasprintf(char **strp, const char *fmt, va_list ap); 78int xvasprintf(char **strp, const char *fmt, va_list ap);
79int xasprintf(char **strp, const char *fmt, ...); 79int xasprintf(char **strp, const char *fmt, ...)__attribute__ ((format (printf, 2, 3)));
80 80
81void usage(const char *) __attribute__((noreturn)); 81void usage(const char *) __attribute__((noreturn));
82void usage2(const char *, const char *) __attribute__((noreturn)); 82void usage2(const char *, const char *) __attribute__((noreturn));