diff --git a/NEWS b/NEWS index 75a0455e..dad76a04 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,9 @@ procps-3.1.2 --> procps-3.1.3 top: user selection -sysctl: -e +sysctl: add -e for Red Hat 8.0 boot scripts +sysctl: the obvious --help, -V, and --version +sysctl: some command line error checking w: stdout, not stderr -- thanks to Sander van Malssen procps-3.1.1 --> procps-3.1.2 diff --git a/proc/ksym.c b/proc/ksym.c index f2eea82e..275c2b0b 100644 --- a/proc/ksym.c +++ b/proc/ksym.c @@ -465,6 +465,8 @@ static void default_message(const char *restrict format, ...) { /*********************************/ +static int use_wchan_file; + int open_psdb_message(const char *restrict override, void (*message)(const char *, ...)) { static const char *sysmap_paths[] = { "/boot/System.map-%s", @@ -474,26 +476,45 @@ int open_psdb_message(const char *restrict override, void (*message)(const char "/System.map", NULL }; + struct stat sbuf; struct utsname uts; char path[64]; const char **fmt = sysmap_paths; - const char *env; - read_and_parse(); + const char *sm; + #ifdef SYSMAP_FILENAME /* debug feature */ override = SYSMAP_FILENAME; #endif - if(override){ /* ought to search some path */ - if(sysmap_mmap(override, message)) return 0; - return -1; /* ought to return "Namelist not found." */ + + // first allow for a user-selected System.map file + if( + (sm=override) + || + (sm=getenv("PS_SYSMAP")) + || + (sm=getenv("PS_SYSTEM_MAP")) + ){ + read_and_parse(); + if(sysmap_mmap(sm, message)) return 0; /* failure is better than ignoring the user & using bad data */ + return -1; /* ought to return "Namelist not found." */ } - /* Arrrgh, the old man page and code did not match. */ - if ((env = getenv("PS_SYSMAP")) && sysmap_mmap(env, message)) return 0; - if ((env = getenv("PS_SYSTEM_MAP")) && sysmap_mmap(env, message)) return 0; + + // next try the Linux 2.5.xx method + if(!stat("/proc/self/wchan", &sbuf)){ + use_wchan_file = 1; // hack + return 0; + } + + // finally, search for the System.map file uname(&uts); do{ + int did_ksyms = 0; snprintf(path, sizeof path, *fmt, uts.release); - if (sysmap_mmap(path, message)) return 0; + if(!stat(path, &sbuf)){ + if (did_ksyms++) read_and_parse(); + if (sysmap_mmap(path, message)) return 0; + } }while(*++fmt); /* TODO: Without System.map, no need to keep ksyms loaded. */ return -1; @@ -507,18 +528,51 @@ int open_psdb(const char *restrict override) { /***************************************/ +const char * read_wchan_file(unsigned pid){ + static char buf[64]; + const char *ret = buf; + ssize_t num; + int fd; + + snprintf(buf, sizeof buf, "/proc/%d/wchan", pid); + fd = open(buf, O_RDONLY); + if(fd==-1) return "?"; + num = read(fd, buf, sizeof buf - 1); + close(fd); + if(num<1) return "?"; // allow for "0" + buf[num] = '\0'; + + if(buf[0]=='0' && buf[1]=='\0') return "-"; + + // would skip over numbers if they existed -- but no + + switch(*ret){ + case 's': if(!strncmp(ret, "sys_", 4)) ret += 4; break; + case 'd': if(!strncmp(ret, "do_", 3)) ret += 3; break; + case '_': while(*ret=='_') ret++; break; + } + return ret; +} + +/***************************************/ + #define MAX_OFFSET (0x1000*sizeof(long)) /* past this is generally junk */ /* return pointer to temporary static buffer with function name */ -const char * wchan(unsigned long address) { +const char * wchan(unsigned long address, unsigned pid) { const symb *mod_symb; const symb *map_symb; const symb *good_symb; const char *ret; - unsigned hash = (address >> 4) & 0xff; /* got 56/63 hits & 7/63 misses */ - if(!address) return dash; - read_and_parse(); + unsigned hash; + // can't cache it due to a race condition :-( + if(use_wchan_file) return read_wchan_file(pid); + + if(!address) return dash; + + read_and_parse(); + hash = (address >> 4) & 0xff; /* got 56/63 hits & 7/63 misses */ if(hashtable[hash].addr == address) return hashtable[hash].name; mod_symb = search(address, ksyms_index, ksyms_count); if(!mod_symb) mod_symb = &fail; diff --git a/proc/wchan.h b/proc/wchan.h index ad71b716..061dfe91 100644 --- a/proc/wchan.h +++ b/proc/wchan.h @@ -5,7 +5,7 @@ EXTERN_C_BEGIN -extern const char * wchan(unsigned long address); +extern const char * wchan(unsigned long address, unsigned pid); extern int open_psdb(const char *restrict override); extern int open_psdb_message(const char *restrict override, void (*message)(const char *, ...)); diff --git a/ps/output.c b/ps/output.c index 72d62ef8..d0216505 100644 --- a/ps/output.c +++ b/ps/output.c @@ -567,7 +567,7 @@ static int pr_wchan(char *restrict const outbuf, const proc_t *restrict const pp */ if(!(pp->wchan & 0xffffff)) return snprintf(outbuf, COLWID, "%s", "-"); if(wchan_is_number) return snprintf(outbuf, COLWID, "%lx", pp->wchan & 0xffffff); - return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan)); + return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan, pp->pid)); } /* Terrible trunctuation, like BSD crap uses: I999 J999 K999 */ @@ -773,7 +773,7 @@ static int pr_wname(char *restrict const outbuf, const proc_t *restrict const pp * more than one thread waiting in the kernel. */ if(!(pp->wchan & 0xffffff)) return snprintf(outbuf, COLWID, "%s", "-"); - return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan)); + return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan, pp->pid)); } static int pr_nwchan(char *restrict const outbuf, const proc_t *restrict const pp){ diff --git a/top.c b/top.c index 7348c005..df939819 100644 --- a/top.c +++ b/top.c @@ -3019,7 +3019,7 @@ static void task_show (const WIN_t *q, const proc_t *p) #endif MKCOL((long)p->wchan); } else { - MKCOL(wchan(p->wchan)); + MKCOL(wchan(p->wchan, p->pid)); } break;