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.c1186
1 files changed, 596 insertions, 590 deletions
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
index 1fcbd981..ae6e9c23 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -1,357 +1,339 @@
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-2008 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-2008"; 39const char *copyright = "2000-2024";
40const char *email = "devel@monitoring-plugins.org"; 40const char *email = "devel@monitoring-plugins.org";
41 41
42#include "common.h" 42#include "common.h"
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
54int process_arguments (int, char **); 56typedef struct {
55int validate_arguments (void); 57 int errorcode;
56int convert_to_seconds (char *); 58 check_procs_config config;
57void 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*/);
60char *warning_range = NULL; 62
61char *critical_range = NULL; 63static int convert_to_seconds(char * /*etime*/, enum metric /*metric*/);
62thresholds *procs_thresholds = NULL; 64static void print_help(void);
63 65void print_usage(void);
64int 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 */ 83
82char *metric_name; 84static int verbose = 0;
83enum metric { 85
84 METRIC_PROCS, 86static int stat_exe(const pid_t pid, struct stat *buf) {
85 METRIC_VSZ,
86 METRIC_RSS,
87 METRIC_CPU,
88 METRIC_ELAPSED
89};
90enum metric metric = METRIC_PROCS;
91
92int verbose = 0;
93int uid;
94pid_t ppid;
95int vsz;
96int rss;
97float pcpu;
98char *statopts;
99char *prog;
100char *exclude_progs;
101char **exclude_progs_arr = NULL;
102char exclude_progs_counter = 0;
103char *args;
104char *input_filename = NULL;
105regex_t re_args;
106char *fmt;
107char *fails;
108char tmp[MAX_INPUT_BUFFER];
109int kthread_filter = 0;
110int usepid = 0; /* whether to test for pid or /proc/pid/exe */
111
112FILE *ps_input = NULL;
113
114static int
115stat_exe (const pid_t pid, struct stat *buf) {
116 char *path; 87 char *path;
117 int ret;
118 xasprintf(&path, "/proc/%d/exe", pid); 88 xasprintf(&path, "/proc/%d/exe", pid);
119 ret = stat(path, buf); 89 int ret = stat(path, buf);
120 free(path); 90 free(path);
121 return ret; 91 return ret;
122} 92}
123 93
124 94int main(int argc, char **argv) {
125int 95 setlocale(LC_ALL, "");
126main (int argc, char **argv)
127{
128 char *input_buffer;
129 char *input_line;
130 char *procprog;
131
132 pid_t mypid = 0;
133 pid_t myppid = 0;
134 struct stat statbuf;
135 dev_t mydev = 0;
136 ino_t myino = 0;
137 int procuid = 0;
138 pid_t procpid = 0;
139 pid_t procppid = 0;
140 pid_t kthread_ppid = 0;
141 int procvsz = 0;
142 int procrss = 0;
143 int procseconds = 0;
144 float procpcpu = 0;
145 char procstat[8];
146 char procetime[MAX_INPUT_BUFFER] = { '\0' };
147 char *procargs;
148
149 const char *zombie = "Z";
150
151 int resultsum = 0; /* bitmask of the filter criteria met by a process */
152 int found = 0; /* counter for number of lines returned in `ps` output */
153 int procs = 0; /* counter for number of processes meeting filter criteria */
154 int pos; /* number of spaces before 'args' in `ps` output */
155 int cols; /* number of columns in ps output */
156 int expected_cols = PS_COLS - 1;
157 int warn = 0; /* number of processes in warn state */
158 int crit = 0; /* number of processes in crit state */
159 int i = 0;
160 int result = STATE_UNKNOWN;
161 int ret = 0;
162 output chld_out, chld_err;
163
164 setlocale (LC_ALL, "");
165 bindtextdomain (PACKAGE, LOCALEDIR);
166 textdomain (PACKAGE);
167 setlocale(LC_NUMERIC, "POSIX"); 96 setlocale(LC_NUMERIC, "POSIX");
168 97 bindtextdomain(PACKAGE, LOCALEDIR);
169 input_buffer = malloc (MAX_INPUT_BUFFER); 98 textdomain(PACKAGE);
170 procprog = malloc (MAX_INPUT_BUFFER);
171
172 xasprintf (&metric_name, "PROCS");
173 metric = METRIC_PROCS;
174 99
175 /* Parse extra opts if any */ 100 /* Parse extra opts if any */
176 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 }
177 107
178 if (process_arguments (argc, argv) == ERROR) 108 check_procs_config config = tmp_config.config;
179 usage4 (_("Could not parse arguments"));
180 109
181 /* find ourself */ 110 /* find ourself */
182 mypid = getpid(); 111 pid_t mypid = getpid();
183 myppid = getppid(); 112 pid_t myppid = getppid();
184 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) {
185 /* usepid might have been set by -T */ 117 /* usepid might have been set by -T */
186 usepid = 1; 118 config.usepid = true;
187 } else { 119 } else {
188 usepid = 0; 120 config.usepid = false;
189 mydev = statbuf.st_dev; 121 mydev = statbuf.st_dev;
190 myino = statbuf.st_ino; 122 myino = statbuf.st_ino;
191 } 123 }
192 124
193 /* Set signal handling and alarm timeout */ 125 /* Set signal handling and alarm timeout */
194 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 126 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
195 die (STATE_UNKNOWN, _("Cannot catch SIGALRM")); 127 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
196 } 128 }
197 (void) alarm ((unsigned) timeout_interval); 129 (void)alarm(timeout_interval);
198 130
199 if (verbose >= 2) 131 if (verbose >= 2) {
200 printf (_("CMD: %s\n"), PS_COMMAND); 132 printf(_("CMD: %s\n"), PS_COMMAND);
133 }
201 134
202 if (input_filename == NULL) { 135 output chld_out;
203 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);
204 if (chld_err.lines > 0) { 140 if (chld_err.lines > 0) {
205 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]);
206 exit(STATE_WARNING); 142 exit(STATE_WARNING);
207 } 143 }
208 } else { 144 } else {
209 result = cmd_file_read( input_filename, &chld_out, 0); 145 result = cmd_file_read(config.input_filename, &chld_out, 0);
210 } 146 }
211 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
212 /* flush first line: j starts at 1 */ 168 /* flush first line: j starts at 1 */
213 for (size_t j = 1; j < chld_out.lines; j++) { 169 for (size_t j = 1; j < chld_out.lines; j++) {
214 input_line = chld_out.line[j]; 170 char *input_line = chld_out.line[j];
215 171
216 if (verbose >= 3) 172 if (verbose >= 3) {
217 printf ("%s", input_line); 173 printf("%s", input_line);
174 }
218 175
219 strcpy (procprog, ""); 176 strcpy(procprog, "");
220 xasprintf (&procargs, "%s", ""); 177 char *procargs;
178 xasprintf(&procargs, "%s", "");
221 179
222 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);
223 182
224 /* Zombie processes do not give a procprog command */ 183 /* Zombie processes do not give a procprog command */
225 if ( cols < expected_cols && strstr(procstat, zombie) ) { 184 const char *zombie = "Z";
185 if (cols < expected_cols && strstr(procstat, zombie)) {
226 cols = expected_cols; 186 cols = expected_cols;
227 } 187 }
228 if ( cols >= expected_cols ) { 188 if (cols >= expected_cols) {
229 resultsum = 0; 189 resultsum = 0;
230 xasprintf (&procargs, "%s", input_line + pos); 190 xasprintf(&procargs, "%s", input_line + pos);
231 strip (procargs); 191 strip(procargs);
232 192
233 /* Some ps return full pathname for command. This removes path */ 193 /* Some ps return full pathname for command. This removes path */
234 strcpy(procprog, base_name(procprog)); 194 strcpy(procprog, base_name(procprog));
235 195
236 /* we need to convert the elapsed time to seconds */ 196 /* we need to convert the elapsed time to seconds */
237 procseconds = convert_to_seconds(procetime); 197 procseconds = convert_to_seconds(procetime, config.metric);
238 198
239 if (verbose >= 3) 199 if (verbose >= 3) {
240 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 "
241 procs, procuid, procvsz, procrss, 201 "prog=%s args=%s\n",
242 procpid, procppid, procpcpu, procstat, 202 procs, procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat,
243 procetime, procprog, procargs); 203 procetime, procprog, procargs);
204 }
244 205
245 /* Ignore self */ 206 /* Ignore self */
246 if ((usepid && mypid == procpid) || 207 int ret = 0;
247 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) || 208 if ((config.usepid && mypid == procpid) ||
248 (ret == -1 && errno == ENOENT)) 209 (((!config.usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) &&
249 ) { 210 statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
250 if (verbose >= 3) 211 (ret == -1 && errno == ENOENT))) {
251 printf("not considering - is myself or gone\n"); 212 if (verbose >= 3) {
213 printf("not considering - is myself or gone\n");
214 }
252 continue; 215 continue;
253 } 216 }
254 /* Ignore parent*/ 217 /* Ignore parent*/
255 else if (myppid == procpid) { 218 if (myppid == procpid) {
256 if (verbose >= 3) 219 if (verbose >= 3) {
257 printf("not considering - is parent\n"); 220 printf("not considering - is parent\n");
221 }
258 continue; 222 continue;
259 } 223 }
260 224
261 /* Ignore our own children */ 225 /* Ignore our own children */
262 if (procppid == mypid) { 226 if (procppid == mypid) {
263 if (verbose >= 3) 227 if (verbose >= 3) {
264 printf("not considering - is our child\n"); 228 printf("not considering - is our child\n");
229 }
265 continue; 230 continue;
266 } 231 }
267 232
268 /* Ignore excluded processes by name */ 233 /* Ignore excluded processes by name */
269 if(options & EXCLUDE_PROGS) { 234 if (config.options & EXCLUDE_PROGS) {
270 int found = 0; 235 bool found = false;
271 int i = 0; 236 for (int i = 0; i < (config.exclude_progs_counter); i++) {
272 237 if (!strcmp(procprog, config.exclude_progs_arr[i])) {
273 for(i=0; i < (exclude_progs_counter); i++) { 238 found = true;
274 if(!strcmp(procprog, exclude_progs_arr[i])) { 239 }
275 found = 1; 240 }
276 } 241 if (!found) {
277 } 242 resultsum |= EXCLUDE_PROGS;
278 if(found == 0) { 243 } else {
279 resultsum |= EXCLUDE_PROGS; 244 if (verbose >= 3) {
280 } else 245 printf("excluding - by ignorelist\n");
281 { 246 }
282 if(verbose >= 3) 247 }
283 printf("excluding - by ignorelist\n");
284 }
285 } 248 }
286 249
287 /* filter kernel threads (children of KTHREAD_PARENT)*/ 250 /* filter kernel threads (children of KTHREAD_PARENT)*/
288 /* TODO adapt for other OSes than GNU/Linux 251 /* TODO adapt for other OSes than GNU/Linux
289 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 :-( */
290 if (kthread_filter == 1) { 253 if (config.kthread_filter) {
291 /* get pid KTHREAD_PARENT */ 254 /* get pid KTHREAD_PARENT */
292 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) 255 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT)) {
293 kthread_ppid = procpid; 256 kthread_ppid = procpid;
257 }
294 258
295 if (kthread_ppid == procppid) { 259 if (kthread_ppid == procppid) {
296 if (verbose >= 2) 260 if (verbose >= 2) {
297 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 }
298 continue; 264 continue;
299 } 265 }
300 } 266 }
301 267
302 if ((options & STAT) && (strstr (procstat, statopts))) 268 if ((config.options & STAT) && (strstr(procstat, config.statopts))) {
303 resultsum |= STAT; 269 resultsum |= STAT;
304 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 270 }
271 if ((config.options & ARGS) && procargs && (strstr(procargs, config.args) != NULL)) {
305 resultsum |= ARGS; 272 resultsum |= ARGS;
306 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)) {
307 resultsum |= EREG_ARGS; 276 resultsum |= EREG_ARGS;
308 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0)) 277 }
278 if ((config.options & PROG) && procprog && (strcmp(config.prog, procprog) == 0)) {
309 resultsum |= PROG; 279 resultsum |= PROG;
310 if ((options & PPID) && (procppid == ppid)) 280 }
281 if ((config.options & PPID) && (procppid == config.ppid)) {
311 resultsum |= PPID; 282 resultsum |= PPID;
312 if ((options & USER) && (procuid == uid)) 283 }
284 if ((config.options & USER) && (procuid == config.uid)) {
313 resultsum |= USER; 285 resultsum |= USER;
314 if ((options & VSZ) && (procvsz >= vsz)) 286 }
287 if ((config.options & VSZ) && (procvsz >= config.vsz)) {
315 resultsum |= VSZ; 288 resultsum |= VSZ;
316 if ((options & RSS) && (procrss >= rss)) 289 }
290 if ((config.options & RSS) && (procrss >= config.rss)) {
317 resultsum |= RSS; 291 resultsum |= RSS;
318 if ((options & PCPU) && (procpcpu >= pcpu)) 292 }
293 if ((config.options & PCPU) && (procpcpu >= config.pcpu)) {
319 resultsum |= PCPU; 294 resultsum |= PCPU;
295 }
320 296
321 found++; 297 found++;
322 298
323 /* Next line if filters not matched */ 299 /* Next line if filters not matched */
324 if (!(options == resultsum || options == ALL)) 300 if (!(config.options == resultsum || config.options == ALL)) {
325 continue; 301 continue;
302 }
326 303
327 procs++; 304 procs++;
328 if (verbose >= 2) { 305 if (verbose >= 2) {
329 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 "
330 procuid, procvsz, procrss, 307 "prog=%s args=%s\n",
331 procpid, procppid, procpcpu, procstat, 308 procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat, procetime,
332 procetime, procprog, procargs); 309 procprog, procargs);
333 } 310 }
334 311
335 if (metric == METRIC_VSZ) 312 mp_state_enum temporary_result = STATE_OK;
336 i = get_status ((double)procvsz, procs_thresholds); 313 if (config.metric == METRIC_VSZ) {
337 else if (metric == METRIC_RSS) 314 temporary_result = get_status((double)procvsz, config.procs_thresholds);
338 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 }
339 /* TODO? float thresholds for --metric=CPU */ 318 /* TODO? float thresholds for --metric=CPU */
340 else if (metric == METRIC_CPU) 319 else if (config.metric == METRIC_CPU) {
341 i = get_status (procpcpu, procs_thresholds); 320 temporary_result = get_status(procpcpu, config.procs_thresholds);
342 else if (metric == METRIC_ELAPSED) 321 } else if (config.metric == METRIC_ELAPSED) {
343 i = get_status ((double)procseconds, procs_thresholds); 322 temporary_result = get_status((double)procseconds, config.procs_thresholds);
323 }
344 324
345 if (metric != METRIC_PROCS) { 325 if (config.metric != METRIC_PROCS) {
346 if (i == STATE_WARNING) { 326 if (temporary_result == STATE_WARNING) {
347 warn++; 327 warn++;
348 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 328 xasprintf(&config.fails, "%s%s%s", config.fails,
349 result = max_state (result, i); 329 (strcmp(config.fails, "") ? ", " : ""), procprog);
330 result = max_state(result, temporary_result);
350 } 331 }
351 if (i == STATE_CRITICAL) { 332 if (temporary_result == STATE_CRITICAL) {
352 crit++; 333 crit++;
353 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 334 xasprintf(&config.fails, "%s%s%s", config.fails,
354 result = max_state (result, i); 335 (strcmp(config.fails, "") ? ", " : ""), procprog);
336 result = max_state(result, temporary_result);
355 } 337 }
356 } 338 }
357 } 339 }
@@ -361,339 +343,366 @@ main (int argc, char **argv)
361 } 343 }
362 } 344 }
363 345
364 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */ 346 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
365 printf (_("Unable to read output\n")); 347 printf(_("Unable to read output\n"));
366 return STATE_UNKNOWN; 348 return STATE_UNKNOWN;
367 } 349 }
368 350
369 if ( result == STATE_UNKNOWN ) 351 if (result == STATE_UNKNOWN) {
370 result = STATE_OK; 352 result = STATE_OK;
353 }
371 354
372 /* Needed if procs found, but none match filter */ 355 /* Needed if procs found, but none match filter */
373 if ( metric == METRIC_PROCS ) { 356 if (config.metric == METRIC_PROCS) {
374 result = max_state (result, get_status ((double)procs, procs_thresholds) ); 357 result = max_state(result, get_status((double)procs, config.procs_thresholds));
375 } 358 }
376 359
377 if ( result == STATE_OK ) { 360 if (result == STATE_OK) {
378 printf ("%s %s: ", metric_name, _("OK")); 361 printf("%s %s: ", config.metric_name, _("OK"));
379 } else if (result == STATE_WARNING) { 362 } else if (result == STATE_WARNING) {
380 printf ("%s %s: ", metric_name, _("WARNING")); 363 printf("%s %s: ", config.metric_name, _("WARNING"));
381 if ( metric != METRIC_PROCS ) { 364 if (config.metric != METRIC_PROCS) {
382 printf (_("%d warn out of "), warn); 365 printf(_("%d warn out of "), warn);
383 } 366 }
384 } else if (result == STATE_CRITICAL) { 367 } else if (result == STATE_CRITICAL) {
385 printf ("%s %s: ", metric_name, _("CRITICAL")); 368 printf("%s %s: ", config.metric_name, _("CRITICAL"));
386 if (metric != METRIC_PROCS) { 369 if (config.metric != METRIC_PROCS) {
387 printf (_("%d crit, %d warn out of "), crit, warn); 370 printf(_("%d crit, %d warn out of "), crit, warn);
388 } 371 }
389 } 372 }
390 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 373 printf(ngettext("%d process", "%d processes", (unsigned long)procs), procs);
391 374
392 if (strcmp(fmt,"") != 0) { 375 if (strcmp(config.fmt, "") != 0) {
393 printf (_(" with %s"), fmt); 376 printf(_(" with %s"), config.fmt);
394 } 377 }
395 378
396 if ( verbose >= 1 && strcmp(fails,"") ) 379 if (verbose >= 1 && strcmp(config.fails, "")) {
397 printf (" [%s]", fails); 380 printf(" [%s]", config.fails);
381 }
398 382
399 if (metric == METRIC_PROCS) 383 if (config.metric == METRIC_PROCS) {
400 printf (" | procs=%d;%s;%s;0;", procs, 384 printf(" | procs=%d;%s;%s;0;", procs, config.warning_range ? config.warning_range : "",
401 warning_range ? warning_range : "", 385 config.critical_range ? config.critical_range : "");
402 critical_range ? critical_range : ""); 386 } else {
403 else 387 printf(" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
404 printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit); 388 }
405 389
406 printf ("\n"); 390 printf("\n");
407 return result; 391 exit(result);
408} 392}
409 393
410
411
412/* process command-line arguments */ 394/* process command-line arguments */
413int 395check_procs_config_wrapper process_arguments(int argc, char **argv) {
414process_arguments (int argc, char **argv) 396 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
415{ 397 {"critical", required_argument, 0, 'c'},
416 int c = 1; 398 {"metric", required_argument, 0, 'm'},
417 char *user; 399 {"timeout", required_argument, 0, 't'},
418 struct passwd *pw; 400 {"status", required_argument, 0, 's'},
419 int option = 0; 401 {"ppid", required_argument, 0, 'p'},
420 int err; 402 {"user", required_argument, 0, 'u'},
421 int cflags = REG_NOSUB | REG_EXTENDED; 403 {"command", required_argument, 0, 'C'},
422 char errbuf[MAX_INPUT_BUFFER]; 404 {"vsz", required_argument, 0, 'z'},
423 char *temp_string; 405 {"rss", required_argument, 0, 'r'},
424 int i=0; 406 {"pcpu", required_argument, 0, 'P'},
425 static struct option longopts[] = { 407 {"elapsed", required_argument, 0, 'e'},
426 {"warning", required_argument, 0, 'w'}, 408 {"argument-array", required_argument, 0, 'a'},
427 {"critical", required_argument, 0, 'c'}, 409 {"help", no_argument, 0, 'h'},
428 {"metric", required_argument, 0, 'm'}, 410 {"version", no_argument, 0, 'V'},
429 {"timeout", required_argument, 0, 't'}, 411 {"verbose", no_argument, 0, 'v'},
430 {"status", required_argument, 0, 's'}, 412 {"ereg-argument-array", required_argument, 0, CHAR_MAX + 1},
431 {"ppid", required_argument, 0, 'p'}, 413 {"input-file", required_argument, 0, CHAR_MAX + 2},
432 {"user", required_argument, 0, 'u'}, 414 {"no-kthreads", required_argument, 0, 'k'},
433 {"command", required_argument, 0, 'C'}, 415 {"traditional-filter", no_argument, 0, 'T'},
434 {"vsz", required_argument, 0, 'z'}, 416 {"exclude-process", required_argument, 0, 'X'},
435 {"rss", required_argument, 0, 'r'}, 417 {0, 0, 0, 0}};
436 {"pcpu", required_argument, 0, 'P'}, 418
437 {"elapsed", required_argument, 0, 'e'}, 419 for (int index = 1; index < argc; index++) {
438 {"argument-array", required_argument, 0, 'a'}, 420 if (strcmp("-to", argv[index]) == 0) {
439 {"help", no_argument, 0, 'h'}, 421 strcpy(argv[index], "-t");
440 {"version", no_argument, 0, 'V'}, 422 }
441 {"verbose", no_argument, 0, 'v'}, 423 }
442 {"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
443 {"input-file", required_argument, 0, CHAR_MAX+2},
444 {"no-kthreads", required_argument, 0, 'k'},
445 {"traditional-filter", no_argument, 0, 'T'},
446 {"exclude-process", required_argument, 0, 'X'},
447 {0, 0, 0, 0}
448 };
449 424
450 for (c = 1; c < argc; c++) 425 check_procs_config_wrapper result = {
451 if (strcmp ("-to", argv[c]) == 0) 426 .errorcode = OK,
452 strcpy (argv[c], "-t"); 427 .config = check_procs_config_init(),
428 };
453 429
454 while (1) { 430 while (true) {
455 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", 431 int option = 0;
456 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);
457 434
458 if (c == -1 || c == EOF) 435 if (option_index == -1 || option_index == EOF) {
459 break; 436 break;
437 }
460 438
461 switch (c) { 439 switch (option_index) {
462 case '?': /* help */ 440 case '?': /* help */
463 usage5 (); 441 usage5();
464 case 'h': /* help */ 442 case 'h': /* help */
465 print_help (); 443 print_help();
466 exit (STATE_UNKNOWN); 444 exit(STATE_UNKNOWN);
467 case 'V': /* version */ 445 case 'V': /* version */
468 print_revision (progname, NP_VERSION); 446 print_revision(progname, NP_VERSION);
469 exit (STATE_UNKNOWN); 447 exit(STATE_UNKNOWN);
470 case 't': /* timeout period */ 448 case 't': /* timeout period */
471 if (!is_integer (optarg)) 449 if (!is_integer(optarg)) {
472 usage2 (_("Timeout interval must be a positive integer"), optarg); 450 usage2(_("Timeout interval must be a positive integer"), optarg);
473 else 451 } else {
474 timeout_interval = atoi (optarg); 452 timeout_interval = atoi(optarg);
453 }
475 break; 454 break;
476 case 'c': /* critical threshold */ 455 case 'c': /* critical threshold */
477 critical_range = optarg; 456 result.config.critical_range = optarg;
478 break; 457 break;
479 case 'w': /* warning threshold */ 458 case 'w': /* warning threshold */
480 warning_range = optarg; 459 result.config.warning_range = optarg;
481 break; 460 break;
482 case 'p': /* process id */ 461 case 'p': { /* process id */
483 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { 462 static char tmp[MAX_INPUT_BUFFER];
484 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid); 463 if (sscanf(optarg, "%d%[^0-9]", &result.config.ppid, tmp) == 1) {
485 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;
486 break; 468 break;
487 } 469 }
488 usage4 (_("Parent Process ID must be an integer!")); 470 usage4(_("Parent Process ID must be an integer!"));
489 case 's': /* status */ 471 }
490 if (statopts) 472 case 's': /* status */
473 if (result.config.statopts) {
491 break; 474 break;
492 else 475 } else {
493 statopts = optarg; 476 result.config.statopts = optarg;
494 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 477 }
495 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;
496 break; 482 break;
497 case 'u': /* user or user id */ 483 case 'u': /* user or user id */ {
498 if (is_integer (optarg)) { 484 struct passwd *pw;
499 uid = atoi (optarg); 485 if (is_integer(optarg)) {
500 pw = getpwuid ((uid_t) uid); 486 result.config.uid = atoi(optarg);
487 pw = getpwuid(result.config.uid);
501 /* check to be sure user exists */ 488 /* check to be sure user exists */
502 if (pw == NULL) 489 if (pw == NULL) {
503 usage2 (_("UID was not found"), optarg); 490 usage2(_("UID was not found"), optarg);
504 } 491 }
505 else { 492 } else {
506 pw = getpwnam (optarg); 493 pw = getpwnam(optarg);
507 /* check to be sure user exists */ 494 /* check to be sure user exists */
508 if (pw == NULL) 495 if (pw == NULL) {
509 usage2 (_("User name was not found"), optarg); 496 usage2(_("User name was not found"), optarg);
497 }
510 /* then get uid */ 498 /* then get uid */
511 uid = pw->pw_uid; 499 result.config.uid = pw->pw_uid;
512 } 500 }
513 user = pw->pw_name; 501
514 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""), 502 char *user = pw->pw_name;
515 uid, user); 503 xasprintf(&result.config.fmt, "%s%sUID = %d (%s)",
516 options |= USER; 504 (result.config.fmt ? result.config.fmt : ""),
517 break; 505 (result.config.options ? ", " : ""), result.config.uid, user);
518 case 'C': /* command */ 506 result.config.options |= USER;
507 } break;
508 case 'C': /* command */
519 /* TODO: allow this to be passed in with --metric */ 509 /* TODO: allow this to be passed in with --metric */
520 if (prog) 510 if (result.config.prog) {
521 break; 511 break;
522 else 512 } else {
523 prog = optarg; 513 result.config.prog = optarg;
524 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 514 }
525 prog); 515 xasprintf(&result.config.fmt, _("%s%scommand name '%s'"),
526 options |= PROG; 516 (result.config.fmt ? result.config.fmt : ""),
517 (result.config.options ? ", " : ""), result.config.prog);
518 result.config.options |= PROG;
527 break; 519 break;
528 case 'X': 520 case 'X':
529 if(exclude_progs) 521 if (result.config.exclude_progs) {
530 break; 522 break;
531 else 523 } else {
532 exclude_progs = optarg; 524 result.config.exclude_progs = optarg;
533 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 525 }
534 exclude_progs); 526 xasprintf(&result.config.fmt, _("%s%sexclude progs '%s'"),
535 char *p = strtok(exclude_progs, ","); 527 (result.config.fmt ? result.config.fmt : ""),
536 528 (result.config.options ? ", " : ""), result.config.exclude_progs);
537 while(p){ 529 char *tmp_pointer = strtok(result.config.exclude_progs, ",");
538 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter); 530
539 exclude_progs_arr[exclude_progs_counter-1] = p; 531 while (tmp_pointer) {
540 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, ",");
541 } 538 }
542 539
543 options |= EXCLUDE_PROGS; 540 result.config.options |= EXCLUDE_PROGS;
544 break; 541 break;
545 case 'a': /* args (full path name with args) */ 542 case 'a': /* args (full path name with args) */
546 /* TODO: allow this to be passed in with --metric */ 543 /* TODO: allow this to be passed in with --metric */
547 if (args) 544 if (result.config.args) {
548 break; 545 break;
549 else 546 } else {
550 args = optarg; 547 result.config.args = optarg;
551 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args); 548 }
552 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;
553 break; 553 break;
554 case CHAR_MAX+1: 554 case CHAR_MAX + 1: {
555 err = regcomp(&re_args, optarg, cflags); 555 int cflags = REG_NOSUB | REG_EXTENDED;
556 int err = regcomp(&result.config.re_args, optarg, cflags);
556 if (err != 0) { 557 if (err != 0) {
557 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER); 558 char errbuf[MAX_INPUT_BUFFER];
558 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);
559 } 562 }
560 /* Strip off any | within the regex optarg */ 563 /* Strip off any | within the regex optarg */
561 temp_string = strdup(optarg); 564 char *temp_string = strdup(optarg);
562 while(temp_string[i]!='\0'){ 565 int index = 0;
563 if(temp_string[i]=='|') 566 while (temp_string[index] != '\0') {
564 temp_string[i]=','; 567 if (temp_string[index] == '|') {
565 i++; 568 temp_string[index] = ',';
566 } 569 }
567 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string); 570 index++;
568 options |= EREG_ARGS; 571 }
569 break; 572 xasprintf(&result.config.fmt, "%s%sregex args '%s'",
570 case 'r': /* RSS */ 573 (result.config.fmt ? result.config.fmt : ""),
571 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) { 574 (result.config.options ? ", " : ""), temp_string);
572 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss); 575 result.config.options |= EREG_ARGS;
573 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;
574 break; 584 break;
575 } 585 }
576 usage4 (_("RSS must be an integer!")); 586 usage4(_("RSS must be an integer!"));
577 case 'z': /* VSZ */ 587 }
578 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) { 588 case 'z': { /* VSZ */
579 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz); 589 static char tmp[MAX_INPUT_BUFFER];
580 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;
581 break; 595 break;
582 } 596 }
583 usage4 (_("VSZ must be an integer!")); 597 usage4(_("VSZ must be an integer!"));
584 case 'P': /* PCPU */ 598 }
599 case 'P': { /* PCPU */
585 /* TODO: -P 1.5.5 is accepted */ 600 /* TODO: -P 1.5.5 is accepted */
586 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) { 601 static char tmp[MAX_INPUT_BUFFER];
587 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu); 602 if (sscanf(optarg, "%f%[^0-9.]", &result.config.pcpu, tmp) == 1) {
588 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;
589 break; 607 break;
590 } 608 }
591 usage4 (_("PCPU must be a float!")); 609 usage4(_("PCPU must be a float!"));
610 }
592 case 'm': 611 case 'm':
593 xasprintf (&metric_name, "%s", optarg); 612 xasprintf(&result.config.metric_name, "%s", optarg);
594 if ( strcmp(optarg, "PROCS") == 0) { 613 if (strcmp(optarg, "PROCS") == 0) {
595 metric = METRIC_PROCS; 614 result.config.metric = METRIC_PROCS;
596 break; 615 break;
597 } 616 }
598 else if ( strcmp(optarg, "VSZ") == 0) { 617 if (strcmp(optarg, "VSZ") == 0) {
599 metric = METRIC_VSZ; 618 result.config.metric = METRIC_VSZ;
600 break; 619 break;
601 } 620 }
602 else if ( strcmp(optarg, "RSS") == 0 ) { 621 if (strcmp(optarg, "RSS") == 0) {
603 metric = METRIC_RSS; 622 result.config.metric = METRIC_RSS;
604 break; 623 break;
605 } 624 }
606 else if ( strcmp(optarg, "CPU") == 0 ) { 625 if (strcmp(optarg, "CPU") == 0) {
607 metric = METRIC_CPU; 626 result.config.metric = METRIC_CPU;
608 break; 627 break;
609 } 628 }
610 else if ( strcmp(optarg, "ELAPSED") == 0) { 629 if (strcmp(optarg, "ELAPSED") == 0) {
611 metric = METRIC_ELAPSED; 630 result.config.metric = METRIC_ELAPSED;
612 break; 631 break;
613 } 632 }
614 633
615 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 634 usage4(_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
616 case 'k': /* linux kernel thread filter */ 635 case 'k': /* linux kernel thread filter */
617 kthread_filter = 1; 636 result.config.kthread_filter = true;
618 break; 637 break;
619 case 'v': /* command */ 638 case 'v': /* command */
620 verbose++; 639 verbose++;
621 break; 640 break;
622 case 'T': 641 case 'T':
623 usepid = 1; 642 result.config.usepid = true;
624 break; 643 break;
625 case CHAR_MAX+2: 644 case CHAR_MAX + 2:
626 input_filename = optarg; 645 result.config.input_filename = optarg;
627 break; 646 break;
628 } 647 }
629 } 648 }
630 649
631 c = optind; 650 int index = optind;
632 if ((! warning_range) && argv[c]) 651 if ((!result.config.warning_range) && argv[index]) {
633 warning_range = argv[c++]; 652 result.config.warning_range = argv[index++];
634 if ((! critical_range) && argv[c]) 653 }
635 critical_range = argv[c++]; 654 if ((!result.config.critical_range) && argv[index]) {
636 if (statopts == NULL && argv[c]) { 655 result.config.critical_range = argv[index++];
637 xasprintf (&statopts, "%s", argv[c++]); 656 }
638 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 657 if (result.config.statopts == NULL && argv[index]) {
639 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;
640 } 663 }
641 664
642 /* this will abort in case of invalid ranges */ 665 /* this will abort in case of invalid ranges */
643 set_thresholds (&procs_thresholds, warning_range, critical_range); 666 set_thresholds(&result.config.procs_thresholds, result.config.warning_range,
667 result.config.critical_range);
644 668
645 return validate_arguments (); 669 return validate_arguments(result);
646} 670}
647 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 }
648 676
677 if (config_wrapper.config.statopts == NULL) {
678 config_wrapper.config.statopts = strdup("");
679 }
649 680
650int 681 if (config_wrapper.config.prog == NULL) {
651validate_arguments () 682 config_wrapper.config.prog = strdup("");
652{ 683 }
653 if (options == 0)
654 options = ALL;
655
656 if (statopts==NULL)
657 statopts = strdup("");
658
659 if (prog==NULL)
660 prog = strdup("");
661 684
662 if (args==NULL) 685 if (config_wrapper.config.args == NULL) {
663 args = strdup(""); 686 config_wrapper.config.args = strdup("");
687 }
664 688
665 if (fmt==NULL) 689 if (config_wrapper.config.fmt == NULL) {
666 fmt = strdup(""); 690 config_wrapper.config.fmt = strdup("");
691 }
667 692
668 if (fails==NULL) 693 if (config_wrapper.config.fails == NULL) {
669 fails = strdup(""); 694 config_wrapper.config.fails = strdup("");
695 }
670 696
671 return options; 697 // return options;
698 return config_wrapper;
672} 699}
673 700
674
675/* convert the elapsed time to seconds */ 701/* convert the elapsed time to seconds */
676int 702int convert_to_seconds(char *etime, enum metric metric) {
677convert_to_seconds(char *etime) { 703 int hyphcnt = 0;
678 704 int coloncnt = 0;
679 char *ptr; 705 for (char *ptr = etime; *ptr != '\0'; ptr++) {
680 int total;
681
682 int hyphcnt;
683 int coloncnt;
684 int days;
685 int hours;
686 int minutes;
687 int seconds;
688
689 hyphcnt = 0;
690 coloncnt = 0;
691 days = 0;
692 hours = 0;
693 minutes = 0;
694 seconds = 0;
695
696 for (ptr = etime; *ptr != '\0'; ptr++) {
697 706
698 if (*ptr == '-') { 707 if (*ptr == '-') {
699 hyphcnt++; 708 hyphcnt++;
@@ -705,9 +714,12 @@ convert_to_seconds(char *etime) {
705 } 714 }
706 } 715 }
707 716
717 int days = 0;
718 int hours = 0;
719 int minutes = 0;
720 int seconds = 0;
708 if (hyphcnt > 0) { 721 if (hyphcnt > 0) {
709 sscanf(etime, "%d-%d:%d:%d", 722 sscanf(etime, "%d-%d:%d:%d", &days, &hours, &minutes, &seconds);
710 &days, &hours, &minutes, &seconds);
711 /* 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
712 * elapsed times for some reason */ 724 * elapsed times for some reason */
713 if (days == 49710) { 725 if (days == 49710) {
@@ -715,135 +727,129 @@ convert_to_seconds(char *etime) {
715 } 727 }
716 } else { 728 } else {
717 if (coloncnt == 2) { 729 if (coloncnt == 2) {
718 sscanf(etime, "%d:%d:%d", 730 sscanf(etime, "%d:%d:%d", &hours, &minutes, &seconds);
719 &hours, &minutes, &seconds);
720 } else if (coloncnt == 1) { 731 } else if (coloncnt == 1) {
721 sscanf(etime, "%d:%d", 732 sscanf(etime, "%d:%d", &minutes, &seconds);
722 &minutes, &seconds);
723 } 733 }
724 } 734 }
725 735
726 total = (days * 86400) + 736 int total = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
727 (hours * 3600) +
728 (minutes * 60) +
729 seconds;
730 737
731 if (verbose >= 3 && metric == METRIC_ELAPSED) { 738 if (verbose >= 3 && metric == METRIC_ELAPSED) {
732 printf("seconds: %d\n", total); 739 printf("seconds: %d\n", total);
733 } 740 }
734 return total; 741 return total;
735} 742}
736 743
737 744void print_help(void) {
738void 745 print_revision(progname, NP_VERSION);
739print_help (void) 746
740{ 747 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
741 print_revision (progname, NP_VERSION); 748 printf(COPYRIGHT, copyright, email);
742 749
743 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 750 printf("%s\n",
744 printf (COPYRIGHT, copyright, email); 751 _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
745 752 printf("%s\n",
746 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"));
747 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number")); 754 printf("%s\n",
748 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."));
749 756
750 printf ("\n\n"); 757 printf("\n\n");
751 758
752 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)")); 759 printf("%s\n",
753 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)"));
754 761 printf("%s\n", _("are excluded from any checks to prevent false positives."));
755 printf ("\n\n"); 762
756 763 printf("\n\n");
757 print_usage (); 764
758 765 print_usage();
759 printf (UT_HELP_VRSN); 766
760 printf (UT_EXTRA_OPTS); 767 printf(UT_HELP_VRSN);
761 printf (" %s\n", "-w, --warning=RANGE"); 768 printf(UT_EXTRA_OPTS);
762 printf (" %s\n", _("Generate warning state if metric is outside this range")); 769 printf(" %s\n", "-w, --warning=RANGE");
763 printf (" %s\n", "-c, --critical=RANGE"); 770 printf(" %s\n", _("Generate warning state if metric is outside this range"));
764 printf (" %s\n", _("Generate critical state if metric is outside this range")); 771 printf(" %s\n", "-c, --critical=RANGE");
765 printf (" %s\n", "-m, --metric=TYPE"); 772 printf(" %s\n", _("Generate critical state if metric is outside this range"));
766 printf (" %s\n", _("Check thresholds against metric. Valid types:")); 773 printf(" %s\n", "-m, --metric=TYPE");
767 printf (" %s\n", _("PROCS - number of processes (default)")); 774 printf(" %s\n", _("Check thresholds against metric. Valid types:"));
768 printf (" %s\n", _("VSZ - virtual memory size")); 775 printf(" %s\n", _("PROCS - number of processes (default)"));
769 printf (" %s\n", _("RSS - resident set memory size")); 776 printf(" %s\n", _("VSZ - virtual memory size"));
770 printf (" %s\n", _("CPU - percentage CPU")); 777 printf(" %s\n", _("RSS - resident set memory size"));
778 printf(" %s\n", _("CPU - percentage CPU"));
771/* only linux etime is support currently */ 779/* only linux etime is support currently */
772#if defined( __linux__ ) 780#if defined(__linux__)
773 printf (" %s\n", _("ELAPSED - time elapsed in seconds")); 781 printf(" %s\n", _("ELAPSED - time elapsed in seconds"));
774#endif /* defined(__linux__) */ 782#endif /* defined(__linux__) */
775 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
776 784
777 printf (" %s\n", "-v, --verbose"); 785 printf(" %s\n", "-v, --verbose");
778 printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); 786 printf(" %s\n", _("Extra information. Up to 3 verbosity levels"));
779 787
780 printf (" %s\n", "-T, --traditional"); 788 printf(" %s\n", "-T, --traditional");
781 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"));
782 790
783 printf ("\n"); 791 printf("\n");
784 printf ("%s\n", "Filters:"); 792 printf("%s\n", "Filters:");
785 printf (" %s\n", "-s, --state=STATUSFLAGS"); 793 printf(" %s\n", "-s, --state=STATUSFLAGS");
786 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"));
787 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,"));
788 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)."));
789 printf (" %s\n", "-p, --ppid=PPID"); 797 printf(" %s\n", "-p, --ppid=PPID");
790 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."));
791 printf (" %s\n", "-z, --vsz=VSZ"); 799 printf(" %s\n", "-z, --vsz=VSZ");
792 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."));
793 printf (" %s\n", "-r, --rss=RSS"); 801 printf(" %s\n", "-r, --rss=RSS");
794 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."));
795 printf (" %s\n", "-P, --pcpu=PCPU"); 803 printf(" %s\n", "-P, --pcpu=PCPU");
796 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."));
797 printf (" %s\n", "-u, --user=USER"); 805 printf(" %s\n", "-u, --user=USER");
798 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."));
799 printf (" %s\n", "-a, --argument-array=STRING"); 807 printf(" %s\n", "-a, --argument-array=STRING");
800 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."));
801 printf (" %s\n", "--ereg-argument-array=STRING"); 809 printf(" %s\n", "--ereg-argument-array=STRING");
802 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."));
803 printf (" %s\n", "-C, --command=COMMAND"); 811 printf(" %s\n", "-C, --command=COMMAND");
804 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)."));
805 printf (" %s\n", "-X, --exclude-process"); 813 printf(" %s\n", "-X, --exclude-process");
806 printf (" %s\n", _("Exclude processes which match this comma separated list")); 814 printf(" %s\n", _("Exclude processes which match this comma separated list"));
807 printf (" %s\n", "-k, --no-kthreads"); 815 printf(" %s\n", "-k, --no-kthreads");
808 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)."));
809 817
810 printf(_("\n\ 818 printf(_("\n\
811RANGEs 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\
812specified 'max:min', a warning status will be generated if the\n\ 820specified 'max:min', a warning status will be generated if the\n\
813count is inside the specified range\n\n")); 821count is inside the specified range\n\n"));
814 822
815 printf(_("\ 823 printf(_("\
816This plugin checks the number of currently running processes and\n\ 824This plugin checks the number of currently running processes and\n\
817generates WARNING or CRITICAL states if the process count is outside\n\ 825generates WARNING or CRITICAL states if the process count is outside\n\
818the specified threshold ranges. The process count can be filtered by\n\ 826the specified threshold ranges. The process count can be filtered by\n\
819process 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\
820be the total number of running processes\n\n")); 828be the total number of running processes\n\n"));
821 829
822 printf ("%s\n", _("Examples:")); 830 printf("%s\n", _("Examples:"));
823 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");
824 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."));
825 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 833 printf(" %s\n\n", _("Critical if < 2 or > 1024 processes"));
826 printf (" %s\n", "check_procs -c 1: -C sshd"); 834 printf(" %s\n", "check_procs -c 1: -C sshd");
827 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"));
828 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd"); 836 printf(" %s\n", "check_procs -w 1024 -c 1: -C sshd");
829 printf (" %s\n", _("Warning if > 1024 processes with command name sshd.")); 837 printf(" %s\n", _("Warning if > 1024 processes with command name sshd."));
830 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."));
831 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");
832 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"));
833 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"));
834 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 842 printf(" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
835 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"));
836 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU"); 844 printf(" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
837 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%%"));
838 846
839 printf (UT_SUPPORT); 847 printf(UT_SUPPORT);
840} 848}
841 849
842void 850void print_usage(void) {
843print_usage (void) 851 printf("%s\n", _("Usage:"));
844{ 852 printf("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
845 printf ("%s\n", _("Usage:")); 853 printf(" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
846 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");
847 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
848 printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
849} 855}