killall, pidof: use argv0 for process matching too
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 30 Jun 2007 08:03:26 +0000 (08:03 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 30 Jun 2007 08:03:26 +0000 (08:03 -0000)
top: show cmdline, not comm field
(fixes problems with re-execed applets showing as processes with name "exe",
and not being found by pidof/killall by applet name)

function                                             old     new   delta
find_pid_by_name                                      98     156     +58
procps_scan                                          692     732     +40
top_main                                            2724    2762     +38
find_pair                                            164     180     +16
collect_int                                          114     123      +9
cmp_main                                             547     555      +8
collect_fork                                         112     119      +7
collect_ctx                                          112     119      +7
read_package_field                                   253     257      +4
passwd_main                                         1983    1985      +2
process_stdin                                        435     433      -2
xstrtoul_range_sfx                                   229     226      -3
get_next_block                                      1852    1849      -3
arith                                               2042    2033      -9
sv_main                                             1236    1226     -10
singlemount                                         4690    4672     -18
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 10/6 up/down: 189/-45)          Total: 144 bytes
   text    data     bss     dec     hex filename
 734789    3028   14400  752217   b7a59 busybox_old
 734933    3028   14400  752361   b7ae9 busybox_unstripped

include/libbb.h
libbb/find_pid_by_name.c
libbb/procps.c
procps/top.c

index 124b11fa8ed5caebc5ff860676af4554e66fd4bf..e80e76403bc2bc09c49a07edb39f4f48772c56b0 100644 (file)
@@ -836,6 +836,8 @@ typedef struct {
        DIR *dir;
 /* Fields are set to 0/NULL if failed to determine (or not requested) */
        char *cmd;
+       char *argv0;
+       /*char *exe;*/
        USE_SELINUX(char *context;)
        /* Everything below must contain no ptrs to malloc'ed data:
         * it is memset(0) for each process in procps_scan() */
@@ -861,13 +863,15 @@ enum {
        PSSCAN_UIDGID   = 1 << 4,
        PSSCAN_COMM     = 1 << 5,
        PSSCAN_CMD      = 1 << 6,
-       PSSCAN_STATE    = 1 << 7,
-       PSSCAN_VSZ      = 1 << 8,
-       PSSCAN_RSS      = 1 << 9,
-       PSSCAN_STIME    = 1 << 10,
-       PSSCAN_UTIME    = 1 << 11,
-       PSSCAN_TTY      = 1 << 12,
-       USE_SELINUX(PSSCAN_CONTEXT  = 1 << 13,)
+       PSSCAN_ARGV0    = 1 << 7,
+       PSSCAN_EXE      = 1 << 8, /* not implemented yet */
+       PSSCAN_STATE    = 1 << 9,
+       PSSCAN_VSZ      = 1 << 10,
+       PSSCAN_RSS      = 1 << 11,
+       PSSCAN_STIME    = 1 << 12,
+       PSSCAN_UTIME    = 1 << 13,
+       PSSCAN_TTY      = 1 << 14,
+       USE_SELINUX(PSSCAN_CONTEXT  = 1 << 15,)
        /* These are all retrieved from proc/NN/stat in one go: */
        PSSCAN_STAT     = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
                        | PSSCAN_COMM | PSSCAN_STATE
index 13ccb545d08ab3e06cb819689eebff2287d4187e..cfc5b346889d975fa864c5ef1c3911c6206084da 100644 (file)
@@ -38,6 +38,14 @@ execXXX("/proc/self/exe", applet_name, params....)
 and therefore comm field contains "exe".
 */
 
+static const char *bb_basename(const char *name)
+{
+       const char *cp = strrchr(name, '/');
+       if (cp)
+               return cp + 1;
+       return name;
+}
+
 /* find_pid_by_name()
  *
  *  Modified by Vladimir Oleynik for use with libbb/procps.c
@@ -55,8 +63,16 @@ pid_t* find_pid_by_name(const char* procName)
        procps_status_t* p = NULL;
 
        pidList = xmalloc(sizeof(*pidList));
-       while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM))) {
-               if (strncmp(p->comm, procName, sizeof(p->comm)-1) == 0) {
+       while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGV0))) {
+               if (
+               /* we require comm to match and to not be truncated */
+               /* in Linux, if comm is 15 chars, it may be a truncated
+                * name, so we don't allow that to match */
+                   (!p->comm[sizeof(p->comm)-2] && strcmp(p->comm, procName) == 0)
+               /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
+                || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
+               /* TOOD: we can also try exe, do we want that? */
+               ) {
                        pidList = xrealloc(pidList, sizeof(*pidList) * (i+2));
                        pidList[i++] = p->pid;
                }
index 5924d60a84487a3eeaff058beec33ba8b72c6d06..8413ce8a1b01fc68ff069e4ebf72295f940bf445 100644 (file)
@@ -92,7 +92,7 @@ static int read_to_buf(const char *filename, void *buf)
        return ret;
 }
 
-procps_status_talloc_procps_scan(int flags)
+procps_status_t *alloc_procps_scan(int flags)
 {
        procps_status_t* sp = xzalloc(sizeof(procps_status_t));
        sp->dir = xopendir("/proc");
@@ -133,7 +133,7 @@ static char *skip_fields(char *str, int count)
 #endif
 
 void BUG_comm_size(void);
-procps_status_tprocps_scan(procps_status_t* sp, int flags)
+procps_status_t *procps_scan(procps_status_t* sp, int flags)
 {
        struct dirent *entry;
        char buf[PROCPS_BUFSIZE];
@@ -266,24 +266,31 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags)
 
                }
 
-               if (flags & PSSCAN_CMD) {
-                       free(sp->cmd);
-                       sp->cmd = NULL;
+               if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
+                       if (sp->argv0) {
+                               free(sp->argv0);
+                               sp->argv0 = NULL;
+                       }
+                       if (sp->cmd) {
+                               free(sp->cmd);
+                               sp->cmd = NULL;
+                       }
                        strcpy(filename_tail, "/cmdline");
+                       /* TODO: to get rid of size limits, read into malloc buf,
+                        * then realloc it down to real size. */
                        n = read_to_buf(filename, buf);
                        if (n <= 0)
                                break;
-                       if (buf[n-1] == '\n') {
-                               if (!--n)
-                                       break;
-                               buf[n] = '\0';
+                       if (flags & PSSCAN_ARGV0)
+                               sp->argv0 = xstrdup(buf);
+                       if (flags & PSSCAN_CMD) {
+                               do {
+                                       n--;
+                                       if ((unsigned char)(buf[n]) < ' ')
+                                               buf[n] = ' ';
+                               } while (n);
+                               sp->cmd = xstrdup(buf);
                        }
-                       do {
-                               n--;
-                               if ((unsigned char)(buf[n]) < ' ')
-                                       buf[n] = ' ';
-                       } while (n);
-                       sp->cmd = xstrdup(buf);
                }
                break;
        }
index c6efe2d773f6f042c03a687ec1b02e910cd75a4b..136f1404aee06b1fc484565e8153eada7d36ceb1 100644 (file)
@@ -40,7 +40,8 @@ typedef struct top_status_t {
        unsigned pid, ppid;
        unsigned uid;
        char state[4];
-       char comm[COMM_LEN];
+/* TODO: read /proc/$PID/cmdline only for processes which are displayed */
+       char cmd[64];
 } top_status_t;
 
 typedef struct jiffy_counts_t{
@@ -444,7 +445,7 @@ static void display_status(int count, int scr_width)
 #endif
                );
                if (col > 0)
-                       printf("%.*s", col, s->comm);
+                       printf("%.*s", col, s->cmd);
                /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
                        jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
                s++;
@@ -559,6 +560,7 @@ int top_main(int argc, char **argv)
                                | PSSCAN_UTIME
                                | PSSCAN_STATE
                                | PSSCAN_COMM
+                               | PSSCAN_CMD
                                | PSSCAN_SID
                                | PSSCAN_UIDGID
                ))) {
@@ -572,7 +574,10 @@ int top_main(int argc, char **argv)
 #endif
                        top[n].uid = p->uid;
                        strcpy(top[n].state, p->state);
-                       strcpy(top[n].comm, p->comm);
+                       if (p->cmd)
+                               safe_strncpy(top[n].cmd, p->cmd, sizeof(top[n].cmd));
+                       else /* mimic ps */
+                               sprintf(top[n].cmd, "[%s]", p->comm);
                }
                if (ntop == 0) {
                        bb_error_msg_and_die("no process info in /proc");
@@ -585,6 +590,7 @@ int top_main(int argc, char **argv)
                        continue;
                }
                do_stats();
+/* TODO: we don't need to sort all 10000 processes, we need to find top 24! */
                qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
 #else
                qsort(top, ntop, sizeof(top_status_t), (void*)sort_function);