replace /proc scanning code by more versatile one. Use it where appropriate. Stop scanning /etc/passwd *for every process*!!! (uid->username) top: reduce memory usage - we won't save unneeded fields from /proc info anymore. Downside: ~+250 bytes of code
No binary (build failed)
—
(log yok)
| @@ -501,23 +501,47 @@ enum { COMM_LEN = 16 }; | |
| #endif | |
| #endif | |
| typedef struct { | |
| - | int pid, ppid; |
| - | char user[9]; |
| - | char state[4]; |
| + | DIR *dir; |
| + | /* Fields are set to 0/NULL if failed to determine (or not requested) */ |
| + | char *cmd; |
| unsigned long rss; | |
| - | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| - | unsigned pcpu; |
| unsigned long stime, utime; | |
| - | #endif |
| - | char *cmd; |
| - | |
| - | /* basename of executable file in call to exec(2), |
| - | size from kernel headers */ |
| - | char short_cmd[COMM_LEN]; |
| + | unsigned pid; |
| + | unsigned ppid; |
| + | unsigned pgid; |
| + | unsigned sid; |
| + | unsigned uid; |
| + | unsigned gid; |
| + | /* basename of executable file in call to exec(2), size from */ |
| + | /* sizeof(task_struct.comm) in /usr/include/linux/sched.h */ |
| + | char state[4]; |
| + | char comm[COMM_LEN]; |
| + | // user/group? - use passwd/group parsing functions |
| } procps_status_t; | |
| - | procps_status_t* procps_scan(int save_user_arg0); |
| + | enum { |
| + | PSSCAN_PID = 1 << 0, |
| + | PSSCAN_PPID = 1 << 1, |
| + | PSSCAN_PGID = 1 << 2, |
| + | PSSCAN_SID = 1 << 3, |
| + | PSSCAN_UIDGID = 1 << 4, |
| + | PSSCAN_COMM = 1 << 5, |
| + | PSSCAN_CMD = 1 << 6, |
| + | PSSCAN_STATE = 1 << 7, |
| + | PSSCAN_RSS = 1 << 8, |
| + | PSSCAN_STIME = 1 << 9, |
| + | PSSCAN_UTIME = 1 << 10, |
| + | /* These are all retrieved from proc/NN/stat in one go: */ |
| + | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID |
| + | | PSSCAN_COMM | PSSCAN_STATE |
| + | | PSSCAN_RSS | PSSCAN_STIME | PSSCAN_UTIME, |
| + | }; |
| + | procps_status_t* alloc_procps_scan(int flags); |
| + | void free_procps_scan(procps_status_t* sp); |
| + | procps_status_t* procps_scan(procps_status_t* sp, int flags); |
| pid_t *find_pid_by_name(const char* procName); | |
| pid_t *pidlist_reverse(pid_t *pidList); | |
| + | void clear_username_cache(void); |
| + | const char* get_cached_username(uid_t uid); |
| extern const char bb_uuenc_tbl_base64[]; | |
| @@ -23,11 +23,11 @@ pid_t* find_pid_by_name(const char* procName) | |
| { | |
| pid_t* pidList; | |
| int i = 0; | |
| - | procps_status_t* p; |
| + | procps_status_t* p = NULL; |
| pidList = xmalloc(sizeof(*pidList)); | |
| - | while ((p = procps_scan(0)) != 0) { |
| - | if (strncmp(p->short_cmd, procName, COMM_LEN-1) == 0) { |
| + | while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM))) { |
| + | if (strncmp(p->comm, procName, sizeof(p->comm)-1) == 0) { |
| pidList = xrealloc(pidList, sizeof(*pidList) * (i+2)); | |
| pidList[i++] = p->pid; | |
| } | |
| @@ -11,6 +11,35 @@ | |
| #include "libbb.h" | |
| + | typedef struct { |
| + | uid_t uid; |
| + | char username[12]; |
| + | } user_map_t; |
| + | |
| + | static user_map_t *username_cache; |
| + | static int username_cache_size; |
| + | |
| + | void clear_username_cache(void) |
| + | { |
| + | free(username_cache); |
| + | username_cache = NULL; |
| + | username_cache_size = 0; |
| + | } |
| + | |
| + | const char* get_cached_username(uid_t uid) |
| + | { |
| + | int i; |
| + | for (i = 0; i < username_cache_size; i++) |
| + | if (username_cache[i].uid == uid) |
| + | return username_cache[i].username; |
| + | i = username_cache_size++; |
| + | username_cache = xrealloc(username_cache, username_cache_size * sizeof(*username_cache)); |
| + | username_cache[i].uid = uid; |
| + | bb_getpwuid(username_cache[i].username, uid, sizeof(username_cache[i].username)); |
| + | return username_cache[i].username; |
| + | } |
| + | |
| + | |
| #define PROCPS_BUFSIZE 1024 | |
| static int read_to_buf(const char *filename, void *buf) | |
| @@ -21,119 +50,171 @@ static int read_to_buf(const char *filename, void *buf) | |
| return ret; | |
| } | |
| + | procps_status_t* alloc_procps_scan(int flags) |
| + | { |
| + | procps_status_t* sp = xzalloc(sizeof(procps_status_t)); |
| + | sp->dir = xopendir("/proc"); |
| + | return sp; |
| + | } |
| - | procps_status_t * procps_scan(int save_user_arg0) |
| + | void free_procps_scan(procps_status_t* sp) |
| { | |
| - | static DIR *dir; |
| - | static procps_status_t ret_status; |
| + | closedir(sp->dir); |
| + | free(sp->cmd); |
| + | free(sp); |
| + | } |
| + | void BUG_comm_size(void); |
| + | procps_status_t* procps_scan(procps_status_t* sp, int flags) |
| + | { |
| struct dirent *entry; | |
| - | char *name; |
| char buf[PROCPS_BUFSIZE]; | |
| - | char status[sizeof("/proc//cmdline") + sizeof(int)*3]; |
| - | char *status_tail; |
| - | procps_status_t curstatus; |
| + | char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; |
| + | char *filename_tail; |
| long tasknice; | |
| - | int pid; |
| + | unsigned pid; |
| int n; | |
| struct stat sb; | |
| - | if (!dir) { |
| - | dir = xopendir("/proc"); |
| - | } |
| + | if (!sp) |
| + | sp = alloc_procps_scan(flags); |
| + | |
| for (;;) { | |
| - | entry = readdir(dir); |
| + | entry = readdir(sp->dir); |
| if (entry == NULL) { | |
| - | closedir(dir); |
| - | dir = 0; |
| - | return 0; |
| + | free_procps_scan(sp); |
| + | return NULL; |
| } | |
| - | name = entry->d_name; |
| - | if (!(*name >= '0' && *name <= '9')) |
| + | if (safe_strtou(entry->d_name, &pid)) |
| continue; | |
| - | memset(&curstatus, 0, sizeof(procps_status_t)); |
| - | pid = atoi(name); |
| - | curstatus.pid = pid; |
| + | /* After this point we have to break, not continue |
| + | * ("continue" would mean that current /proc/NNN |
| + | * is not a valid process info) */ |
| - | status_tail = status + sprintf(status, "/proc/%d", pid); |
| - | if (stat(status, &sb)) |
| - | continue; |
| - | bb_getpwuid(curstatus.user, sb.st_uid, sizeof(curstatus.user)); |
| + | memset(&sp->rss, 0, sizeof(*sp) - offsetof(procps_status_t, rss)); |
| - | /* see proc(5) for some details on this */ |
| - | strcpy(status_tail, "/stat"); |
| - | n = read_to_buf(status, buf); |
| - | if (n < 0) |
| - | continue; |
| - | name = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ |
| - | if (name == 0 || name[1] != ' ') |
| - | continue; |
| - | *name = 0; |
| - | sscanf(buf, "%*s (%15c", curstatus.short_cmd); |
| - | n = sscanf(name+2, |
| - | "%c %d " |
| - | "%*s %*s %*s %*s " /* pgrp, session, tty, tpgid */ |
| - | "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ |
| - | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| - | "%lu %lu " /* utime, stime */ |
| - | #else |
| - | "%*s %*s " /* utime, stime */ |
| - | #endif |
| - | "%*s %*s %*s " /* cutime, cstime, priority */ |
| - | "%ld " /* nice */ |
| - | "%*s %*s %*s " /* timeout, it_real_value, start_time */ |
| - | "%*s " /* vsize */ |
| - | "%ld", /* rss */ |
| - | curstatus.state, &curstatus.ppid, |
| - | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| - | &curstatus.utime, &curstatus.stime, |
| - | #endif |
| - | &tasknice, |
| - | &curstatus.rss); |
| - | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| - | if (n != 6) |
| - | #else |
| - | if (n != 4) |
| - | #endif |
| - | continue; |
| + | sp->pid = pid; |
| + | if (!(flags & ~PSSCAN_PID)) break; |
| - | if (curstatus.rss == 0 && curstatus.state[0] != 'Z') |
| - | curstatus.state[1] = 'W'; |
| - | else |
| - | curstatus.state[1] = ' '; |
| - | if (tasknice < 0) |
| - | curstatus.state[2] = '<'; |
| - | else if (tasknice > 0) |
| - | curstatus.state[2] = 'N'; |
| - | else |
| - | curstatus.state[2] = ' '; |
| + | filename_tail = filename + sprintf(filename, "/proc/%d", pid); |
| + | |
| + | if (flags & PSSCAN_UIDGID) { |
| + | if (stat(filename, &sb)) |
| + | break; |
| + | /* Need comment - is this effective or read UID/GID? */ |
| + | sp->uid = sb.st_uid; |
| + | sp->gid = sb.st_gid; |
| + | } |
| + | |
| + | if (flags & PSSCAN_STAT) { |
| + | char *cp; |
| + | /* see proc(5) for some details on this */ |
| + | strcpy(filename_tail, "/stat"); |
| + | n = read_to_buf(filename, buf); |
| + | if (n < 0) |
| + | break; |
| + | cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ |
| + | if (!cp || cp[1] != ' ') |
| + | break; |
| + | cp[0] = '\0'; |
| + | if (sizeof(sp->comm) < 16) |
| + | BUG_comm_size(); |
| + | sscanf(buf, "%*s (%15c", sp->comm); |
| + | n = sscanf(cp+2, |
| + | "%c %u " /* state, ppid */ |
| + | "%u %u %*s %*s " /* pgid, sid, tty, tpgid */ |
| + | "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ |
| + | "%lu %lu " /* utime, stime */ |
| + | "%*s %*s %*s " /* cutime, cstime, priority */ |
| + | "%ld " /* nice */ |
| + | "%*s %*s %*s " /* timeout, it_real_value, start_time */ |
| + | "%*s " /* vsize */ |
| + | "%lu", /* rss */ |
| + | sp->state, &sp->ppid, |
| + | &sp->pgid, &sp->sid, |
| + | &sp->utime, &sp->stime, |
| + | &tasknice, |
| + | &sp->rss); |
| + | if (n != 8) |
| + | break; |
| + | |
| + | if (sp->rss == 0 && sp->state[0] != 'Z') |
| + | sp->state[1] = 'W'; |
| + | else |
| + | sp->state[1] = ' '; |
| + | if (tasknice < 0) |
| + | sp->state[2] = '<'; |
| + | else if (tasknice > 0) |
| + | sp->state[2] = 'N'; |
| + | else |
| + | sp->state[2] = ' '; |
| #ifdef PAGE_SHIFT | |
| - | curstatus.rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ |
| + | sp->rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ |
| #else | |
| - | curstatus.rss *= (getpagesize() >> 10); /* 2**10 = 1kb */ |
| + | sp->rss *= (getpagesize() >> 10); /* 2**10 = 1kb */ |
| #endif | |
| + | } |
| - | if (save_user_arg0) { |
| - | strcpy(status_tail, "/cmdline"); |
| - | n = read_to_buf(status, buf); |
| - | if (n > 0) { |
| - | if (buf[n-1]=='\n') |
| - | buf[--n] = 0; |
| - | name = buf; |
| - | while (n) { |
| - | if (((unsigned char)*name) < ' ') |
| - | *name = ' '; |
| - | name++; |
| - | n--; |
| - | } |
| - | *name = 0; |
| - | if (buf[0]) |
| - | curstatus.cmd = strdup(buf); |
| - | /* if NULL it work true also */ |
| + | if (flags & PSSCAN_CMD) { |
| + | free(sp->cmd); |
| + | sp->cmd = NULL; |
| + | strcpy(filename_tail, "/cmdline"); |
| + | n = read_to_buf(filename, buf); |
| + | if (n <= 0) |
| + | break; |
| + | if (buf[n-1] == '\n') { |
| + | if (!--n) |
| + | break; |
| + | buf[n] = '\0'; |
| } | |
| + | do { |
| + | n--; |
| + | if ((unsigned char)(buf[n]) < ' ') |
| + | buf[n] = ' '; |
| + | } while (n); |
| + | sp->cmd = strdup(buf); |
| } | |
| - | return memcpy(&ret_status, &curstatus, sizeof(procps_status_t)); |
| + | break; |
| } | |
| + | return sp; |
| } | |
| + | /* from kernel: |
| + | // pid comm S ppid pgid sid tty_nr tty_pgrp flg |
| + | sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ |
| + | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ |
| + | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", |
| + | task->pid, |
| + | tcomm, |
| + | state, |
| + | ppid, |
| + | pgid, |
| + | sid, |
| + | tty_nr, |
| + | tty_pgrp, |
| + | task->flags, |
| + | min_flt, |
| + | |
| + | cmin_flt, |
| + | maj_flt, |
| + | cmaj_flt, |
| + | cputime_to_clock_t(utime), |
| + | cputime_to_clock_t(stime), |
| + | cputime_to_clock_t(cutime), |
| + | cputime_to_clock_t(cstime), |
| + | priority, |
| + | nice, |
| + | num_threads, |
| + | // 0, |
| + | start_time, |
| + | vsize, |
| + | mm ? get_mm_rss(mm) : 0, |
| + | rsslim, |
| + | mm ? mm->start_code : 0, |
| + | mm ? mm->end_code : 0, |
| + | mm ? mm->start_stack : 0, |
| + | esp, |
| + | eip, |
| + | the rest is some obsolete cruft |
| + | */ |
| @@ -82,7 +82,7 @@ do_it_now: | |
| if (killall5) { | |
| pid_t sid; | |
| - | procps_status_t* p; |
| + | procps_status_t* p = NULL; |
| // Cannot happen anyway? We don't TERM ourself, we STOP | |
| // /* kill(-1, sig) on Linux (at least 2.1.x) | |
| @@ -94,8 +94,8 @@ do_it_now: | |
| pid = getpid(); | |
| sid = getsid(pid); | |
| /* Now kill all processes except our session */ | |
| - | while ((p = procps_scan(0))!=0) { |
| - | if (getsid(p->pid)!=sid && p->pid!=pid && p->pid!=1) |
| + | while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { |
| + | if (p->sid != sid && p->pid != pid && p->pid != 1) |
| kill(p->pid, signo); | |
| } | |
| /* And let them continue */ | |
| @@ -11,7 +11,7 @@ | |
| int ps_main(int argc, char **argv) | |
| { | |
| - | procps_status_t * p; |
| + | procps_status_t *p = NULL; |
| int i, len; | |
| SKIP_SELINUX(const) int use_selinux = 0; | |
| USE_SELINUX(security_context_t sid = NULL;) | |
| @@ -50,7 +50,13 @@ int ps_main(int argc, char **argv) | |
| else | |
| puts(" PID Uid VmSize Stat Command"); | |
| - | while ((p = procps_scan(1)) != 0) { |
| + | while ((p = procps_scan(p, 0 |
| + | | PSSCAN_PID |
| + | | PSSCAN_UIDGID |
| + | | PSSCAN_STATE |
| + | | PSSCAN_RSS |
| + | | PSSCAN_CMD |
| + | ))) { |
| char *namecmd = p->cmd; | |
| #if ENABLE_SELINUX | |
| if (use_selinux) { | |
| @@ -71,13 +77,18 @@ int ps_main(int argc, char **argv) | |
| } else { | |
| safe_strncpy(sbuf, "unknown", 7); | |
| } | |
| - | len = printf("%5u %-32s %s ", (unsigned)p->pid, sbuf, p->state); |
| + | len = printf("%5u %-32s %s ", p->pid, sbuf, p->state); |
| } else | |
| #endif | |
| + | { |
| + | const char *user = get_cached_username(p->uid); |
| if (p->rss == 0) | |
| - | len = printf("%5u %-8s %s ", (unsigned)p->pid, p->user, p->state); |
| + | len = printf("%5u %-8s %s ", |
| + | p->pid, user, p->state); |
| else | |
| - | len = printf("%5u %-8s %6ld %s ", (unsigned)p->pid, p->user, p->rss, p->state); |
| + | len = printf("%5u %-8s %6ld %s ", |
| + | p->pid, user, p->rss, p->state); |
| + | } |
| i = terminal_width-len; | |
| @@ -88,16 +99,15 @@ int ps_main(int argc, char **argv) | |
| namecmd[i] = 0; | |
| puts(namecmd); | |
| } else { | |
| - | namecmd = p->short_cmd; |
| + | namecmd = p->comm; |
| if (i < 2) | |
| i = 2; | |
| if (strlen(namecmd) > ((size_t)i-2)) | |
| namecmd[i-2] = 0; | |
| printf("[%s]\n", namecmd); | |
| } | |
| - | /* no check needed, but to make valgrind happy.. */ |
| - | if (ENABLE_FEATURE_CLEAN_UP && p->cmd) |
| - | free(p->cmd); |
| } | |
| + | if (ENABLE_FEATURE_CLEAN_UP) |
| + | clear_username_cache(); |
| return EXIT_SUCCESS; | |
| } | |
| @@ -30,37 +30,76 @@ | |
| #include "busybox.h" | |
| - | typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q); |
| - | static procps_status_t *top; /* Hehe */ |
| + | typedef struct { |
| + | unsigned long rss; |
| + | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| + | unsigned long ticks; |
| + | unsigned pcpu; /* delta of ticks */ |
| + | #endif |
| + | unsigned pid, ppid; |
| + | unsigned uid; |
| + | char state[4]; |
| + | char comm[COMM_LEN]; |
| + | } top_status_t; |
| + | static top_status_t *top; |
| static int ntop; | |
| + | /* This structure stores some critical information from one frame to |
| + | the next. Used for finding deltas. */ |
| + | struct save_hist { |
| + | unsigned long ticks; |
| + | unsigned pid; |
| + | }; |
| + | static struct save_hist *prev_hist; |
| + | static int prev_hist_count; |
| + | /* static int hist_iterations; */ |
| + | static unsigned total_pcpu; |
| + | /* static unsigned long total_rss; */ |
| + | |
| + | |
| #define OPT_BATCH_MODE (option_mask32 & 0x4) | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| - | static int pid_sort(procps_status_t *P, procps_status_t *Q) |
| + | static int pid_sort(top_status_t *P, top_status_t *Q) |
| { | |
| + | /* Buggy wrt pids with high bit set */ |
| + | /* (linux pids are in [1..2^15-1]) */ |
| return (Q->pid - P->pid); | |
| } | |
| #endif | |
| - | static int mem_sort(procps_status_t *P, procps_status_t *Q) |
| + | static int mem_sort(top_status_t *P, top_status_t *Q) |
| { | |
| - | return (int)(Q->rss - P->rss); |
| + | /* We want to avoid unsigned->signed and truncation errors */ |
| + | if (Q->rss < P->rss) return -1; |
| + | return Q->rss != P->rss; /* 0 if ==, 1 if > */ |
| } | |
| - | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| + | |
| + | typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q); |
| + | |
| + | #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| + | |
| + | static cmp_funcp sort_function; |
| + | |
| + | #else |
| enum { SORT_DEPTH = 3 }; | |
| - | static cmp_t sort_function[SORT_DEPTH]; |
| - | static int pcpu_sort(procps_status_t *P, procps_status_t *Q) |
| + | static cmp_funcp sort_function[SORT_DEPTH]; |
| + | |
| + | static int pcpu_sort(top_status_t *P, top_status_t *Q) |
| { | |
| - | return (Q->pcpu - P->pcpu); |
| + | /* Buggy wrt ticks with high bit set */ |
| + | /* Affects only processes for which ticks overflow */ |
| + | return (int)Q->pcpu - (int)P->pcpu; |
| } | |
| - | static int time_sort(procps_status_t *P, procps_status_t *Q) |
| + | static int time_sort(top_status_t *P, top_status_t *Q) |
| { | |
| - | return (int)((Q->stime + Q->utime) - (P->stime + P->utime)); |
| + | /* We want to avoid unsigned->signed and truncation errors */ |
| + | if (Q->ticks < P->ticks) return -1; |
| + | return Q->ticks != P->ticks; /* 0 if ==, 1 if > */ |
| } | |
| static int mult_lvl_cmp(void* a, void* b) { | |
| @@ -74,24 +113,6 @@ static int mult_lvl_cmp(void* a, void* b) { | |
| return 0; | |
| } | |
| - | /* This structure stores some critical information from one frame to |
| - | the next. Mostly used for sorting. */ |
| - | struct save_hist { |
| - | int ticks; |
| - | pid_t pid; |
| - | }; |
| - | |
| - | /* |
| - | * Calculates percent cpu usage for each task. |
| - | */ |
| - | |
| - | static struct save_hist *prev_hist; |
| - | static int prev_hist_count; |
| - | /* static int hist_iterations; */ |
| - | |
| - | |
| - | static unsigned total_pcpu; |
| - | /* static unsigned long total_rss; */ |
| typedef struct { | |
| unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal; | |
| @@ -115,11 +136,12 @@ static void get_jiffy_counts(void) | |
| jif.busy = jif.total - jif.idle - jif.iowait; | |
| } | |
| + | |
| static void do_stats(void) | |
| { | |
| - | procps_status_t *cur; |
| + | top_status_t *cur; |
| pid_t pid; | |
| - | int total_time, i, last_i, n; |
| + | int i, last_i, n; |
| struct save_hist *new_hist; | |
| get_jiffy_counts(); | |
| @@ -139,8 +161,7 @@ static void do_stats(void) | |
| * and system time | |
| */ | |
| pid = cur->pid; | |
| - | total_time = cur->stime + cur->utime; |
| - | new_hist[n].ticks = total_time; |
| + | new_hist[n].ticks = cur->ticks; |
| new_hist[n].pid = pid; | |
| /* find matching entry from previous pass */ | |
| @@ -150,13 +171,13 @@ static void do_stats(void) | |
| last_i = i; | |
| if (prev_hist_count) do { | |
| if (prev_hist[i].pid == pid) { | |
| - | cur->pcpu = total_time - prev_hist[i].ticks; |
| + | cur->pcpu = cur->ticks - prev_hist[i].ticks; |
| + | total_pcpu += cur->pcpu; |
| break; | |
| } | |
| i = (i+1) % prev_hist_count; | |
| /* hist_iterations++; */ | |
| } while (i != last_i); | |
| - | total_pcpu += cur->pcpu; |
| /* total_rss += cur->rss; */ | |
| } | |
| @@ -167,10 +188,9 @@ static void do_stats(void) | |
| prev_hist = new_hist; | |
| prev_hist_count = ntop; | |
| } | |
| - | #else |
| - | static cmp_t sort_function; |
| #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | |
| + | |
| /* display generic info (meminfo / loadavg) */ | |
| static unsigned long display_generic(int scr_width) | |
| { | |
| @@ -265,7 +285,7 @@ static void display_status(int count, int scr_width) | |
| bits_per_int = sizeof(int)*8 | |
| }; | |
| - | procps_status_t *s = top; |
| + | top_status_t *s = top; |
| char rss_str_buf[8]; | |
| unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */ | |
| unsigned pmem_shift, pmem_scale; | |
| @@ -333,14 +353,19 @@ static void display_status(int count, int scr_width) | |
| sprintf(rss_str_buf, "%6ldM", s->rss/1024); | |
| else | |
| sprintf(rss_str_buf, "%7ld", s->rss); | |
| - | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);) |
| - | col -= printf("\n%5u %-8s %s %s%6u%3u.%c" \ |
| - | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") " ", |
| - | (unsigned)s->pid, s->user, s->state, rss_str_buf, (unsigned)s->ppid, |
| + | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE( |
| + | pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10); |
| + | ) |
| + | col -= printf("\n%5u %-8s %s " |
| + | "%s%6u" |
| + | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") |
| + | "%3u.%c ", |
| + | s->pid, get_cached_username(s->uid), s->state, |
| + | rss_str_buf, s->ppid, |
| USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,) | |
| pmem.quot, '0'+pmem.rem); | |
| if (col > 0) | |
| - | printf("%.*s", col, s->short_cmd); |
| + | printf("%.*s", col, s->comm); |
| /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, | |
| jif.busy - prev_jif.busy, jif.total - prev_jif.total); */ | |
| s++; | |
| @@ -350,18 +375,20 @@ static void display_status(int count, int scr_width) | |
| fflush(stdout); | |
| } | |
| + | |
| static void clearmems(void) | |
| { | |
| + | clear_username_cache(); |
| free(top); | |
| top = 0; | |
| ntop = 0; | |
| } | |
| + | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| #include <termios.h> | |
| #include <signal.h> | |
| - | |
| static struct termios initial_settings; | |
| static void reset_term(void) | |
| @@ -427,7 +454,7 @@ int top_main(int argc, char **argv) | |
| #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | |
| while (1) { | |
| - | procps_status_t *p; |
| + | procps_status_t *p = NULL; |
| /* Default to 25 lines - 5 lines for status */ | |
| lines = 24 - 3; | |
| @@ -442,11 +469,26 @@ int top_main(int argc, char **argv) | |
| #endif /* FEATURE_USE_TERMIOS */ | |
| /* read process IDs & status for all the processes */ | |
| - | while ((p = procps_scan(0)) != 0) { |
| + | while ((p = procps_scan(p, 0 |
| + | | PSSCAN_PID |
| + | | PSSCAN_PPID |
| + | | PSSCAN_RSS |
| + | | PSSCAN_STIME |
| + | | PSSCAN_UTIME |
| + | | PSSCAN_STATE |
| + | | PSSCAN_COMM |
| + | | PSSCAN_SID |
| + | | PSSCAN_UIDGID |
| + | ))) { |
| int n = ntop; | |
| - | |
| - | top = xrealloc(top, (++ntop)*sizeof(procps_status_t)); |
| - | memcpy(top + n, p, sizeof(procps_status_t)); |
| + | top = xrealloc(top, (++ntop)*sizeof(top_status_t)); |
| + | top[n].pid = p->pid; |
| + | top[n].ppid = p->ppid; |
| + | top[n].rss = p->rss; |
| + | top[n].ticks = p->stime + p->utime; |
| + | top[n].uid = p->uid; |
| + | strcpy(top[n].state, p->state); |
| + | strcpy(top[n].comm, p->comm); |
| } | |
| if (ntop == 0) { | |
| bb_error_msg_and_die("can't find process info in /proc"); | |
| @@ -459,9 +501,9 @@ int top_main(int argc, char **argv) | |
| continue; | |
| } | |
| do_stats(); | |
| - | qsort(top, ntop, sizeof(procps_status_t), (void*)mult_lvl_cmp); |
| + | qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp); |
| #else | |
| - | qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function); |
| + | qsort(top, ntop, sizeof(top_status_t), (void*)sort_function); |
| #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | |
| count = lines; | |
| if (OPT_BATCH_MODE || count > ntop) { | |