diff options
| author | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-11-05 00:43:51 +0000 |
|---|---|---|
| committer | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2006-11-05 00:43:51 +0000 |
| commit | 48b1ebd12ec4ef182b4ea423f2309705ae141e8e (patch) | |
| tree | 5deb7d2b82c280440761cceb4281738867d5631a | |
| parent | d2c185589694b83e492144a6a5d0f79e16dd9b74 (diff) | |
| download | busybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.tar.gz busybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.tar.bz2 busybox-w32-48b1ebd12ec4ef182b4ea423f2309705ae141e8e.zip | |
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
git-svn-id: svn://busybox.net/trunk/busybox@16509 69ca8d6d-28ef-0310-b511-8ec308f3f277
| -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 }; | |||
| 501 | #endif | 501 | #endif |
| 502 | #endif | 502 | #endif |
| 503 | typedef struct { | 503 | typedef struct { |
| 504 | int pid, ppid; | 504 | DIR *dir; |
| 505 | char user[9]; | 505 | /* Fields are set to 0/NULL if failed to determine (or not requested) */ |
| 506 | char state[4]; | 506 | char *cmd; |
| 507 | unsigned long rss; | 507 | unsigned long rss; |
| 508 | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 509 | unsigned pcpu; | ||
| 510 | unsigned long stime, utime; | 508 | unsigned long stime, utime; |
| 511 | #endif | 509 | unsigned pid; |
| 512 | char *cmd; | 510 | unsigned ppid; |
| 513 | 511 | unsigned pgid; | |
| 514 | /* basename of executable file in call to exec(2), | 512 | unsigned sid; |
| 515 | size from kernel headers */ | 513 | unsigned uid; |
| 516 | char short_cmd[COMM_LEN]; | 514 | unsigned gid; |
| 515 | /* basename of executable file in call to exec(2), size from */ | ||
| 516 | /* sizeof(task_struct.comm) in /usr/include/linux/sched.h */ | ||
| 517 | char state[4]; | ||
| 518 | char comm[COMM_LEN]; | ||
| 519 | // user/group? - use passwd/group parsing functions | ||
| 517 | } procps_status_t; | 520 | } procps_status_t; |
| 518 | procps_status_t* procps_scan(int save_user_arg0); | 521 | enum { |
| 522 | PSSCAN_PID = 1 << 0, | ||
| 523 | PSSCAN_PPID = 1 << 1, | ||
| 524 | PSSCAN_PGID = 1 << 2, | ||
| 525 | PSSCAN_SID = 1 << 3, | ||
| 526 | PSSCAN_UIDGID = 1 << 4, | ||
| 527 | PSSCAN_COMM = 1 << 5, | ||
| 528 | PSSCAN_CMD = 1 << 6, | ||
| 529 | PSSCAN_STATE = 1 << 7, | ||
| 530 | PSSCAN_RSS = 1 << 8, | ||
| 531 | PSSCAN_STIME = 1 << 9, | ||
| 532 | PSSCAN_UTIME = 1 << 10, | ||
| 533 | /* These are all retrieved from proc/NN/stat in one go: */ | ||
| 534 | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID | ||
| 535 | | PSSCAN_COMM | PSSCAN_STATE | ||
| 536 | | PSSCAN_RSS | PSSCAN_STIME | PSSCAN_UTIME, | ||
| 537 | }; | ||
| 538 | procps_status_t* alloc_procps_scan(int flags); | ||
| 539 | void free_procps_scan(procps_status_t* sp); | ||
| 540 | procps_status_t* procps_scan(procps_status_t* sp, int flags); | ||
| 519 | pid_t *find_pid_by_name(const char* procName); | 541 | pid_t *find_pid_by_name(const char* procName); |
| 520 | pid_t *pidlist_reverse(pid_t *pidList); | 542 | pid_t *pidlist_reverse(pid_t *pidList); |
| 543 | void clear_username_cache(void); | ||
| 544 | const char* get_cached_username(uid_t uid); | ||
| 521 | 545 | ||
| 522 | 546 | ||
| 523 | extern const char bb_uuenc_tbl_base64[]; | 547 | 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) | |||
| 23 | { | 23 | { |
| 24 | pid_t* pidList; | 24 | pid_t* pidList; |
| 25 | int i = 0; | 25 | int i = 0; |
| 26 | procps_status_t* p; | 26 | procps_status_t* p = NULL; |
| 27 | 27 | ||
| 28 | pidList = xmalloc(sizeof(*pidList)); | 28 | pidList = xmalloc(sizeof(*pidList)); |
| 29 | while ((p = procps_scan(0)) != 0) { | 29 | while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM))) { |
| 30 | if (strncmp(p->short_cmd, procName, COMM_LEN-1) == 0) { | 30 | if (strncmp(p->comm, procName, sizeof(p->comm)-1) == 0) { |
| 31 | pidList = xrealloc(pidList, sizeof(*pidList) * (i+2)); | 31 | pidList = xrealloc(pidList, sizeof(*pidList) * (i+2)); |
| 32 | pidList[i++] = p->pid; | 32 | pidList[i++] = p->pid; |
| 33 | } | 33 | } |
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 @@ | |||
| 11 | #include "libbb.h" | 11 | #include "libbb.h" |
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | typedef struct { | ||
| 15 | uid_t uid; | ||
| 16 | char username[12]; | ||
| 17 | } user_map_t; | ||
| 18 | |||
| 19 | static user_map_t *username_cache; | ||
| 20 | static int username_cache_size; | ||
| 21 | |||
| 22 | void clear_username_cache(void) | ||
| 23 | { | ||
| 24 | free(username_cache); | ||
| 25 | username_cache = NULL; | ||
| 26 | username_cache_size = 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | const char* get_cached_username(uid_t uid) | ||
| 30 | { | ||
| 31 | int i; | ||
| 32 | for (i = 0; i < username_cache_size; i++) | ||
| 33 | if (username_cache[i].uid == uid) | ||
| 34 | return username_cache[i].username; | ||
| 35 | i = username_cache_size++; | ||
| 36 | username_cache = xrealloc(username_cache, username_cache_size * sizeof(*username_cache)); | ||
| 37 | username_cache[i].uid = uid; | ||
| 38 | bb_getpwuid(username_cache[i].username, uid, sizeof(username_cache[i].username)); | ||
| 39 | return username_cache[i].username; | ||
| 40 | } | ||
| 41 | |||
| 42 | |||
| 14 | #define PROCPS_BUFSIZE 1024 | 43 | #define PROCPS_BUFSIZE 1024 |
| 15 | 44 | ||
| 16 | static int read_to_buf(const char *filename, void *buf) | 45 | static int read_to_buf(const char *filename, void *buf) |
| @@ -21,119 +50,171 @@ static int read_to_buf(const char *filename, void *buf) | |||
| 21 | return ret; | 50 | return ret; |
| 22 | } | 51 | } |
| 23 | 52 | ||
| 53 | procps_status_t* alloc_procps_scan(int flags) | ||
| 54 | { | ||
| 55 | procps_status_t* sp = xzalloc(sizeof(procps_status_t)); | ||
| 56 | sp->dir = xopendir("/proc"); | ||
| 57 | return sp; | ||
| 58 | } | ||
| 24 | 59 | ||
| 25 | procps_status_t * procps_scan(int save_user_arg0) | 60 | void free_procps_scan(procps_status_t* sp) |
| 26 | { | 61 | { |
| 27 | static DIR *dir; | 62 | closedir(sp->dir); |
| 28 | static procps_status_t ret_status; | 63 | free(sp->cmd); |
| 64 | free(sp); | ||
| 65 | } | ||
| 29 | 66 | ||
| 67 | void BUG_comm_size(void); | ||
| 68 | procps_status_t* procps_scan(procps_status_t* sp, int flags) | ||
| 69 | { | ||
| 30 | struct dirent *entry; | 70 | struct dirent *entry; |
| 31 | char *name; | ||
| 32 | char buf[PROCPS_BUFSIZE]; | 71 | char buf[PROCPS_BUFSIZE]; |
| 33 | char status[sizeof("/proc//cmdline") + sizeof(int)*3]; | 72 | char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; |
| 34 | char *status_tail; | 73 | char *filename_tail; |
| 35 | procps_status_t curstatus; | ||
| 36 | long tasknice; | 74 | long tasknice; |
| 37 | int pid; | 75 | unsigned pid; |
| 38 | int n; | 76 | int n; |
| 39 | struct stat sb; | 77 | struct stat sb; |
| 40 | 78 | ||
| 41 | if (!dir) { | 79 | if (!sp) |
| 42 | dir = xopendir("/proc"); | 80 | sp = alloc_procps_scan(flags); |
| 43 | } | 81 | |
| 44 | for (;;) { | 82 | for (;;) { |
| 45 | entry = readdir(dir); | 83 | entry = readdir(sp->dir); |
| 46 | if (entry == NULL) { | 84 | if (entry == NULL) { |
| 47 | closedir(dir); | 85 | free_procps_scan(sp); |
| 48 | dir = 0; | 86 | return NULL; |
| 49 | return 0; | ||
| 50 | } | 87 | } |
| 51 | name = entry->d_name; | 88 | if (safe_strtou(entry->d_name, &pid)) |
| 52 | if (!(*name >= '0' && *name <= '9')) | ||
| 53 | continue; | 89 | continue; |
| 54 | 90 | ||
| 55 | memset(&curstatus, 0, sizeof(procps_status_t)); | 91 | /* After this point we have to break, not continue |
| 56 | pid = atoi(name); | 92 | * ("continue" would mean that current /proc/NNN |
| 57 | curstatus.pid = pid; | 93 | * is not a valid process info) */ |
| 58 | 94 | ||
| 59 | status_tail = status + sprintf(status, "/proc/%d", pid); | 95 | memset(&sp->rss, 0, sizeof(*sp) - offsetof(procps_status_t, rss)); |
| 60 | if (stat(status, &sb)) | ||
| 61 | continue; | ||
| 62 | bb_getpwuid(curstatus.user, sb.st_uid, sizeof(curstatus.user)); | ||
| 63 | 96 | ||
| 64 | /* see proc(5) for some details on this */ | 97 | sp->pid = pid; |
| 65 | strcpy(status_tail, "/stat"); | 98 | if (!(flags & ~PSSCAN_PID)) break; |
| 66 | n = read_to_buf(status, buf); | ||
| 67 | if (n < 0) | ||
| 68 | continue; | ||
| 69 | name = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ | ||
| 70 | if (name == 0 || name[1] != ' ') | ||
| 71 | continue; | ||
| 72 | *name = 0; | ||
| 73 | sscanf(buf, "%*s (%15c", curstatus.short_cmd); | ||
| 74 | n = sscanf(name+2, | ||
| 75 | "%c %d " | ||
| 76 | "%*s %*s %*s %*s " /* pgrp, session, tty, tpgid */ | ||
| 77 | "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ | ||
| 78 | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 79 | "%lu %lu " /* utime, stime */ | ||
| 80 | #else | ||
| 81 | "%*s %*s " /* utime, stime */ | ||
| 82 | #endif | ||
| 83 | "%*s %*s %*s " /* cutime, cstime, priority */ | ||
| 84 | "%ld " /* nice */ | ||
| 85 | "%*s %*s %*s " /* timeout, it_real_value, start_time */ | ||
| 86 | "%*s " /* vsize */ | ||
| 87 | "%ld", /* rss */ | ||
| 88 | curstatus.state, &curstatus.ppid, | ||
| 89 | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 90 | &curstatus.utime, &curstatus.stime, | ||
| 91 | #endif | ||
| 92 | &tasknice, | ||
| 93 | &curstatus.rss); | ||
| 94 | #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 95 | if (n != 6) | ||
| 96 | #else | ||
| 97 | if (n != 4) | ||
| 98 | #endif | ||
| 99 | continue; | ||
| 100 | 99 | ||
| 101 | if (curstatus.rss == 0 && curstatus.state[0] != 'Z') | 100 | filename_tail = filename + sprintf(filename, "/proc/%d", pid); |
| 102 | curstatus.state[1] = 'W'; | 101 | |
| 103 | else | 102 | if (flags & PSSCAN_UIDGID) { |
| 104 | curstatus.state[1] = ' '; | 103 | if (stat(filename, &sb)) |
| 105 | if (tasknice < 0) | 104 | break; |
| 106 | curstatus.state[2] = '<'; | 105 | /* Need comment - is this effective or read UID/GID? */ |
| 107 | else if (tasknice > 0) | 106 | sp->uid = sb.st_uid; |
| 108 | curstatus.state[2] = 'N'; | 107 | sp->gid = sb.st_gid; |
| 109 | else | 108 | } |
| 110 | curstatus.state[2] = ' '; | 109 | |
| 110 | if (flags & PSSCAN_STAT) { | ||
| 111 | char *cp; | ||
| 112 | /* see proc(5) for some details on this */ | ||
| 113 | strcpy(filename_tail, "/stat"); | ||
| 114 | n = read_to_buf(filename, buf); | ||
| 115 | if (n < 0) | ||
| 116 | break; | ||
| 117 | cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ | ||
| 118 | if (!cp || cp[1] != ' ') | ||
| 119 | break; | ||
| 120 | cp[0] = '\0'; | ||
| 121 | if (sizeof(sp->comm) < 16) | ||
| 122 | BUG_comm_size(); | ||
| 123 | sscanf(buf, "%*s (%15c", sp->comm); | ||
| 124 | n = sscanf(cp+2, | ||
| 125 | "%c %u " /* state, ppid */ | ||
| 126 | "%u %u %*s %*s " /* pgid, sid, tty, tpgid */ | ||
| 127 | "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ | ||
| 128 | "%lu %lu " /* utime, stime */ | ||
| 129 | "%*s %*s %*s " /* cutime, cstime, priority */ | ||
| 130 | "%ld " /* nice */ | ||
| 131 | "%*s %*s %*s " /* timeout, it_real_value, start_time */ | ||
| 132 | "%*s " /* vsize */ | ||
| 133 | "%lu", /* rss */ | ||
| 134 | sp->state, &sp->ppid, | ||
| 135 | &sp->pgid, &sp->sid, | ||
| 136 | &sp->utime, &sp->stime, | ||
| 137 | &tasknice, | ||
| 138 | &sp->rss); | ||
| 139 | if (n != 8) | ||
| 140 | break; | ||
| 141 | |||
| 142 | if (sp->rss == 0 && sp->state[0] != 'Z') | ||
| 143 | sp->state[1] = 'W'; | ||
| 144 | else | ||
| 145 | sp->state[1] = ' '; | ||
| 146 | if (tasknice < 0) | ||
| 147 | sp->state[2] = '<'; | ||
| 148 | else if (tasknice > 0) | ||
| 149 | sp->state[2] = 'N'; | ||
| 150 | else | ||
| 151 | sp->state[2] = ' '; | ||
| 111 | 152 | ||
| 112 | #ifdef PAGE_SHIFT | 153 | #ifdef PAGE_SHIFT |
| 113 | curstatus.rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ | 154 | sp->rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ |
| 114 | #else | 155 | #else |
| 115 | curstatus.rss *= (getpagesize() >> 10); /* 2**10 = 1kb */ | 156 | sp->rss *= (getpagesize() >> 10); /* 2**10 = 1kb */ |
| 116 | #endif | 157 | #endif |
| 158 | } | ||
| 117 | 159 | ||
| 118 | if (save_user_arg0) { | 160 | if (flags & PSSCAN_CMD) { |
| 119 | strcpy(status_tail, "/cmdline"); | 161 | free(sp->cmd); |
| 120 | n = read_to_buf(status, buf); | 162 | sp->cmd = NULL; |
| 121 | if (n > 0) { | 163 | strcpy(filename_tail, "/cmdline"); |
| 122 | if (buf[n-1]=='\n') | 164 | n = read_to_buf(filename, buf); |
| 123 | buf[--n] = 0; | 165 | if (n <= 0) |
| 124 | name = buf; | 166 | break; |
| 125 | while (n) { | 167 | if (buf[n-1] == '\n') { |
| 126 | if (((unsigned char)*name) < ' ') | 168 | if (!--n) |
| 127 | *name = ' '; | 169 | break; |
| 128 | name++; | 170 | buf[n] = '\0'; |
| 129 | n--; | ||
| 130 | } | ||
| 131 | *name = 0; | ||
| 132 | if (buf[0]) | ||
| 133 | curstatus.cmd = strdup(buf); | ||
| 134 | /* if NULL it work true also */ | ||
| 135 | } | 171 | } |
| 172 | do { | ||
| 173 | n--; | ||
| 174 | if ((unsigned char)(buf[n]) < ' ') | ||
| 175 | buf[n] = ' '; | ||
| 176 | } while (n); | ||
| 177 | sp->cmd = strdup(buf); | ||
| 136 | } | 178 | } |
| 137 | return memcpy(&ret_status, &curstatus, sizeof(procps_status_t)); | 179 | break; |
| 138 | } | 180 | } |
| 181 | return sp; | ||
| 139 | } | 182 | } |
| 183 | /* from kernel: | ||
| 184 | // pid comm S ppid pgid sid tty_nr tty_pgrp flg | ||
| 185 | sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ | ||
| 186 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ | ||
| 187 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", | ||
| 188 | task->pid, | ||
| 189 | tcomm, | ||
| 190 | state, | ||
| 191 | ppid, | ||
| 192 | pgid, | ||
| 193 | sid, | ||
| 194 | tty_nr, | ||
| 195 | tty_pgrp, | ||
| 196 | task->flags, | ||
| 197 | min_flt, | ||
| 198 | |||
| 199 | cmin_flt, | ||
| 200 | maj_flt, | ||
| 201 | cmaj_flt, | ||
| 202 | cputime_to_clock_t(utime), | ||
| 203 | cputime_to_clock_t(stime), | ||
| 204 | cputime_to_clock_t(cutime), | ||
| 205 | cputime_to_clock_t(cstime), | ||
| 206 | priority, | ||
| 207 | nice, | ||
| 208 | num_threads, | ||
| 209 | // 0, | ||
| 210 | start_time, | ||
| 211 | vsize, | ||
| 212 | mm ? get_mm_rss(mm) : 0, | ||
| 213 | rsslim, | ||
| 214 | mm ? mm->start_code : 0, | ||
| 215 | mm ? mm->end_code : 0, | ||
| 216 | mm ? mm->start_stack : 0, | ||
| 217 | esp, | ||
| 218 | eip, | ||
| 219 | the rest is some obsolete cruft | ||
| 220 | */ | ||
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: | |||
| 82 | 82 | ||
| 83 | if (killall5) { | 83 | if (killall5) { |
| 84 | pid_t sid; | 84 | pid_t sid; |
| 85 | procps_status_t* p; | 85 | procps_status_t* p = NULL; |
| 86 | 86 | ||
| 87 | // Cannot happen anyway? We don't TERM ourself, we STOP | 87 | // Cannot happen anyway? We don't TERM ourself, we STOP |
| 88 | // /* kill(-1, sig) on Linux (at least 2.1.x) | 88 | // /* kill(-1, sig) on Linux (at least 2.1.x) |
| @@ -94,8 +94,8 @@ do_it_now: | |||
| 94 | pid = getpid(); | 94 | pid = getpid(); |
| 95 | sid = getsid(pid); | 95 | sid = getsid(pid); |
| 96 | /* Now kill all processes except our session */ | 96 | /* Now kill all processes except our session */ |
| 97 | while ((p = procps_scan(0))!=0) { | 97 | while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { |
| 98 | if (getsid(p->pid)!=sid && p->pid!=pid && p->pid!=1) | 98 | if (p->sid != sid && p->pid != pid && p->pid != 1) |
| 99 | kill(p->pid, signo); | 99 | kill(p->pid, signo); |
| 100 | } | 100 | } |
| 101 | /* And let them continue */ | 101 | /* 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 @@ | |||
| 11 | 11 | ||
| 12 | int ps_main(int argc, char **argv) | 12 | int ps_main(int argc, char **argv) |
| 13 | { | 13 | { |
| 14 | procps_status_t * p; | 14 | procps_status_t *p = NULL; |
| 15 | int i, len; | 15 | int i, len; |
| 16 | SKIP_SELINUX(const) int use_selinux = 0; | 16 | SKIP_SELINUX(const) int use_selinux = 0; |
| 17 | USE_SELINUX(security_context_t sid = NULL;) | 17 | USE_SELINUX(security_context_t sid = NULL;) |
| @@ -50,7 +50,13 @@ int ps_main(int argc, char **argv) | |||
| 50 | else | 50 | else |
| 51 | puts(" PID Uid VmSize Stat Command"); | 51 | puts(" PID Uid VmSize Stat Command"); |
| 52 | 52 | ||
| 53 | while ((p = procps_scan(1)) != 0) { | 53 | while ((p = procps_scan(p, 0 |
| 54 | | PSSCAN_PID | ||
| 55 | | PSSCAN_UIDGID | ||
| 56 | | PSSCAN_STATE | ||
| 57 | | PSSCAN_RSS | ||
| 58 | | PSSCAN_CMD | ||
| 59 | ))) { | ||
| 54 | char *namecmd = p->cmd; | 60 | char *namecmd = p->cmd; |
| 55 | #if ENABLE_SELINUX | 61 | #if ENABLE_SELINUX |
| 56 | if (use_selinux) { | 62 | if (use_selinux) { |
| @@ -71,13 +77,18 @@ int ps_main(int argc, char **argv) | |||
| 71 | } else { | 77 | } else { |
| 72 | safe_strncpy(sbuf, "unknown", 7); | 78 | safe_strncpy(sbuf, "unknown", 7); |
| 73 | } | 79 | } |
| 74 | len = printf("%5u %-32s %s ", (unsigned)p->pid, sbuf, p->state); | 80 | len = printf("%5u %-32s %s ", p->pid, sbuf, p->state); |
| 75 | } else | 81 | } else |
| 76 | #endif | 82 | #endif |
| 83 | { | ||
| 84 | const char *user = get_cached_username(p->uid); | ||
| 77 | if (p->rss == 0) | 85 | if (p->rss == 0) |
| 78 | len = printf("%5u %-8s %s ", (unsigned)p->pid, p->user, p->state); | 86 | len = printf("%5u %-8s %s ", |
| 87 | p->pid, user, p->state); | ||
| 79 | else | 88 | else |
| 80 | len = printf("%5u %-8s %6ld %s ", (unsigned)p->pid, p->user, p->rss, p->state); | 89 | len = printf("%5u %-8s %6ld %s ", |
| 90 | p->pid, user, p->rss, p->state); | ||
| 91 | } | ||
| 81 | 92 | ||
| 82 | i = terminal_width-len; | 93 | i = terminal_width-len; |
| 83 | 94 | ||
| @@ -88,16 +99,15 @@ int ps_main(int argc, char **argv) | |||
| 88 | namecmd[i] = 0; | 99 | namecmd[i] = 0; |
| 89 | puts(namecmd); | 100 | puts(namecmd); |
| 90 | } else { | 101 | } else { |
| 91 | namecmd = p->short_cmd; | 102 | namecmd = p->comm; |
| 92 | if (i < 2) | 103 | if (i < 2) |
| 93 | i = 2; | 104 | i = 2; |
| 94 | if (strlen(namecmd) > ((size_t)i-2)) | 105 | if (strlen(namecmd) > ((size_t)i-2)) |
| 95 | namecmd[i-2] = 0; | 106 | namecmd[i-2] = 0; |
| 96 | printf("[%s]\n", namecmd); | 107 | printf("[%s]\n", namecmd); |
| 97 | } | 108 | } |
| 98 | /* no check needed, but to make valgrind happy.. */ | ||
| 99 | if (ENABLE_FEATURE_CLEAN_UP && p->cmd) | ||
| 100 | free(p->cmd); | ||
| 101 | } | 109 | } |
| 110 | if (ENABLE_FEATURE_CLEAN_UP) | ||
| 111 | clear_username_cache(); | ||
| 102 | return EXIT_SUCCESS; | 112 | return EXIT_SUCCESS; |
| 103 | } | 113 | } |
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 @@ | |||
| 30 | 30 | ||
| 31 | #include "busybox.h" | 31 | #include "busybox.h" |
| 32 | 32 | ||
| 33 | typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q); | ||
| 34 | 33 | ||
| 35 | static procps_status_t *top; /* Hehe */ | 34 | typedef struct { |
| 35 | unsigned long rss; | ||
| 36 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 37 | unsigned long ticks; | ||
| 38 | unsigned pcpu; /* delta of ticks */ | ||
| 39 | #endif | ||
| 40 | unsigned pid, ppid; | ||
| 41 | unsigned uid; | ||
| 42 | char state[4]; | ||
| 43 | char comm[COMM_LEN]; | ||
| 44 | } top_status_t; | ||
| 45 | static top_status_t *top; | ||
| 36 | static int ntop; | 46 | static int ntop; |
| 47 | /* This structure stores some critical information from one frame to | ||
| 48 | the next. Used for finding deltas. */ | ||
| 49 | struct save_hist { | ||
| 50 | unsigned long ticks; | ||
| 51 | unsigned pid; | ||
| 52 | }; | ||
| 53 | static struct save_hist *prev_hist; | ||
| 54 | static int prev_hist_count; | ||
| 55 | /* static int hist_iterations; */ | ||
| 56 | static unsigned total_pcpu; | ||
| 57 | /* static unsigned long total_rss; */ | ||
| 58 | |||
| 59 | |||
| 37 | #define OPT_BATCH_MODE (option_mask32 & 0x4) | 60 | #define OPT_BATCH_MODE (option_mask32 & 0x4) |
| 38 | 61 | ||
| 39 | #if ENABLE_FEATURE_USE_TERMIOS | 62 | #if ENABLE_FEATURE_USE_TERMIOS |
| 40 | static int pid_sort(procps_status_t *P, procps_status_t *Q) | 63 | static int pid_sort(top_status_t *P, top_status_t *Q) |
| 41 | { | 64 | { |
| 65 | /* Buggy wrt pids with high bit set */ | ||
| 66 | /* (linux pids are in [1..2^15-1]) */ | ||
| 42 | return (Q->pid - P->pid); | 67 | return (Q->pid - P->pid); |
| 43 | } | 68 | } |
| 44 | #endif | 69 | #endif |
| 45 | 70 | ||
| 46 | static int mem_sort(procps_status_t *P, procps_status_t *Q) | 71 | static int mem_sort(top_status_t *P, top_status_t *Q) |
| 47 | { | 72 | { |
| 48 | return (int)(Q->rss - P->rss); | 73 | /* We want to avoid unsigned->signed and truncation errors */ |
| 74 | if (Q->rss < P->rss) return -1; | ||
| 75 | return Q->rss != P->rss; /* 0 if ==, 1 if > */ | ||
| 49 | } | 76 | } |
| 50 | 77 | ||
| 51 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 78 | |
| 79 | typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q); | ||
| 80 | |||
| 81 | #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 82 | |||
| 83 | static cmp_funcp sort_function; | ||
| 84 | |||
| 85 | #else | ||
| 52 | 86 | ||
| 53 | enum { SORT_DEPTH = 3 }; | 87 | enum { SORT_DEPTH = 3 }; |
| 54 | static cmp_t sort_function[SORT_DEPTH]; | ||
| 55 | 88 | ||
| 56 | static int pcpu_sort(procps_status_t *P, procps_status_t *Q) | 89 | static cmp_funcp sort_function[SORT_DEPTH]; |
| 90 | |||
| 91 | static int pcpu_sort(top_status_t *P, top_status_t *Q) | ||
| 57 | { | 92 | { |
| 58 | return (Q->pcpu - P->pcpu); | 93 | /* Buggy wrt ticks with high bit set */ |
| 94 | /* Affects only processes for which ticks overflow */ | ||
| 95 | return (int)Q->pcpu - (int)P->pcpu; | ||
| 59 | } | 96 | } |
| 60 | 97 | ||
| 61 | static int time_sort(procps_status_t *P, procps_status_t *Q) | 98 | static int time_sort(top_status_t *P, top_status_t *Q) |
| 62 | { | 99 | { |
| 63 | return (int)((Q->stime + Q->utime) - (P->stime + P->utime)); | 100 | /* We want to avoid unsigned->signed and truncation errors */ |
| 101 | if (Q->ticks < P->ticks) return -1; | ||
| 102 | return Q->ticks != P->ticks; /* 0 if ==, 1 if > */ | ||
| 64 | } | 103 | } |
| 65 | 104 | ||
| 66 | static int mult_lvl_cmp(void* a, void* b) { | 105 | static int mult_lvl_cmp(void* a, void* b) { |
| @@ -74,24 +113,6 @@ static int mult_lvl_cmp(void* a, void* b) { | |||
| 74 | return 0; | 113 | return 0; |
| 75 | } | 114 | } |
| 76 | 115 | ||
| 77 | /* This structure stores some critical information from one frame to | ||
| 78 | the next. Mostly used for sorting. */ | ||
| 79 | struct save_hist { | ||
| 80 | int ticks; | ||
| 81 | pid_t pid; | ||
| 82 | }; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Calculates percent cpu usage for each task. | ||
| 86 | */ | ||
| 87 | |||
| 88 | static struct save_hist *prev_hist; | ||
| 89 | static int prev_hist_count; | ||
| 90 | /* static int hist_iterations; */ | ||
| 91 | |||
| 92 | |||
| 93 | static unsigned total_pcpu; | ||
| 94 | /* static unsigned long total_rss; */ | ||
| 95 | 116 | ||
| 96 | typedef struct { | 117 | typedef struct { |
| 97 | unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal; | 118 | unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal; |
| @@ -115,11 +136,12 @@ static void get_jiffy_counts(void) | |||
| 115 | jif.busy = jif.total - jif.idle - jif.iowait; | 136 | jif.busy = jif.total - jif.idle - jif.iowait; |
| 116 | } | 137 | } |
| 117 | 138 | ||
| 139 | |||
| 118 | static void do_stats(void) | 140 | static void do_stats(void) |
| 119 | { | 141 | { |
| 120 | procps_status_t *cur; | 142 | top_status_t *cur; |
| 121 | pid_t pid; | 143 | pid_t pid; |
| 122 | int total_time, i, last_i, n; | 144 | int i, last_i, n; |
| 123 | struct save_hist *new_hist; | 145 | struct save_hist *new_hist; |
| 124 | 146 | ||
| 125 | get_jiffy_counts(); | 147 | get_jiffy_counts(); |
| @@ -139,8 +161,7 @@ static void do_stats(void) | |||
| 139 | * and system time | 161 | * and system time |
| 140 | */ | 162 | */ |
| 141 | pid = cur->pid; | 163 | pid = cur->pid; |
| 142 | total_time = cur->stime + cur->utime; | 164 | new_hist[n].ticks = cur->ticks; |
| 143 | new_hist[n].ticks = total_time; | ||
| 144 | new_hist[n].pid = pid; | 165 | new_hist[n].pid = pid; |
| 145 | 166 | ||
| 146 | /* find matching entry from previous pass */ | 167 | /* find matching entry from previous pass */ |
| @@ -150,13 +171,13 @@ static void do_stats(void) | |||
| 150 | last_i = i; | 171 | last_i = i; |
| 151 | if (prev_hist_count) do { | 172 | if (prev_hist_count) do { |
| 152 | if (prev_hist[i].pid == pid) { | 173 | if (prev_hist[i].pid == pid) { |
| 153 | cur->pcpu = total_time - prev_hist[i].ticks; | 174 | cur->pcpu = cur->ticks - prev_hist[i].ticks; |
| 175 | total_pcpu += cur->pcpu; | ||
| 154 | break; | 176 | break; |
| 155 | } | 177 | } |
| 156 | i = (i+1) % prev_hist_count; | 178 | i = (i+1) % prev_hist_count; |
| 157 | /* hist_iterations++; */ | 179 | /* hist_iterations++; */ |
| 158 | } while (i != last_i); | 180 | } while (i != last_i); |
| 159 | total_pcpu += cur->pcpu; | ||
| 160 | /* total_rss += cur->rss; */ | 181 | /* total_rss += cur->rss; */ |
| 161 | } | 182 | } |
| 162 | 183 | ||
| @@ -167,10 +188,9 @@ static void do_stats(void) | |||
| 167 | prev_hist = new_hist; | 188 | prev_hist = new_hist; |
| 168 | prev_hist_count = ntop; | 189 | prev_hist_count = ntop; |
| 169 | } | 190 | } |
| 170 | #else | ||
| 171 | static cmp_t sort_function; | ||
| 172 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 191 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
| 173 | 192 | ||
| 193 | |||
| 174 | /* display generic info (meminfo / loadavg) */ | 194 | /* display generic info (meminfo / loadavg) */ |
| 175 | static unsigned long display_generic(int scr_width) | 195 | static unsigned long display_generic(int scr_width) |
| 176 | { | 196 | { |
| @@ -265,7 +285,7 @@ static void display_status(int count, int scr_width) | |||
| 265 | bits_per_int = sizeof(int)*8 | 285 | bits_per_int = sizeof(int)*8 |
| 266 | }; | 286 | }; |
| 267 | 287 | ||
| 268 | procps_status_t *s = top; | 288 | top_status_t *s = top; |
| 269 | char rss_str_buf[8]; | 289 | char rss_str_buf[8]; |
| 270 | unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */ | 290 | unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */ |
| 271 | unsigned pmem_shift, pmem_scale; | 291 | unsigned pmem_shift, pmem_scale; |
| @@ -333,14 +353,19 @@ static void display_status(int count, int scr_width) | |||
| 333 | sprintf(rss_str_buf, "%6ldM", s->rss/1024); | 353 | sprintf(rss_str_buf, "%6ldM", s->rss/1024); |
| 334 | else | 354 | else |
| 335 | sprintf(rss_str_buf, "%7ld", s->rss); | 355 | sprintf(rss_str_buf, "%7ld", s->rss); |
| 336 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);) | 356 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE( |
| 337 | col -= printf("\n%5u %-8s %s %s%6u%3u.%c" \ | 357 | pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10); |
| 338 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") " ", | 358 | ) |
| 339 | (unsigned)s->pid, s->user, s->state, rss_str_buf, (unsigned)s->ppid, | 359 | col -= printf("\n%5u %-8s %s " |
| 360 | "%s%6u" | ||
| 361 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") | ||
| 362 | "%3u.%c ", | ||
| 363 | s->pid, get_cached_username(s->uid), s->state, | ||
| 364 | rss_str_buf, s->ppid, | ||
| 340 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,) | 365 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,) |
| 341 | pmem.quot, '0'+pmem.rem); | 366 | pmem.quot, '0'+pmem.rem); |
| 342 | if (col > 0) | 367 | if (col > 0) |
| 343 | printf("%.*s", col, s->short_cmd); | 368 | printf("%.*s", col, s->comm); |
| 344 | /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, | 369 | /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, |
| 345 | jif.busy - prev_jif.busy, jif.total - prev_jif.total); */ | 370 | jif.busy - prev_jif.busy, jif.total - prev_jif.total); */ |
| 346 | s++; | 371 | s++; |
| @@ -350,18 +375,20 @@ static void display_status(int count, int scr_width) | |||
| 350 | fflush(stdout); | 375 | fflush(stdout); |
| 351 | } | 376 | } |
| 352 | 377 | ||
| 378 | |||
| 353 | static void clearmems(void) | 379 | static void clearmems(void) |
| 354 | { | 380 | { |
| 381 | clear_username_cache(); | ||
| 355 | free(top); | 382 | free(top); |
| 356 | top = 0; | 383 | top = 0; |
| 357 | ntop = 0; | 384 | ntop = 0; |
| 358 | } | 385 | } |
| 359 | 386 | ||
| 387 | |||
| 360 | #if ENABLE_FEATURE_USE_TERMIOS | 388 | #if ENABLE_FEATURE_USE_TERMIOS |
| 361 | #include <termios.h> | 389 | #include <termios.h> |
| 362 | #include <signal.h> | 390 | #include <signal.h> |
| 363 | 391 | ||
| 364 | |||
| 365 | static struct termios initial_settings; | 392 | static struct termios initial_settings; |
| 366 | 393 | ||
| 367 | static void reset_term(void) | 394 | static void reset_term(void) |
| @@ -427,7 +454,7 @@ int top_main(int argc, char **argv) | |||
| 427 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 454 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
| 428 | 455 | ||
| 429 | while (1) { | 456 | while (1) { |
| 430 | procps_status_t *p; | 457 | procps_status_t *p = NULL; |
| 431 | 458 | ||
| 432 | /* Default to 25 lines - 5 lines for status */ | 459 | /* Default to 25 lines - 5 lines for status */ |
| 433 | lines = 24 - 3; | 460 | lines = 24 - 3; |
| @@ -442,11 +469,26 @@ int top_main(int argc, char **argv) | |||
| 442 | #endif /* FEATURE_USE_TERMIOS */ | 469 | #endif /* FEATURE_USE_TERMIOS */ |
| 443 | 470 | ||
| 444 | /* read process IDs & status for all the processes */ | 471 | /* read process IDs & status for all the processes */ |
| 445 | while ((p = procps_scan(0)) != 0) { | 472 | while ((p = procps_scan(p, 0 |
| 473 | | PSSCAN_PID | ||
| 474 | | PSSCAN_PPID | ||
| 475 | | PSSCAN_RSS | ||
| 476 | | PSSCAN_STIME | ||
| 477 | | PSSCAN_UTIME | ||
| 478 | | PSSCAN_STATE | ||
| 479 | | PSSCAN_COMM | ||
| 480 | | PSSCAN_SID | ||
| 481 | | PSSCAN_UIDGID | ||
| 482 | ))) { | ||
| 446 | int n = ntop; | 483 | int n = ntop; |
| 447 | 484 | top = xrealloc(top, (++ntop)*sizeof(top_status_t)); | |
| 448 | top = xrealloc(top, (++ntop)*sizeof(procps_status_t)); | 485 | top[n].pid = p->pid; |
| 449 | memcpy(top + n, p, sizeof(procps_status_t)); | 486 | top[n].ppid = p->ppid; |
| 487 | top[n].rss = p->rss; | ||
| 488 | top[n].ticks = p->stime + p->utime; | ||
| 489 | top[n].uid = p->uid; | ||
| 490 | strcpy(top[n].state, p->state); | ||
| 491 | strcpy(top[n].comm, p->comm); | ||
| 450 | } | 492 | } |
| 451 | if (ntop == 0) { | 493 | if (ntop == 0) { |
| 452 | bb_error_msg_and_die("can't find process info in /proc"); | 494 | bb_error_msg_and_die("can't find process info in /proc"); |
| @@ -459,9 +501,9 @@ int top_main(int argc, char **argv) | |||
| 459 | continue; | 501 | continue; |
| 460 | } | 502 | } |
| 461 | do_stats(); | 503 | do_stats(); |
| 462 | qsort(top, ntop, sizeof(procps_status_t), (void*)mult_lvl_cmp); | 504 | qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp); |
| 463 | #else | 505 | #else |
| 464 | qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function); | 506 | qsort(top, ntop, sizeof(top_status_t), (void*)sort_function); |
| 465 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 507 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
| 466 | count = lines; | 508 | count = lines; |
| 467 | if (OPT_BATCH_MODE || count > ntop) { | 509 | if (OPT_BATCH_MODE || count > ntop) { |
