1 /******************************************************************************
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 $Id$
19 ******************************************************************************/
21 const char *progname = "check_procs";
22 const char *revision = "$Revision$";
23 const char *copyright = "2000-2004";
24 const char *email = "nagiosplug-devel@lists.sourceforge.net";
26 #include "common.h"
27 #include "popen.h"
28 #include "utils.h"
30 #include <pwd.h>
32 int process_arguments (int, char **);
33 int validate_arguments (void);
34 int check_thresholds (int);
35 int convert_to_seconds (char *);
36 void print_help (void);
37 void print_usage (void);
39 int wmax = -1;
40 int cmax = -1;
41 int wmin = -1;
42 int cmin = -1;
44 int options = 0; /* bitmask of filter criteria to test against */
45 #define ALL 1
46 #define STAT 2
47 #define PPID 4
48 #define USER 8
49 #define PROG 16
50 #define ARGS 32
51 #define VSZ 64
52 #define RSS 128
53 #define PCPU 256
54 #define ELAPSED 512
55 /* Different metrics */
56 char *metric_name;
57 enum metric {
58 METRIC_PROCS,
59 METRIC_VSZ,
60 METRIC_RSS,
61 METRIC_CPU,
62 METRIC_ELAPSED
63 };
64 enum metric metric = METRIC_PROCS;
66 int verbose = 0;
67 int uid;
68 int ppid;
69 int vsz;
70 int rss;
71 float pcpu;
72 char *statopts;
73 char *prog;
74 char *args;
75 char *fmt;
76 char *fails;
77 char tmp[MAX_INPUT_BUFFER];
81 int
82 main (int argc, char **argv)
83 {
84 char *input_buffer;
85 char *input_line;
86 char *procprog;
88 int procuid = 0;
89 int procppid = 0;
90 int procvsz = 0;
91 int procrss = 0;
92 int procseconds = 0;
93 float procpcpu = 0;
94 char procstat[8];
95 char procetime[MAX_INPUT_BUFFER];
96 char *procargs;
97 char *temp_string;
99 const char *zombie = "Z";
101 int resultsum = 0; /* bitmask of the filter criteria met by a process */
102 int found = 0; /* counter for number of lines returned in `ps` output */
103 int procs = 0; /* counter for number of processes meeting filter criteria */
104 int pos; /* number of spaces before 'args' in `ps` output */
105 int cols; /* number of columns in ps output */
106 int expected_cols = PS_COLS - 1;
107 int warn = 0; /* number of processes in warn state */
108 int crit = 0; /* number of processes in crit state */
109 int i = 0;
111 int result = STATE_UNKNOWN;
113 setlocale (LC_ALL, "");
114 bindtextdomain (PACKAGE, LOCALEDIR);
115 textdomain (PACKAGE);
117 input_buffer = malloc (MAX_INPUT_BUFFER);
118 procprog = malloc (MAX_INPUT_BUFFER);
120 asprintf (&metric_name, "PROCS");
121 metric = METRIC_PROCS;
123 if (process_arguments (argc, argv) == ERROR)
124 usage4 (_("Could not parse arguments"));
126 /* Set signal handling and alarm timeout */
127 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
128 usage4 (_("Cannot catch SIGALRM"));
129 }
130 alarm (timeout_interval);
132 if (verbose >= 2)
133 printf (_("CMD: %s\n"), PS_COMMAND);
135 child_process = spopen (PS_COMMAND);
136 if (child_process == NULL) {
137 printf (_("Could not open pipe: %s\n"), PS_COMMAND);
138 return STATE_UNKNOWN;
139 }
141 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
142 if (child_stderr == NULL)
143 printf (_("Could not open stderr for %s\n"), PS_COMMAND);
145 /* flush first line */
146 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
147 while ( input_buffer[strlen(input_buffer)-1] != '\n' )
148 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
150 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
151 asprintf (&input_line, "%s", input_buffer);
152 while ( input_buffer[strlen(input_buffer)-1] != '\n' ) {
153 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
154 asprintf (&input_line, "%s%s", input_line, input_buffer);
155 }
157 if (verbose >= 3)
158 printf ("%s", input_line);
160 strcpy (procprog, "");
161 asprintf (&procargs, "%s", "");
163 cols = sscanf (input_line, PS_FORMAT, PS_VARLIST);
165 /* Zombie processes do not give a procprog command */
166 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
167 cols = expected_cols;
168 }
169 if ( cols >= expected_cols ) {
170 resultsum = 0;
171 asprintf (&procargs, "%s", input_line + pos);
172 strip (procargs);
174 /* Some ps return full pathname for command. This removes path */
175 temp_string = strtok ((char *)procprog, "/");
176 while (temp_string) {
177 strcpy(procprog, temp_string);
178 temp_string = strtok (NULL, "/");
179 }
181 /* we need to convert the elapsed time to seconds */
182 procseconds = convert_to_seconds(procetime);
184 if (verbose >= 3)
185 printf ("%d %d %d %d %d %.2f %s %s %s %s\n",
186 procs, procuid, procvsz, procrss,
187 procppid, procpcpu, procstat,
188 procetime, procprog, procargs);
190 /* Ignore self */
191 if (strcmp (procprog, progname) == 0) {
192 continue;
193 }
195 if ((options & STAT) && (strstr (statopts, procstat)))
196 resultsum |= STAT;
197 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL))
198 resultsum |= ARGS;
199 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
200 resultsum |= PROG;
201 if ((options & PPID) && (procppid == ppid))
202 resultsum |= PPID;
203 if ((options & USER) && (procuid == uid))
204 resultsum |= USER;
205 if ((options & VSZ) && (procvsz >= vsz))
206 resultsum |= VSZ;
207 if ((options & RSS) && (procrss >= rss))
208 resultsum |= RSS;
209 if ((options & PCPU) && (procpcpu >= pcpu))
210 resultsum |= PCPU;
212 found++;
214 /* Next line if filters not matched */
215 if (!(options == resultsum || options == ALL))
216 continue;
218 procs++;
220 if (metric == METRIC_VSZ)
221 i = check_thresholds (procvsz);
222 else if (metric == METRIC_RSS)
223 i = check_thresholds (procrss);
224 /* TODO? float thresholds for --metric=CPU */
225 else if (metric == METRIC_CPU)
226 i = check_thresholds ((int)procpcpu);
227 else if (metric == METRIC_ELAPSED)
228 i = check_thresholds (procseconds);
230 if (metric != METRIC_PROCS) {
231 if (i == STATE_WARNING) {
232 warn++;
233 asprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
234 result = max_state (result, i);
235 }
236 if (i == STATE_CRITICAL) {
237 crit++;
238 asprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
239 result = max_state (result, i);
240 }
241 }
242 }
243 /* This should not happen */
244 else if (verbose) {
245 printf(_("Not parseable: %s"), input_buffer);
246 }
247 }
249 /* If we get anything on STDERR, at least set warning */
250 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
251 if (verbose)
252 printf ("STDERR: %s", input_buffer);
253 result = max_state (result, STATE_WARNING);
254 printf (_("System call sent warnings to stderr\n"));
255 }
257 (void) fclose (child_stderr);
259 /* close the pipe */
260 if (spclose (child_process)) {
261 printf (_("System call returned nonzero status\n"));
262 result = max_state (result, STATE_WARNING);
263 }
265 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
266 printf (_("Unable to read output\n"));
267 return result;
268 }
270 if ( result == STATE_UNKNOWN )
271 result = STATE_OK;
273 /* Needed if procs found, but none match filter */
274 if ( metric == METRIC_PROCS ) {
275 result = max_state (result, check_thresholds (procs) );
276 }
278 if ( result == STATE_OK ) {
279 printf ("%s %s: ", metric_name, _("OK"));
280 } else if (result == STATE_WARNING) {
281 printf ("%s %s: ", metric_name, _("WARNING"));
282 if ( metric != METRIC_PROCS ) {
283 printf (_("%d warn out of "), warn);
284 }
285 } else if (result == STATE_CRITICAL) {
286 printf ("%s %s: ", metric_name, _("CRITICAL"));
287 if (metric != METRIC_PROCS) {
288 printf (_("%d crit, %d warn out of "), crit, warn);
289 }
290 }
291 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs);
293 if (strcmp(fmt,"") != 0) {
294 printf (_(" with %s"), fmt);
295 }
297 if ( verbose >= 1 && strcmp(fails,"") )
298 printf (" [%s]", fails);
300 printf ("\n");
301 return result;
302 }
306 /* process command-line arguments */
307 int
308 process_arguments (int argc, char **argv)
309 {
310 int c = 1;
311 char *user;
312 struct passwd *pw;
313 int option = 0;
314 static struct option longopts[] = {
315 {"warning", required_argument, 0, 'w'},
316 {"critical", required_argument, 0, 'c'},
317 {"metric", required_argument, 0, 'm'},
318 {"timeout", required_argument, 0, 't'},
319 {"status", required_argument, 0, 's'},
320 {"ppid", required_argument, 0, 'p'},
321 {"command", required_argument, 0, 'C'},
322 {"vsz", required_argument, 0, 'z'},
323 {"rss", required_argument, 0, 'r'},
324 {"pcpu", required_argument, 0, 'P'},
325 {"elapsed", required_argument, 0, 'e'},
326 {"argument-array", required_argument, 0, 'a'},
327 {"help", no_argument, 0, 'h'},
328 {"version", no_argument, 0, 'V'},
329 {"verbose", no_argument, 0, 'v'},
330 {0, 0, 0, 0}
331 };
333 for (c = 1; c < argc; c++)
334 if (strcmp ("-to", argv[c]) == 0)
335 strcpy (argv[c], "-t");
337 while (1) {
338 c = getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:z:r:m:P:",
339 longopts, &option);
341 if (c == -1 || c == EOF)
342 break;
344 switch (c) {
345 case '?': /* help */
346 usage2 (_("Unknown argument"), optarg);
347 case 'h': /* help */
348 print_help ();
349 exit (STATE_OK);
350 case 'V': /* version */
351 print_revision (progname, revision);
352 exit (STATE_OK);
353 case 't': /* timeout period */
354 if (!is_integer (optarg))
355 usage2 (_("Timeout interval must be a positive integer"), optarg);
356 else
357 timeout_interval = atoi (optarg);
358 break;
359 case 'c': /* critical threshold */
360 if (is_integer (optarg))
361 cmax = atoi (optarg);
362 else if (sscanf (optarg, ":%d", &cmax) == 1)
363 break;
364 else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2)
365 break;
366 else if (sscanf (optarg, "%d:", &cmin) == 1)
367 break;
368 else
369 usage4 (_("Critical Process Count must be an integer!"));
370 break;
371 case 'w': /* warning threshold */
372 if (is_integer (optarg))
373 wmax = atoi (optarg);
374 else if (sscanf (optarg, ":%d", &wmax) == 1)
375 break;
376 else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2)
377 break;
378 else if (sscanf (optarg, "%d:", &wmin) == 1)
379 break;
380 else
381 usage4 (_("Warning Process Count must be an integer!"));
382 break;
383 case 'p': /* process id */
384 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
385 asprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid);
386 options |= PPID;
387 break;
388 }
389 usage4 (_("Parent Process ID must be an integer!"));
390 case 's': /* status */
391 if (statopts)
392 break;
393 else
394 statopts = optarg;
395 asprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
396 options |= STAT;
397 break;
398 case 'u': /* user or user id */
399 if (is_integer (optarg)) {
400 uid = atoi (optarg);
401 pw = getpwuid ((uid_t) uid);
402 /* check to be sure user exists */
403 if (pw == NULL)
404 usage2 (_("UID %s was not found"), optarg);
405 }
406 else {
407 pw = getpwnam (optarg);
408 /* check to be sure user exists */
409 if (pw == NULL)
410 usage2 (_("User name %s was not found"), optarg);
411 /* then get uid */
412 uid = pw->pw_uid;
413 }
414 user = pw->pw_name;
415 asprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""),
416 uid, user);
417 options |= USER;
418 break;
419 case 'C': /* command */
420 /* TODO: allow this to be passed in with --metric */
421 if (prog)
422 break;
423 else
424 prog = optarg;
425 asprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
426 prog);
427 options |= PROG;
428 break;
429 case 'a': /* args (full path name with args) */
430 /* TODO: allow this to be passed in with --metric */
431 if (args)
432 break;
433 else
434 args = optarg;
435 asprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args);
436 options |= ARGS;
437 break;
438 case 'r': /* RSS */
439 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) {
440 asprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss);
441 options |= RSS;
442 break;
443 }
444 usage4 (_("RSS must be an integer!"));
445 case 'z': /* VSZ */
446 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) {
447 asprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz);
448 options |= VSZ;
449 break;
450 }
451 usage4 (_("VSZ must be an integer!"));
452 case 'P': /* PCPU */
453 /* TODO: -P 1.5.5 is accepted */
454 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) {
455 asprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu);
456 options |= PCPU;
457 break;
458 }
459 usage4 (_("PCPU must be a float!"));
460 case 'm':
461 asprintf (&metric_name, "%s", optarg);
462 if ( strcmp(optarg, "PROCS") == 0) {
463 metric = METRIC_PROCS;
464 break;
465 }
466 else if ( strcmp(optarg, "VSZ") == 0) {
467 metric = METRIC_VSZ;
468 break;
469 }
470 else if ( strcmp(optarg, "RSS") == 0 ) {
471 metric = METRIC_RSS;
472 break;
473 }
474 else if ( strcmp(optarg, "CPU") == 0 ) {
475 metric = METRIC_CPU;
476 break;
477 }
478 else if ( strcmp(optarg, "ELAPSED") == 0) {
479 metric = METRIC_ELAPSED;
480 break;
481 }
483 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
484 case 'v': /* command */
485 verbose++;
486 break;
487 }
488 }
490 c = optind;
491 if (wmax == -1 && argv[c])
492 wmax = atoi (argv[c++]);
493 if (cmax == -1 && argv[c])
494 cmax = atoi (argv[c++]);
495 if (statopts == NULL && argv[c]) {
496 asprintf (&statopts, "%s", argv[c++]);
497 asprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
498 options |= STAT;
499 }
501 return validate_arguments ();
502 }
506 int
507 validate_arguments ()
508 {
510 if (wmax >= 0 && wmin == -1)
511 wmin = 0;
512 if (cmax >= 0 && cmin == -1)
513 cmin = 0;
514 if (wmax >= wmin && cmax >= cmin) { /* standard ranges */
515 if (wmax > cmax && cmax != -1) {
516 printf (_("wmax (%d) cannot be greater than cmax (%d)\n"), wmax, cmax);
517 return ERROR;
518 }
519 if (cmin > wmin && wmin != -1) {
520 printf (_("wmin (%d) cannot be less than cmin (%d)\n"), wmin, cmin);
521 return ERROR;
522 }
523 }
525 /* if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */
526 /* printf ("At least one threshold must be set\n"); */
527 /* return ERROR; */
528 /* } */
530 if (options == 0)
531 options = ALL;
533 if (statopts==NULL)
534 statopts = strdup("");
536 if (prog==NULL)
537 prog = strdup("");
539 if (args==NULL)
540 args = strdup("");
542 if (fmt==NULL)
543 fmt = strdup("");
545 if (fails==NULL)
546 fails = strdup("");
548 return options;
549 }
553 /* Check thresholds against value */
554 int
555 check_thresholds (int value)
556 {
557 if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
558 return OK;
559 }
560 else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
561 if (value > cmax && value < cmin)
562 return STATE_CRITICAL;
563 }
564 else if (cmax >= 0 && value > cmax) {
565 return STATE_CRITICAL;
566 }
567 else if (cmin >= 0 && value < cmin) {
568 return STATE_CRITICAL;
569 }
571 if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
572 if (value > wmax && value < wmin) {
573 return STATE_WARNING;
574 }
575 }
576 else if (wmax >= 0 && value > wmax) {
577 return STATE_WARNING;
578 }
579 else if (wmin >= 0 && value < wmin) {
580 return STATE_WARNING;
581 }
582 return STATE_OK;
583 }
586 /* convert the elapsed time to seconds */
587 int
588 convert_to_seconds(char *etime) {
590 char *ptr;
591 int total;
593 int hyphcnt;
594 int coloncnt;
595 int days;
596 int hours;
597 int minutes;
598 int seconds;
600 hyphcnt = 0;
601 coloncnt = 0;
602 days = 0;
603 hours = 0;
604 minutes = 0;
605 seconds = 0;
607 for (ptr = etime; *ptr != '\0'; ptr++) {
609 if (*ptr == '-') {
610 hyphcnt++;
611 continue;
612 }
613 if (*ptr == ':') {
614 coloncnt++;
615 continue;
616 }
617 }
619 if (hyphcnt > 0) {
620 sscanf(etime, "%d-%d:%d:%d",
621 &days, &hours, &minutes, &seconds);
622 /* linux 2.6.5/2.6.6 reporting some processes with infinite
623 * elapsed times for some reason */
624 if (days == 49710) {
625 return 0;
626 }
627 } else {
628 if (coloncnt == 2) {
629 sscanf(etime, "%d:%d:%d",
630 &hours, &minutes, &seconds);
631 } else if (coloncnt == 1) {
632 sscanf(etime, "%d:%d",
633 &minutes, &seconds);
634 }
635 }
637 total = (days * 86400) +
638 (hours * 3600) +
639 (minutes * 60) +
640 seconds;
642 if (verbose >= 3) {
643 printf("seconds: %d\n", total);
644 }
645 return total;
646 }
649 void
650 print_help (void)
651 {
652 print_revision (progname, revision);
654 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>");
655 printf (COPYRIGHT, copyright, email);
657 printf(_("\
658 Checks all processes and generates WARNING or CRITICAL states if the specified\n\
659 metric is outside the required threshold ranges. The metric defaults to number\n\
660 of processes. Search filters can be applied to limit the processes to check.\n\n"));
662 print_usage ();
664 printf(_("\n\
665 Required Arguments:\n\
666 -w, --warning=RANGE\n\
667 Generate warning state if metric is outside this range\n\
668 -c, --critical=RANGE\n\
669 Generate critical state if metric is outside this range\n"));
671 printf(_("\n\
672 Optional Arguments:\n\
673 -m, --metric=TYPE\n\
674 Check thresholds against metric. Valid types:\n\
675 PROCS - number of processes (default)\n\
676 VSZ - virtual memory size\n\
677 RSS - resident set memory size\n\
678 CPU - percentage cpu\n"));
679 /* only linux etime is support currently */
680 #if defined( __linux__ )
681 printf(_("\
682 ELAPSED - time elapsed in seconds\n"));
683 #endif /* defined(__linux__) */
684 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
686 printf(_("\
687 -v, --verbose\n\
688 Extra information. Up to 3 verbosity levels\n"));
690 printf(_("\n\
691 Optional Filters:\n\
692 -s, --state=STATUSFLAGS\n\
693 Only scan for processes that have, in the output of `ps`, one or\n\
694 more of the status flags you specify (for example R, Z, S, RS,\n\
695 RSZDT, plus others based on the output of your 'ps' command).\n\
696 -p, --ppid=PPID\n\
697 Only scan for children of the parent process ID indicated.\n\
698 -z, --vsz=VSZ\n\
699 Only scan for processes with vsz higher than indicated.\n\
700 -r, --rss=RSS\n\
701 Only scan for processes with rss higher than indicated.\n"));
703 printf(_("\
704 -P, --pcpu=PCPU\n\
705 Only scan for processes with pcpu higher than indicated.\n\
706 -u, --user=USER\n\
707 Only scan for processes with user name or ID indicated.\n\
708 -a, --argument-array=STRING\n\
709 Only scan for processes with args that contain STRING.\n\
710 -C, --command=COMMAND\n\
711 Only scan for exact matches of COMMAND (without path).\n"));
713 printf(_("\n\
714 RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
715 specified 'max:min', a warning status will be generated if the\n\
716 count is inside the specified range\n\n"));
718 printf(_("\
719 This plugin checks the number of currently running processes and\n\
720 generates WARNING or CRITICAL states if the process count is outside\n\
721 the specified threshold ranges. The process count can be filtered by\n\
722 process owner, parent process PID, current state (e.g., 'Z'), or may\n\
723 be the total number of running processes\n\n"));
725 printf(_("\
726 Examples:\n\
727 check_procs -w 2:2 -c 2:1024 -C portsentry\n\
728 Warning if not two processes with command name portsentry. Critical\n\
729 if < 2 or > 1024 processes\n\n\
730 check_procs -w 10 -a '/usr/local/bin/perl' -u root\n\
731 Warning alert if > 10 processes with command arguments containing \n\
732 '/usr/local/bin/perl' and owned by root\n\n\
733 check_procs -w 50000 -c 100000 --metric=VSZ\n\
734 Alert if vsz of any processes over 50K or 100K\n\
735 check_procs -w 10 -c 20 --metric=CPU\n\
736 Alert if cpu of any processes over 10%% or 20%%\n\n"));
738 printf (_(UT_SUPPORT));
739 }
741 void
742 print_usage (void)
743 {
744 printf ("\
745 Usage: %s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n\
746 [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n\
747 [-C command] [-t timeout] [-v]\n", progname);
748 }