From a7465b61f4a5eedc08d1a1223c2f32b86ad5fd0b Mon Sep 17 00:00:00 2001 From: Mike Massonnet Date: Sat, 8 May 2010 00:10:22 +0200 Subject: [PATCH] Fix for scanf failing at parsing process names with spaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code still uses scanf to parse the stat file, but the process name is being cleansed so that it never fails. The name is read from the “comm” file. It is still a truncated version of the name, and will likely remain for very long like this. There is one solution, but since the name isn't currently used inside the interface there is no point wasting time. --- src/task-manager-linux.c | 42 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/task-manager-linux.c b/src/task-manager-linux.c index 56583cb..f1aa1e9 100644 --- a/src/task-manager-linux.c +++ b/src/task-manager-linux.c @@ -116,19 +116,9 @@ get_task_cmdline (Task *task) gchar c; snprintf (filename, 96, "/proc/%i/cmdline", task->pid); - if ((file = fopen (filename, "r")) == NULL) - return; - - /* Drop parentheses around task->name */ - // FIXME comm concats the name to 15 chars - { - gchar *p; - g_strlcpy (task->name, &task->name[1], sizeof (task->name)); - p = g_strrstr (task->name, ")"); - *p = '\0'; - } /* Read byte per byte until EOF */ + file = fopen (filename, "r"); for (i = 0; (c = fgetc (file)) != EOF && i < sizeof (task->cmdline) - 1; i++) task->cmdline[i] = (c == '\0') ? ' ' : c; if (task->cmdline[i-1] == ' ') @@ -181,6 +171,7 @@ get_task_details (guint pid, Task *task) FILE *file; gchar filename[96]; gchar buffer[1024]; + gchar *p1, *p2; snprintf (filename, 96, "/proc/%d/stat", pid); if ((file = fopen (filename, "r")) == NULL) @@ -189,19 +180,34 @@ get_task_details (guint pid, Task *task) fgets (buffer, 1024, file); fclose (file); + /* Scanning the short process name is unreliable with scanf when it contains spaces */ + p1 = g_strrstr (buffer, "("); + p2 = g_strrstr (buffer, ")"); + while (p1 <= p2) { - gchar dummy[255]; + *p1 = 'x'; + p1++; + } + + /* Retrieve the short name from the comm file */ + snprintf (filename, 96, "/proc/%d/comm", pid); + file = fopen (filename, "r"); + fscanf (file, "%255s", task->name); + fclose (file); + + /* Parse the stat file */ + { + gchar dummy[256]; gint idummy; gulong jiffies_user, jiffies_system; struct passwd *pw; struct stat sstat; - guint ppid = 0; sscanf(buffer, "%i %255s %1s %i %i %i %i %i %255s %255s %255s %255s %255s %i %i %i %i %i %i %i %i %i %i %i %255s %255s %255s %i %255s %255s %255s %255s %255s %255s %255s %255s %255s %255s %i %255s %255s", &task->pid, // processid - task->name, // processname + dummy, // processname task->state, // processstate - &ppid, // parentid + &task->ppid, // parentid &idummy, // processs groupid &idummy, // session id @@ -249,11 +255,6 @@ get_task_details (guint pid, Task *task) dummy ); - // FIXME sscanf sucks, big news, process names with spaces don't pass - if (ppid == 0) - return FALSE; - - task->ppid = ppid; task->rss *= get_pagesize (); get_cpu_percent (task->pid, jiffies_user, &task->cpu_user, jiffies_system, &task->cpu_system); @@ -263,6 +264,7 @@ get_task_details (guint pid, Task *task) g_strlcpy (task->uid_name, (pw != NULL) ? pw->pw_name : "nobody", sizeof (task->uid_name)); } + /* Read the full command line */ get_task_cmdline (task); return TRUE;