On Wed, Feb 10, 2016 at 11:04:18PM +0000, Edd Barrett wrote:
> Hey,
>
> I'd like top(1)'s filter feature (-g) to search process arguments. This
> would make searching for (e.g.) Python scripts by name much easier. The
> current behaviour only searches the program name, which for scripts is
> the interpreter binary name (e.g. python2.7). Currently the best you
> could do to find a Python script by name is to filter for "python", then
> press "C" to enable argument display, then scan the args by eyeball.
>
> Here is a diff that allows searching of arguments, but only if
> arguments are currently being displayed.
>
> I know the timing is bad, but any comments?
>
>
> Index: machine.c
> ===================================================================
> RCS file: /home/edd/cvsync/src/usr.bin/top/machine.c,v
> retrieving revision 1.85
> diff -u -p -r1.85 machine.c
> --- machine.c 20 Aug 2015 22:32:42 -0000 1.85
> +++ machine.c 6 Feb 2016 15:12:42 -0000
> @@ -57,6 +57,8 @@
> static int swapmode(int *, int *);
> static char *state_abbr(struct kinfo_proc *);
> static char *format_comm(struct kinfo_proc *);
> +int cmd_matches(struct kinfo_proc *proc, char *cmd);
> +static char **get_proc_args(struct kinfo_proc *kp);
>
> /* get_process_info passes back a handle. This is what it looks like: */
>
> @@ -360,6 +362,54 @@ getprocs(int op, int arg, int *cnt)
> return (procbase);
> }
>
> +static char **
> +get_proc_args(struct kinfo_proc *kp)
> +{
> + static char **s;
> + size_t siz = 100;
> + int mib[4];
> +
> + for (;; siz *= 2) {
> + if ((s = realloc(s, siz)) == NULL)
> + err(1, NULL);
> + mib[0] = CTL_KERN;
> + mib[1] = KERN_PROC_ARGS;
> + mib[2] = kp->p_pid;
> + mib[3] = KERN_PROC_ARGV;
> + if (sysctl(mib, 4, s, &siz, NULL, 0) == 0)
> + break;
> + if (errno != ENOMEM)
> + return (NULL);
> + }
> + return (s);
> +}
> +
> +int
> +cmd_matches(struct kinfo_proc *proc, char *term)
> +{
> + extern int show_args;
> + char **args = NULL, **arg = NULL;
> +
> + if (!term) {
> + /* No command filter set */
> + return (1);
> + } else {
> + /* Filter set, process name needs to contain term */
> + if (strstr(proc->p_comm, term)) {
> + return (1);
> + }
> + /* If showing arguments, search those as well */
> + if (show_args) {
> + args = get_proc_args(proc);
> + for (arg = args; *arg != NULL; arg++) {
^^^^
NULL pointer dereference is possible here.
Also, unclear why you need both arg and args variables.
--patrick
> + if (strstr(*arg, term))
> + return (1);
> + }
> + }
> + }
> + return (0);
> +}
> +
> caddr_t
> get_process_info(struct system_info *si, struct process_select *sel,
> int (*compare) (const void *, const void *))
> @@ -421,8 +471,7 @@ get_process_info(struct system_info *si,
> (!hide_uid || pp->p_ruid != sel->huid) &&
> (!show_uid || pp->p_ruid == sel->uid) &&
> (!show_pid || pp->p_pid == sel->pid) &&
> - (!show_cmd || strstr(pp->p_comm,
> - sel->command))) {
> + (!show_cmd || cmd_matches(pp, sel->command))) {
> *prefp++ = pp;
> active_procs++;
> }
> @@ -462,27 +511,17 @@ state_abbr(struct kinfo_proc *pp)
> static char *
> format_comm(struct kinfo_proc *kp)
> {
> - static char **s, buf[MAX_COLS];
> - size_t siz = 100;
> - char **p;
> - int mib[4];
> + static char buf[MAX_COLS];
> + char **p, **s;
> extern int show_args;
>
> if (!show_args)
> return (kp->p_comm);
>
> - for (;; siz *= 2) {
> - if ((s = realloc(s, siz)) == NULL)
> - err(1, NULL);
> - mib[0] = CTL_KERN;
> - mib[1] = KERN_PROC_ARGS;
> - mib[2] = kp->p_pid;
> - mib[3] = KERN_PROC_ARGV;
> - if (sysctl(mib, 4, s, &siz, NULL, 0) == 0)
> - break;
> - if (errno != ENOMEM)
> - return (kp->p_comm);
> - }
> + s = get_proc_args(kp);
> + if (s == NULL)
> + return (kp->p_comm);
> +
> buf[0] = '\0';
> for (p = s; *p != NULL; p++) {
> if (p != s)
> Index: top.1
> ===================================================================
> RCS file: /home/edd/cvsync/src/usr.bin/top/top.1,v
> retrieving revision 1.66
> diff -u -p -r1.66 top.1
> --- top.1 6 May 2015 07:53:29 -0000 1.66
> +++ top.1 6 Feb 2016 15:03:50 -0000
> @@ -107,7 +107,8 @@ The default is 1 for dumb terminals.
> .It Fl g Ar string
> Display only processes that contain
> .Ar string
> -in their command name.
> +in their command name. If displaying of arguments is enabled, the
> +arguments are searched too.
> .It Fl H
> Show process threads in the display.
> Normally, only the main process is shown.
> @@ -305,7 +306,8 @@ command.
> .It g Ar string
> Display only processes that contain
> .Ar string
> -in their command name.
> +in their command name. If displaying of arguments is enabled, the
> +arguments are searched too.
> .Sq g+
> shows all processes.
> .It H
>
> --
> Best Regards
> Edd Barrett
>
> http://www.theunixzoo.co.uk
>