diff options
author | Ron Yorston <rmy@pobox.com> | 2012-03-22 15:21:20 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2012-03-22 15:21:20 +0000 |
commit | 0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2 (patch) | |
tree | 6709ddd6071a9c238ba69233540bbcfe560c6a44 /procps | |
parent | 67758035a4fe040c6ac69b39d61bcd6bddd7b827 (diff) | |
parent | 56a3b82e9692a25ef9c9269e88feac0d579ce8e8 (diff) | |
download | busybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.tar.gz busybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.tar.bz2 busybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.zip |
Merge commit '56a3b82e9692a25ef9c9269e88feac0d579ce8e8' into merge
Conflicts:
coreutils/ls.c
include/platform.h
libbb/bb_basename.c
Diffstat (limited to 'procps')
-rw-r--r-- | procps/fuser.c | 386 | ||||
-rw-r--r-- | procps/iostat.c | 335 | ||||
-rw-r--r-- | procps/mpstat.c | 3 | ||||
-rw-r--r-- | procps/nmeter.c | 26 | ||||
-rw-r--r-- | procps/powertop.c | 2 | ||||
-rw-r--r-- | procps/top.c | 282 |
6 files changed, 513 insertions, 521 deletions
diff --git a/procps/fuser.c b/procps/fuser.c index 7837ff883..8d63a7313 100644 --- a/procps/fuser.c +++ b/procps/fuser.c | |||
@@ -37,33 +37,18 @@ typedef struct inode_list { | |||
37 | dev_t dev; | 37 | dev_t dev; |
38 | } inode_list; | 38 | } inode_list; |
39 | 39 | ||
40 | typedef struct pid_list { | ||
41 | struct pid_list *next; | ||
42 | pid_t pid; | ||
43 | } pid_list; | ||
44 | |||
45 | |||
46 | struct globals { | 40 | struct globals { |
47 | pid_list *pid_list_head; | 41 | int recursion_depth; |
42 | pid_t mypid; | ||
48 | inode_list *inode_list_head; | 43 | inode_list *inode_list_head; |
44 | smallint kill_failed; | ||
45 | int killsig; | ||
49 | } FIX_ALIASING; | 46 | } FIX_ALIASING; |
50 | #define G (*(struct globals*)&bb_common_bufsiz1) | 47 | #define G (*(struct globals*)&bb_common_bufsiz1) |
51 | #define INIT_G() do { } while (0) | 48 | #define INIT_G() do { \ |
52 | 49 | G.mypid = getpid(); \ | |
53 | 50 | G.killsig = SIGKILL; \ | |
54 | static void add_pid(const pid_t pid) | 51 | } while (0) |
55 | { | ||
56 | pid_list **curr = &G.pid_list_head; | ||
57 | |||
58 | while (*curr) { | ||
59 | if ((*curr)->pid == pid) | ||
60 | return; | ||
61 | curr = &(*curr)->next; | ||
62 | } | ||
63 | |||
64 | *curr = xzalloc(sizeof(pid_list)); | ||
65 | (*curr)->pid = pid; | ||
66 | } | ||
67 | 52 | ||
68 | static void add_inode(const struct stat *st) | 53 | static void add_inode(const struct stat *st) |
69 | { | 54 | { |
@@ -83,48 +68,7 @@ static void add_inode(const struct stat *st) | |||
83 | (*curr)->inode = st->st_ino; | 68 | (*curr)->inode = st->st_ino; |
84 | } | 69 | } |
85 | 70 | ||
86 | static void scan_proc_net(const char *path, unsigned port) | 71 | static smallint search_dev_inode(const struct stat *st) |
87 | { | ||
88 | char line[MAX_LINE + 1]; | ||
89 | long long uint64_inode; | ||
90 | unsigned tmp_port; | ||
91 | FILE *f; | ||
92 | struct stat st; | ||
93 | int fd; | ||
94 | |||
95 | /* find socket dev */ | ||
96 | st.st_dev = 0; | ||
97 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
98 | if (fd >= 0) { | ||
99 | fstat(fd, &st); | ||
100 | close(fd); | ||
101 | } | ||
102 | |||
103 | f = fopen_for_read(path); | ||
104 | if (!f) | ||
105 | return; | ||
106 | |||
107 | while (fgets(line, MAX_LINE, f)) { | ||
108 | char addr[68]; | ||
109 | if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " | ||
110 | "%*x:%*x %*x %*d %*d %llu", | ||
111 | addr, &tmp_port, &uint64_inode) == 3 | ||
112 | ) { | ||
113 | int len = strlen(addr); | ||
114 | if (len == 8 && (option_mask32 & OPT_IP6)) | ||
115 | continue; | ||
116 | if (len > 8 && (option_mask32 & OPT_IP4)) | ||
117 | continue; | ||
118 | if (tmp_port == port) { | ||
119 | st.st_ino = uint64_inode; | ||
120 | add_inode(&st); | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | fclose(f); | ||
125 | } | ||
126 | |||
127 | static int search_dev_inode(const struct stat *st) | ||
128 | { | 72 | { |
129 | inode_list *ilist = G.inode_list_head; | 73 | inode_list *ilist = G.inode_list_head; |
130 | 74 | ||
@@ -140,130 +84,202 @@ static int search_dev_inode(const struct stat *st) | |||
140 | return 0; | 84 | return 0; |
141 | } | 85 | } |
142 | 86 | ||
143 | static void scan_pid_maps(const char *fname, pid_t pid) | 87 | enum { |
88 | PROC_NET = 0, | ||
89 | PROC_DIR, | ||
90 | PROC_DIR_LINKS, | ||
91 | PROC_SUBDIR_LINKS, | ||
92 | }; | ||
93 | |||
94 | static smallint scan_proc_net_or_maps(const char *path, unsigned port) | ||
144 | { | 95 | { |
145 | FILE *file; | 96 | FILE *f; |
146 | char line[MAX_LINE + 1]; | 97 | char line[MAX_LINE + 1], addr[68]; |
147 | int major, minor; | 98 | int major, minor, r; |
148 | long long uint64_inode; | 99 | long long uint64_inode; |
149 | struct stat st; | 100 | unsigned tmp_port; |
101 | smallint retval; | ||
102 | struct stat statbuf; | ||
103 | const char *fmt; | ||
104 | void *fag, *sag; | ||
150 | 105 | ||
151 | file = fopen_for_read(fname); | 106 | f = fopen_for_read(path); |
152 | if (!file) | 107 | if (!f) |
153 | return; | 108 | return 0; |
154 | 109 | ||
155 | while (fgets(line, MAX_LINE, file)) { | 110 | if (G.recursion_depth == PROC_NET) { |
156 | if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3) | 111 | int fd; |
157 | continue; | ||
158 | st.st_ino = uint64_inode; | ||
159 | if (major == 0 && minor == 0 && st.st_ino == 0) | ||
160 | continue; | ||
161 | st.st_dev = makedev(major, minor); | ||
162 | if (search_dev_inode(&st)) | ||
163 | add_pid(pid); | ||
164 | } | ||
165 | fclose(file); | ||
166 | } | ||
167 | 112 | ||
168 | static void scan_link(const char *lname, pid_t pid) | 113 | /* find socket dev */ |
169 | { | 114 | statbuf.st_dev = 0; |
170 | struct stat st; | 115 | fd = socket(AF_INET, SOCK_DGRAM, 0); |
116 | if (fd >= 0) { | ||
117 | fstat(fd, &statbuf); | ||
118 | close(fd); | ||
119 | } | ||
171 | 120 | ||
172 | if (stat(lname, &st) >= 0) { | 121 | fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x " |
173 | if (search_dev_inode(&st)) | 122 | "%*x:%*x %*x:%*x %*x %*d %*d %llu"; |
174 | add_pid(pid); | 123 | fag = addr; |
124 | sag = &tmp_port; | ||
125 | } else { | ||
126 | fmt = "%*s %*s %*s %x:%x %llu"; | ||
127 | fag = &major; | ||
128 | sag = &minor; | ||
175 | } | 129 | } |
176 | } | ||
177 | |||
178 | static void scan_dir_links(const char *dname, pid_t pid) | ||
179 | { | ||
180 | DIR *d; | ||
181 | struct dirent *de; | ||
182 | char *lname; | ||
183 | |||
184 | d = opendir(dname); | ||
185 | if (!d) | ||
186 | return; | ||
187 | 130 | ||
188 | while ((de = readdir(d)) != NULL) { | 131 | retval = 0; |
189 | lname = concat_subpath_file(dname, de->d_name); | 132 | while (fgets(line, MAX_LINE, f)) { |
190 | if (lname == NULL) | 133 | r = sscanf(line, fmt, fag, sag, &uint64_inode); |
134 | if (r != 3) | ||
191 | continue; | 135 | continue; |
192 | scan_link(lname, pid); | 136 | |
193 | free(lname); | 137 | statbuf.st_ino = uint64_inode; |
138 | if (G.recursion_depth == PROC_NET) { | ||
139 | r = strlen(addr); | ||
140 | if (r == 8 && (option_mask32 & OPT_IP6)) | ||
141 | continue; | ||
142 | if (r > 8 && (option_mask32 & OPT_IP4)) | ||
143 | continue; | ||
144 | if (tmp_port == port) | ||
145 | add_inode(&statbuf); | ||
146 | } else { | ||
147 | if (major != 0 && minor != 0 && statbuf.st_ino != 0) { | ||
148 | statbuf.st_dev = makedev(major, minor); | ||
149 | retval = search_dev_inode(&statbuf); | ||
150 | if (retval) | ||
151 | break; | ||
152 | } | ||
153 | } | ||
194 | } | 154 | } |
195 | closedir(d); | 155 | fclose(f); |
156 | |||
157 | return retval; | ||
196 | } | 158 | } |
197 | 159 | ||
198 | /* NB: does chdir internally */ | 160 | static smallint scan_recursive(const char *path) |
199 | static void scan_proc_pids(void) | ||
200 | { | 161 | { |
201 | DIR *d; | 162 | DIR *d; |
202 | struct dirent *de; | 163 | struct dirent *d_ent; |
203 | pid_t pid; | 164 | smallint stop_scan; |
204 | 165 | smallint retval; | |
205 | xchdir("/proc"); | 166 | |
206 | d = opendir("/proc"); | 167 | d = opendir(path); |
207 | if (!d) | 168 | if (d == NULL) |
208 | return; | 169 | return 0; |
209 | 170 | ||
210 | while ((de = readdir(d)) != NULL) { | 171 | G.recursion_depth++; |
211 | pid = (pid_t)bb_strtou(de->d_name, NULL, 10); | 172 | retval = 0; |
212 | if (errno) | 173 | stop_scan = 0; |
213 | continue; | 174 | while (!stop_scan && (d_ent = readdir(d)) != NULL) { |
214 | if (chdir(de->d_name) < 0) | 175 | struct stat statbuf; |
215 | continue; | 176 | pid_t pid; |
216 | scan_link("cwd", pid); | 177 | char *subpath; |
217 | scan_link("exe", pid); | 178 | |
218 | scan_link("root", pid); | 179 | subpath = concat_subpath_file(path, d_ent->d_name); |
219 | 180 | if (subpath == NULL) | |
220 | scan_dir_links("fd", pid); | 181 | continue; /* . or .. */ |
221 | scan_dir_links("lib", pid); | 182 | |
222 | scan_dir_links("mmap", pid); | 183 | switch (G.recursion_depth) { |
184 | case PROC_DIR: | ||
185 | pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10); | ||
186 | if (errno != 0 | ||
187 | || pid == G.mypid | ||
188 | /* "this PID doesn't use specified FILEs or PORT/PROTO": */ | ||
189 | || scan_recursive(subpath) == 0 | ||
190 | ) { | ||
191 | break; | ||
192 | } | ||
193 | if (option_mask32 & OPT_KILL) { | ||
194 | if (kill(pid, G.killsig) != 0) { | ||
195 | bb_perror_msg("kill pid %s", d_ent->d_name); | ||
196 | G.kill_failed = 1; | ||
197 | } | ||
198 | } | ||
199 | if (!(option_mask32 & OPT_SILENT)) | ||
200 | printf("%s ", d_ent->d_name); | ||
201 | retval = 1; | ||
202 | break; | ||
223 | 203 | ||
224 | scan_pid_maps("maps", pid); | 204 | case PROC_DIR_LINKS: |
225 | xchdir("/proc"); | 205 | switch ( |
206 | index_in_substrings( | ||
207 | "cwd" "\0" "exe" "\0" | ||
208 | "root" "\0" "fd" "\0" | ||
209 | "lib" "\0" "mmap" "\0" | ||
210 | "maps" "\0", | ||
211 | d_ent->d_name | ||
212 | ) | ||
213 | ) { | ||
214 | enum { | ||
215 | CWD_LINK, | ||
216 | EXE_LINK, | ||
217 | ROOT_LINK, | ||
218 | FD_DIR_LINKS, | ||
219 | LIB_DIR_LINKS, | ||
220 | MMAP_DIR_LINKS, | ||
221 | MAPS, | ||
222 | }; | ||
223 | case CWD_LINK: | ||
224 | case EXE_LINK: | ||
225 | case ROOT_LINK: | ||
226 | goto scan_link; | ||
227 | case FD_DIR_LINKS: | ||
228 | case LIB_DIR_LINKS: | ||
229 | case MMAP_DIR_LINKS: | ||
230 | stop_scan = scan_recursive(subpath); | ||
231 | if (stop_scan) | ||
232 | retval = stop_scan; | ||
233 | break; | ||
234 | case MAPS: | ||
235 | stop_scan = scan_proc_net_or_maps(subpath, 0); | ||
236 | if (stop_scan) | ||
237 | retval = stop_scan; | ||
238 | default: | ||
239 | break; | ||
240 | } | ||
241 | break; | ||
242 | case PROC_SUBDIR_LINKS: | ||
243 | scan_link: | ||
244 | if (stat(subpath, &statbuf) < 0) | ||
245 | break; | ||
246 | stop_scan = search_dev_inode(&statbuf); | ||
247 | if (stop_scan) | ||
248 | retval = stop_scan; | ||
249 | default: | ||
250 | break; | ||
251 | } | ||
252 | free(subpath); | ||
226 | } | 253 | } |
227 | closedir(d); | 254 | closedir(d); |
255 | G.recursion_depth--; | ||
256 | return retval; | ||
228 | } | 257 | } |
229 | 258 | ||
230 | int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 259 | int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
231 | int fuser_main(int argc UNUSED_PARAM, char **argv) | 260 | int fuser_main(int argc UNUSED_PARAM, char **argv) |
232 | { | 261 | { |
233 | pid_list *plist; | ||
234 | pid_t mypid; | ||
235 | char **pp; | 262 | char **pp; |
236 | struct stat st; | 263 | |
237 | unsigned port; | 264 | INIT_G(); |
238 | int opt; | 265 | |
239 | int exitcode; | ||
240 | int killsig; | ||
241 | /* | ||
242 | fuser [OPTIONS] FILE or PORT/PROTO | ||
243 | Find processes which use FILEs or PORTs | ||
244 | -m Find processes which use same fs as FILEs | ||
245 | -4 Search only IPv4 space | ||
246 | -6 Search only IPv6 space | ||
247 | -s Don't display PIDs | ||
248 | -k Kill found processes | ||
249 | -SIGNAL Signal to send (default: KILL) | ||
250 | */ | ||
251 | /* Handle -SIGNAL. Oh my... */ | 266 | /* Handle -SIGNAL. Oh my... */ |
252 | killsig = SIGKILL; /* yes, the default is not SIGTERM */ | ||
253 | pp = argv; | 267 | pp = argv; |
254 | while (*++pp) { | 268 | while (*++pp) { |
269 | int sig; | ||
255 | char *arg = *pp; | 270 | char *arg = *pp; |
271 | |||
256 | if (arg[0] != '-') | 272 | if (arg[0] != '-') |
257 | continue; | 273 | continue; |
258 | if (arg[1] == '-' && arg[2] == '\0') /* "--" */ | 274 | if (arg[1] == '-' && arg[2] == '\0') /* "--" */ |
259 | break; | 275 | break; |
260 | if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') | 276 | if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') |
261 | continue; /* it's "-4" or "-6" */ | 277 | continue; /* it's "-4" or "-6" */ |
262 | opt = get_signum(&arg[1]); | 278 | sig = get_signum(&arg[1]); |
263 | if (opt < 0) | 279 | if (sig < 0) |
264 | continue; | 280 | continue; |
265 | /* "-SIGNAL" option found. Remove it and bail out */ | 281 | /* "-SIGNAL" option found. Remove it and bail out */ |
266 | killsig = opt; | 282 | G.killsig = sig; |
267 | do { | 283 | do { |
268 | pp[0] = arg = pp[1]; | 284 | pp[0] = arg = pp[1]; |
269 | pp++; | 285 | pp++; |
@@ -272,57 +288,35 @@ Find processes which use FILEs or PORTs | |||
272 | } | 288 | } |
273 | 289 | ||
274 | opt_complementary = "-1"; /* at least one param */ | 290 | opt_complementary = "-1"; /* at least one param */ |
275 | opt = getopt32(argv, OPTION_STRING); | 291 | getopt32(argv, OPTION_STRING); |
276 | argv += optind; | 292 | argv += optind; |
277 | 293 | ||
278 | pp = argv; | 294 | pp = argv; |
279 | while (*pp) { | 295 | while (*pp) { |
280 | /* parse net arg */ | 296 | /* parse net arg */ |
281 | char path[20], tproto[5]; | 297 | unsigned port; |
282 | if (sscanf(*pp, "%u/%4s", &port, tproto) != 2) | 298 | char path[sizeof("/proc/net/TCP6")]; |
283 | goto file; | 299 | |
284 | sprintf(path, "/proc/net/%s", tproto); | 300 | strcpy(path, "/proc/net/"); |
285 | if (access(path, R_OK) != 0) { /* PORT/PROTO */ | 301 | if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2 |
286 | scan_proc_net(path, port); | 302 | && access(path, R_OK) == 0 |
287 | } else { /* FILE */ | 303 | ) { |
288 | file: | 304 | /* PORT/PROTO */ |
289 | xstat(*pp, &st); | 305 | scan_proc_net_or_maps(path, port); |
290 | add_inode(&st); | 306 | } else { |
307 | /* FILE */ | ||
308 | struct stat statbuf; | ||
309 | xstat(*pp, &statbuf); | ||
310 | add_inode(&statbuf); | ||
291 | } | 311 | } |
292 | pp++; | 312 | pp++; |
293 | } | 313 | } |
294 | 314 | ||
295 | scan_proc_pids(); /* changes dir to "/proc" */ | 315 | if (scan_recursive("/proc")) { |
296 | 316 | if (!(option_mask32 & OPT_SILENT)) | |
297 | mypid = getpid(); | 317 | bb_putchar('\n'); |
298 | plist = G.pid_list_head; | 318 | return G.kill_failed; |
299 | while (1) { | ||
300 | if (!plist) | ||
301 | return EXIT_FAILURE; | ||
302 | if (plist->pid != mypid) | ||
303 | break; | ||
304 | plist = plist->next; | ||
305 | } | ||
306 | |||
307 | exitcode = EXIT_SUCCESS; | ||
308 | do { | ||
309 | if (plist->pid != mypid) { | ||
310 | if (opt & OPT_KILL) { | ||
311 | if (kill(plist->pid, killsig) != 0) { | ||
312 | bb_perror_msg("kill pid %u", (unsigned)plist->pid); | ||
313 | exitcode = EXIT_FAILURE; | ||
314 | } | ||
315 | } | ||
316 | if (!(opt & OPT_SILENT)) { | ||
317 | printf("%u ", (unsigned)plist->pid); | ||
318 | } | ||
319 | } | ||
320 | plist = plist->next; | ||
321 | } while (plist); | ||
322 | |||
323 | if (!(opt & (OPT_SILENT))) { | ||
324 | bb_putchar('\n'); | ||
325 | } | 319 | } |
326 | 320 | ||
327 | return exitcode; | 321 | return EXIT_FAILURE; |
328 | } | 322 | } |
diff --git a/procps/iostat.c b/procps/iostat.c index 06a33eb1d..cd233c72f 100644 --- a/procps/iostat.c +++ b/procps/iostat.c | |||
@@ -24,8 +24,6 @@ | |||
24 | #define debug(fmt, ...) ((void)0) | 24 | #define debug(fmt, ...) ((void)0) |
25 | 25 | ||
26 | #define MAX_DEVICE_NAME 12 | 26 | #define MAX_DEVICE_NAME 12 |
27 | #define CURRENT 0 | ||
28 | #define LAST 1 | ||
29 | 27 | ||
30 | #if 1 | 28 | #if 1 |
31 | typedef unsigned long long cputime_t; | 29 | typedef unsigned long long cputime_t; |
@@ -39,18 +37,33 @@ typedef long icputime_t; | |||
39 | # define CPUTIME_MAX (~0UL) | 37 | # define CPUTIME_MAX (~0UL) |
40 | #endif | 38 | #endif |
41 | 39 | ||
42 | struct stats_cpu { | 40 | enum { |
43 | cputime_t cpu_user; | 41 | STATS_CPU_USER, |
44 | cputime_t cpu_nice; | 42 | STATS_CPU_NICE, |
45 | cputime_t cpu_system; | 43 | STATS_CPU_SYSTEM, |
46 | cputime_t cpu_idle; | 44 | STATS_CPU_IDLE, |
47 | cputime_t cpu_iowait; | 45 | STATS_CPU_IOWAIT, |
48 | cputime_t cpu_steal; | 46 | STATS_CPU_IRQ, |
49 | cputime_t cpu_irq; | 47 | STATS_CPU_SOFTIRQ, |
50 | cputime_t cpu_softirq; | 48 | STATS_CPU_STEAL, |
51 | cputime_t cpu_guest; | 49 | STATS_CPU_GUEST, |
50 | |||
51 | GLOBAL_UPTIME, | ||
52 | SMP_UPTIME, | ||
53 | |||
54 | N_STATS_CPU, | ||
52 | }; | 55 | }; |
53 | 56 | ||
57 | typedef struct { | ||
58 | cputime_t vector[N_STATS_CPU]; | ||
59 | } stats_cpu_t; | ||
60 | |||
61 | typedef struct { | ||
62 | stats_cpu_t *prev; | ||
63 | stats_cpu_t *curr; | ||
64 | cputime_t itv; | ||
65 | } stats_cpu_pair_t; | ||
66 | |||
54 | struct stats_dev { | 67 | struct stats_dev { |
55 | char dname[MAX_DEVICE_NAME]; | 68 | char dname[MAX_DEVICE_NAME]; |
56 | unsigned long long rd_sectors; | 69 | unsigned long long rd_sectors; |
@@ -59,24 +72,24 @@ struct stats_dev { | |||
59 | unsigned long wr_ops; | 72 | unsigned long wr_ops; |
60 | }; | 73 | }; |
61 | 74 | ||
62 | /* List of devices entered on the command line */ | ||
63 | struct device_list { | ||
64 | char dname[MAX_DEVICE_NAME]; | ||
65 | }; | ||
66 | |||
67 | /* Globals. Sort by size and access frequency. */ | 75 | /* Globals. Sort by size and access frequency. */ |
68 | struct globals { | 76 | struct globals { |
69 | smallint show_all; | 77 | smallint show_all; |
70 | unsigned devlist_i; /* Index to the list of devices */ | ||
71 | unsigned total_cpus; /* Number of CPUs */ | 78 | unsigned total_cpus; /* Number of CPUs */ |
72 | unsigned clk_tck; /* Number of clock ticks per second */ | 79 | unsigned clk_tck; /* Number of clock ticks per second */ |
73 | struct device_list *dlist; | 80 | llist_t *dev_list; /* List of devices entered on the command line */ |
74 | struct stats_dev *saved_stats_dev; | 81 | struct stats_dev *saved_stats_dev; |
75 | struct tm tmtime; | 82 | struct tm tmtime; |
83 | struct { | ||
84 | const char *str; | ||
85 | unsigned div; | ||
86 | } unit; | ||
76 | }; | 87 | }; |
77 | #define G (*ptr_to_globals) | 88 | #define G (*ptr_to_globals) |
78 | #define INIT_G() do { \ | 89 | #define INIT_G() do { \ |
79 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 90 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
91 | G.unit.str = "Blk"; \ | ||
92 | G.unit.div = 1; \ | ||
80 | } while (0) | 93 | } while (0) |
81 | 94 | ||
82 | /* Must match option string! */ | 95 | /* Must match option string! */ |
@@ -104,12 +117,12 @@ static void print_header(void) | |||
104 | char buf[16]; | 117 | char buf[16]; |
105 | struct utsname uts; | 118 | struct utsname uts; |
106 | 119 | ||
107 | if (uname(&uts) < 0) | 120 | uname(&uts); /* never fails */ |
108 | bb_perror_msg_and_die("uname"); | ||
109 | 121 | ||
122 | /* Date representation for the current locale */ | ||
110 | strftime(buf, sizeof(buf), "%x", &G.tmtime); | 123 | strftime(buf, sizeof(buf), "%x", &G.tmtime); |
111 | 124 | ||
112 | printf("%s %s (%s) \t%s \t_%s_\t(%d CPU)\n\n", | 125 | printf("%s %s (%s) \t%s \t_%s_\t(%u CPU)\n\n", |
113 | uts.sysname, uts.release, uts.nodename, | 126 | uts.sysname, uts.release, uts.nodename, |
114 | buf, uts.machine, G.total_cpus); | 127 | buf, uts.machine, G.total_cpus); |
115 | } | 128 | } |
@@ -124,61 +137,58 @@ static void get_localtime(struct tm *ptm) | |||
124 | static void print_timestamp(void) | 137 | static void print_timestamp(void) |
125 | { | 138 | { |
126 | char buf[20]; | 139 | char buf[20]; |
140 | /* %x: date representation for the current locale */ | ||
141 | /* %X: time representation for the current locale */ | ||
127 | strftime(buf, sizeof(buf), "%x %X", &G.tmtime); | 142 | strftime(buf, sizeof(buf), "%x %X", &G.tmtime); |
128 | printf("%s\n", buf); | 143 | printf("%s\n", buf); |
129 | } | 144 | } |
130 | 145 | ||
131 | /* Fetch CPU statistics from /proc/stat */ | 146 | static cputime_t get_smp_uptime(void) |
132 | static void get_cpu_statistics(struct stats_cpu *sc) | ||
133 | { | 147 | { |
134 | FILE *fp; | 148 | FILE *fp; |
135 | char buf[1024]; | 149 | unsigned long sec, dec; |
136 | |||
137 | fp = xfopen_for_read("/proc/stat"); | ||
138 | 150 | ||
139 | memset(sc, 0, sizeof(*sc)); | 151 | fp = xfopen_for_read("/proc/uptime"); |
140 | 152 | ||
141 | while (fgets(buf, sizeof(buf), fp)) { | 153 | if (fscanf(fp, "%lu.%lu", &sec, &dec) != 2) |
142 | /* Does the line starts with "cpu "? */ | 154 | bb_error_msg_and_die("can't read '%s'", "/proc/uptime"); |
143 | if (starts_with_cpu(buf) && buf[3] == ' ') { | ||
144 | sscanf(buf + 4 + 1, | ||
145 | "%"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %" | ||
146 | FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u", | ||
147 | &sc->cpu_user, &sc->cpu_nice, &sc->cpu_system, | ||
148 | &sc->cpu_idle, &sc->cpu_iowait, &sc->cpu_irq, | ||
149 | &sc->cpu_softirq, &sc->cpu_steal, &sc->cpu_guest); | ||
150 | } | ||
151 | } | ||
152 | 155 | ||
153 | fclose(fp); | 156 | fclose(fp); |
157 | |||
158 | return (cputime_t)sec * G.clk_tck + dec * G.clk_tck / 100; | ||
154 | } | 159 | } |
155 | 160 | ||
156 | static cputime_t get_smp_uptime(void) | 161 | /* Fetch CPU statistics from /proc/stat */ |
162 | static void get_cpu_statistics(stats_cpu_t *sc) | ||
157 | { | 163 | { |
158 | FILE *fp; | 164 | FILE *fp; |
159 | char buf[sizeof(long)*3 * 2 + 4]; | 165 | char buf[1024], *ibuf = buf + 4; |
160 | unsigned long sec, dec; | ||
161 | 166 | ||
162 | fp = xfopen_for_read("/proc/uptime"); | 167 | fp = xfopen_for_read("/proc/stat"); |
163 | 168 | ||
164 | if (fgets(buf, sizeof(buf), fp)) | 169 | memset(sc, 0, sizeof(*sc)); |
165 | if (sscanf(buf, "%lu.%lu", &sec, &dec) != 2) | ||
166 | bb_error_msg_and_die("can't read /proc/uptime"); | ||
167 | 170 | ||
168 | fclose(fp); | 171 | while (fgets(buf, sizeof(buf), fp)) { |
172 | /* Does the line starts with "cpu "? */ | ||
173 | if (!starts_with_cpu(buf) || buf[3] != ' ') { | ||
174 | continue; | ||
175 | } | ||
176 | for (int i = STATS_CPU_USER; i <= STATS_CPU_GUEST; i++) { | ||
177 | ibuf = skip_whitespace(ibuf); | ||
178 | sscanf(ibuf, "%"FMT_DATA"u", &sc->vector[i]); | ||
179 | if (i != STATS_CPU_GUEST) { | ||
180 | sc->vector[GLOBAL_UPTIME] += sc->vector[i]; | ||
181 | } | ||
182 | ibuf = skip_non_whitespace(ibuf); | ||
183 | } | ||
184 | break; | ||
185 | } | ||
169 | 186 | ||
170 | return (cputime_t)sec * G.clk_tck + dec * G.clk_tck / 100; | 187 | if (this_is_smp()) { |
171 | } | 188 | sc->vector[SMP_UPTIME] = get_smp_uptime(); |
189 | } | ||
172 | 190 | ||
173 | /* | 191 | fclose(fp); |
174 | * Obtain current uptime in jiffies. | ||
175 | * Uptime is sum of individual CPUs' uptimes. | ||
176 | */ | ||
177 | static cputime_t get_uptime(const struct stats_cpu *sc) | ||
178 | { | ||
179 | /* NB: Don't include cpu_guest, it is already in cpu_user */ | ||
180 | return sc->cpu_user + sc->cpu_nice + sc->cpu_system + sc->cpu_idle + | ||
181 | + sc->cpu_iowait + sc->cpu_irq + sc->cpu_steal + sc->cpu_softirq; | ||
182 | } | 192 | } |
183 | 193 | ||
184 | static ALWAYS_INLINE cputime_t get_interval(cputime_t old, cputime_t new) | 194 | static ALWAYS_INLINE cputime_t get_interval(cputime_t old, cputime_t new) |
@@ -219,65 +229,51 @@ static double percent_value(cputime_t prev, cputime_t curr, cputime_t itv) | |||
219 | return ((double)overflow_safe_sub(prev, curr)) / itv * 100; | 229 | return ((double)overflow_safe_sub(prev, curr)) / itv * 100; |
220 | } | 230 | } |
221 | 231 | ||
222 | static void print_stats_cpu_struct(const struct stats_cpu *p, | 232 | static void print_stats_cpu_struct(stats_cpu_pair_t *stats) |
223 | const struct stats_cpu *c, cputime_t itv) | ||
224 | { | 233 | { |
234 | cputime_t *p = stats->prev->vector; | ||
235 | cputime_t *c = stats->curr->vector; | ||
225 | printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", | 236 | printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", |
226 | percent_value(p->cpu_user , c->cpu_user , itv), | 237 | percent_value(p[STATS_CPU_USER] , c[STATS_CPU_USER] , stats->itv), |
227 | percent_value(p->cpu_nice , c->cpu_nice , itv), | 238 | percent_value(p[STATS_CPU_NICE] , c[STATS_CPU_NICE] , stats->itv), |
228 | percent_value(p->cpu_system + p->cpu_softirq + p->cpu_irq, | 239 | percent_value(p[STATS_CPU_SYSTEM] + p[STATS_CPU_SOFTIRQ] + p[STATS_CPU_IRQ], |
229 | c->cpu_system + c->cpu_softirq + c->cpu_irq, itv), | 240 | c[STATS_CPU_SYSTEM] + c[STATS_CPU_SOFTIRQ] + c[STATS_CPU_IRQ], stats->itv), |
230 | percent_value(p->cpu_iowait , c->cpu_iowait , itv), | 241 | percent_value(p[STATS_CPU_IOWAIT], c[STATS_CPU_IOWAIT], stats->itv), |
231 | percent_value(p->cpu_steal , c->cpu_steal , itv), | 242 | percent_value(p[STATS_CPU_STEAL] , c[STATS_CPU_STEAL] , stats->itv), |
232 | percent_value(p->cpu_idle , c->cpu_idle , itv) | 243 | percent_value(p[STATS_CPU_IDLE] , c[STATS_CPU_IDLE] , stats->itv) |
233 | ); | 244 | ); |
234 | } | 245 | } |
235 | 246 | ||
236 | static void print_stats_dev_struct(const struct stats_dev *p, | 247 | static void print_stats_dev_struct(const struct stats_dev *p, |
237 | const struct stats_dev *c, cputime_t itv) | 248 | const struct stats_dev *c, cputime_t itv) |
238 | { | 249 | { |
239 | int unit = 1; | ||
240 | |||
241 | if (option_mask32 & OPT_k) | ||
242 | unit = 2; | ||
243 | else if (option_mask32 & OPT_m) | ||
244 | unit = 2048; | ||
245 | |||
246 | if (option_mask32 & OPT_z) | 250 | if (option_mask32 & OPT_z) |
247 | if (p->rd_ops == c->rd_ops && p->wr_ops == c->wr_ops) | 251 | if (p->rd_ops == c->rd_ops && p->wr_ops == c->wr_ops) |
248 | return; | 252 | return; |
249 | 253 | ||
250 | printf("%-13s", c->dname); | 254 | printf("%-13s %8.2f %12.2f %12.2f %10llu %10llu \n", c->dname, |
251 | printf(" %8.2f %12.2f %12.2f %10llu %10llu \n", | ||
252 | percent_value(p->rd_ops + p->wr_ops , | 255 | percent_value(p->rd_ops + p->wr_ops , |
253 | /**/ c->rd_ops + c->wr_ops , itv), | 256 | /**/ c->rd_ops + c->wr_ops , itv), |
254 | percent_value(p->rd_sectors, c->rd_sectors, itv) / unit, | 257 | percent_value(p->rd_sectors, c->rd_sectors, itv) / G.unit.div, |
255 | percent_value(p->wr_sectors, c->wr_sectors, itv) / unit, | 258 | percent_value(p->wr_sectors, c->wr_sectors, itv) / G.unit.div, |
256 | (c->rd_sectors - p->rd_sectors) / unit, | 259 | (c->rd_sectors - p->rd_sectors) / G.unit.div, |
257 | (c->wr_sectors - p->wr_sectors) / unit); | 260 | (c->wr_sectors - p->wr_sectors) / G.unit.div); |
258 | } | 261 | } |
259 | 262 | ||
260 | static void cpu_report(const struct stats_cpu *last, | 263 | static void cpu_report(stats_cpu_pair_t *stats) |
261 | const struct stats_cpu *cur, | ||
262 | cputime_t itv) | ||
263 | { | 264 | { |
264 | /* Always print a header */ | 265 | /* Always print a header */ |
265 | puts("avg-cpu: %user %nice %system %iowait %steal %idle"); | 266 | puts("avg-cpu: %user %nice %system %iowait %steal %idle"); |
266 | 267 | ||
267 | /* Print current statistics */ | 268 | /* Print current statistics */ |
268 | print_stats_cpu_struct(last, cur, itv); | 269 | print_stats_cpu_struct(stats); |
269 | } | 270 | } |
270 | 271 | ||
271 | static void print_devstat_header(void) | 272 | static void print_devstat_header(void) |
272 | { | 273 | { |
273 | printf("Device: tps"); | 274 | printf("Device:%15s%6s%s/s%6s%s/s%6s%s%6s%s\n", "tps", |
274 | 275 | G.unit.str, "_read", G.unit.str, "_wrtn", | |
275 | if (option_mask32 & OPT_m) | 276 | G.unit.str, "_read", G.unit.str, "_wrtn"); |
276 | puts(" MB_read/s MB_wrtn/s MB_read MB_wrtn"); | ||
277 | else if (option_mask32 & OPT_k) | ||
278 | puts(" kB_read/s kB_wrtn/s kB_read kB_wrtn"); | ||
279 | else | ||
280 | puts(" Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn"); | ||
281 | } | 277 | } |
282 | 278 | ||
283 | /* | 279 | /* |
@@ -289,37 +285,6 @@ static int is_partition(const char *dev) | |||
289 | return ((dev[0] - 's') | (dev[1] - 'd') | (dev[2] - 'a')) == 0 && isdigit(dev[3]); | 285 | return ((dev[0] - 's') | (dev[1] - 'd') | (dev[2] - 'a')) == 0 && isdigit(dev[3]); |
290 | } | 286 | } |
291 | 287 | ||
292 | /* | ||
293 | * Return number of numbers on cmdline. | ||
294 | * Reasonable values are only 0 (no interval/count specified), | ||
295 | * 1 (interval specified) and 2 (both interval and count specified) | ||
296 | */ | ||
297 | static int numbers_on_cmdline(int argc, char *argv[]) | ||
298 | { | ||
299 | int sum = 0; | ||
300 | |||
301 | if (isdigit(argv[argc-1][0])) | ||
302 | sum++; | ||
303 | if (argc > 2 && isdigit(argv[argc-2][0])) | ||
304 | sum++; | ||
305 | |||
306 | return sum; | ||
307 | } | ||
308 | |||
309 | static int is_dev_in_dlist(const char *dev) | ||
310 | { | ||
311 | int i; | ||
312 | |||
313 | /* Go through the device list */ | ||
314 | for (i = 0; i < G.devlist_i; i++) | ||
315 | if (strcmp(G.dlist[i].dname, dev) == 0) | ||
316 | /* Found a match */ | ||
317 | return 1; | ||
318 | |||
319 | /* No match found */ | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static void do_disk_statistics(cputime_t itv) | 288 | static void do_disk_statistics(cputime_t itv) |
324 | { | 289 | { |
325 | FILE *fp; | 290 | FILE *fp; |
@@ -356,7 +321,7 @@ static void do_disk_statistics(cputime_t itv) | |||
356 | break; | 321 | break; |
357 | } | 322 | } |
358 | 323 | ||
359 | if (!G.devlist_i && !is_partition(sd.dname)) { | 324 | if (!G.dev_list && !is_partition(sd.dname)) { |
360 | /* User didn't specify device */ | 325 | /* User didn't specify device */ |
361 | if (!G.show_all && !sd.rd_ops && !sd.wr_ops) { | 326 | if (!G.show_all && !sd.rd_ops && !sd.wr_ops) { |
362 | /* Don't print unused device */ | 327 | /* Don't print unused device */ |
@@ -367,7 +332,7 @@ static void do_disk_statistics(cputime_t itv) | |||
367 | i++; | 332 | i++; |
368 | } else { | 333 | } else { |
369 | /* Is device in device list? */ | 334 | /* Is device in device list? */ |
370 | if (is_dev_in_dlist(sd.dname)) { | 335 | if (llist_find_str(G.dev_list, sd.dname)) { |
371 | /* Print current statistics */ | 336 | /* Print current statistics */ |
372 | print_stats_dev_struct(&G.saved_stats_dev[i], &sd, itv); | 337 | print_stats_dev_struct(&G.saved_stats_dev[i], &sd, itv); |
373 | G.saved_stats_dev[i] = sd; | 338 | G.saved_stats_dev[i] = sd; |
@@ -389,28 +354,6 @@ static void dev_report(cputime_t itv) | |||
389 | do_disk_statistics(itv); | 354 | do_disk_statistics(itv); |
390 | } | 355 | } |
391 | 356 | ||
392 | static void save_to_devlist(const char *dname) | ||
393 | { | ||
394 | int i; | ||
395 | struct device_list *tmp = G.dlist; | ||
396 | |||
397 | if (strncmp(dname, "/dev/", 5) == 0) | ||
398 | /* We'll ignore prefix '/dev/' */ | ||
399 | dname += 5; | ||
400 | |||
401 | /* Go through the list */ | ||
402 | for (i = 0; i < G.devlist_i; i++, tmp++) | ||
403 | if (strcmp(tmp->dname, dname) == 0) | ||
404 | /* Already in the list */ | ||
405 | return; | ||
406 | |||
407 | /* Add device name to the list */ | ||
408 | strncpy(tmp->dname, dname, MAX_DEVICE_NAME - 1); | ||
409 | |||
410 | /* Update device list index */ | ||
411 | G.devlist_i++; | ||
412 | } | ||
413 | |||
414 | static unsigned get_number_of_devices(void) | 357 | static unsigned get_number_of_devices(void) |
415 | { | 358 | { |
416 | FILE *fp; | 359 | FILE *fp; |
@@ -440,18 +383,6 @@ static unsigned get_number_of_devices(void) | |||
440 | return n; | 383 | return n; |
441 | } | 384 | } |
442 | 385 | ||
443 | static int number_of_ALL_on_cmdline(char **argv) | ||
444 | { | ||
445 | int alls = 0; | ||
446 | |||
447 | /* Iterate over cmd line arguments, count "ALL" */ | ||
448 | while (*argv) | ||
449 | if (strcmp(*argv++, "ALL") == 0) | ||
450 | alls++; | ||
451 | |||
452 | return alls; | ||
453 | } | ||
454 | |||
455 | //usage:#define iostat_trivial_usage | 386 | //usage:#define iostat_trivial_usage |
456 | //usage: "[-c] [-d] [-t] [-z] [-k|-m] [ALL|BLOCKDEV...] [INTERVAL [COUNT]]" | 387 | //usage: "[-c] [-d] [-t] [-z] [-k|-m] [ALL|BLOCKDEV...] [INTERVAL [COUNT]]" |
457 | //usage:#define iostat_full_usage "\n\n" | 388 | //usage:#define iostat_full_usage "\n\n" |
@@ -465,19 +396,17 @@ static int number_of_ALL_on_cmdline(char **argv) | |||
465 | //usage: "\n -m Use Mb/s" | 396 | //usage: "\n -m Use Mb/s" |
466 | 397 | ||
467 | int iostat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 398 | int iostat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
468 | int iostat_main(int argc, char **argv) | 399 | int iostat_main(int argc UNUSED_PARAM, char **argv) |
469 | { | 400 | { |
470 | int opt, dev_num; | 401 | int opt, dev_num; |
471 | unsigned interval = 0; | 402 | unsigned interval; |
472 | int count; | 403 | int count; |
473 | cputime_t global_uptime[2] = { 0 }; | 404 | stats_cpu_t stats_data[2]; |
474 | cputime_t smp_uptime[2] = { 0 }; | 405 | smallint current_stats; |
475 | cputime_t itv; | ||
476 | struct stats_cpu stats_cur, stats_last; | ||
477 | 406 | ||
478 | INIT_G(); | 407 | INIT_G(); |
479 | 408 | ||
480 | memset(&stats_last, 0, sizeof(stats_last)); | 409 | memset(&stats_data, 0, sizeof(stats_data)); |
481 | 410 | ||
482 | /* Get number of clock ticks per sec */ | 411 | /* Get number of clock ticks per sec */ |
483 | G.clk_tck = get_user_hz(); | 412 | G.clk_tck = get_user_hz(); |
@@ -496,25 +425,24 @@ int iostat_main(int argc, char **argv) | |||
496 | opt |= OPT_c + OPT_d; | 425 | opt |= OPT_c + OPT_d; |
497 | 426 | ||
498 | argv += optind; | 427 | argv += optind; |
499 | argc -= optind; | ||
500 | |||
501 | dev_num = argc - numbers_on_cmdline(argc, argv); | ||
502 | /* We don't want to allocate space for 'ALL' */ | ||
503 | dev_num -= number_of_ALL_on_cmdline(argv); | ||
504 | if (dev_num > 0) | ||
505 | /* Make space for device list */ | ||
506 | G.dlist = xzalloc(sizeof(G.dlist[0]) * dev_num); | ||
507 | 428 | ||
508 | /* Store device names into device list */ | 429 | /* Store device names into device list */ |
430 | dev_num = 0; | ||
509 | while (*argv && !isdigit(*argv[0])) { | 431 | while (*argv && !isdigit(*argv[0])) { |
510 | if (strcmp(*argv, "ALL") != 0) | 432 | if (strcmp(*argv, "ALL") != 0) { |
511 | /* If not ALL, save device name */ | 433 | /* If not ALL, save device name */ |
512 | save_to_devlist(*argv); | 434 | char *dev_name = skip_dev_pfx(*argv); |
513 | else | 435 | if (!llist_find_str(G.dev_list, dev_name)) { |
436 | llist_add_to(&G.dev_list, dev_name); | ||
437 | dev_num++; | ||
438 | } | ||
439 | } else { | ||
514 | G.show_all = 1; | 440 | G.show_all = 1; |
441 | } | ||
515 | argv++; | 442 | argv++; |
516 | } | 443 | } |
517 | 444 | ||
445 | interval = 0; | ||
518 | count = 1; | 446 | count = 1; |
519 | if (*argv) { | 447 | if (*argv) { |
520 | /* Get interval */ | 448 | /* Get interval */ |
@@ -533,28 +461,46 @@ int iostat_main(int argc, char **argv) | |||
533 | ); | 461 | ); |
534 | } | 462 | } |
535 | 463 | ||
464 | if (opt & OPT_m) { | ||
465 | G.unit.str = " MB"; | ||
466 | G.unit.div = 2048; | ||
467 | } | ||
468 | |||
469 | if (opt & OPT_k) { | ||
470 | G.unit.str = " kB"; | ||
471 | G.unit.div = 2; | ||
472 | } | ||
473 | |||
474 | get_localtime(&G.tmtime); | ||
475 | |||
536 | /* Display header */ | 476 | /* Display header */ |
537 | print_header(); | 477 | print_header(); |
538 | 478 | ||
479 | current_stats = 0; | ||
539 | /* Main loop */ | 480 | /* Main loop */ |
540 | for (;;) { | 481 | for (;;) { |
482 | stats_cpu_pair_t stats; | ||
483 | |||
484 | stats.prev = &stats_data[current_stats ^ 1]; | ||
485 | stats.curr = &stats_data[current_stats]; | ||
486 | |||
541 | /* Fill the time structure */ | 487 | /* Fill the time structure */ |
542 | get_localtime(&G.tmtime); | 488 | get_localtime(&G.tmtime); |
543 | 489 | ||
544 | /* Fetch current CPU statistics */ | 490 | /* Fetch current CPU statistics */ |
545 | get_cpu_statistics(&stats_cur); | 491 | get_cpu_statistics(stats.curr); |
546 | |||
547 | /* Fetch current uptime */ | ||
548 | global_uptime[CURRENT] = get_uptime(&stats_cur); | ||
549 | 492 | ||
550 | /* Get interval */ | 493 | /* Get interval */ |
551 | itv = get_interval(global_uptime[LAST], global_uptime[CURRENT]); | 494 | stats.itv = get_interval( |
495 | stats.prev->vector[GLOBAL_UPTIME], | ||
496 | stats.curr->vector[GLOBAL_UPTIME] | ||
497 | ); | ||
552 | 498 | ||
553 | if (opt & OPT_t) | 499 | if (opt & OPT_t) |
554 | print_timestamp(); | 500 | print_timestamp(); |
555 | 501 | ||
556 | if (opt & OPT_c) { | 502 | if (opt & OPT_c) { |
557 | cpu_report(&stats_last, &stats_cur, itv); | 503 | cpu_report(&stats); |
558 | if (opt & OPT_d) | 504 | if (opt & OPT_d) |
559 | /* Separate outputs by a newline */ | 505 | /* Separate outputs by a newline */ |
560 | bb_putchar('\n'); | 506 | bb_putchar('\n'); |
@@ -562,32 +508,31 @@ int iostat_main(int argc, char **argv) | |||
562 | 508 | ||
563 | if (opt & OPT_d) { | 509 | if (opt & OPT_d) { |
564 | if (this_is_smp()) { | 510 | if (this_is_smp()) { |
565 | smp_uptime[CURRENT] = get_smp_uptime(); | 511 | stats.itv = get_interval( |
566 | itv = get_interval(smp_uptime[LAST], smp_uptime[CURRENT]); | 512 | stats.prev->vector[SMP_UPTIME], |
567 | smp_uptime[LAST] = smp_uptime[CURRENT]; | 513 | stats.curr->vector[SMP_UPTIME] |
514 | ); | ||
568 | } | 515 | } |
569 | dev_report(itv); | 516 | dev_report(stats.itv); |
570 | } | 517 | } |
571 | 518 | ||
519 | bb_putchar('\n'); | ||
520 | |||
572 | if (count > 0) { | 521 | if (count > 0) { |
573 | if (--count == 0) | 522 | if (--count == 0) |
574 | break; | 523 | break; |
575 | } | 524 | } |
576 | 525 | ||
577 | /* Backup current stats */ | 526 | /* Swap stats */ |
578 | global_uptime[LAST] = global_uptime[CURRENT]; | 527 | current_stats ^= 1; |
579 | stats_last = stats_cur; | ||
580 | 528 | ||
581 | bb_putchar('\n'); | ||
582 | sleep(interval); | 529 | sleep(interval); |
583 | } | 530 | } |
584 | 531 | ||
585 | bb_putchar('\n'); | ||
586 | |||
587 | if (ENABLE_FEATURE_CLEAN_UP) { | 532 | if (ENABLE_FEATURE_CLEAN_UP) { |
588 | free(&G); | 533 | llist_free(G.dev_list, NULL); |
589 | free(G.dlist); | ||
590 | free(G.saved_stats_dev); | 534 | free(G.saved_stats_dev); |
535 | free(&G); | ||
591 | } | 536 | } |
592 | 537 | ||
593 | return EXIT_SUCCESS; | 538 | return EXIT_SUCCESS; |
diff --git a/procps/mpstat.c b/procps/mpstat.c index d643c999f..da8f34dab 100644 --- a/procps/mpstat.c +++ b/procps/mpstat.c | |||
@@ -36,11 +36,10 @@ | |||
36 | * We are printing headers in the " IRQNAME/s" form, experimentally | 36 | * We are printing headers in the " IRQNAME/s" form, experimentally |
37 | * anything smaller than 10 chars looks ugly for /proc/softirqs stats. | 37 | * anything smaller than 10 chars looks ugly for /proc/softirqs stats. |
38 | */ | 38 | */ |
39 | #define INTRATE_SCRWIDTH 10 | 39 | #define INTRATE_SCRWIDTH 10 |
40 | #define INTRATE_SCRWIDTH_STR "10" | 40 | #define INTRATE_SCRWIDTH_STR "10" |
41 | 41 | ||
42 | /* System files */ | 42 | /* System files */ |
43 | #define SYSFS_DEVCPU "/sys/devices/system/cpu" | ||
44 | #define PROCFS_STAT "/proc/stat" | 43 | #define PROCFS_STAT "/proc/stat" |
45 | #define PROCFS_INTERRUPTS "/proc/interrupts" | 44 | #define PROCFS_INTERRUPTS "/proc/interrupts" |
46 | #define PROCFS_SOFTIRQS "/proc/softirqs" | 45 | #define PROCFS_SOFTIRQS "/proc/softirqs" |
diff --git a/procps/nmeter.c b/procps/nmeter.c index 48b56a399..999955982 100644 --- a/procps/nmeter.c +++ b/procps/nmeter.c | |||
@@ -24,20 +24,20 @@ | |||
24 | //usage: "\n -d MSEC Milliseconds between updates (default:1000)" | 24 | //usage: "\n -d MSEC Milliseconds between updates (default:1000)" |
25 | //usage: "\n" | 25 | //usage: "\n" |
26 | //usage: "\nFormat specifiers:" | 26 | //usage: "\nFormat specifiers:" |
27 | //usage: "\n %Nc or %[cN] Monitor CPU. N - bar size (default:10)" | 27 | //usage: "\n %Nc or %[cN] CPU. N - bar size (default:10)" |
28 | //usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)" | 28 | //usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)" |
29 | //usage: "\n %[niface] Monitor network interface 'iface'" | 29 | //usage: "\n %[nINTERFACE] Network INTERFACE" |
30 | //usage: "\n %m Monitor allocated memory" | 30 | //usage: "\n %m Allocated memory" |
31 | //usage: "\n %[mf] Monitor free memory" | 31 | //usage: "\n %[mf] Free memory" |
32 | //usage: "\n %[mt] Monitor total memory" | 32 | //usage: "\n %[mt] Total memory" |
33 | //usage: "\n %s Monitor allocated swap" | 33 | //usage: "\n %s Allocated swap" |
34 | //usage: "\n %f Monitor number of used file descriptors" | 34 | //usage: "\n %f Number of used file descriptors" |
35 | //usage: "\n %Ni Monitor total/specific IRQ rate" | 35 | //usage: "\n %Ni Total/specific IRQ rate" |
36 | //usage: "\n %x Monitor context switch rate" | 36 | //usage: "\n %x Context switch rate" |
37 | //usage: "\n %p Monitor forks" | 37 | //usage: "\n %p Forks" |
38 | //usage: "\n %[pn] Monitor # of processes" | 38 | //usage: "\n %[pn] # of processes" |
39 | //usage: "\n %b Monitor block io" | 39 | //usage: "\n %b Block io" |
40 | //usage: "\n %Nt Show time (with N decimal points)" | 40 | //usage: "\n %Nt Time (with N decimal points)" |
41 | //usage: "\n %r Print <cr> instead of <lf> at EOL" | 41 | //usage: "\n %r Print <cr> instead of <lf> at EOL" |
42 | 42 | ||
43 | //TODO: | 43 | //TODO: |
diff --git a/procps/powertop.c b/procps/powertop.c index bfe5a9568..008cdfca4 100644 --- a/procps/powertop.c +++ b/procps/powertop.c | |||
@@ -393,11 +393,9 @@ static NOINLINE int process_timer_stats(void) | |||
393 | char buf[128]; | 393 | char buf[128]; |
394 | char line[15 + 3 + 128]; | 394 | char line[15 + 3 + 128]; |
395 | int n; | 395 | int n; |
396 | ullong totalticks; | ||
397 | FILE *fp; | 396 | FILE *fp; |
398 | 397 | ||
399 | buf[0] = '\0'; | 398 | buf[0] = '\0'; |
400 | totalticks = 0; | ||
401 | 399 | ||
402 | n = 0; | 400 | n = 0; |
403 | fp = NULL; | 401 | fp = NULL; |
diff --git a/procps/top.c b/procps/top.c index ee6555188..011bbf183 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -92,9 +92,9 @@ enum { SORT_DEPTH = 3 }; | |||
92 | struct globals { | 92 | struct globals { |
93 | top_status_t *top; | 93 | top_status_t *top; |
94 | int ntop; | 94 | int ntop; |
95 | smallint inverted; | ||
95 | #if ENABLE_FEATURE_TOPMEM | 96 | #if ENABLE_FEATURE_TOPMEM |
96 | smallint sort_field; | 97 | smallint sort_field; |
97 | smallint inverted; | ||
98 | #endif | 98 | #endif |
99 | #if ENABLE_FEATURE_TOP_SMP_CPU | 99 | #if ENABLE_FEATURE_TOP_SMP_CPU |
100 | smallint smp_cpu_info; /* one/many cpu info lines? */ | 100 | smallint smp_cpu_info; /* one/many cpu info lines? */ |
@@ -194,9 +194,9 @@ static int mult_lvl_cmp(void* a, void* b) | |||
194 | for (i = 0; i < SORT_DEPTH; i++) { | 194 | for (i = 0; i < SORT_DEPTH; i++) { |
195 | cmp_val = (*sort_function[i])(a, b); | 195 | cmp_val = (*sort_function[i])(a, b); |
196 | if (cmp_val != 0) | 196 | if (cmp_val != 0) |
197 | return cmp_val; | 197 | break; |
198 | } | 198 | } |
199 | return 0; | 199 | return inverted ? -cmp_val : cmp_val; |
200 | } | 200 | } |
201 | 201 | ||
202 | static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) | 202 | static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) |
@@ -797,7 +797,7 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) | |||
797 | 797 | ||
798 | display_topmem_header(scr_width, &lines_rem); | 798 | display_topmem_header(scr_width, &lines_rem); |
799 | strcpy(line_buf, HDR_STR " COMMAND"); | 799 | strcpy(line_buf, HDR_STR " COMMAND"); |
800 | line_buf[5 + sort_field * 6] = '*'; | 800 | line_buf[11 + sort_field * 6] = "^_"[inverted]; |
801 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); | 801 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); |
802 | lines_rem--; | 802 | lines_rem--; |
803 | 803 | ||
@@ -850,8 +850,114 @@ enum { | |||
850 | | PSSCAN_PID | 850 | | PSSCAN_PID |
851 | | PSSCAN_SMAPS | 851 | | PSSCAN_SMAPS |
852 | | PSSCAN_COMM, | 852 | | PSSCAN_COMM, |
853 | EXIT_MASK = (unsigned)-1, | ||
853 | }; | 854 | }; |
854 | 855 | ||
856 | #if ENABLE_FEATURE_USE_TERMIOS | ||
857 | static unsigned handle_input(unsigned scan_mask, unsigned interval) | ||
858 | { | ||
859 | unsigned char c; | ||
860 | struct pollfd pfd[1]; | ||
861 | |||
862 | pfd[0].fd = 0; | ||
863 | pfd[0].events = POLLIN; | ||
864 | |||
865 | while (1) { | ||
866 | if (safe_poll(pfd, 1, interval * 1000) <= 0) | ||
867 | return scan_mask; | ||
868 | interval = 0; | ||
869 | |||
870 | if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ | ||
871 | option_mask32 |= OPT_EOF; | ||
872 | return scan_mask; | ||
873 | } | ||
874 | |||
875 | if (c == initial_settings.c_cc[VINTR]) | ||
876 | return EXIT_MASK; | ||
877 | if (c == initial_settings.c_cc[VEOF]) | ||
878 | return EXIT_MASK; | ||
879 | c |= 0x20; /* lowercase */ | ||
880 | if (c == 'q') | ||
881 | return EXIT_MASK; | ||
882 | |||
883 | if (c == 'n') { | ||
884 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
885 | sort_function[0] = pid_sort; | ||
886 | continue; | ||
887 | } | ||
888 | if (c == 'm') { | ||
889 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
890 | sort_function[0] = mem_sort; | ||
891 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
892 | sort_function[1] = pcpu_sort; | ||
893 | sort_function[2] = time_sort; | ||
894 | # endif | ||
895 | continue; | ||
896 | } | ||
897 | # if ENABLE_FEATURE_SHOW_THREADS | ||
898 | if (c == 'h' | ||
899 | IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) | ||
900 | ) { | ||
901 | scan_mask ^= PSSCAN_TASKS; | ||
902 | continue; | ||
903 | } | ||
904 | # endif | ||
905 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
906 | if (c == 'p') { | ||
907 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
908 | sort_function[0] = pcpu_sort; | ||
909 | sort_function[1] = mem_sort; | ||
910 | sort_function[2] = time_sort; | ||
911 | continue; | ||
912 | } | ||
913 | if (c == 't') { | ||
914 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
915 | sort_function[0] = time_sort; | ||
916 | sort_function[1] = mem_sort; | ||
917 | sort_function[2] = pcpu_sort; | ||
918 | continue; | ||
919 | } | ||
920 | # if ENABLE_FEATURE_TOPMEM | ||
921 | if (c == 's') { | ||
922 | scan_mask = TOPMEM_MASK; | ||
923 | free(prev_hist); | ||
924 | prev_hist = NULL; | ||
925 | prev_hist_count = 0; | ||
926 | sort_field = (sort_field + 1) % NUM_SORT_FIELD; | ||
927 | continue; | ||
928 | } | ||
929 | # endif | ||
930 | if (c == 'r') { | ||
931 | inverted ^= 1; | ||
932 | continue; | ||
933 | } | ||
934 | # if ENABLE_FEATURE_TOP_SMP_CPU | ||
935 | /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ | ||
936 | if (c == 'c' || c == '1') { | ||
937 | /* User wants to toggle per cpu <> aggregate */ | ||
938 | if (smp_cpu_info) { | ||
939 | free(cpu_prev_jif); | ||
940 | free(cpu_jif); | ||
941 | cpu_jif = &cur_jif; | ||
942 | cpu_prev_jif = &prev_jif; | ||
943 | } else { | ||
944 | /* Prepare for xrealloc() */ | ||
945 | cpu_jif = cpu_prev_jif = NULL; | ||
946 | } | ||
947 | num_cpus = 0; | ||
948 | smp_cpu_info = !smp_cpu_info; | ||
949 | get_jiffy_counts(); | ||
950 | continue; | ||
951 | } | ||
952 | # endif | ||
953 | # endif | ||
954 | break; /* unknown key -> force refresh */ | ||
955 | } | ||
956 | |||
957 | return scan_mask; | ||
958 | } | ||
959 | #endif | ||
960 | |||
855 | //usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU | 961 | //usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU |
856 | //usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ | 962 | //usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ |
857 | //usage:#else | 963 | //usage:#else |
@@ -871,8 +977,9 @@ enum { | |||
871 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") | 977 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") |
872 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") | 978 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") |
873 | //usage: IF_FEATURE_TOPMEM( | 979 | //usage: IF_FEATURE_TOPMEM( |
874 | //usage: "\n"" S: show memory, R: reverse memory sort" | 980 | //usage: "\n"" S: show memory" |
875 | //usage: ) | 981 | //usage: ) |
982 | //usage: "\n"" R: reverse sort" | ||
876 | //usage: IF_SHOW_THREADS_OR_TOP_SMP( | 983 | //usage: IF_SHOW_THREADS_OR_TOP_SMP( |
877 | //usage: "\n"" " | 984 | //usage: "\n"" " |
878 | //usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") | 985 | //usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") |
@@ -880,23 +987,36 @@ enum { | |||
880 | //usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") | 987 | //usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") |
881 | //usage: ) | 988 | //usage: ) |
882 | //usage: "\n"" Q,^C: exit" | 989 | //usage: "\n"" Q,^C: exit" |
990 | //usage: "\n" | ||
991 | //usage: "\n""Options:" | ||
992 | //usage: "\n"" -b Batch mode" | ||
993 | //usage: "\n"" -n N Exit after N iterations" | ||
994 | //usage: "\n"" -d N Delay between updates" | ||
995 | //usage: IF_FEATURE_TOPMEM( | ||
996 | //usage: "\n"" -m Same as 's' key" | ||
997 | //usage: ) | ||
998 | |||
999 | /* Interactive testing: | ||
1000 | * echo sss | ./busybox top | ||
1001 | * - shows memory screen | ||
1002 | * echo sss | ./busybox top -bn1 >mem | ||
1003 | * - saves memory screen - the *whole* list, not first NROWS processes! | ||
1004 | * echo .m.s.s.s.s.s.s.q | ./busybox top -b >z | ||
1005 | * - saves several different screens, and exits | ||
1006 | * | ||
1007 | * TODO: -i STRING param as a better alternative? | ||
1008 | */ | ||
883 | 1009 | ||
884 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1010 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
885 | int top_main(int argc UNUSED_PARAM, char **argv) | 1011 | int top_main(int argc UNUSED_PARAM, char **argv) |
886 | { | 1012 | { |
887 | int iterations; | 1013 | int iterations; |
888 | unsigned lines, col; | 1014 | unsigned lines, col; |
889 | int lines_rem; | ||
890 | unsigned interval; | 1015 | unsigned interval; |
891 | char *str_interval, *str_iterations; | 1016 | char *str_interval, *str_iterations; |
892 | unsigned scan_mask = TOP_MASK; | 1017 | unsigned scan_mask = TOP_MASK; |
893 | #if ENABLE_FEATURE_USE_TERMIOS | 1018 | #if ENABLE_FEATURE_USE_TERMIOS |
894 | struct termios new_settings; | 1019 | struct termios new_settings; |
895 | struct pollfd pfd[1]; | ||
896 | unsigned char c; | ||
897 | |||
898 | pfd[0].fd = 0; | ||
899 | pfd[0].events = POLLIN; | ||
900 | #endif | 1020 | #endif |
901 | 1021 | ||
902 | INIT_G(); | 1022 | INIT_G(); |
@@ -933,15 +1053,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
933 | 1053 | ||
934 | /* change to /proc */ | 1054 | /* change to /proc */ |
935 | xchdir("/proc"); | 1055 | xchdir("/proc"); |
936 | #if ENABLE_FEATURE_USE_TERMIOS | ||
937 | tcgetattr(0, (void *) &initial_settings); | ||
938 | memcpy(&new_settings, &initial_settings, sizeof(new_settings)); | ||
939 | /* unbuffered input, turn off echo */ | ||
940 | new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); | ||
941 | |||
942 | bb_signals(BB_FATAL_SIGS, sig_catcher); | ||
943 | tcsetattr_stdin_TCSANOW(&new_settings); | ||
944 | #endif | ||
945 | 1056 | ||
946 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 1057 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
947 | sort_function[0] = pcpu_sort; | 1058 | sort_function[0] = pcpu_sort; |
@@ -951,21 +1062,41 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
951 | sort_function[0] = mem_sort; | 1062 | sort_function[0] = mem_sort; |
952 | #endif | 1063 | #endif |
953 | 1064 | ||
954 | while (1) { | 1065 | #if ENABLE_FEATURE_USE_TERMIOS |
1066 | tcgetattr(0, (void *) &initial_settings); | ||
1067 | memcpy(&new_settings, &initial_settings, sizeof(new_settings)); | ||
1068 | if (!OPT_BATCH_MODE) { | ||
1069 | /* unbuffered input, turn off echo */ | ||
1070 | new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); | ||
1071 | tcsetattr_stdin_TCSANOW(&new_settings); | ||
1072 | } | ||
1073 | |||
1074 | bb_signals(BB_FATAL_SIGS, sig_catcher); | ||
1075 | |||
1076 | /* Eat initial input, if any */ | ||
1077 | scan_mask = handle_input(scan_mask, 0); | ||
1078 | #endif | ||
1079 | |||
1080 | while (scan_mask != EXIT_MASK) { | ||
955 | procps_status_t *p = NULL; | 1081 | procps_status_t *p = NULL; |
956 | 1082 | ||
957 | lines = 24; /* default */ | 1083 | if (OPT_BATCH_MODE) { |
958 | col = 79; | 1084 | lines = INT_MAX; |
1085 | col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ | ||
1086 | } else { | ||
1087 | lines = 24; /* default */ | ||
1088 | col = 79; | ||
959 | #if ENABLE_FEATURE_USE_TERMIOS | 1089 | #if ENABLE_FEATURE_USE_TERMIOS |
960 | /* We output to stdout, we need size of stdout (not stdin)! */ | 1090 | /* We output to stdout, we need size of stdout (not stdin)! */ |
961 | get_terminal_width_height(STDOUT_FILENO, &col, &lines); | 1091 | get_terminal_width_height(STDOUT_FILENO, &col, &lines); |
962 | if (lines < 5 || col < 10) { | 1092 | if (lines < 5 || col < 10) { |
963 | sleep(interval); | 1093 | sleep(interval); |
964 | continue; | 1094 | continue; |
965 | } | 1095 | } |
966 | #endif | 1096 | #endif |
967 | if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ | 1097 | if (col > LINE_BUF_SIZE - 2) |
968 | col = LINE_BUF_SIZE-2; | 1098 | col = LINE_BUF_SIZE - 2; |
1099 | } | ||
969 | 1100 | ||
970 | /* read process IDs & status for all the processes */ | 1101 | /* read process IDs & status for all the processes */ |
971 | while ((p = procps_scan(p, scan_mask)) != NULL) { | 1102 | while ((p = procps_scan(p, scan_mask)) != NULL) { |
@@ -1033,15 +1164,11 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1033 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); | 1164 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); |
1034 | } | 1165 | } |
1035 | #endif | 1166 | #endif |
1036 | lines_rem = lines; | ||
1037 | if (OPT_BATCH_MODE) { | ||
1038 | lines_rem = INT_MAX; | ||
1039 | } | ||
1040 | if (scan_mask != TOPMEM_MASK) | 1167 | if (scan_mask != TOPMEM_MASK) |
1041 | display_process_list(lines_rem, col); | 1168 | display_process_list(lines, col); |
1042 | #if ENABLE_FEATURE_TOPMEM | 1169 | #if ENABLE_FEATURE_TOPMEM |
1043 | else | 1170 | else |
1044 | display_topmem_process_list(lines_rem, col); | 1171 | display_topmem_process_list(lines, col); |
1045 | #endif | 1172 | #endif |
1046 | clearmems(); | 1173 | clearmems(); |
1047 | if (iterations >= 0 && !--iterations) | 1174 | if (iterations >= 0 && !--iterations) |
@@ -1049,84 +1176,13 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1049 | #if !ENABLE_FEATURE_USE_TERMIOS | 1176 | #if !ENABLE_FEATURE_USE_TERMIOS |
1050 | sleep(interval); | 1177 | sleep(interval); |
1051 | #else | 1178 | #else |
1052 | if (option_mask32 & (OPT_b|OPT_EOF)) | 1179 | if (option_mask32 & OPT_EOF) |
1053 | /* batch mode, or EOF on stdin ("top </dev/null") */ | 1180 | /* EOF on stdin ("top </dev/null") */ |
1054 | sleep(interval); | 1181 | sleep(interval); |
1055 | else if (safe_poll(pfd, 1, interval * 1000) > 0) { | 1182 | else |
1056 | if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ | 1183 | scan_mask = handle_input(scan_mask, interval); |
1057 | option_mask32 |= OPT_EOF; | ||
1058 | continue; | ||
1059 | } | ||
1060 | if (c == initial_settings.c_cc[VINTR]) | ||
1061 | break; | ||
1062 | c |= 0x20; /* lowercase */ | ||
1063 | if (c == 'q') | ||
1064 | break; | ||
1065 | if (c == 'n') { | ||
1066 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1067 | sort_function[0] = pid_sort; | ||
1068 | } | ||
1069 | if (c == 'm') { | ||
1070 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1071 | sort_function[0] = mem_sort; | ||
1072 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
1073 | sort_function[1] = pcpu_sort; | ||
1074 | sort_function[2] = time_sort; | ||
1075 | # endif | ||
1076 | } | ||
1077 | # if ENABLE_FEATURE_SHOW_THREADS | ||
1078 | if (c == 'h' | ||
1079 | IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) | ||
1080 | ) { | ||
1081 | scan_mask ^= PSSCAN_TASKS; | ||
1082 | } | ||
1083 | # endif | ||
1084 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
1085 | if (c == 'p') { | ||
1086 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1087 | sort_function[0] = pcpu_sort; | ||
1088 | sort_function[1] = mem_sort; | ||
1089 | sort_function[2] = time_sort; | ||
1090 | } | ||
1091 | if (c == 't') { | ||
1092 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1093 | sort_function[0] = time_sort; | ||
1094 | sort_function[1] = mem_sort; | ||
1095 | sort_function[2] = pcpu_sort; | ||
1096 | } | ||
1097 | # if ENABLE_FEATURE_TOPMEM | ||
1098 | if (c == 's') { | ||
1099 | scan_mask = TOPMEM_MASK; | ||
1100 | free(prev_hist); | ||
1101 | prev_hist = NULL; | ||
1102 | prev_hist_count = 0; | ||
1103 | sort_field = (sort_field + 1) % NUM_SORT_FIELD; | ||
1104 | } | ||
1105 | if (c == 'r') | ||
1106 | inverted ^= 1; | ||
1107 | # endif | ||
1108 | # if ENABLE_FEATURE_TOP_SMP_CPU | ||
1109 | /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ | ||
1110 | if (c == 'c' || c == '1') { | ||
1111 | /* User wants to toggle per cpu <> aggregate */ | ||
1112 | if (smp_cpu_info) { | ||
1113 | free(cpu_prev_jif); | ||
1114 | free(cpu_jif); | ||
1115 | cpu_jif = &cur_jif; | ||
1116 | cpu_prev_jif = &prev_jif; | ||
1117 | } else { | ||
1118 | /* Prepare for xrealloc() */ | ||
1119 | cpu_jif = cpu_prev_jif = NULL; | ||
1120 | } | ||
1121 | num_cpus = 0; | ||
1122 | smp_cpu_info = !smp_cpu_info; | ||
1123 | get_jiffy_counts(); | ||
1124 | } | ||
1125 | # endif | ||
1126 | # endif | ||
1127 | } | ||
1128 | #endif /* FEATURE_USE_TERMIOS */ | 1184 | #endif /* FEATURE_USE_TERMIOS */ |
1129 | } /* end of "while (1)" */ | 1185 | } /* end of "while (not Q)" */ |
1130 | 1186 | ||
1131 | bb_putchar('\n'); | 1187 | bb_putchar('\n'); |
1132 | #if ENABLE_FEATURE_USE_TERMIOS | 1188 | #if ENABLE_FEATURE_USE_TERMIOS |