diff --git a/doc/variables.xml b/doc/variables.xml
index f97ab572..9753c507 100644
--- a/doc/variables.xml
+++ b/doc/variables.xml
@@ -1849,9 +1849,21 @@
- if PROCESS is running, display everything
- $if_running and the matching $endif. This uses the
- ``pidof'' command, so the -x switch is also supported.
+ If PROCESS is running, display everything
+ between $if_running and the corresponding $else or $endif.
+ Note that PROCESS may be either a full command line with
+ arguments (without the directory prefix), or simply the name
+ of an executable. For example, either of the following will
+ be true if there is a running process with the command line
+ /usr/bin/conky -u 5:
+
+
+ ${if_running conky -u 5} or
+ ${if_running conky}
+
+
+ It is important not to include trailing spaces. For example,
+ ${if_running conky } will be false.
diff --git a/src/linux.cc b/src/linux.cc
index a43f4a38..181da2f4 100644
--- a/src/linux.cc
+++ b/src/linux.cc
@@ -2628,6 +2628,7 @@ static void process_parse_stat(struct process *process)
{
char line[BUFFER_LEN] = { 0 }, filename[BUFFER_LEN], procname[BUFFER_LEN];
char cmdline[BUFFER_LEN] = { 0 }, cmdline_filename[BUFFER_LEN], cmdline_procname[BUFFER_LEN];
+ char basename[BUFFER_LEN] = { 0 };
char tmpstr[BUFFER_LEN] = { 0 };
char state[4];
int ps, cmdline_ps;
@@ -2675,36 +2676,39 @@ static void process_parse_stat(struct process *process)
return;
}
- /* Some processes have null-separated arguments, let's fix it */
- for(int i = 0; i < endl; i++)
- if (cmdline[i] == 0)
+ /* Some processes have null-separated arguments (see proc(5)); let's fix it */
+ int i = endl;
+ while (i && cmdline[i-1] == 0) {
+ /* Skip past any trailing null characters */
+ --i;
+ }
+ while (i--) {
+ /* Replace null character between arguments with a space */
+ if (cmdline[i] == 0) {
cmdline[i] = ' ';
+ }
+ }
cmdline[endl] = 0;
+
/* We want to transform for example "/usr/bin/python program.py" to "python program.py"
* 1. search for first space
* 2. search for last / before first space
- * 3. copy string from it's position */
-
- char * space_ptr = strchr(cmdline, ' ');
- if (space_ptr == NULL)
- {
+ * 3. copy string from its position
+ */
+ char *space_ptr = strchr(cmdline, ' ');
+ if (space_ptr == NULL) {
strcpy(tmpstr, cmdline);
- }
- else
- {
+ } else {
long int space_pos = space_ptr - cmdline;
strncpy(tmpstr, cmdline, space_pos);
tmpstr[space_pos] = 0;
}
- char * slash_ptr = strrchr(tmpstr, '/');
- if (slash_ptr == NULL )
- {
+ char *slash_ptr = strrchr(tmpstr, '/');
+ if (slash_ptr == NULL) {
strncpy(cmdline_procname, cmdline, BUFFER_LEN);
- }
- else
- {
+ } else {
long int slash_pos = slash_ptr - tmpstr;
strncpy(cmdline_procname, cmdline + slash_pos + 1, BUFFER_LEN - slash_pos);
cmdline_procname[BUFFER_LEN - slash_pos] = 0;
@@ -2713,15 +2717,16 @@ static void process_parse_stat(struct process *process)
/* Extract cpu times from data in /proc filesystem */
lparen = strchr(line, '(');
rparen = strrchr(line, ')');
- if(!lparen || !rparen || rparen < lparen)
+ if (!lparen || !rparen || rparen < lparen)
return; // this should not happen
rc = MIN((unsigned)(rparen - lparen - 1), sizeof(procname) - 1);
strncpy(procname, lparen + 1, rc);
procname[rc] = '\0';
+ strncpy(basename, procname, strlen(procname) + 1);
if (strlen(procname) < strlen(cmdline_procname))
- strncpy(procname, cmdline_procname, strlen(cmdline_procname)+1);
+ strncpy(procname, cmdline_procname, strlen(cmdline_procname) + 1);
rc = sscanf(rparen + 1, "%3s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu "
"%lu %*s %*s %*s %d %*s %*s %*s %llu %llu", state, &process->user_time,
@@ -2731,43 +2736,13 @@ static void process_parse_stat(struct process *process)
return;
}
- if(state[0]=='R')
+ if (state[0] == 'R')
++ info.run_procs;
- /* remove any "kdeinit: " */
- if (procname == strstr(procname, "kdeinit")) {
- snprintf(filename, sizeof(filename), PROCFS_CMDLINE_TEMPLATE,
- process->pid);
-
- ps = open(filename, O_RDONLY);
- if (ps < 0) {
- /* The process must have finished in the last few jiffies! */
- return;
- }
-
- endl = read(ps, line, BUFFER_LEN - 1);
- close(ps);
- if(endl < 0)
- return;
- line[endl] = 0;
-
- /* account for "kdeinit: " */
- if ((char *) line == strstr(line, "kdeinit: ")) {
- r = ((char *) line) + 9;
- } else {
- r = (char *) line;
- }
-
- q = procname;
- /* stop at space */
- while (*r && *r != ' ') {
- *q++ = *r++;
- }
- *q = 0;
- }
-
free_and_zero(process->name);
+ free_and_zero(process->basename);
process->name = strndup(procname, text_buffer_size.get(*::state));
+ process->basename = strndup(basename, text_buffer_size.get(*::state));
process->rss *= getpagesize();
process->total_cpu_time = process->user_time + process->kernel_time;
diff --git a/src/top.cc b/src/top.cc
index 04cf4050..98907f48 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -32,7 +32,6 @@
#include "prioqueue.h"
#include "top.h"
#include "logging.h"
-#include
/* hash table size - always a power of 2 */
#define HTABSIZE 256
@@ -117,6 +116,7 @@ void free_all_processes(void)
while (pr) {
next = pr->next;
free_and_zero(pr->name);
+ free_and_zero(pr->basename);
free(pr);
pr = next;
}
@@ -131,7 +131,10 @@ struct process *get_process_by_name(const char *name)
struct process *p = first_process;
while (p) {
- if (p->name && !strcmp(p->name, name))
+ /* Try matching against the full command line first. If that fails,
+ * fall back to the basename.
+ */
+ if ((p->name && !strcmp(p->name, name)) || (p->basename && !strcmp(p->basename, name)))
return p;
p = p->next;
}
@@ -165,6 +168,7 @@ static struct process *new_process(pid_t pid)
p->pid = pid;
p->name = 0;
+ p->basename = 0;
p->amount = 0;
p->user_time = 0;
p->total = 0;
@@ -230,6 +234,7 @@ static void delete_process(struct process *p)
first_process = p->next;
free_and_zero(p->name);
+ free_and_zero(p->basename);
/* remove the process from the hash table */
unhash_process(p);
free(p);
@@ -481,7 +486,7 @@ struct top_data {
static conky::range_config_setting top_name_width("top_name_width", 0,
std::numeric_limits::max(), 15, true);
-static conky::simple_config_setting top_name_verbose("top_name_verbose", false, false);
+static conky::simple_config_setting top_name_verbose("top_name_verbose", false, true);
static void print_top_name(struct text_object *obj, char *p, int p_max_size)
{
@@ -491,13 +496,14 @@ static void print_top_name(struct text_object *obj, char *p, int p_max_size)
if (!td || !td->list || !td->list[td->num])
return;
- std::string top_name = td->list[td->num]->name;
- if (!top_name_verbose.get(*state)) {
- top_name = top_name.substr(0, top_name.find_first_of(' '));
- }
-
width = MIN(p_max_size, (int)top_name_width.get(*state) + 1);
- snprintf(p, width + 1, "%-*s", width, top_name.c_str());
+ if (top_name_verbose.get(*state)) {
+ /* print the full command line */
+ snprintf(p, width + 1, "%-*s", width, td->list[td->num]->name);
+ } else {
+ /* print only the basename (i.e. executable name) */
+ snprintf(p, width + 1, "%-*s", width, td->list[td->num]->basename);
+ }
}
static void print_top_mem(struct text_object *obj, char *p, int p_max_size)
diff --git a/src/top.h b/src/top.h
index e9aabe61..328e28d1 100644
--- a/src/top.h
+++ b/src/top.h
@@ -87,6 +87,7 @@ struct process {
pid_t pid;
char *name;
+ char *basename;
uid_t uid;
float amount;
// User and kernel times are in hundredths of seconds