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