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