version 1.50, 2007/04/01 19:07:48 |
version 1.51, 2007/05/29 00:56:56 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
const char copyright[] = "Copyright (c) 1984 through 1996, William LeFebvre"; |
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/time.h> |
#include <curses.h> |
#include <err.h> |
#include <err.h> |
#include <errno.h> |
#include <errno.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <ctype.h> |
|
#include <signal.h> |
#include <signal.h> |
#include <string.h> |
#include <string.h> |
#include <poll.h> |
#include <poll.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <limits.h> |
#include <limits.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <sys/stat.h> |
|
|
|
/* includes specific to top */ |
/* includes specific to top */ |
#include "display.h" /* interface to display package */ |
#include "display.h" /* interface to display package */ |
|
|
/* The buffer that stdio will use */ |
/* The buffer that stdio will use */ |
char stdoutbuf[BUFFERSIZE]; |
char stdoutbuf[BUFFERSIZE]; |
|
|
extern int overstrike; |
|
|
|
/* signal handling routines */ |
/* signal handling routines */ |
static void leave(int); |
static void leave(int); |
static void onalrm(int); |
static void onalrm(int); |
static void tstop(int); |
static void tstop(int); |
static void winch(int); |
static void sigwinch(int); |
|
|
volatile sig_atomic_t leaveflag, tstopflag, winchflag; |
volatile sig_atomic_t leaveflag, tstopflag, winchflag; |
|
|
|
|
extern int (*proc_compares[])(const void *, const void *); |
extern int (*proc_compares[])(const void *, const void *); |
int order_index; |
int order_index; |
|
|
/* pointers to display routines */ |
|
void (*d_loadave)(int, double *) = i_loadave; |
|
void (*d_procstates)(int, int *) = i_procstates; |
|
void (*d_cpustates)(int64_t *) = i_cpustates; |
|
void (*d_memory)(int *) = i_memory; |
|
void (*d_message)(void) = i_message; |
|
void (*d_header)(char *) = i_header; |
|
void (*d_process)(int, char *) = i_process; |
|
|
|
int displays = 0; /* indicates unspecified */ |
int displays = 0; /* indicates unspecified */ |
char do_unames = Yes; |
char do_unames = Yes; |
struct process_select ps; |
struct process_select ps; |
|
|
int old_system = No; |
int old_system = No; |
int old_threads = No; |
int old_threads = No; |
int show_args = No; |
int show_args = No; |
|
pid_t hlpid = -1; |
|
|
#if Default_TOPN == Infinity |
#if Default_TOPN == Infinity |
char topn_specified = No; |
char topn_specified = No; |
|
|
#define CMD_threads 19 |
#define CMD_threads 19 |
#define CMD_grep 20 |
#define CMD_grep 20 |
#define CMD_add 21 |
#define CMD_add 21 |
|
#define CMD_hl 22 |
|
|
static void |
static void |
usage(void) |
usage(void) |
|
|
siginterrupt(SIGINT, 1); |
siginterrupt(SIGINT, 1); |
(void) signal(SIGQUIT, leave); |
(void) signal(SIGQUIT, leave); |
(void) signal(SIGTSTP, tstop); |
(void) signal(SIGTSTP, tstop); |
(void) signal(SIGWINCH, winch); |
if (smart_terminal) |
|
(void) signal(SIGWINCH, sigwinch); |
sigprocmask(SIG_SETMASK, &oldmask, NULL); |
sigprocmask(SIG_SETMASK, &oldmask, NULL); |
if (warnings) { |
if (warnings) { |
fputs("....", stderr); |
fputs("....", stderr); |
|
|
proc_compares[order_index]); |
proc_compares[order_index]); |
|
|
/* display the load averages */ |
/* display the load averages */ |
(*d_loadave)(system_info.last_pid, system_info.load_avg); |
i_loadave(system_info.last_pid, system_info.load_avg); |
|
|
/* display the current time */ |
/* display the current time */ |
/* this method of getting the time SHOULD be fairly portable */ |
/* this method of getting the time SHOULD be fairly portable */ |
|
|
i_timeofday(&curr_time); |
i_timeofday(&curr_time); |
|
|
/* display process state breakdown */ |
/* display process state breakdown */ |
(*d_procstates)(system_info.p_total, system_info.procstates); |
i_procstates(system_info.p_total, system_info.procstates); |
|
|
/* display the cpu state percentage breakdown */ |
/* display the cpu state percentage breakdown */ |
(*d_cpustates)(system_info.cpustates); |
i_cpustates(system_info.cpustates); |
|
|
/* display memory stats */ |
/* display memory stats */ |
(*d_memory)(system_info.memory); |
i_memory(system_info.memory); |
|
|
/* handle message area */ |
/* handle message area */ |
(*d_message)(); |
i_message(); |
|
|
/* update the header area */ |
/* update the header area */ |
(*d_header)(header_text); |
i_header(header_text); |
|
|
if (topn > 0) { |
if (topn > 0) { |
/* determine number of processes to actually display */ |
/* determine number of processes to actually display */ |
|
|
if (active_procs > max_topn) |
if (active_procs > max_topn) |
active_procs = max_topn; |
active_procs = max_topn; |
/* now show the top "n" processes. */ |
/* now show the top "n" processes. */ |
for (i = 0; i < active_procs; i++) |
for (i = 0; i < active_procs; i++) { |
(*d_process)(i, format_next_process(processes, |
pid_t pid; |
get_userid)); |
char * s; |
|
|
|
s = format_next_process(processes, get_userid, |
|
&pid); |
|
i_process(i, s, pid == hlpid); |
|
} |
} else |
} else |
i = 0; |
i = 0; |
|
|
|
|
/* now, flush the output buffer */ |
/* now, flush the output buffer */ |
fflush(stdout); |
fflush(stdout); |
|
|
|
if (smart_terminal) |
|
refresh(); |
|
|
/* only do the rest if we have more displays to show */ |
/* only do the rest if we have more displays to show */ |
if (displays) { |
if (displays) { |
/* switch out for new display on smart terminals */ |
/* switch out for new display on smart terminals */ |
if (smart_terminal) { |
|
if (overstrike) { |
|
reset_display(); |
|
} else { |
|
d_loadave = u_loadave; |
|
d_procstates = u_procstates; |
|
d_cpustates = u_cpustates; |
|
d_memory = u_memory; |
|
d_message = u_message; |
|
d_header = u_header; |
|
d_process = u_process; |
|
} |
|
} |
|
no_command = Yes; |
no_command = Yes; |
if (!interactive) { |
if (!interactive) { |
/* set up alarm */ |
/* set up alarm */ |
|
|
int change, i; |
int change, i; |
struct pollfd pfd[1]; |
struct pollfd pfd[1]; |
uid_t uid; |
uid_t uid; |
static char command_chars[] = "\f qh?en#sdkriIuSopCTg+"; |
static char command_chars[] = "\f qh?en#sdkriIuSopCTg+P"; |
|
|
/* |
/* |
* assume valid command unless told |
* assume valid command unless told |
|
|
* dimensions |
* dimensions |
*/ |
*/ |
get_screensize(); |
get_screensize(); |
|
resizeterm(screen_length, screen_width + 1); |
|
|
/* tell display to resize */ |
/* tell display to resize */ |
max_topn = display_resize(); |
max_topn = display_resize(); |
|
|
/* reset the signal handler */ |
/* reset the signal handler */ |
(void) signal(SIGWINCH, winch); |
(void) signal(SIGWINCH, sigwinch); |
|
|
reset_display(); |
reset_display(); |
winchflag = 0; |
winchflag = 0; |
|
|
if ((iptr = strchr(command_chars, ch)) == NULL) { |
if ((iptr = strchr(command_chars, ch)) == NULL) { |
/* illegal command */ |
/* illegal command */ |
new_message(MT_standout, " Command not understood"); |
new_message(MT_standout, " Command not understood"); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
no_command = Yes; |
no_command = Yes; |
fflush(stdout); |
fflush(stdout); |
return (0); |
return (0); |
} |
} |
|
|
change = iptr - command_chars; |
change = iptr - command_chars; |
if (overstrike && change > CMD_OSLIMIT) { |
|
/* error */ |
|
new_message(MT_standout, |
|
" Command cannot be handled by this terminal"); |
|
if (putchar('\r') == EOF) |
|
exit(1); |
|
no_command = Yes; |
|
fflush(stdout); |
|
return (0); |
|
} |
|
|
|
switch (change) { |
switch (change) { |
case CMD_redraw: /* redraw screen */ |
case CMD_redraw: /* redraw screen */ |
|
|
|
|
case CMD_help1: /* help */ |
case CMD_help1: /* help */ |
case CMD_help2: |
case CMD_help2: |
reset_display(); |
|
clear(); |
clear(); |
show_help(); |
show_help(); |
standout("Hit any key to continue: "); |
anykey(); |
fflush(stdout); |
clear(); |
while (1) { |
|
len = read(STDIN_FILENO, &ch, 1); |
|
if (len == -1 && errno == EINTR) |
|
continue; |
|
if (len == 0) |
|
exit(1); |
|
break; |
|
} |
|
break; |
break; |
|
|
case CMD_errors: /* show errors */ |
case CMD_errors: /* show errors */ |
if (error_count() == 0) { |
if (error_count() == 0) { |
new_message(MT_standout, |
new_message(MT_standout, |
" Currently no errors to report."); |
" Currently no errors to report."); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
no_command = Yes; |
no_command = Yes; |
} else { |
} else { |
reset_display(); |
|
clear(); |
clear(); |
show_errors(); |
show_errors(); |
standout("Hit any key to continue: "); |
anykey(); |
fflush(stdout); |
clear(); |
while (1) { |
|
len = read(STDIN_FILENO, &ch, 1); |
|
if (len == -1 && errno == EINTR) |
|
continue; |
|
if (len == 0) |
|
exit(1); |
|
break; |
|
} |
|
} |
} |
break; |
break; |
|
|
|
|
" This terminal can only " |
" This terminal can only " |
"display %d processes.", |
"display %d processes.", |
max_topn); |
max_topn); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
} |
} |
if (newval == 0) |
if (newval == 0) |
display_header(No); |
display_header(No); |
else if (newval > topn && topn == 0) { |
else if (newval > topn && topn == 0) { |
/* redraw the header */ |
/* redraw the header */ |
display_header(Yes); |
display_header(Yes); |
d_header = i_header; |
|
} |
} |
topn = newval; |
topn = newval; |
} |
} |
|
|
} else { |
} else { |
new_message(MT_standout, |
new_message(MT_standout, |
"Delay should be a non-negative number"); |
"Delay should be a non-negative number"); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
no_command = Yes; |
no_command = Yes; |
} |
} |
|
|
|
|
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
if ((errmsg = kill_procs(tempbuf2)) != NULL) { |
if ((errmsg = kill_procs(tempbuf2)) != NULL) { |
new_message(MT_standout, "%s", errmsg); |
new_message(MT_standout, "%s", errmsg); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
no_command = Yes; |
no_command = Yes; |
} |
} |
} else |
} else |
|
|
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
if ((errmsg = renice_procs(tempbuf2)) != NULL) { |
if ((errmsg = renice_procs(tempbuf2)) != NULL) { |
new_message(MT_standout, "%s", errmsg); |
new_message(MT_standout, "%s", errmsg); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
no_command = Yes; |
no_command = Yes; |
} |
} |
} else |
} else |
|
|
new_message(MT_standout | MT_delayed, |
new_message(MT_standout | MT_delayed, |
" %sisplaying idle processes.", |
" %sisplaying idle processes.", |
ps.idle ? "D" : "Not d"); |
ps.idle ? "D" : "Not d"); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
break; |
break; |
|
|
case CMD_user: |
case CMD_user: |
|
|
no_command = Yes; |
no_command = Yes; |
} else |
} else |
ps.uid = uid; |
ps.uid = uid; |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
} else |
} else |
clear_message(); |
clear_message(); |
break; |
break; |
|
|
no_command = Yes; |
no_command = Yes; |
} else |
} else |
order_index = i; |
order_index = i; |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
} else |
} else |
clear_message(); |
clear_message(); |
break; |
break; |
|
|
ps.system = Yes; |
ps.system = Yes; |
} |
} |
} |
} |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
} else |
} else |
clear_message(); |
clear_message(); |
break; |
break; |
|
|
ps.command = NULL; |
ps.command = NULL; |
else |
else |
ps.command = strdup(tempbuf2); |
ps.command = strdup(tempbuf2); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
} else |
} else |
clear_message(); |
clear_message(); |
break; |
break; |
|
|
|
case CMD_hl: |
|
new_message(MT_standout, "Process ID to higlight: "); |
|
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
|
if (tempbuf2[0] == '+' && |
|
tempbuf2[1] == '\0') { |
|
hlpid = -1; |
|
} else { |
|
unsigned long long num; |
|
const char *errstr; |
|
|
|
num = strtonum(tempbuf2, 0, INT_MAX, |
|
&errstr); |
|
if (errstr != NULL || !find_pid(num)) { |
|
new_message(MT_standout, |
|
" %s: unknown pid", |
|
tempbuf2); |
|
no_command = Yes; |
|
} else |
|
hlpid = (pid_t)num; |
|
} |
|
putr(); |
|
} else |
|
clear_message(); |
|
break; |
|
|
case CMD_add: |
case CMD_add: |
ps.uid = (uid_t)-1; /* uid */ |
ps.uid = (uid_t)-1; /* uid */ |
ps.pid = (pid_t)-1; /* pid */ |
ps.pid = (pid_t)-1; /* pid */ |
ps.system = old_system; |
ps.system = old_system; |
ps.command = NULL; /* grep */ |
ps.command = NULL; /* grep */ |
|
hlpid = -1; |
break; |
break; |
|
|
default: |
default: |
new_message(MT_standout, " BAD CASE IN SWITCH!"); |
new_message(MT_standout, " BAD CASE IN SWITCH!"); |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
} |
} |
} |
} |
|
|
|
|
static void |
static void |
reset_display(void) |
reset_display(void) |
{ |
{ |
d_loadave = i_loadave; |
if (smart_terminal) { |
d_procstates = i_procstates; |
clear(); |
d_cpustates = i_cpustates; |
refresh(); |
d_memory = i_memory; |
} |
d_message = i_message; |
|
d_header = i_header; |
|
d_process = i_process; |
|
} |
} |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
|
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
void |
void |
winch(int signo) |
sigwinch(int signo) |
{ |
{ |
winchflag = 1; |
winchflag = 1; |
} |
} |