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-2006";
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 pid_t 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 pid_t mypid = 0;
89 int procuid = 0;
90 pid_t procpid = 0;
91 pid_t procppid = 0;
92 int procvsz = 0;
93 int procrss = 0;
94 int procseconds = 0;
95 float procpcpu = 0;
96 char procstat[8];
97 char procetime[MAX_INPUT_BUFFER] = { '\0' };
98 char *procargs;
100 const char *zombie = "Z";
102 int resultsum = 0; /* bitmask of the filter criteria met by a process */
103 int found = 0; /* counter for number of lines returned in `ps` output */
104 int procs = 0; /* counter for number of processes meeting filter criteria */
105 int pos; /* number of spaces before 'args' in `ps` output */
106 int cols; /* number of columns in ps output */
107 int expected_cols = PS_COLS - 1;
108 int warn = 0; /* number of processes in warn state */
109 int crit = 0; /* number of processes in crit state */
110 int i = 0;
111 int result = STATE_UNKNOWN;
113 setlocale (LC_ALL, "");
114 bindtextdomain (PACKAGE, LOCALEDIR);
115 textdomain (PACKAGE);
116 setlocale(LC_NUMERIC, "POSIX");
118 input_buffer = malloc (MAX_INPUT_BUFFER);
119 procprog = malloc (MAX_INPUT_BUFFER);
121 asprintf (&metric_name, "PROCS");
122 metric = METRIC_PROCS;
124 if (process_arguments (argc, argv) == ERROR)
125 usage4 (_("Could not parse arguments"));
127 /* get our pid */
128 mypid = getpid();
130 /* Set signal handling and alarm timeout */
131 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
132 usage4 (_("Cannot catch SIGALRM"));
133 }
134 alarm (timeout_interval);
136 if (verbose >= 2)
137 printf (_("CMD: %s\n"), PS_COMMAND);
139 child_process = spopen (PS_COMMAND);
140 if (child_process == NULL) {
141 printf (_("Could not open pipe: %s\n"), PS_COMMAND);
142 return STATE_UNKNOWN;
143 }
145 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
146 if (child_stderr == NULL)
147 printf (_("Could not open stderr for %s\n"), PS_COMMAND);
149 /* flush first line */
150 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
151 while ( input_buffer[strlen(input_buffer)-1] != '\n' )
152 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
154 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
155 asprintf (&input_line, "%s", input_buffer);
156 while ( input_buffer[strlen(input_buffer)-1] != '\n' ) {
157 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
158 asprintf (&input_line, "%s%s", input_line, input_buffer);
159 }
161 if (verbose >= 3)
162 printf ("%s", input_line);
164 strcpy (procprog, "");
165 asprintf (&procargs, "%s", "");
167 cols = sscanf (input_line, PS_FORMAT, PS_VARLIST);
169 /* Zombie processes do not give a procprog command */
170 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
171 cols = expected_cols;
172 }
173 if ( cols >= expected_cols ) {
174 resultsum = 0;
175 asprintf (&procargs, "%s", input_line + pos);
176 strip (procargs);
178 /* Some ps return full pathname for command. This removes path */
179 procprog = basename(procprog);
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 %d %.2f %s %s %s %s\n",
186 procs, procuid, procvsz, procrss,
187 procpid, procppid, procpcpu, procstat,
188 procetime, procprog, procargs);
190 /* Ignore self */
191 if (mypid == procpid) continue;
193 if ((options & STAT) && (strstr (statopts, procstat)))
194 resultsum |= STAT;
195 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL))
196 resultsum |= ARGS;
197 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
198 resultsum |= PROG;
199 if ((options & PPID) && (procppid == ppid))
200 resultsum |= PPID;
201 if ((options & USER) && (procuid == uid))
202 resultsum |= USER;
203 if ((options & VSZ) && (procvsz >= vsz))
204 resultsum |= VSZ;
205 if ((options & RSS) && (procrss >= rss))
206 resultsum |= RSS;
207 if ((options & PCPU) && (procpcpu >= pcpu))
208 resultsum |= PCPU;
210 found++;
212 /* Next line if filters not matched */
213 if (!(options == resultsum || options == ALL))
214 continue;
216 procs++;
218 if (metric == METRIC_VSZ)
219 i = check_thresholds (procvsz);
220 else if (metric == METRIC_RSS)
221 i = check_thresholds (procrss);
222 /* TODO? float thresholds for --metric=CPU */
223 else if (metric == METRIC_CPU)
224 i = check_thresholds ((int)procpcpu);
225 else if (metric == METRIC_ELAPSED)
226 i = check_thresholds (procseconds);
228 if (metric != METRIC_PROCS) {
229 if (i == STATE_WARNING) {
230 warn++;
231 asprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
232 result = max_state (result, i);
233 }
234 if (i == STATE_CRITICAL) {
235 crit++;
236 asprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
237 result = max_state (result, i);
238 }
239 }
240 }
241 /* This should not happen */
242 else if (verbose) {
243 printf(_("Not parseable: %s"), input_buffer);
244 }
245 }
247 /* If we get anything on STDERR, at least set warning */
248 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
249 if (verbose)
250 printf ("STDERR: %s", input_buffer);
251 result = max_state (result, STATE_WARNING);
252 printf (_("System call sent warnings to stderr\n"));
253 }
255 (void) fclose (child_stderr);
257 /* close the pipe */
258 if (spclose (child_process)) {
259 printf (_("System call returned nonzero status\n"));
260 result = max_state (result, STATE_WARNING);
261 }
263 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
264 printf (_("Unable to read output\n"));
265 return result;
266 }
268 if ( result == STATE_UNKNOWN )
269 result = STATE_OK;
271 /* Needed if procs found, but none match filter */
272 if ( metric == METRIC_PROCS ) {
273 result = max_state (result, check_thresholds (procs) );
274 }
276 if ( result == STATE_OK ) {
277 printf ("%s %s: ", metric_name, _("OK"));
278 } else if (result == STATE_WARNING) {
279 printf ("%s %s: ", metric_name, _("WARNING"));
280 if ( metric != METRIC_PROCS ) {
281 printf (_("%d warn out of "), warn);
282 }
283 } else if (result == STATE_CRITICAL) {
284 printf ("%s %s: ", metric_name, _("CRITICAL"));
285 if (metric != METRIC_PROCS) {
286 printf (_("%d crit, %d warn out of "), crit, warn);
287 }
288 }
289 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs);
291 if (strcmp(fmt,"") != 0) {
292 printf (_(" with %s"), fmt);
293 }
295 if ( verbose >= 1 && strcmp(fails,"") )
296 printf (" [%s]", fails);
298 printf ("\n");
299 return result;
300 }
304 /* process command-line arguments */
305 int
306 process_arguments (int argc, char **argv)
307 {
308 int c = 1;
309 char *user;
310 struct passwd *pw;
311 int option = 0;
312 static struct option longopts[] = {
313 {"warning", required_argument, 0, 'w'},
314 {"critical", required_argument, 0, 'c'},
315 {"metric", required_argument, 0, 'm'},
316 {"timeout", required_argument, 0, 't'},
317 {"status", required_argument, 0, 's'},
318 {"ppid", required_argument, 0, 'p'},
319 {"command", required_argument, 0, 'C'},
320 {"vsz", required_argument, 0, 'z'},
321 {"rss", required_argument, 0, 'r'},
322 {"pcpu", required_argument, 0, 'P'},
323 {"elapsed", required_argument, 0, 'e'},
324 {"argument-array", required_argument, 0, 'a'},
325 {"help", no_argument, 0, 'h'},
326 {"version", no_argument, 0, 'V'},
327 {"verbose", no_argument, 0, 'v'},
328 {0, 0, 0, 0}
329 };
331 for (c = 1; c < argc; c++)
332 if (strcmp ("-to", argv[c]) == 0)
333 strcpy (argv[c], "-t");
335 while (1) {
336 c = getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:z:r:m:P:",
337 longopts, &option);
339 if (c == -1 || c == EOF)
340 break;
342 switch (c) {
343 case '?': /* help */
344 usage2 (_("Unknown argument"), optarg);
345 case 'h': /* help */
346 print_help ();
347 exit (STATE_OK);
348 case 'V': /* version */
349 print_revision (progname, revision);
350 exit (STATE_OK);
351 case 't': /* timeout period */
352 if (!is_integer (optarg))
353 usage2 (_("Timeout interval must be a positive integer"), optarg);
354 else
355 timeout_interval = atoi (optarg);
356 break;
357 case 'c': /* critical threshold */
358 if (is_integer (optarg))
359 cmax = atoi (optarg);
360 else if (sscanf (optarg, ":%d", &cmax) == 1)
361 break;
362 else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2)
363 break;
364 else if (sscanf (optarg, "%d:", &cmin) == 1)
365 break;
366 else
367 usage4 (_("Critical Process Count must be an integer!"));
368 break;
369 case 'w': /* warning threshold */
370 if (is_integer (optarg))
371 wmax = atoi (optarg);
372 else if (sscanf (optarg, ":%d", &wmax) == 1)
373 break;
374 else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2)
375 break;
376 else if (sscanf (optarg, "%d:", &wmin) == 1)
377 break;
378 else
379 usage4 (_("Warning Process Count must be an integer!"));
380 break;
381 case 'p': /* process id */
382 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
383 asprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid);
384 options |= PPID;
385 break;
386 }
387 usage4 (_("Parent Process ID must be an integer!"));
388 case 's': /* status */
389 if (statopts)
390 break;
391 else
392 statopts = optarg;
393 asprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
394 options |= STAT;
395 break;
396 case 'u': /* user or user id */
397 if (is_integer (optarg)) {
398 uid = atoi (optarg);
399 pw = getpwuid ((uid_t) uid);
400 /* check to be sure user exists */
401 if (pw == NULL)
402 usage2 (_("UID %s was not found"), optarg);
403 }
404 else {
405 pw = getpwnam (optarg);
406 /* check to be sure user exists */
407 if (pw == NULL)
408 usage2 (_("User name %s was not found"), optarg);
409 /* then get uid */
410 uid = pw->pw_uid;
411 }
412 user = pw->pw_name;
413 asprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""),
414 uid, user);
415 options |= USER;
416 break;
417 case 'C': /* command */
418 /* TODO: allow this to be passed in with --metric */
419 if (prog)
420 break;
421 else
422 prog = optarg;
423 asprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
424 prog);
425 options |= PROG;
426 break;
427 case 'a': /* args (full path name with args) */
428 /* TODO: allow this to be passed in with --metric */
429 if (args)
430 break;
431 else
432 args = optarg;
433 asprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args);
434 options |= ARGS;
435 break;
436 case 'r': /* RSS */
437 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) {
438 asprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss);
439 options |= RSS;
440 break;
441 }
442 usage4 (_("RSS must be an integer!"));
443 case 'z': /* VSZ */
444 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) {
445 asprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz);
446 options |= VSZ;
447 break;
448 }
449 usage4 (_("VSZ must be an integer!"));
450 case 'P': /* PCPU */
451 /* TODO: -P 1.5.5 is accepted */
452 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) {
453 asprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu);
454 options |= PCPU;
455 break;
456 }
457 usage4 (_("PCPU must be a float!"));
458 case 'm':
459 asprintf (&metric_name, "%s", optarg);
460 if ( strcmp(optarg, "PROCS") == 0) {
461 metric = METRIC_PROCS;
462 break;
463 }
464 else if ( strcmp(optarg, "VSZ") == 0) {
465 metric = METRIC_VSZ;
466 break;
467 }
468 else if ( strcmp(optarg, "RSS") == 0 ) {
469 metric = METRIC_RSS;
470 break;
471 }
472 else if ( strcmp(optarg, "CPU") == 0 ) {
473 metric = METRIC_CPU;
474 break;
475 }
476 else if ( strcmp(optarg, "ELAPSED") == 0) {
477 metric = METRIC_ELAPSED;
478 break;
479 }
481 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
482 case 'v': /* command */
483 verbose++;
484 break;
485 }
486 }
488 c = optind;
489 if (wmax == -1 && argv[c])
490 wmax = atoi (argv[c++]);
491 if (cmax == -1 && argv[c])
492 cmax = atoi (argv[c++]);
493 if (statopts == NULL && argv[c]) {
494 asprintf (&statopts, "%s", argv[c++]);
495 asprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
496 options |= STAT;
497 }
499 return validate_arguments ();
500 }
504 int
505 validate_arguments ()
506 {
508 if (wmax >= 0 && wmin == -1)
509 wmin = 0;
510 if (cmax >= 0 && cmin == -1)
511 cmin = 0;
512 if (wmax >= wmin && cmax >= cmin) { /* standard ranges */
513 if (wmax > cmax && cmax != -1) {
514 printf (_("wmax (%d) cannot be greater than cmax (%d)\n"), wmax, cmax);
515 return ERROR;
516 }
517 if (cmin > wmin && wmin != -1) {
518 printf (_("wmin (%d) cannot be less than cmin (%d)\n"), wmin, cmin);
519 return ERROR;
520 }
521 }
523 /* if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */
524 /* printf ("At least one threshold must be set\n"); */
525 /* return ERROR; */
526 /* } */
528 if (options == 0)
529 options = ALL;
531 if (statopts==NULL)
532 statopts = strdup("");
534 if (prog==NULL)
535 prog = strdup("");
537 if (args==NULL)
538 args = strdup("");
540 if (fmt==NULL)
541 fmt = strdup("");
543 if (fails==NULL)
544 fails = strdup("");
546 return options;
547 }
551 /* Check thresholds against value */
552 int
553 check_thresholds (int value)
554 {
555 if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
556 return OK;
557 }
558 else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
559 if (value > cmax && value < cmin)
560 return STATE_CRITICAL;
561 }
562 else if (cmax >= 0 && value > cmax) {
563 return STATE_CRITICAL;
564 }
565 else if (cmin >= 0 && value < cmin) {
566 return STATE_CRITICAL;
567 }
569 if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
570 if (value > wmax && value < wmin) {
571 return STATE_WARNING;
572 }
573 }
574 else if (wmax >= 0 && value > wmax) {
575 return STATE_WARNING;
576 }
577 else if (wmin >= 0 && value < wmin) {
578 return STATE_WARNING;
579 }
580 return STATE_OK;
581 }
584 /* convert the elapsed time to seconds */
585 int
586 convert_to_seconds(char *etime) {
588 char *ptr;
589 int total;
591 int hyphcnt;
592 int coloncnt;
593 int days;
594 int hours;
595 int minutes;
596 int seconds;
598 hyphcnt = 0;
599 coloncnt = 0;
600 days = 0;
601 hours = 0;
602 minutes = 0;
603 seconds = 0;
605 for (ptr = etime; *ptr != '\0'; ptr++) {
607 if (*ptr == '-') {
608 hyphcnt++;
609 continue;
610 }
611 if (*ptr == ':') {
612 coloncnt++;
613 continue;
614 }
615 }
617 if (hyphcnt > 0) {
618 sscanf(etime, "%d-%d:%d:%d",
619 &days, &hours, &minutes, &seconds);
620 /* linux 2.6.5/2.6.6 reporting some processes with infinite
621 * elapsed times for some reason */
622 if (days == 49710) {
623 return 0;
624 }
625 } else {
626 if (coloncnt == 2) {
627 sscanf(etime, "%d:%d:%d",
628 &hours, &minutes, &seconds);
629 } else if (coloncnt == 1) {
630 sscanf(etime, "%d:%d",
631 &minutes, &seconds);
632 }
633 }
635 total = (days * 86400) +
636 (hours * 3600) +
637 (minutes * 60) +
638 seconds;
640 if (verbose >= 3 && metric == METRIC_ELAPSED) {
641 printf("seconds: %d\n", total);
642 }
643 return total;
644 }
647 void
648 print_help (void)
649 {
650 print_revision (progname, revision);
652 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>");
653 printf (COPYRIGHT, copyright, email);
655 printf(_("\
656 Checks all processes and generates WARNING or CRITICAL states if the specified\n\
657 metric is outside the required threshold ranges. The metric defaults to number\n\
658 of processes. Search filters can be applied to limit the processes to check.\n\n"));
660 print_usage ();
662 printf(_("\n\
663 Required Arguments:\n\
664 -w, --warning=RANGE\n\
665 Generate warning state if metric is outside this range\n\
666 -c, --critical=RANGE\n\
667 Generate critical state if metric is outside this range\n"));
669 printf(_("\n\
670 Optional Arguments:\n\
671 -m, --metric=TYPE\n\
672 Check thresholds against metric. Valid types:\n\
673 PROCS - number of processes (default)\n\
674 VSZ - virtual memory size\n\
675 RSS - resident set memory size\n\
676 CPU - percentage cpu\n"));
677 /* only linux etime is support currently */
678 #if defined( __linux__ )
679 printf(_("\
680 ELAPSED - time elapsed in seconds\n"));
681 #endif /* defined(__linux__) */
682 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
684 printf(_("\
685 -v, --verbose\n\
686 Extra information. Up to 3 verbosity levels\n"));
688 printf(_("\n\
689 Optional Filters:\n\
690 -s, --state=STATUSFLAGS\n\
691 Only scan for processes that have, in the output of `ps`, one or\n\
692 more of the status flags you specify (for example R, Z, S, RS,\n\
693 RSZDT, plus others based on the output of your 'ps' command).\n\
694 -p, --ppid=PPID\n\
695 Only scan for children of the parent process ID indicated.\n\
696 -z, --vsz=VSZ\n\
697 Only scan for processes with vsz higher than indicated.\n\
698 -r, --rss=RSS\n\
699 Only scan for processes with rss higher than indicated.\n"));
701 printf(_("\
702 -P, --pcpu=PCPU\n\
703 Only scan for processes with pcpu higher than indicated.\n\
704 -u, --user=USER\n\
705 Only scan for processes with user name or ID indicated.\n\
706 -a, --argument-array=STRING\n\
707 Only scan for processes with args that contain STRING.\n\
708 -C, --command=COMMAND\n\
709 Only scan for exact matches of COMMAND (without path).\n"));
711 printf(_("\n\
712 RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
713 specified 'max:min', a warning status will be generated if the\n\
714 count is inside the specified range\n\n"));
716 printf(_("\
717 This plugin checks the number of currently running processes and\n\
718 generates WARNING or CRITICAL states if the process count is outside\n\
719 the specified threshold ranges. The process count can be filtered by\n\
720 process owner, parent process PID, current state (e.g., 'Z'), or may\n\
721 be the total number of running processes\n\n"));
723 printf(_("\
724 Examples:\n\
725 check_procs -w 2:2 -c 2:1024 -C portsentry\n\
726 Warning if not two processes with command name portsentry. Critical\n\
727 if < 2 or > 1024 processes\n\n\
728 check_procs -w 10 -a '/usr/local/bin/perl' -u root\n\
729 Warning alert if > 10 processes with command arguments containing \n\
730 '/usr/local/bin/perl' and owned by root\n\n\
731 check_procs -w 50000 -c 100000 --metric=VSZ\n\
732 Alert if vsz of any processes over 50K or 100K\n\
733 check_procs -w 10 -c 20 --metric=CPU\n\
734 Alert if cpu of any processes over 10%% or 20%%\n\n"));
736 printf (_(UT_SUPPORT));
737 }
739 void
740 print_usage (void)
741 {
742 printf (_("Usage:"));
743 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
744 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
745 printf (" [-C command] [-t timeout] [-v]\n");
746 }