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
> 

Reply via email to