aboutsummaryrefslogtreecommitdiff
path: root/procps
diff options
context:
space:
mode:
Diffstat (limited to 'procps')
-rw-r--r--procps/Config.src54
-rw-r--r--procps/ps.c6
-rw-r--r--procps/top.c161
3 files changed, 133 insertions, 88 deletions
diff --git a/procps/Config.src b/procps/Config.src
index 5cd47c84f..527d9ee0c 100644
--- a/procps/Config.src
+++ b/procps/Config.src
@@ -140,60 +140,6 @@ config BB_SYSCTL
140 help 140 help
141 Configure kernel parameters at runtime. 141 Configure kernel parameters at runtime.
142 142
143config TOP
144 bool "top"
145 default y
146 help
147 The top program provides a dynamic real-time view of a running
148 system.
149
150config FEATURE_TOP_CPU_USAGE_PERCENTAGE
151 bool "Show CPU per-process usage percentage"
152 default y
153 depends on TOP
154 help
155 Make top display CPU usage for each process.
156 This adds about 2k.
157
158config FEATURE_TOP_CPU_GLOBAL_PERCENTS
159 bool "Show CPU global usage percentage"
160 default y
161 depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE
162 help
163 Makes top display "CPU: NN% usr NN% sys..." line.
164 This adds about 0.5k.
165
166config FEATURE_TOP_SMP_CPU
167 bool "SMP CPU usage display ('c' key)"
168 default y
169 depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS
170 help
171 Allow 'c' key to switch between individual/cumulative CPU stats
172 This adds about 0.5k.
173
174config FEATURE_TOP_DECIMALS
175 bool "Show 1/10th of a percent in CPU/mem statistics"
176 default y
177 depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE
178 help
179 Show 1/10th of a percent in CPU/mem statistics.
180 This adds about 0.3k.
181
182config FEATURE_TOP_SMP_PROCESS
183 bool "Show CPU process runs on ('j' field)"
184 default y
185 depends on TOP
186 help
187 Show CPU where process was last found running on.
188 This is the 'j' field.
189
190config FEATURE_TOPMEM
191 bool "Topmem command ('s' key)"
192 default y
193 depends on TOP
194 help
195 Enable 's' in top (gives lots of memory info).
196
197config FEATURE_SHOW_THREADS 143config FEATURE_SHOW_THREADS
198 bool "Support for showing threads in ps/pstree/top" 144 bool "Support for showing threads in ps/pstree/top"
199 default y 145 default y
diff --git a/procps/ps.c b/procps/ps.c
index dc6fda61d..e14356482 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -665,9 +665,9 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
665 time_t now = now; 665 time_t now = now;
666 long uptime; 666 long uptime;
667#endif 667#endif
668 int opts = 0;
669 /* If we support any options, parse argv */ 668 /* If we support any options, parse argv */
670#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG 669#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG
670 int opts = 0;
671# if ENABLE_FEATURE_PS_WIDE 671# if ENABLE_FEATURE_PS_WIDE
672 /* -w is a bit complicated */ 672 /* -w is a bit complicated */
673 int w_count = 0; 673 int w_count = 0;
@@ -721,10 +721,10 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
721 * We also show STIME (standard says that -f shows it, -l doesn't). 721 * We also show STIME (standard says that -f shows it, -l doesn't).
722 */ 722 */
723 puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD"); 723 puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD");
724#if ENABLE_FEATURE_PS_LONG 724# if ENABLE_FEATURE_PS_LONG
725 now = time(NULL); 725 now = time(NULL);
726 uptime = get_uptime(); 726 uptime = get_uptime();
727#endif 727# endif
728 } 728 }
729 else { 729 else {
730 puts(" PID USER VSZ STAT COMMAND"); 730 puts(" PID USER VSZ STAT COMMAND");
diff --git a/procps/top.c b/procps/top.c
index 15eb624cc..b08444a76 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -50,6 +50,60 @@
50 * chroot . ./top -bn1 >top1.out 50 * chroot . ./top -bn1 >top1.out
51 */ 51 */
52 52
53//config:config TOP
54//config: bool "top"
55//config: default y
56//config: help
57//config: The top program provides a dynamic real-time view of a running
58//config: system.
59//config:
60//config:config FEATURE_TOP_CPU_USAGE_PERCENTAGE
61//config: bool "Show CPU per-process usage percentage"
62//config: default y
63//config: depends on TOP
64//config: help
65//config: Make top display CPU usage for each process.
66//config: This adds about 2k.
67//config:
68//config:config FEATURE_TOP_CPU_GLOBAL_PERCENTS
69//config: bool "Show CPU global usage percentage"
70//config: default y
71//config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE
72//config: help
73//config: Makes top display "CPU: NN% usr NN% sys..." line.
74//config: This adds about 0.5k.
75//config:
76//config:config FEATURE_TOP_SMP_CPU
77//config: bool "SMP CPU usage display ('c' key)"
78//config: default y
79//config: depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS
80//config: help
81//config: Allow 'c' key to switch between individual/cumulative CPU stats
82//config: This adds about 0.5k.
83//config:
84//config:config FEATURE_TOP_DECIMALS
85//config: bool "Show 1/10th of a percent in CPU/mem statistics"
86//config: default y
87//config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE
88//config: help
89//config: Show 1/10th of a percent in CPU/mem statistics.
90//config: This adds about 0.3k.
91//config:
92//config:config FEATURE_TOP_SMP_PROCESS
93//config: bool "Show CPU process runs on ('j' field)"
94//config: default y
95//config: depends on TOP
96//config: help
97//config: Show CPU where process was last found running on.
98//config: This is the 'j' field.
99//config:
100//config:config FEATURE_TOPMEM
101//config: bool "Topmem command ('s' key)"
102//config: default y
103//config: depends on TOP
104//config: help
105//config: Enable 's' in top (gives lots of memory info).
106
53#include "libbb.h" 107#include "libbb.h"
54 108
55 109
@@ -99,8 +153,13 @@ struct globals {
99#if ENABLE_FEATURE_TOP_SMP_CPU 153#if ENABLE_FEATURE_TOP_SMP_CPU
100 smallint smp_cpu_info; /* one/many cpu info lines? */ 154 smallint smp_cpu_info; /* one/many cpu info lines? */
101#endif 155#endif
156 unsigned lines; /* screen height */
102#if ENABLE_FEATURE_USE_TERMIOS 157#if ENABLE_FEATURE_USE_TERMIOS
103 struct termios initial_settings; 158 struct termios initial_settings;
159 int scroll_ofs;
160#define G_scroll_ofs G.scroll_ofs
161#else
162#define G_scroll_ofs 0
104#endif 163#endif
105#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 164#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
106 cmp_funcp sort_function[1]; 165 cmp_funcp sort_function[1];
@@ -118,6 +177,9 @@ struct globals {
118 jiffy_counts_t *cpu_jif, *cpu_prev_jif; 177 jiffy_counts_t *cpu_jif, *cpu_prev_jif;
119 int num_cpus; 178 int num_cpus;
120#endif 179#endif
180#if ENABLE_FEATURE_USE_TERMIOS
181 char kbd_input[KEYCODE_BUFFER_SIZE];
182#endif
121 char line_buf[80]; 183 char line_buf[80];
122}; //FIX_ALIASING; - large code growth 184}; //FIX_ALIASING; - large code growth
123enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; 185enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) };
@@ -602,9 +664,9 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
602 664
603 /* Ok, all preliminary data is ready, go through the list */ 665 /* Ok, all preliminary data is ready, go through the list */
604 scr_width += 2; /* account for leading '\n' and trailing NUL */ 666 scr_width += 2; /* account for leading '\n' and trailing NUL */
605 if (lines_rem > ntop) 667 if (lines_rem > ntop - G_scroll_ofs)
606 lines_rem = ntop; 668 lines_rem = ntop - G_scroll_ofs;
607 s = top; 669 s = top + G_scroll_ofs;
608 while (--lines_rem >= 0) { 670 while (--lines_rem >= 0) {
609 unsigned col; 671 unsigned col;
610 CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); 672 CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
@@ -649,14 +711,14 @@ static void clearmems(void)
649 clear_username_cache(); 711 clear_username_cache();
650 free(top); 712 free(top);
651 top = NULL; 713 top = NULL;
652 ntop = 0;
653} 714}
654 715
655#if ENABLE_FEATURE_USE_TERMIOS 716#if ENABLE_FEATURE_USE_TERMIOS
656 717
657static void reset_term(void) 718static void reset_term(void)
658{ 719{
659 tcsetattr_stdin_TCSANOW(&initial_settings); 720 if (!OPT_BATCH_MODE)
721 tcsetattr_stdin_TCSANOW(&initial_settings);
660 if (ENABLE_FEATURE_CLEAN_UP) { 722 if (ENABLE_FEATURE_CLEAN_UP) {
661 clearmems(); 723 clearmems();
662# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 724# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
@@ -665,10 +727,10 @@ static void reset_term(void)
665 } 727 }
666} 728}
667 729
668static void sig_catcher(int sig UNUSED_PARAM) 730static void sig_catcher(int sig)
669{ 731{
670 reset_term(); 732 reset_term();
671 _exit(EXIT_FAILURE); 733 kill_myself_with_sig(sig);
672} 734}
673 735
674#endif /* FEATURE_USE_TERMIOS */ 736#endif /* FEATURE_USE_TERMIOS */
@@ -793,7 +855,7 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width)
793{ 855{
794#define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" 856#define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK"
795#define MIN_WIDTH sizeof(HDR_STR) 857#define MIN_WIDTH sizeof(HDR_STR)
796 const topmem_status_t *s = topmem; 858 const topmem_status_t *s = topmem + G_scroll_ofs;
797 859
798 display_topmem_header(scr_width, &lines_rem); 860 display_topmem_header(scr_width, &lines_rem);
799 strcpy(line_buf, HDR_STR " COMMAND"); 861 strcpy(line_buf, HDR_STR " COMMAND");
@@ -801,8 +863,8 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width)
801 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); 863 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf);
802 lines_rem--; 864 lines_rem--;
803 865
804 if (lines_rem > ntop) 866 if (lines_rem > ntop - G_scroll_ofs)
805 lines_rem = ntop; 867 lines_rem = ntop - G_scroll_ofs;
806 while (--lines_rem >= 0) { 868 while (--lines_rem >= 0) {
807 /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ 869 /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */
808 ulltoa6_and_space(s->pid , &line_buf[0*6]); 870 ulltoa6_and_space(s->pid , &line_buf[0*6]);
@@ -856,26 +918,63 @@ enum {
856#if ENABLE_FEATURE_USE_TERMIOS 918#if ENABLE_FEATURE_USE_TERMIOS
857static unsigned handle_input(unsigned scan_mask, unsigned interval) 919static unsigned handle_input(unsigned scan_mask, unsigned interval)
858{ 920{
859 unsigned char c;
860 struct pollfd pfd[1]; 921 struct pollfd pfd[1];
861 922
923 if (option_mask32 & OPT_EOF) {
924 /* EOF on stdin ("top </dev/null") */
925 sleep(interval);
926 return scan_mask;
927 }
928
862 pfd[0].fd = 0; 929 pfd[0].fd = 0;
863 pfd[0].events = POLLIN; 930 pfd[0].events = POLLIN;
864 931
865 while (1) { 932 while (1) {
866 if (safe_poll(pfd, 1, interval * 1000) <= 0) 933 int32_t c;
867 return scan_mask;
868 interval = 0;
869 934
870 if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ 935 c = read_key(STDIN_FILENO, G.kbd_input, interval * 1000);
936 if (c == -1 && errno != EAGAIN) {
937 /* error/EOF */
871 option_mask32 |= OPT_EOF; 938 option_mask32 |= OPT_EOF;
872 return scan_mask; 939 break;
873 } 940 }
941 interval = 0;
874 942
875 if (c == initial_settings.c_cc[VINTR]) 943 if (c == initial_settings.c_cc[VINTR])
876 return EXIT_MASK; 944 return EXIT_MASK;
877 if (c == initial_settings.c_cc[VEOF]) 945 if (c == initial_settings.c_cc[VEOF])
878 return EXIT_MASK; 946 return EXIT_MASK;
947
948 if (c == KEYCODE_UP) {
949 G_scroll_ofs--;
950 goto normalize_ofs;
951 }
952 if (c == KEYCODE_DOWN) {
953 G_scroll_ofs++;
954 goto normalize_ofs;
955 }
956 if (c == KEYCODE_HOME) {
957 G_scroll_ofs = 0;
958 break;
959 }
960 if (c == KEYCODE_END) {
961 G_scroll_ofs = ntop - G.lines / 2;
962 goto normalize_ofs;
963 }
964 if (c == KEYCODE_PAGEUP) {
965 G_scroll_ofs -= G.lines / 2;
966 goto normalize_ofs;
967 }
968 if (c == KEYCODE_PAGEDOWN) {
969 G_scroll_ofs += G.lines / 2;
970 normalize_ofs:
971 if (G_scroll_ofs >= ntop)
972 G_scroll_ofs = ntop - 1;
973 if (G_scroll_ofs < 0)
974 G_scroll_ofs = 0;
975 break;
976 }
977
879 c |= 0x20; /* lowercase */ 978 c |= 0x20; /* lowercase */
880 if (c == 'q') 979 if (c == 'q')
881 return EXIT_MASK; 980 return EXIT_MASK;
@@ -1011,7 +1110,7 @@ int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1011int top_main(int argc UNUSED_PARAM, char **argv) 1110int top_main(int argc UNUSED_PARAM, char **argv)
1012{ 1111{
1013 int iterations; 1112 int iterations;
1014 unsigned lines, col; 1113 unsigned col;
1015 unsigned interval; 1114 unsigned interval;
1016 char *str_interval, *str_iterations; 1115 char *str_interval, *str_iterations;
1017 unsigned scan_mask = TOP_MASK; 1116 unsigned scan_mask = TOP_MASK;
@@ -1062,10 +1161,13 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1062 sort_function[0] = mem_sort; 1161 sort_function[0] = mem_sort;
1063#endif 1162#endif
1064 1163
1164 if (OPT_BATCH_MODE) {
1165 option_mask32 |= OPT_EOF;
1166 }
1065#if ENABLE_FEATURE_USE_TERMIOS 1167#if ENABLE_FEATURE_USE_TERMIOS
1066 tcgetattr(0, (void *) &initial_settings); 1168 else {
1067 memcpy(&new_settings, &initial_settings, sizeof(new_settings)); 1169 tcgetattr(0, (void *) &initial_settings);
1068 if (!OPT_BATCH_MODE) { 1170 memcpy(&new_settings, &initial_settings, sizeof(new_settings));
1069 /* unbuffered input, turn off echo */ 1171 /* unbuffered input, turn off echo */
1070 new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); 1172 new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
1071 tcsetattr_stdin_TCSANOW(&new_settings); 1173 tcsetattr_stdin_TCSANOW(&new_settings);
@@ -1081,15 +1183,15 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1081 procps_status_t *p = NULL; 1183 procps_status_t *p = NULL;
1082 1184
1083 if (OPT_BATCH_MODE) { 1185 if (OPT_BATCH_MODE) {
1084 lines = INT_MAX; 1186 G.lines = INT_MAX;
1085 col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ 1187 col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */
1086 } else { 1188 } else {
1087 lines = 24; /* default */ 1189 G.lines = 24; /* default */
1088 col = 79; 1190 col = 79;
1089#if ENABLE_FEATURE_USE_TERMIOS 1191#if ENABLE_FEATURE_USE_TERMIOS
1090 /* We output to stdout, we need size of stdout (not stdin)! */ 1192 /* We output to stdout, we need size of stdout (not stdin)! */
1091 get_terminal_width_height(STDOUT_FILENO, &col, &lines); 1193 get_terminal_width_height(STDOUT_FILENO, &col, &G.lines);
1092 if (lines < 5 || col < 10) { 1194 if (G.lines < 5 || col < 10) {
1093 sleep(interval); 1195 sleep(interval);
1094 continue; 1196 continue;
1095 } 1197 }
@@ -1099,6 +1201,7 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1099 } 1201 }
1100 1202
1101 /* read process IDs & status for all the processes */ 1203 /* read process IDs & status for all the processes */
1204 ntop = 0;
1102 while ((p = procps_scan(p, scan_mask)) != NULL) { 1205 while ((p = procps_scan(p, scan_mask)) != NULL) {
1103 int n; 1206 int n;
1104#if ENABLE_FEATURE_TOPMEM 1207#if ENABLE_FEATURE_TOPMEM
@@ -1165,10 +1268,10 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1165 } 1268 }
1166#endif 1269#endif
1167 if (scan_mask != TOPMEM_MASK) 1270 if (scan_mask != TOPMEM_MASK)
1168 display_process_list(lines, col); 1271 display_process_list(G.lines, col);
1169#if ENABLE_FEATURE_TOPMEM 1272#if ENABLE_FEATURE_TOPMEM
1170 else 1273 else
1171 display_topmem_process_list(lines, col); 1274 display_topmem_process_list(G.lines, col);
1172#endif 1275#endif
1173 clearmems(); 1276 clearmems();
1174 if (iterations >= 0 && !--iterations) 1277 if (iterations >= 0 && !--iterations)
@@ -1176,11 +1279,7 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1176#if !ENABLE_FEATURE_USE_TERMIOS 1279#if !ENABLE_FEATURE_USE_TERMIOS
1177 sleep(interval); 1280 sleep(interval);
1178#else 1281#else
1179 if (option_mask32 & OPT_EOF) 1282 scan_mask = handle_input(scan_mask, interval);
1180 /* EOF on stdin ("top </dev/null") */
1181 sleep(interval);
1182 else
1183 scan_mask = handle_input(scan_mask, interval);
1184#endif /* FEATURE_USE_TERMIOS */ 1283#endif /* FEATURE_USE_TERMIOS */
1185 } /* end of "while (not Q)" */ 1284 } /* end of "while (not Q)" */
1186 1285