diff options
-rw-r--r-- | include/libbb.h | 48 | ||||
-rw-r--r-- | libbb/find_pid_by_name.c | 6 | ||||
-rw-r--r-- | libbb/procps.c | 261 | ||||
-rw-r--r-- | procps/kill.c | 6 | ||||
-rw-r--r-- | procps/ps.c | 28 | ||||
-rw-r--r-- | procps/top.c | 144 |
6 files changed, 325 insertions, 168 deletions
diff --git a/include/libbb.h b/include/libbb.h index 7b5221d87..607433118 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -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[]; diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c index 05f7f968f..e98616940 100644 --- a/libbb/find_pid_by_name.c +++ b/libbb/find_pid_by_name.c @@ -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; } diff --git a/libbb/procps.c b/libbb/procps.c index 15f77153a..dee5638e4 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -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 +*/ diff --git a/procps/kill.c b/procps/kill.c index 9b96b4c1a..18121f06f 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -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 */ diff --git a/procps/ps.c b/procps/ps.c index 9d6e42d79..2ff6e77d4 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -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; } diff --git a/procps/top.c b/procps/top.c index c76fdc312..8d732d4b2 100644 --- a/procps/top.c +++ b/procps/top.c @@ -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) { |