summaryrefslogtreecommitdiffstats
path: root/plugins/check_procs.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_procs.c')
-rw-r--r--plugins/check_procs.c1178
1 files changed, 593 insertions, 585 deletions
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
index 1d78ccee..ae6e9c23 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,297 @@ 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 "
239 procs, procuid, procvsz, procrss, 201 "prog=%s args=%s\n",
240 procpid, procppid, procpcpu, procstat, 202 procs, procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat,
241 procetime, procprog, procargs); 203 procetime, procprog, procargs);
204 }
242 205
243 /* Ignore self */ 206 /* Ignore self */
244 if ((usepid && mypid == procpid) || 207 int ret = 0;
245 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) || 208 if ((config.usepid && mypid == procpid) ||
246 (ret == -1 && errno == ENOENT)) 209 (((!config.usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) &&
247 ) { 210 statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
248 if (verbose >= 3) 211 (ret == -1 && errno == ENOENT))) {
249 printf("not considering - is myself or gone\n"); 212 if (verbose >= 3) {
213 printf("not considering - is myself or gone\n");
214 }
250 continue; 215 continue;
251 } 216 }
252 /* Ignore parent*/ 217 /* Ignore parent*/
253 else if (myppid == procpid) { 218 if (myppid == procpid) {
254 if (verbose >= 3) 219 if (verbose >= 3) {
255 printf("not considering - is parent\n"); 220 printf("not considering - is parent\n");
221 }
256 continue; 222 continue;
257 } 223 }
258 224
259 /* Ignore our own children */ 225 /* Ignore our own children */
260 if (procppid == mypid) { 226 if (procppid == mypid) {
261 if (verbose >= 3) 227 if (verbose >= 3) {
262 printf("not considering - is our child\n"); 228 printf("not considering - is our child\n");
229 }
263 continue; 230 continue;
264 } 231 }
265 232
266 /* Ignore excluded processes by name */ 233 /* Ignore excluded processes by name */
267 if(options & EXCLUDE_PROGS) { 234 if (config.options & EXCLUDE_PROGS) {
268 int found = 0; 235 bool found = false;
269 int i = 0; 236 for (int i = 0; i < (config.exclude_progs_counter); i++) {
270 237 if (!strcmp(procprog, config.exclude_progs_arr[i])) {
271 for(i=0; i < (exclude_progs_counter); i++) { 238 found = true;
272 if(!strcmp(procprog, exclude_progs_arr[i])) { 239 }
273 found = 1; 240 }
274 } 241 if (!found) {
275 } 242 resultsum |= EXCLUDE_PROGS;
276 if(found == 0) { 243 } else {
277 resultsum |= EXCLUDE_PROGS; 244 if (verbose >= 3) {
278 } else 245 printf("excluding - by ignorelist\n");
279 { 246 }
280 if(verbose >= 3) 247 }
281 printf("excluding - by ignorelist\n");
282 }
283 } 248 }
284 249
285 /* filter kernel threads (children of KTHREAD_PARENT)*/ 250 /* filter kernel threads (children of KTHREAD_PARENT)*/
286 /* TODO adapt for other OSes than GNU/Linux 251 /* TODO adapt for other OSes than GNU/Linux
287 sorry for not doing that, but I've no other OSes to test :-( */ 252 sorry for not doing that, but I've no other OSes to test :-( */
288 if (kthread_filter == 1) { 253 if (config.kthread_filter) {
289 /* get pid KTHREAD_PARENT */ 254 /* get pid KTHREAD_PARENT */
290 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) 255 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT)) {
291 kthread_ppid = procpid; 256 kthread_ppid = procpid;
257 }
292 258
293 if (kthread_ppid == procppid) { 259 if (kthread_ppid == procppid) {
294 if (verbose >= 2) 260 if (verbose >= 2) {
295 printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs); 261 printf("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid,
262 procppid, procprog, procargs);
263 }
296 continue; 264 continue;
297 } 265 }
298 } 266 }
299 267
300 if ((options & STAT) && (strstr (procstat, statopts))) 268 if ((config.options & STAT) && (strstr(procstat, config.statopts))) {
301 resultsum |= STAT; 269 resultsum |= STAT;
302 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 270 }
271 if ((config.options & ARGS) && procargs && (strstr(procargs, config.args) != NULL)) {
303 resultsum |= ARGS; 272 resultsum |= ARGS;
304 if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0)) 273 }
274 if ((config.options & EREG_ARGS) && procargs &&
275 (regexec(&config.re_args, procargs, (size_t)0, NULL, 0) == 0)) {
305 resultsum |= EREG_ARGS; 276 resultsum |= EREG_ARGS;
306 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0)) 277 }
278 if ((config.options & PROG) && procprog && (strcmp(config.prog, procprog) == 0)) {
307 resultsum |= PROG; 279 resultsum |= PROG;
308 if ((options & PPID) && (procppid == ppid)) 280 }
281 if ((config.options & PPID) && (procppid == config.ppid)) {
309 resultsum |= PPID; 282 resultsum |= PPID;
310 if ((options & USER) && (procuid == uid)) 283 }
284 if ((config.options & USER) && (procuid == config.uid)) {
311 resultsum |= USER; 285 resultsum |= USER;
312 if ((options & VSZ) && (procvsz >= vsz)) 286 }
287 if ((config.options & VSZ) && (procvsz >= config.vsz)) {
313 resultsum |= VSZ; 288 resultsum |= VSZ;
314 if ((options & RSS) && (procrss >= rss)) 289 }
290 if ((config.options & RSS) && (procrss >= config.rss)) {
315 resultsum |= RSS; 291 resultsum |= RSS;
316 if ((options & PCPU) && (procpcpu >= pcpu)) 292 }
293 if ((config.options & PCPU) && (procpcpu >= config.pcpu)) {
317 resultsum |= PCPU; 294 resultsum |= PCPU;
295 }
318 296
319 found++; 297 found++;
320 298
321 /* Next line if filters not matched */ 299 /* Next line if filters not matched */
322 if (!(options == resultsum || options == ALL)) 300 if (!(config.options == resultsum || config.options == ALL)) {
323 continue; 301 continue;
302 }
324 303
325 procs++; 304 procs++;
326 if (verbose >= 2) { 305 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", 306 printf("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s "
328 procuid, procvsz, procrss, 307 "prog=%s args=%s\n",
329 procpid, procppid, procpcpu, procstat, 308 procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat, procetime,
330 procetime, procprog, procargs); 309 procprog, procargs);
331 } 310 }
332 311
333 if (metric == METRIC_VSZ) 312 mp_state_enum temporary_result = STATE_OK;
334 i = get_status ((double)procvsz, procs_thresholds); 313 if (config.metric == METRIC_VSZ) {
335 else if (metric == METRIC_RSS) 314 temporary_result = get_status((double)procvsz, config.procs_thresholds);
336 i = get_status ((double)procrss, procs_thresholds); 315 } else if (config.metric == METRIC_RSS) {
316 temporary_result = get_status((double)procrss, config.procs_thresholds);
317 }
337 /* TODO? float thresholds for --metric=CPU */ 318 /* TODO? float thresholds for --metric=CPU */
338 else if (metric == METRIC_CPU) 319 else if (config.metric == METRIC_CPU) {
339 i = get_status (procpcpu, procs_thresholds); 320 temporary_result = get_status(procpcpu, config.procs_thresholds);
340 else if (metric == METRIC_ELAPSED) 321 } else if (config.metric == METRIC_ELAPSED) {
341 i = get_status ((double)procseconds, procs_thresholds); 322 temporary_result = get_status((double)procseconds, config.procs_thresholds);
323 }
342 324
343 if (metric != METRIC_PROCS) { 325 if (config.metric != METRIC_PROCS) {
344 if (i == STATE_WARNING) { 326 if (temporary_result == STATE_WARNING) {
345 warn++; 327 warn++;
346 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 328 xasprintf(&config.fails, "%s%s%s", config.fails,
347 result = max_state (result, i); 329 (strcmp(config.fails, "") ? ", " : ""), procprog);
330 result = max_state(result, temporary_result);
348 } 331 }
349 if (i == STATE_CRITICAL) { 332 if (temporary_result == STATE_CRITICAL) {
350 crit++; 333 crit++;
351 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 334 xasprintf(&config.fails, "%s%s%s", config.fails,
352 result = max_state (result, i); 335 (strcmp(config.fails, "") ? ", " : ""), procprog);
336 result = max_state(result, temporary_result);
353 } 337 }
354 } 338 }
355 } 339 }
@@ -359,339 +343,366 @@ main (int argc, char **argv)
359 } 343 }
360 } 344 }
361 345
362 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */ 346 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
363 printf (_("Unable to read output\n")); 347 printf(_("Unable to read output\n"));
364 return STATE_UNKNOWN; 348 return STATE_UNKNOWN;
365 } 349 }
366 350
367 if ( result == STATE_UNKNOWN ) 351 if (result == STATE_UNKNOWN) {
368 result = STATE_OK; 352 result = STATE_OK;
353 }
369 354
370 /* Needed if procs found, but none match filter */ 355 /* Needed if procs found, but none match filter */
371 if ( metric == METRIC_PROCS ) { 356 if (config.metric == METRIC_PROCS) {
372 result = max_state (result, get_status ((double)procs, procs_thresholds) ); 357 result = max_state(result, get_status((double)procs, config.procs_thresholds));
373 } 358 }
374 359
375 if ( result == STATE_OK ) { 360 if (result == STATE_OK) {
376 printf ("%s %s: ", metric_name, _("OK")); 361 printf("%s %s: ", config.metric_name, _("OK"));
377 } else if (result == STATE_WARNING) { 362 } else if (result == STATE_WARNING) {
378 printf ("%s %s: ", metric_name, _("WARNING")); 363 printf("%s %s: ", config.metric_name, _("WARNING"));
379 if ( metric != METRIC_PROCS ) { 364 if (config.metric != METRIC_PROCS) {
380 printf (_("%d warn out of "), warn); 365 printf(_("%d warn out of "), warn);
381 } 366 }
382 } else if (result == STATE_CRITICAL) { 367 } else if (result == STATE_CRITICAL) {
383 printf ("%s %s: ", metric_name, _("CRITICAL")); 368 printf("%s %s: ", config.metric_name, _("CRITICAL"));
384 if (metric != METRIC_PROCS) { 369 if (config.metric != METRIC_PROCS) {
385 printf (_("%d crit, %d warn out of "), crit, warn); 370 printf(_("%d crit, %d warn out of "), crit, warn);
386 } 371 }
387 } 372 }
388 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 373 printf(ngettext("%d process", "%d processes", (unsigned long)procs), procs);
389 374
390 if (strcmp(fmt,"") != 0) { 375 if (strcmp(config.fmt, "") != 0) {
391 printf (_(" with %s"), fmt); 376 printf(_(" with %s"), config.fmt);
392 } 377 }
393 378
394 if ( verbose >= 1 && strcmp(fails,"") ) 379 if (verbose >= 1 && strcmp(config.fails, "")) {
395 printf (" [%s]", fails); 380 printf(" [%s]", config.fails);
381 }
396 382
397 if (metric == METRIC_PROCS) 383 if (config.metric == METRIC_PROCS) {
398 printf (" | procs=%d;%s;%s;0;", procs, 384 printf(" | procs=%d;%s;%s;0;", procs, config.warning_range ? config.warning_range : "",
399 warning_range ? warning_range : "", 385 config.critical_range ? config.critical_range : "");
400 critical_range ? critical_range : ""); 386 } else {
401 else 387 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); 388 }
403 389
404 printf ("\n"); 390 printf("\n");
405 return result; 391 exit(result);
406} 392}
407 393
408
409
410/* process command-line arguments */ 394/* process command-line arguments */
411int 395check_procs_config_wrapper process_arguments(int argc, char **argv) {
412process_arguments (int argc, char **argv) 396 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
413{ 397 {"critical", required_argument, 0, 'c'},
414 int c = 1; 398 {"metric", required_argument, 0, 'm'},
415 char *user; 399 {"timeout", required_argument, 0, 't'},
416 struct passwd *pw; 400 {"status", required_argument, 0, 's'},
417 int option = 0; 401 {"ppid", required_argument, 0, 'p'},
418 int err; 402 {"user", required_argument, 0, 'u'},
419 int cflags = REG_NOSUB | REG_EXTENDED; 403 {"command", required_argument, 0, 'C'},
420 char errbuf[MAX_INPUT_BUFFER]; 404 {"vsz", required_argument, 0, 'z'},
421 char *temp_string; 405 {"rss", required_argument, 0, 'r'},
422 int i=0; 406 {"pcpu", required_argument, 0, 'P'},
423 static struct option longopts[] = { 407 {"elapsed", required_argument, 0, 'e'},
424 {"warning", required_argument, 0, 'w'}, 408 {"argument-array", required_argument, 0, 'a'},
425 {"critical", required_argument, 0, 'c'}, 409 {"help", no_argument, 0, 'h'},
426 {"metric", required_argument, 0, 'm'}, 410 {"version", no_argument, 0, 'V'},
427 {"timeout", required_argument, 0, 't'}, 411 {"verbose", no_argument, 0, 'v'},
428 {"status", required_argument, 0, 's'}, 412 {"ereg-argument-array", required_argument, 0, CHAR_MAX + 1},
429 {"ppid", required_argument, 0, 'p'}, 413 {"input-file", required_argument, 0, CHAR_MAX + 2},
430 {"user", required_argument, 0, 'u'}, 414 {"no-kthreads", required_argument, 0, 'k'},
431 {"command", required_argument, 0, 'C'}, 415 {"traditional-filter", no_argument, 0, 'T'},
432 {"vsz", required_argument, 0, 'z'}, 416 {"exclude-process", required_argument, 0, 'X'},
433 {"rss", required_argument, 0, 'r'}, 417 {0, 0, 0, 0}};
434 {"pcpu", required_argument, 0, 'P'}, 418
435 {"elapsed", required_argument, 0, 'e'}, 419 for (int index = 1; index < argc; index++) {
436 {"argument-array", required_argument, 0, 'a'}, 420 if (strcmp("-to", argv[index]) == 0) {
437 {"help", no_argument, 0, 'h'}, 421 strcpy(argv[index], "-t");
438 {"version", no_argument, 0, 'V'}, 422 }
439 {"verbose", no_argument, 0, 'v'}, 423 }
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 424
448 for (c = 1; c < argc; c++) 425 check_procs_config_wrapper result = {
449 if (strcmp ("-to", argv[c]) == 0) 426 .errorcode = OK,
450 strcpy (argv[c], "-t"); 427 .config = check_procs_config_init(),
428 };
451 429
452 while (1) { 430 while (true) {
453 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", 431 int option = 0;
454 longopts, &option); 432 int option_index =
433 getopt_long(argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", longopts, &option);
455 434
456 if (c == -1 || c == EOF) 435 if (option_index == -1 || option_index == EOF) {
457 break; 436 break;
437 }
458 438
459 switch (c) { 439 switch (option_index) {
460 case '?': /* help */ 440 case '?': /* help */
461 usage5 (); 441 usage5();
462 case 'h': /* help */ 442 case 'h': /* help */
463 print_help (); 443 print_help();
464 exit (STATE_UNKNOWN); 444 exit(STATE_UNKNOWN);
465 case 'V': /* version */ 445 case 'V': /* version */
466 print_revision (progname, NP_VERSION); 446 print_revision(progname, NP_VERSION);
467 exit (STATE_UNKNOWN); 447 exit(STATE_UNKNOWN);
468 case 't': /* timeout period */ 448 case 't': /* timeout period */
469 if (!is_integer (optarg)) 449 if (!is_integer(optarg)) {
470 usage2 (_("Timeout interval must be a positive integer"), optarg); 450 usage2(_("Timeout interval must be a positive integer"), optarg);
471 else 451 } else {
472 timeout_interval = atoi (optarg); 452 timeout_interval = atoi(optarg);
453 }
473 break; 454 break;
474 case 'c': /* critical threshold */ 455 case 'c': /* critical threshold */
475 critical_range = optarg; 456 result.config.critical_range = optarg;
476 break; 457 break;
477 case 'w': /* warning threshold */ 458 case 'w': /* warning threshold */
478 warning_range = optarg; 459 result.config.warning_range = optarg;
479 break; 460 break;
480 case 'p': /* process id */ 461 case 'p': { /* process id */
481 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { 462 static char tmp[MAX_INPUT_BUFFER];
482 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid); 463 if (sscanf(optarg, "%d%[^0-9]", &result.config.ppid, tmp) == 1) {
483 options |= PPID; 464 xasprintf(&result.config.fmt, "%s%sPPID = %d",
465 (result.config.fmt ? result.config.fmt : ""),
466 (result.config.options ? ", " : ""), result.config.ppid);
467 result.config.options |= PPID;
484 break; 468 break;
485 } 469 }
486 usage4 (_("Parent Process ID must be an integer!")); 470 usage4(_("Parent Process ID must be an integer!"));
487 case 's': /* status */ 471 }
488 if (statopts) 472 case 's': /* status */
473 if (result.config.statopts) {
489 break; 474 break;
490 else 475 } else {
491 statopts = optarg; 476 result.config.statopts = optarg;
492 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 477 }
493 options |= STAT; 478 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"),
479 (result.config.fmt ? result.config.fmt : ""),
480 (result.config.options ? ", " : ""), result.config.statopts);
481 result.config.options |= STAT;
494 break; 482 break;
495 case 'u': /* user or user id */ 483 case 'u': /* user or user id */ {
496 if (is_integer (optarg)) { 484 struct passwd *pw;
497 uid = atoi (optarg); 485 if (is_integer(optarg)) {
498 pw = getpwuid ((uid_t) uid); 486 result.config.uid = atoi(optarg);
487 pw = getpwuid(result.config.uid);
499 /* check to be sure user exists */ 488 /* check to be sure user exists */
500 if (pw == NULL) 489 if (pw == NULL) {
501 usage2 (_("UID was not found"), optarg); 490 usage2(_("UID was not found"), optarg);
502 } 491 }
503 else { 492 } else {
504 pw = getpwnam (optarg); 493 pw = getpwnam(optarg);
505 /* check to be sure user exists */ 494 /* check to be sure user exists */
506 if (pw == NULL) 495 if (pw == NULL) {
507 usage2 (_("User name was not found"), optarg); 496 usage2(_("User name was not found"), optarg);
497 }
508 /* then get uid */ 498 /* then get uid */
509 uid = pw->pw_uid; 499 result.config.uid = pw->pw_uid;
510 } 500 }
511 user = pw->pw_name; 501
512 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""), 502 char *user = pw->pw_name;
513 uid, user); 503 xasprintf(&result.config.fmt, "%s%sUID = %d (%s)",
514 options |= USER; 504 (result.config.fmt ? result.config.fmt : ""),
515 break; 505 (result.config.options ? ", " : ""), result.config.uid, user);
516 case 'C': /* command */ 506 result.config.options |= USER;
507 } break;
508 case 'C': /* command */
517 /* TODO: allow this to be passed in with --metric */ 509 /* TODO: allow this to be passed in with --metric */
518 if (prog) 510 if (result.config.prog) {
519 break; 511 break;
520 else 512 } else {
521 prog = optarg; 513 result.config.prog = optarg;
522 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 514 }
523 prog); 515 xasprintf(&result.config.fmt, _("%s%scommand name '%s'"),
524 options |= PROG; 516 (result.config.fmt ? result.config.fmt : ""),
517 (result.config.options ? ", " : ""), result.config.prog);
518 result.config.options |= PROG;
525 break; 519 break;
526 case 'X': 520 case 'X':
527 if(exclude_progs) 521 if (result.config.exclude_progs) {
528 break; 522 break;
529 else 523 } else {
530 exclude_progs = optarg; 524 result.config.exclude_progs = optarg;
531 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 525 }
532 exclude_progs); 526 xasprintf(&result.config.fmt, _("%s%sexclude progs '%s'"),
533 char *p = strtok(exclude_progs, ","); 527 (result.config.fmt ? result.config.fmt : ""),
534 528 (result.config.options ? ", " : ""), result.config.exclude_progs);
535 while(p){ 529 char *tmp_pointer = strtok(result.config.exclude_progs, ",");
536 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter); 530
537 exclude_progs_arr[exclude_progs_counter-1] = p; 531 while (tmp_pointer) {
538 p = strtok(NULL, ","); 532 result.config.exclude_progs_arr =
533 realloc(result.config.exclude_progs_arr,
534 sizeof(char *) * ++result.config.exclude_progs_counter);
535 result.config.exclude_progs_arr[result.config.exclude_progs_counter - 1] =
536 tmp_pointer;
537 tmp_pointer = strtok(NULL, ",");
539 } 538 }
540 539
541 options |= EXCLUDE_PROGS; 540 result.config.options |= EXCLUDE_PROGS;
542 break; 541 break;
543 case 'a': /* args (full path name with args) */ 542 case 'a': /* args (full path name with args) */
544 /* TODO: allow this to be passed in with --metric */ 543 /* TODO: allow this to be passed in with --metric */
545 if (args) 544 if (result.config.args) {
546 break; 545 break;
547 else 546 } else {
548 args = optarg; 547 result.config.args = optarg;
549 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args); 548 }
550 options |= ARGS; 549 xasprintf(&result.config.fmt, "%s%sargs '%s'",
550 (result.config.fmt ? result.config.fmt : ""),
551 (result.config.options ? ", " : ""), result.config.args);
552 result.config.options |= ARGS;
551 break; 553 break;
552 case CHAR_MAX+1: 554 case CHAR_MAX + 1: {
553 err = regcomp(&re_args, optarg, cflags); 555 int cflags = REG_NOSUB | REG_EXTENDED;
556 int err = regcomp(&result.config.re_args, optarg, cflags);
554 if (err != 0) { 557 if (err != 0) {
555 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER); 558 char errbuf[MAX_INPUT_BUFFER];
556 die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 559 regerror(err, &result.config.re_args, errbuf, MAX_INPUT_BUFFER);
560 die(STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"),
561 _("Could not compile regular expression"), errbuf);
557 } 562 }
558 /* Strip off any | within the regex optarg */ 563 /* Strip off any | within the regex optarg */
559 temp_string = strdup(optarg); 564 char *temp_string = strdup(optarg);
560 while(temp_string[i]!='\0'){ 565 int index = 0;
561 if(temp_string[i]=='|') 566 while (temp_string[index] != '\0') {
562 temp_string[i]=','; 567 if (temp_string[index] == '|') {
563 i++; 568 temp_string[index] = ',';
564 } 569 }
565 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string); 570 index++;
566 options |= EREG_ARGS; 571 }
567 break; 572 xasprintf(&result.config.fmt, "%s%sregex args '%s'",
568 case 'r': /* RSS */ 573 (result.config.fmt ? result.config.fmt : ""),
569 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) { 574 (result.config.options ? ", " : ""), temp_string);
570 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss); 575 result.config.options |= EREG_ARGS;
571 options |= RSS; 576 } break;
577 case 'r': { /* RSS */
578 static char tmp[MAX_INPUT_BUFFER];
579 if (sscanf(optarg, "%d%[^0-9]", &result.config.rss, tmp) == 1) {
580 xasprintf(&result.config.fmt, "%s%sRSS >= %d",
581 (result.config.fmt ? result.config.fmt : ""),
582 (result.config.options ? ", " : ""), result.config.rss);
583 result.config.options |= RSS;
572 break; 584 break;
573 } 585 }
574 usage4 (_("RSS must be an integer!")); 586 usage4(_("RSS must be an integer!"));
575 case 'z': /* VSZ */ 587 }
576 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) { 588 case 'z': { /* VSZ */
577 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz); 589 static char tmp[MAX_INPUT_BUFFER];
578 options |= VSZ; 590 if (sscanf(optarg, "%d%[^0-9]", &result.config.vsz, tmp) == 1) {
591 xasprintf(&result.config.fmt, "%s%sVSZ >= %d",
592 (result.config.fmt ? result.config.fmt : ""),
593 (result.config.options ? ", " : ""), result.config.vsz);
594 result.config.options |= VSZ;
579 break; 595 break;
580 } 596 }
581 usage4 (_("VSZ must be an integer!")); 597 usage4(_("VSZ must be an integer!"));
582 case 'P': /* PCPU */ 598 }
599 case 'P': { /* PCPU */
583 /* TODO: -P 1.5.5 is accepted */ 600 /* TODO: -P 1.5.5 is accepted */
584 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) { 601 static char tmp[MAX_INPUT_BUFFER];
585 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu); 602 if (sscanf(optarg, "%f%[^0-9.]", &result.config.pcpu, tmp) == 1) {
586 options |= PCPU; 603 xasprintf(&result.config.fmt, "%s%sPCPU >= %.2f",
604 (result.config.fmt ? result.config.fmt : ""),
605 (result.config.options ? ", " : ""), result.config.pcpu);
606 result.config.options |= PCPU;
587 break; 607 break;
588 } 608 }
589 usage4 (_("PCPU must be a float!")); 609 usage4(_("PCPU must be a float!"));
610 }
590 case 'm': 611 case 'm':
591 xasprintf (&metric_name, "%s", optarg); 612 xasprintf(&result.config.metric_name, "%s", optarg);
592 if ( strcmp(optarg, "PROCS") == 0) { 613 if (strcmp(optarg, "PROCS") == 0) {
593 metric = METRIC_PROCS; 614 result.config.metric = METRIC_PROCS;
594 break; 615 break;
595 } 616 }
596 else if ( strcmp(optarg, "VSZ") == 0) { 617 if (strcmp(optarg, "VSZ") == 0) {
597 metric = METRIC_VSZ; 618 result.config.metric = METRIC_VSZ;
598 break; 619 break;
599 } 620 }
600 else if ( strcmp(optarg, "RSS") == 0 ) { 621 if (strcmp(optarg, "RSS") == 0) {
601 metric = METRIC_RSS; 622 result.config.metric = METRIC_RSS;
602 break; 623 break;
603 } 624 }
604 else if ( strcmp(optarg, "CPU") == 0 ) { 625 if (strcmp(optarg, "CPU") == 0) {
605 metric = METRIC_CPU; 626 result.config.metric = METRIC_CPU;
606 break; 627 break;
607 } 628 }
608 else if ( strcmp(optarg, "ELAPSED") == 0) { 629 if (strcmp(optarg, "ELAPSED") == 0) {
609 metric = METRIC_ELAPSED; 630 result.config.metric = METRIC_ELAPSED;
610 break; 631 break;
611 } 632 }
612 633
613 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 634 usage4(_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
614 case 'k': /* linux kernel thread filter */ 635 case 'k': /* linux kernel thread filter */
615 kthread_filter = 1; 636 result.config.kthread_filter = true;
616 break; 637 break;
617 case 'v': /* command */ 638 case 'v': /* command */
618 verbose++; 639 verbose++;
619 break; 640 break;
620 case 'T': 641 case 'T':
621 usepid = 1; 642 result.config.usepid = true;
622 break; 643 break;
623 case CHAR_MAX+2: 644 case CHAR_MAX + 2:
624 input_filename = optarg; 645 result.config.input_filename = optarg;
625 break; 646 break;
626 } 647 }
627 } 648 }
628 649
629 c = optind; 650 int index = optind;
630 if ((! warning_range) && argv[c]) 651 if ((!result.config.warning_range) && argv[index]) {
631 warning_range = argv[c++]; 652 result.config.warning_range = argv[index++];
632 if ((! critical_range) && argv[c]) 653 }
633 critical_range = argv[c++]; 654 if ((!result.config.critical_range) && argv[index]) {
634 if (statopts == NULL && argv[c]) { 655 result.config.critical_range = argv[index++];
635 xasprintf (&statopts, "%s", argv[c++]); 656 }
636 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 657 if (result.config.statopts == NULL && argv[index]) {
637 options |= STAT; 658 xasprintf(&result.config.statopts, "%s", argv[index++]);
659 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"),
660 (result.config.fmt ? result.config.fmt : ""), (result.config.options ? ", " : ""),
661 result.config.statopts);
662 result.config.options |= STAT;
638 } 663 }
639 664
640 /* this will abort in case of invalid ranges */ 665 /* this will abort in case of invalid ranges */
641 set_thresholds (&procs_thresholds, warning_range, critical_range); 666 set_thresholds(&result.config.procs_thresholds, result.config.warning_range,
667 result.config.critical_range);
642 668
643 return validate_arguments (); 669 return validate_arguments(result);
644} 670}
645 671
672check_procs_config_wrapper validate_arguments(check_procs_config_wrapper config_wrapper) {
673 if (config_wrapper.config.options == 0) {
674 config_wrapper.config.options = ALL;
675 }
646 676
677 if (config_wrapper.config.statopts == NULL) {
678 config_wrapper.config.statopts = strdup("");
679 }
647 680
648int 681 if (config_wrapper.config.prog == NULL) {
649validate_arguments () 682 config_wrapper.config.prog = strdup("");
650{ 683 }
651 if (options == 0)
652 options = ALL;
653
654 if (statopts==NULL)
655 statopts = strdup("");
656
657 if (prog==NULL)
658 prog = strdup("");
659 684
660 if (args==NULL) 685 if (config_wrapper.config.args == NULL) {
661 args = strdup(""); 686 config_wrapper.config.args = strdup("");
687 }
662 688
663 if (fmt==NULL) 689 if (config_wrapper.config.fmt == NULL) {
664 fmt = strdup(""); 690 config_wrapper.config.fmt = strdup("");
691 }
665 692
666 if (fails==NULL) 693 if (config_wrapper.config.fails == NULL) {
667 fails = strdup(""); 694 config_wrapper.config.fails = strdup("");
695 }
668 696
669 return options; 697 // return options;
698 return config_wrapper;
670} 699}
671 700
672
673/* convert the elapsed time to seconds */ 701/* convert the elapsed time to seconds */
674int 702int convert_to_seconds(char *etime, enum metric metric) {
675convert_to_seconds(char *etime) { 703 int hyphcnt = 0;
676 704 int coloncnt = 0;
677 char *ptr; 705 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 706
696 if (*ptr == '-') { 707 if (*ptr == '-') {
697 hyphcnt++; 708 hyphcnt++;
@@ -703,9 +714,12 @@ convert_to_seconds(char *etime) {
703 } 714 }
704 } 715 }
705 716
717 int days = 0;
718 int hours = 0;
719 int minutes = 0;
720 int seconds = 0;
706 if (hyphcnt > 0) { 721 if (hyphcnt > 0) {
707 sscanf(etime, "%d-%d:%d:%d", 722 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 723 /* linux 2.6.5/2.6.6 reporting some processes with infinite
710 * elapsed times for some reason */ 724 * elapsed times for some reason */
711 if (days == 49710) { 725 if (days == 49710) {
@@ -713,135 +727,129 @@ convert_to_seconds(char *etime) {
713 } 727 }
714 } else { 728 } else {
715 if (coloncnt == 2) { 729 if (coloncnt == 2) {
716 sscanf(etime, "%d:%d:%d", 730 sscanf(etime, "%d:%d:%d", &hours, &minutes, &seconds);
717 &hours, &minutes, &seconds);
718 } else if (coloncnt == 1) { 731 } else if (coloncnt == 1) {
719 sscanf(etime, "%d:%d", 732 sscanf(etime, "%d:%d", &minutes, &seconds);
720 &minutes, &seconds);
721 } 733 }
722 } 734 }
723 735
724 total = (days * 86400) + 736 int total = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
725 (hours * 3600) +
726 (minutes * 60) +
727 seconds;
728 737
729 if (verbose >= 3 && metric == METRIC_ELAPSED) { 738 if (verbose >= 3 && metric == METRIC_ELAPSED) {
730 printf("seconds: %d\n", total); 739 printf("seconds: %d\n", total);
731 } 740 }
732 return total; 741 return total;
733} 742}
734 743
735 744void print_help(void) {
736void 745 print_revision(progname, NP_VERSION);
737print_help (void) 746
738{ 747 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
739 print_revision (progname, NP_VERSION); 748 printf(COPYRIGHT, copyright, email);
740 749
741 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 750 printf("%s\n",
742 printf (COPYRIGHT, copyright, email); 751 _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
743 752 printf("%s\n",
744 printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified")); 753 _("metric is outside the required threshold ranges. The metric defaults to number"));
745 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number")); 754 printf("%s\n",
746 printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check.")); 755 _("of processes. Search filters can be applied to limit the processes to check."));
747 756
748 printf ("\n\n"); 757 printf("\n\n");
749 758
750 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)")); 759 printf("%s\n",
751 printf ("%s\n", _("are excluded from any checks to prevent false positives.")); 760 _("The parent process, check_procs itself and any child process of check_procs (ps)"));
752 761 printf("%s\n", _("are excluded from any checks to prevent false positives."));
753 printf ("\n\n"); 762
754 763 printf("\n\n");
755 print_usage (); 764
756 765 print_usage();
757 printf (UT_HELP_VRSN); 766
758 printf (UT_EXTRA_OPTS); 767 printf(UT_HELP_VRSN);
759 printf (" %s\n", "-w, --warning=RANGE"); 768 printf(UT_EXTRA_OPTS);
760 printf (" %s\n", _("Generate warning state if metric is outside this range")); 769 printf(" %s\n", "-w, --warning=RANGE");
761 printf (" %s\n", "-c, --critical=RANGE"); 770 printf(" %s\n", _("Generate warning state if metric is outside this range"));
762 printf (" %s\n", _("Generate critical state if metric is outside this range")); 771 printf(" %s\n", "-c, --critical=RANGE");
763 printf (" %s\n", "-m, --metric=TYPE"); 772 printf(" %s\n", _("Generate critical state if metric is outside this range"));
764 printf (" %s\n", _("Check thresholds against metric. Valid types:")); 773 printf(" %s\n", "-m, --metric=TYPE");
765 printf (" %s\n", _("PROCS - number of processes (default)")); 774 printf(" %s\n", _("Check thresholds against metric. Valid types:"));
766 printf (" %s\n", _("VSZ - virtual memory size")); 775 printf(" %s\n", _("PROCS - number of processes (default)"));
767 printf (" %s\n", _("RSS - resident set memory size")); 776 printf(" %s\n", _("VSZ - virtual memory size"));
768 printf (" %s\n", _("CPU - percentage CPU")); 777 printf(" %s\n", _("RSS - resident set memory size"));
778 printf(" %s\n", _("CPU - percentage CPU"));
769/* only linux etime is support currently */ 779/* only linux etime is support currently */
770#if defined( __linux__ ) 780#if defined(__linux__)
771 printf (" %s\n", _("ELAPSED - time elapsed in seconds")); 781 printf(" %s\n", _("ELAPSED - time elapsed in seconds"));
772#endif /* defined(__linux__) */ 782#endif /* defined(__linux__) */
773 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
774 784
775 printf (" %s\n", "-v, --verbose"); 785 printf(" %s\n", "-v, --verbose");
776 printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); 786 printf(" %s\n", _("Extra information. Up to 3 verbosity levels"));
777 787
778 printf (" %s\n", "-T, --traditional"); 788 printf(" %s\n", "-T, --traditional");
779 printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe")); 789 printf(" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
780 790
781 printf ("\n"); 791 printf("\n");
782 printf ("%s\n", "Filters:"); 792 printf("%s\n", "Filters:");
783 printf (" %s\n", "-s, --state=STATUSFLAGS"); 793 printf(" %s\n", "-s, --state=STATUSFLAGS");
784 printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or")); 794 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,")); 795 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).")); 796 printf(" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
787 printf (" %s\n", "-p, --ppid=PPID"); 797 printf(" %s\n", "-p, --ppid=PPID");
788 printf (" %s\n", _("Only scan for children of the parent process ID indicated.")); 798 printf(" %s\n", _("Only scan for children of the parent process ID indicated."));
789 printf (" %s\n", "-z, --vsz=VSZ"); 799 printf(" %s\n", "-z, --vsz=VSZ");
790 printf (" %s\n", _("Only scan for processes with VSZ higher than indicated.")); 800 printf(" %s\n", _("Only scan for processes with VSZ higher than indicated."));
791 printf (" %s\n", "-r, --rss=RSS"); 801 printf(" %s\n", "-r, --rss=RSS");
792 printf (" %s\n", _("Only scan for processes with RSS higher than indicated.")); 802 printf(" %s\n", _("Only scan for processes with RSS higher than indicated."));
793 printf (" %s\n", "-P, --pcpu=PCPU"); 803 printf(" %s\n", "-P, --pcpu=PCPU");
794 printf (" %s\n", _("Only scan for processes with PCPU higher than indicated.")); 804 printf(" %s\n", _("Only scan for processes with PCPU higher than indicated."));
795 printf (" %s\n", "-u, --user=USER"); 805 printf(" %s\n", "-u, --user=USER");
796 printf (" %s\n", _("Only scan for processes with user name or ID indicated.")); 806 printf(" %s\n", _("Only scan for processes with user name or ID indicated."));
797 printf (" %s\n", "-a, --argument-array=STRING"); 807 printf(" %s\n", "-a, --argument-array=STRING");
798 printf (" %s\n", _("Only scan for processes with args that contain STRING.")); 808 printf(" %s\n", _("Only scan for processes with args that contain STRING."));
799 printf (" %s\n", "--ereg-argument-array=STRING"); 809 printf(" %s\n", "--ereg-argument-array=STRING");
800 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); 810 printf(" %s\n", _("Only scan for processes with args that contain the regex STRING."));
801 printf (" %s\n", "-C, --command=COMMAND"); 811 printf(" %s\n", "-C, --command=COMMAND");
802 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); 812 printf(" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
803 printf (" %s\n", "-X, --exclude-process"); 813 printf(" %s\n", "-X, --exclude-process");
804 printf (" %s\n", _("Exclude processes which match this comma separated list")); 814 printf(" %s\n", _("Exclude processes which match this comma separated list"));
805 printf (" %s\n", "-k, --no-kthreads"); 815 printf(" %s\n", "-k, --no-kthreads");
806 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); 816 printf(" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
807 817
808 printf(_("\n\ 818 printf(_("\n\
809RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ 819RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
810specified 'max:min', a warning status will be generated if the\n\ 820specified 'max:min', a warning status will be generated if the\n\
811count is inside the specified range\n\n")); 821count is inside the specified range\n\n"));
812 822
813 printf(_("\ 823 printf(_("\
814This plugin checks the number of currently running processes and\n\ 824This plugin checks the number of currently running processes and\n\
815generates WARNING or CRITICAL states if the process count is outside\n\ 825generates WARNING or CRITICAL states if the process count is outside\n\
816the specified threshold ranges. The process count can be filtered by\n\ 826the specified threshold ranges. The process count can be filtered by\n\
817process owner, parent process PID, current state (e.g., 'Z'), or may\n\ 827process owner, parent process PID, current state (e.g., 'Z'), or may\n\
818be the total number of running processes\n\n")); 828be the total number of running processes\n\n"));
819 829
820 printf ("%s\n", _("Examples:")); 830 printf("%s\n", _("Examples:"));
821 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry"); 831 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.")); 832 printf(" %s\n", _("Warning if not two processes with command name portsentry."));
823 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 833 printf(" %s\n\n", _("Critical if < 2 or > 1024 processes"));
824 printf (" %s\n", "check_procs -c 1: -C sshd"); 834 printf(" %s\n", "check_procs -c 1: -C sshd");
825 printf (" %s\n", _("Critical if not at least 1 process with command sshd")); 835 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"); 836 printf(" %s\n", "check_procs -w 1024 -c 1: -C sshd");
827 printf (" %s\n", _("Warning if > 1024 processes with command name sshd.")); 837 printf(" %s\n", _("Warning if > 1024 processes with command name sshd."));
828 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd.")); 838 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"); 839 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")); 840 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")); 841 printf(" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
832 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 842 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")); 843 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"); 844 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%%")); 845 printf(" %s\n", _("Alert if CPU of any processes over 10%% or 20%%"));
836 846
837 printf (UT_SUPPORT); 847 printf(UT_SUPPORT);
838} 848}
839 849
840void 850void print_usage(void) {
841print_usage (void) 851 printf("%s\n", _("Usage:"));
842{ 852 printf("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
843 printf ("%s\n", _("Usage:")); 853 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); 854 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} 855}