top: make it possible to feed commands via pipe
function old new delta handle_input - 492 +492 mult_lvl_cmp 38 49 +11 packed_usage 28247 28257 +10 top_main 1345 928 -417 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/1 up/down: 513/-417) Total: 96 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
a348b4557d
commit
7d9a1d25e5
265
procps/top.c
265
procps/top.c
@ -92,9 +92,9 @@ enum { SORT_DEPTH = 3 };
|
|||||||
struct globals {
|
struct globals {
|
||||||
top_status_t *top;
|
top_status_t *top;
|
||||||
int ntop;
|
int ntop;
|
||||||
|
smallint inverted;
|
||||||
#if ENABLE_FEATURE_TOPMEM
|
#if ENABLE_FEATURE_TOPMEM
|
||||||
smallint sort_field;
|
smallint sort_field;
|
||||||
smallint inverted;
|
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_FEATURE_TOP_SMP_CPU
|
#if ENABLE_FEATURE_TOP_SMP_CPU
|
||||||
smallint smp_cpu_info; /* one/many cpu info lines? */
|
smallint smp_cpu_info; /* one/many cpu info lines? */
|
||||||
@ -194,9 +194,9 @@ static int mult_lvl_cmp(void* a, void* b)
|
|||||||
for (i = 0; i < SORT_DEPTH; i++) {
|
for (i = 0; i < SORT_DEPTH; i++) {
|
||||||
cmp_val = (*sort_function[i])(a, b);
|
cmp_val = (*sort_function[i])(a, b);
|
||||||
if (cmp_val != 0)
|
if (cmp_val != 0)
|
||||||
return cmp_val;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return inverted ? -cmp_val : cmp_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif)
|
static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif)
|
||||||
@ -850,8 +850,105 @@ enum {
|
|||||||
| PSSCAN_PID
|
| PSSCAN_PID
|
||||||
| PSSCAN_SMAPS
|
| PSSCAN_SMAPS
|
||||||
| PSSCAN_COMM,
|
| PSSCAN_COMM,
|
||||||
|
EXIT_MASK = (unsigned)-1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_USE_TERMIOS
|
||||||
|
static unsigned handle_input(unsigned scan_mask, unsigned interval)
|
||||||
|
{
|
||||||
|
unsigned char c, *p, buf[64];
|
||||||
|
int len;
|
||||||
|
struct pollfd pfd[1];
|
||||||
|
|
||||||
|
pfd[0].fd = 0;
|
||||||
|
pfd[0].events = POLLIN;
|
||||||
|
if (safe_poll(pfd, 1, interval * 1000) <= 0)
|
||||||
|
return scan_mask;
|
||||||
|
|
||||||
|
len = safe_read(STDIN_FILENO, &buf, sizeof(buf)-1);
|
||||||
|
if (len <= 0) { /* error/EOF? */
|
||||||
|
option_mask32 |= OPT_EOF;
|
||||||
|
return scan_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[len] = 0;
|
||||||
|
p = buf;
|
||||||
|
while ((c = *p++) != 0) {
|
||||||
|
if (c == initial_settings.c_cc[VINTR])
|
||||||
|
return EXIT_MASK;
|
||||||
|
if (c == initial_settings.c_cc[VEOF])
|
||||||
|
return EXIT_MASK;
|
||||||
|
c |= 0x20; /* lowercase */
|
||||||
|
if (c == 'q')
|
||||||
|
return EXIT_MASK;
|
||||||
|
if (c == 'n') {
|
||||||
|
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
||||||
|
sort_function[0] = pid_sort;
|
||||||
|
}
|
||||||
|
if (c == 'm') {
|
||||||
|
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
||||||
|
sort_function[0] = mem_sort;
|
||||||
|
# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
||||||
|
sort_function[1] = pcpu_sort;
|
||||||
|
sort_function[2] = time_sort;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
# if ENABLE_FEATURE_SHOW_THREADS
|
||||||
|
if (c == 'h'
|
||||||
|
IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK)
|
||||||
|
) {
|
||||||
|
scan_mask ^= PSSCAN_TASKS;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
||||||
|
if (c == 'p') {
|
||||||
|
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
||||||
|
sort_function[0] = pcpu_sort;
|
||||||
|
sort_function[1] = mem_sort;
|
||||||
|
sort_function[2] = time_sort;
|
||||||
|
}
|
||||||
|
if (c == 't') {
|
||||||
|
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
||||||
|
sort_function[0] = time_sort;
|
||||||
|
sort_function[1] = mem_sort;
|
||||||
|
sort_function[2] = pcpu_sort;
|
||||||
|
}
|
||||||
|
# if ENABLE_FEATURE_TOPMEM
|
||||||
|
if (c == 's') {
|
||||||
|
scan_mask = TOPMEM_MASK;
|
||||||
|
free(prev_hist);
|
||||||
|
prev_hist = NULL;
|
||||||
|
prev_hist_count = 0;
|
||||||
|
sort_field = (sort_field + 1) % NUM_SORT_FIELD;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
if (c == 'r')
|
||||||
|
inverted ^= 1;
|
||||||
|
# if ENABLE_FEATURE_TOP_SMP_CPU
|
||||||
|
/* procps-2.0.18 uses 'C', 3.2.7 uses '1' */
|
||||||
|
if (c == 'c' || c == '1') {
|
||||||
|
/* User wants to toggle per cpu <> aggregate */
|
||||||
|
if (smp_cpu_info) {
|
||||||
|
free(cpu_prev_jif);
|
||||||
|
free(cpu_jif);
|
||||||
|
cpu_jif = &cur_jif;
|
||||||
|
cpu_prev_jif = &prev_jif;
|
||||||
|
} else {
|
||||||
|
/* Prepare for xrealloc() */
|
||||||
|
cpu_jif = cpu_prev_jif = NULL;
|
||||||
|
}
|
||||||
|
num_cpus = 0;
|
||||||
|
smp_cpu_info = !smp_cpu_info;
|
||||||
|
get_jiffy_counts();
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return scan_mask;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU
|
//usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU
|
||||||
//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__
|
//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__
|
||||||
//usage:#else
|
//usage:#else
|
||||||
@ -871,8 +968,9 @@ enum {
|
|||||||
//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu")
|
//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu")
|
||||||
//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time")
|
//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time")
|
||||||
//usage: IF_FEATURE_TOPMEM(
|
//usage: IF_FEATURE_TOPMEM(
|
||||||
//usage: "\n"" S: show memory, R: reverse memory sort"
|
//usage: "\n"" S: show memory"
|
||||||
//usage: )
|
//usage: )
|
||||||
|
//usage: "\n"" R: reverse sort"
|
||||||
//usage: IF_SHOW_THREADS_OR_TOP_SMP(
|
//usage: IF_SHOW_THREADS_OR_TOP_SMP(
|
||||||
//usage: "\n"" "
|
//usage: "\n"" "
|
||||||
//usage: IF_FEATURE_SHOW_THREADS("H: toggle threads")
|
//usage: IF_FEATURE_SHOW_THREADS("H: toggle threads")
|
||||||
@ -880,23 +978,34 @@ enum {
|
|||||||
//usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP")
|
//usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP")
|
||||||
//usage: )
|
//usage: )
|
||||||
//usage: "\n"" Q,^C: exit"
|
//usage: "\n"" Q,^C: exit"
|
||||||
|
//usage: "\n"
|
||||||
|
//usage: "\n""Options:"
|
||||||
|
//usage: "\n"" -b Batch mode"
|
||||||
|
//usage: "\n"" -n N Exit after N iterations"
|
||||||
|
//usage: "\n"" -d N Delay between updates"
|
||||||
|
//usage: IF_FEATURE_TOPMEM(
|
||||||
|
//usage: "\n"" -m Same as 's' key"
|
||||||
|
//usage: )
|
||||||
|
|
||||||
|
/* Interactive testing:
|
||||||
|
* echo sss | ./busybox top
|
||||||
|
* - shows memory screen
|
||||||
|
* echo sss | ./busybox top -bn1 >mem
|
||||||
|
* - saves memory screen - the *whole* list, not first NROWS porcesses!
|
||||||
|
*
|
||||||
|
* TODO: -i STRING param as a better alternative?
|
||||||
|
*/
|
||||||
|
|
||||||
int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||||
int top_main(int argc UNUSED_PARAM, char **argv)
|
int top_main(int argc UNUSED_PARAM, char **argv)
|
||||||
{
|
{
|
||||||
int iterations;
|
int iterations;
|
||||||
unsigned lines, col;
|
unsigned lines, col;
|
||||||
int lines_rem;
|
|
||||||
unsigned interval;
|
unsigned interval;
|
||||||
char *str_interval, *str_iterations;
|
char *str_interval, *str_iterations;
|
||||||
unsigned scan_mask = TOP_MASK;
|
unsigned scan_mask = TOP_MASK;
|
||||||
#if ENABLE_FEATURE_USE_TERMIOS
|
#if ENABLE_FEATURE_USE_TERMIOS
|
||||||
struct termios new_settings;
|
struct termios new_settings;
|
||||||
struct pollfd pfd[1];
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
pfd[0].fd = 0;
|
|
||||||
pfd[0].events = POLLIN;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
INIT_G();
|
INIT_G();
|
||||||
@ -933,15 +1042,6 @@ int top_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
|
|
||||||
/* change to /proc */
|
/* change to /proc */
|
||||||
xchdir("/proc");
|
xchdir("/proc");
|
||||||
#if ENABLE_FEATURE_USE_TERMIOS
|
|
||||||
tcgetattr(0, (void *) &initial_settings);
|
|
||||||
memcpy(&new_settings, &initial_settings, sizeof(new_settings));
|
|
||||||
/* unbuffered input, turn off echo */
|
|
||||||
new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
|
|
||||||
|
|
||||||
bb_signals(BB_FATAL_SIGS, sig_catcher);
|
|
||||||
tcsetattr_stdin_TCSANOW(&new_settings);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
||||||
sort_function[0] = pcpu_sort;
|
sort_function[0] = pcpu_sort;
|
||||||
@ -951,21 +1051,41 @@ int top_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
sort_function[0] = mem_sort;
|
sort_function[0] = mem_sort;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1) {
|
#if ENABLE_FEATURE_USE_TERMIOS
|
||||||
|
tcgetattr(0, (void *) &initial_settings);
|
||||||
|
memcpy(&new_settings, &initial_settings, sizeof(new_settings));
|
||||||
|
if (!OPT_BATCH_MODE) {
|
||||||
|
/* unbuffered input, turn off echo */
|
||||||
|
new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
|
||||||
|
tcsetattr_stdin_TCSANOW(&new_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
bb_signals(BB_FATAL_SIGS, sig_catcher);
|
||||||
|
|
||||||
|
/* Eat initial input, if any */
|
||||||
|
scan_mask = handle_input(scan_mask, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (scan_mask != EXIT_MASK) {
|
||||||
procps_status_t *p = NULL;
|
procps_status_t *p = NULL;
|
||||||
|
|
||||||
lines = 24; /* default */
|
if (OPT_BATCH_MODE) {
|
||||||
col = 79;
|
lines = INT_MAX;
|
||||||
|
col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */
|
||||||
|
} else {
|
||||||
|
lines = 24; /* default */
|
||||||
|
col = 79;
|
||||||
#if ENABLE_FEATURE_USE_TERMIOS
|
#if ENABLE_FEATURE_USE_TERMIOS
|
||||||
/* We output to stdout, we need size of stdout (not stdin)! */
|
/* We output to stdout, we need size of stdout (not stdin)! */
|
||||||
get_terminal_width_height(STDOUT_FILENO, &col, &lines);
|
get_terminal_width_height(STDOUT_FILENO, &col, &lines);
|
||||||
if (lines < 5 || col < 10) {
|
if (lines < 5 || col < 10) {
|
||||||
sleep(interval);
|
sleep(interval);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */
|
if (col > LINE_BUF_SIZE - 2)
|
||||||
col = LINE_BUF_SIZE-2;
|
col = LINE_BUF_SIZE - 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* read process IDs & status for all the processes */
|
/* read process IDs & status for all the processes */
|
||||||
while ((p = procps_scan(p, scan_mask)) != NULL) {
|
while ((p = procps_scan(p, scan_mask)) != NULL) {
|
||||||
@ -1033,15 +1153,11 @@ int top_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort);
|
qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
lines_rem = lines;
|
|
||||||
if (OPT_BATCH_MODE) {
|
|
||||||
lines_rem = INT_MAX;
|
|
||||||
}
|
|
||||||
if (scan_mask != TOPMEM_MASK)
|
if (scan_mask != TOPMEM_MASK)
|
||||||
display_process_list(lines_rem, col);
|
display_process_list(lines, col);
|
||||||
#if ENABLE_FEATURE_TOPMEM
|
#if ENABLE_FEATURE_TOPMEM
|
||||||
else
|
else
|
||||||
display_topmem_process_list(lines_rem, col);
|
display_topmem_process_list(lines, col);
|
||||||
#endif
|
#endif
|
||||||
clearmems();
|
clearmems();
|
||||||
if (iterations >= 0 && !--iterations)
|
if (iterations >= 0 && !--iterations)
|
||||||
@ -1052,81 +1168,10 @@ int top_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
if (option_mask32 & (OPT_b|OPT_EOF))
|
if (option_mask32 & (OPT_b|OPT_EOF))
|
||||||
/* batch mode, or EOF on stdin ("top </dev/null") */
|
/* batch mode, or EOF on stdin ("top </dev/null") */
|
||||||
sleep(interval);
|
sleep(interval);
|
||||||
else if (safe_poll(pfd, 1, interval * 1000) > 0) {
|
else
|
||||||
if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */
|
scan_mask = handle_input(scan_mask, interval);
|
||||||
option_mask32 |= OPT_EOF;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == initial_settings.c_cc[VINTR])
|
|
||||||
break;
|
|
||||||
c |= 0x20; /* lowercase */
|
|
||||||
if (c == 'q')
|
|
||||||
break;
|
|
||||||
if (c == 'n') {
|
|
||||||
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
|
||||||
sort_function[0] = pid_sort;
|
|
||||||
}
|
|
||||||
if (c == 'm') {
|
|
||||||
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
|
||||||
sort_function[0] = mem_sort;
|
|
||||||
# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
|
||||||
sort_function[1] = pcpu_sort;
|
|
||||||
sort_function[2] = time_sort;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
# if ENABLE_FEATURE_SHOW_THREADS
|
|
||||||
if (c == 'h'
|
|
||||||
IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK)
|
|
||||||
) {
|
|
||||||
scan_mask ^= PSSCAN_TASKS;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
|
|
||||||
if (c == 'p') {
|
|
||||||
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
|
||||||
sort_function[0] = pcpu_sort;
|
|
||||||
sort_function[1] = mem_sort;
|
|
||||||
sort_function[2] = time_sort;
|
|
||||||
}
|
|
||||||
if (c == 't') {
|
|
||||||
IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
|
|
||||||
sort_function[0] = time_sort;
|
|
||||||
sort_function[1] = mem_sort;
|
|
||||||
sort_function[2] = pcpu_sort;
|
|
||||||
}
|
|
||||||
# if ENABLE_FEATURE_TOPMEM
|
|
||||||
if (c == 's') {
|
|
||||||
scan_mask = TOPMEM_MASK;
|
|
||||||
free(prev_hist);
|
|
||||||
prev_hist = NULL;
|
|
||||||
prev_hist_count = 0;
|
|
||||||
sort_field = (sort_field + 1) % NUM_SORT_FIELD;
|
|
||||||
}
|
|
||||||
if (c == 'r')
|
|
||||||
inverted ^= 1;
|
|
||||||
# endif
|
|
||||||
# if ENABLE_FEATURE_TOP_SMP_CPU
|
|
||||||
/* procps-2.0.18 uses 'C', 3.2.7 uses '1' */
|
|
||||||
if (c == 'c' || c == '1') {
|
|
||||||
/* User wants to toggle per cpu <> aggregate */
|
|
||||||
if (smp_cpu_info) {
|
|
||||||
free(cpu_prev_jif);
|
|
||||||
free(cpu_jif);
|
|
||||||
cpu_jif = &cur_jif;
|
|
||||||
cpu_prev_jif = &prev_jif;
|
|
||||||
} else {
|
|
||||||
/* Prepare for xrealloc() */
|
|
||||||
cpu_jif = cpu_prev_jif = NULL;
|
|
||||||
}
|
|
||||||
num_cpus = 0;
|
|
||||||
smp_cpu_info = !smp_cpu_info;
|
|
||||||
get_jiffy_counts();
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif /* FEATURE_USE_TERMIOS */
|
#endif /* FEATURE_USE_TERMIOS */
|
||||||
} /* end of "while (1)" */
|
} /* end of "while (not Q)" */
|
||||||
|
|
||||||
bb_putchar('\n');
|
bb_putchar('\n');
|
||||||
#if ENABLE_FEATURE_USE_TERMIOS
|
#if ENABLE_FEATURE_USE_TERMIOS
|
||||||
|
Loading…
Reference in New Issue
Block a user