fix tiny memleak when $top is used wrong
[monky] / src / top.c
index ff5fa00..d230679 100644 (file)
--- a/src/top.c
+++ b/src/top.c
@@ -11,7 +11,7 @@
  *
  * Copyright (c) 2005 Adi Zaimi, Dan Piponi <dan@tanelorn.demon.co.uk>,
  *                                       Dave Clark <clarkd@skynet.ca>
- * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
+ * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
  *     (see AUTHORS)
  * All rights reserved.
  *
@@ -131,7 +131,7 @@ struct process *get_process_by_name(const char *name)
        struct process *p = first_process;
 
        while (p) {
-               if (!strcmp(p->name, name))
+               if (p->name && !strcmp(p->name, name))
                        return p;
                p = p->next;
        }
@@ -200,6 +200,7 @@ static struct process *new_process(int p)
 static int process_parse_stat(struct process *process)
 {
        char line[BUFFER_LEN] = { 0 }, filename[BUFFER_LEN], procname[BUFFER_LEN];
+       char state[4];
        int ps;
        unsigned long user_time = 0;
        unsigned long kernel_time = 0;
@@ -235,13 +236,17 @@ static int process_parse_stat(struct process *process)
        rc = MIN((unsigned)(rparen - lparen - 1), sizeof(procname) - 1);
        strncpy(procname, lparen + 1, rc);
        procname[rc] = '\0';
-       rc = sscanf(rparen + 1, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu "
-                       "%lu %*s %*s %*s %d %*s %*s %*s %u %u", &process->user_time,
+       rc = sscanf(rparen + 1, "%3s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu "
+                       "%lu %*s %*s %*s %d %*s %*s %*s %u %u", state, &process->user_time,
                        &process->kernel_time, &nice_val, &process->vsize, &process->rss);
-       if (rc < 5) {
+       if (rc < 6) {
                NORM_ERR("scaning data for %s failed, got only %d fields", procname, rc);
                return 1;
        }
+
+       if(state[0]=='R')
+               ++ info.run_procs;
+
        /* remove any "kdeinit: " */
        if (procname == strstr(procname, "kdeinit")) {
                snprintf(filename, sizeof(filename), PROCFS_CMDLINE_TEMPLATE,
@@ -424,6 +429,7 @@ static int update_process_table(void)
                return 1;
        }
 
+       info.run_procs = 0;
        ++g_time;
 
        /* Get list of processes from /proc directory */
@@ -874,16 +880,22 @@ int parse_top_args(const char *s, const char *arg, struct text_object *obj)
 #else /* IOSTATS */
                        NORM_ERR("must be one of: name, cpu, pid, mem, time, mem_res, mem_vsize");
 #endif /* IOSTATS */
+                       free_and_zero(td->s);
+                       free_and_zero(obj->data.opaque);
                        return 0;
                }
                if (n < 1 || n > 10) {
                        NORM_ERR("invalid num arg for top. Must be between 1 and 10.");
+                       free_and_zero(td->s);
+                       free_and_zero(obj->data.opaque);
                        return 0;
                } else {
                        td->num = n - 1;
                }
        } else {
                NORM_ERR("invalid argument count for top");
+               free_and_zero(td->s);
+               free_and_zero(obj->data.opaque);
                return 0;
        }
        return 1;
@@ -929,11 +941,22 @@ static char *format_time(unsigned long timeval, const int width)
        return strndup("<inf>", text_buffer_size);
 }
 
-void print_top(struct text_object *obj, char *p, int top_name_width)
+static unsigned int top_name_width = 15;
+
+/* return zero on success, non-zero otherwise */
+int set_top_name_width(const char *s)
+{
+       if (!s)
+               return 0;
+       return !(sscanf(s, "%u", &top_name_width) == 1);
+}
+
+void print_top(struct text_object *obj, char *p, int p_max_size)
 {
        struct information *cur = &info;
        struct top_data *td = obj->data.opaque;
        struct process **needed = 0;
+       int width;
 
        if (!td)
                return;
@@ -948,60 +971,69 @@ void print_top(struct text_object *obj, char *p, int top_name_width)
                case OBJ_top_time:
                        needed = cur->time;
                        break;
+#ifdef IOSTATS
                case OBJ_top_io:
                        needed = cur->io;
                        break;
+#endif /* IOSTATS */
                default:
                        return;
        }
 
+
        if (needed[td->num]) {
                char *timeval;
 
                switch (td->type) {
                        case TOP_NAME:
-                               snprintf(p, top_name_width + 1, "%-*s", top_name_width,
+                               width = MIN(p_max_size, (int)top_name_width + 1);
+                               snprintf(p, width + 1, "%-*s", width,
                                                needed[td->num]->name);
                                break;
                        case TOP_CPU:
-                               snprintf(p, 7, "%6.2f",
+                               width = MIN(p_max_size, 7);
+                               snprintf(p, width, "%6.2f",
                                                needed[td->num]->amount);
                                break;
                        case TOP_PID:
-                               snprintf(p, 6, "%5i",
+                               width = MIN(p_max_size, 6);
+                               snprintf(p, width, "%5i",
                                                needed[td->num]->pid);
                                break;
                        case TOP_MEM:
                                /* Calculate a percentage of residential mem from total mem available.
                                 * Since rss is bytes and memmax kilobytes, dividing by 10 suffices here. */
-                               snprintf(p, 7, "%6.2f",
+                               width = MIN(p_max_size, 7);
+                               snprintf(p, width, "%6.2f",
                                                (float) ((float)needed[td->num]->rss / cur->memmax) / 10);
                                break;
                        case TOP_TIME:
+                               width = MIN(p_max_size, 10);
                                timeval = format_time(
                                                needed[td->num]->total_cpu_time, 9);
-                               snprintf(p, 10, "%9s", timeval);
+                               snprintf(p, width, "%9s", timeval);
                                free(timeval);
                                break;
                        case TOP_MEM_RES:
                                human_readable(needed[td->num]->rss,
-                                               p, 255);
+                                               p, p_max_size);
                                break;
                        case TOP_MEM_VSIZE:
                                human_readable(needed[td->num]->vsize,
-                                               p, 255);
+                                               p, p_max_size);
                                break;
 #ifdef IOSTATS
                        case TOP_READ_BYTES:
                                human_readable(needed[td->num]->read_bytes / update_interval,
-                                               p, 255);
+                                               p, p_max_size);
                                break;
                        case TOP_WRITE_BYTES:
                                human_readable(needed[td->num]->write_bytes / update_interval,
-                                               p, 255);
+                                               p, p_max_size);
                                break;
                        case TOP_IO_PERC:
-                               snprintf(p, 7, "%6.2f",
+                               width = MIN(p_max_size, 7);
+                               snprintf(p, width, "%6.2f",
                                                needed[td->num]->io_perc);
                                break;
 #endif