Index: usr.bin/top/commands.h =================================================================== --- usr.bin/top/commands.h +++ usr.bin/top/commands.h @@ -46,6 +46,7 @@ CMD_order, CMD_pid , CMD_toggletid, + CMD_filter, }; struct command { Index: usr.bin/top/commands.c =================================================================== --- usr.bin/top/commands.c +++ usr.bin/top/commands.c @@ -56,6 +56,7 @@ {'C', "toggle the displaying of weighted CPU percentage", false, CMD_wcputog}, {'d', "change number of displays to show", false, CMD_displays}, {'e', "list errors generated by last \"kill\" or \"renice\" command", false, CMD_errors}, + {'/', "filter by command (enter for all)", false, CMD_filter}, {'H', "toggle the displaying of threads", false, CMD_thrtog}, {'h', "show this help text", true, CMD_help}, {'?', NULL, true, CMD_help}, Index: usr.bin/top/machine.c =================================================================== --- usr.bin/top/machine.c +++ usr.bin/top/machine.c @@ -224,6 +224,7 @@ static int swapmode(int *retavail, int *retfree); static void update_layout(void); static int find_uid(uid_t needle, int *haystack); +static int cmd_match(struct kinfo_proc *pp, const char *pattern); static int find_uid(uid_t needle, int *haystack) @@ -730,6 +731,32 @@ return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy)); } +static int +cmd_match(struct kinfo_proc *pp, const char *pattern) +{ + char **argv; + + /* matched with command name */ + if (strcasestr(pp->ki_comm, pattern) != NULL) + return (1); + + /* when displaying command arguments, check those too */ + if (fmt_flags & FMT_SHOWARGS) { + argv = kvm_getargv(kd, pp, 0); + + if (argv != NULL) { + while (*argv != NULL) { + /* found a match */ + if (strcasestr(*argv, pattern) != NULL) + return (1); + argv++; + } + } + } + /* no match */ + return (0); +} + static struct handle handle; void * @@ -843,6 +870,10 @@ if (!sel->kidle && pp->ki_tdflags & TDF_IDLETD && sel->pid == -1) /* skip kernel idle process */ + continue; + + if (sel->command != NULL && !cmd_match(pp, sel->command)) + /* skip processes that don't match the command name */ continue; PCTCPU(pp) = proc_calc_pctcpu(pp); Index: usr.bin/top/top.h =================================================================== --- usr.bin/top/top.h +++ usr.bin/top/top.h @@ -31,6 +31,7 @@ extern enum displaymodes displaymode; +extern int fmt_flags; extern int pcpu_stats; extern int overstrike; extern pid_t mypid; Index: usr.bin/top/top.1 =================================================================== --- usr.bin/top/top.1 +++ usr.bin/top/top.1 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.Dd September 21, 2019 +.Dd November 4, 2020 .Dt TOP 1 .Os .Sh NAME @@ -11,6 +11,7 @@ .Op Fl J Ar jail .Op Fl U Ar uid .Op Fl d Ar count +.Op Fl g Ar string .Op Fl m Ar cpu|io .Op Fl s Ar time .Op Fl o Ar field @@ -144,6 +145,15 @@ .Ar count = 1 no information is available about the percentage of time spent by the CPU in every state. +.It Fl g Ar string +Show only those processes that contain +.Ar string +in their command name. +When used with +.Fl a , +processes with command arguments that contain +.Ar string +will also be displayed. .It Fl s Ar time Set the delay between screen updates to .Ar time @@ -239,10 +249,19 @@ .It d Change the number of displays to show (prompt for new number). Remember that the next display counts as one, so typing -.It d1 +.Dq d1 will make .Nm show one final display and then immediately exit. +.It / +Display only processes where the command name matches a simple text +pattern (prompt for pattern). +When +.Dq a +is toggled, the command arguments will also be checked. +Pressing +.Dq enter +with no input will display all processes. .It m Toggle the display between 'cpu' and 'io' modes. .It n or # Index: usr.bin/top/top.c =================================================================== --- usr.bin/top/top.c +++ usr.bin/top/top.c @@ -52,7 +52,7 @@ /* The buffer that stdio will use */ static char stdoutbuf[Buffersize]; -static int fmt_flags = 0; +int fmt_flags = 0; int pcpu_stats = false; /* signal handling routines */ @@ -99,6 +99,7 @@ { "batch", no_argument, NULL, 'b' }, /* c reserved */ { "displays", required_argument, NULL, 'd' }, + { "cmd-filter", required_argument, NULL, 'g' }, { "interactive", no_argument, NULL, 'i' }, { "jail-id", no_argument, NULL, 'j' }, { "display-mode", required_argument, NULL, 'm' }, @@ -229,6 +230,7 @@ struct statics statics; void * processes; + char cmd[50]; static char tempbuf1[50]; static char tempbuf2[50]; sigset_t old_sigmask, new_sigmask; @@ -312,7 +314,7 @@ optind = 1; } - while ((i = getopt_long(ac, __DECONST(char * const *, av), "CSIHPabijJ:nquvzs:d:U:m:o:p:Ttw", longopts, NULL)) != EOF) + while ((i = getopt_long(ac, __DECONST(char * const *, av), "CSIHPabijJ:nquvzs:d:g:U:m:o:p:Ttw", longopts, NULL)) != EOF) { switch(i) { @@ -363,6 +365,10 @@ displays = i; } break; + case 'g': + snprintf(cmd, sizeof(cmd), "%s", optarg); + ps.command = cmd; + break; case 'p': { unsigned long long num; const char *errstr; @@ -464,7 +470,7 @@ default: errx(1, -"[-abCHIijnPqStuvwz] [-d count] [-m io | cpu] [-o field] [-p pid]\n" +"[-abCgHIijnPqStuvwz] [-d count] [-g string] [-m io | cpu] [-o field] [-p pid]\n" " [-s time] [-J jail] [-U username] [number]"); } } @@ -976,6 +982,17 @@ case CMD_user: if (handle_user(tempbuf2, sizeof(tempbuf2))) no_command = true; + break; + + case CMD_filter: + new_message(MT_standout, + " Filter by command (enter for all): "); + + if (readline(cmd, sizeof(cmd), false) > 0) { + ps.command = cmd; + putchar('\r'); + } else + clear_message(); break; case CMD_thrtog: