version 1.19, 2003/06/12 22:30:23 |
version 1.20, 2003/06/13 21:52:25 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
const char copyright[] = "Copyright (c) 1984 through 1996, William LeFebvre"; |
|
|
|
/* |
/* |
* Top users/processes display for Unix |
* Top users/processes display for Unix |
* Version 3 |
* Version 3 |
|
|
* 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"; |
* See the file "Changes" for information on version-to-version changes. |
|
*/ |
|
|
|
/* |
|
* This file contains "main" and other high-level routines. |
|
*/ |
|
|
|
/* |
|
* The following preprocessor variables, when defined, are used to |
|
* distinguish between different Unix implementations: |
|
* |
|
* FD_SET - macros FD_SET and FD_ZERO are used when defined |
|
*/ |
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <ctype.h> |
#include <ctype.h> |
|
|
#include "utils.h" |
#include "utils.h" |
|
|
/* Size of the stdio buffer given to stdout */ |
/* Size of the stdio buffer given to stdout */ |
#define Buffersize 2048 |
#define BUFFERSIZE 2048 |
|
|
/* The buffer that stdio will use */ |
/* The buffer that stdio will use */ |
char stdoutbuf[Buffersize]; |
char stdoutbuf[BUFFERSIZE]; |
|
|
/* imported from screen.c */ |
extern int overstrike; |
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); |
#ifdef SIGWINCH |
#ifdef SIGWINCH |
static void winch(int); |
static void winch(int); |
#endif |
#endif |
|
|
volatile sig_atomic_t leaveflag; |
volatile sig_atomic_t leaveflag; |
volatile sig_atomic_t tstopflag; |
volatile sig_atomic_t tstopflag; |
volatile sig_atomic_t winchflag; |
volatile sig_atomic_t winchflag; |
|
|
static void reset_display(void); |
static void reset_display(void); |
|
int rundisplay(void); |
|
|
/* values which need to be accessed by signal handlers */ |
/* values which need to be accessed by signal handlers */ |
static int max_topn; /* maximum displayable processes */ |
static int max_topn; /* maximum displayable processes */ |
|
|
/* miscellaneous things */ |
/* miscellaneous things */ |
char *myname = "top"; |
jmp_buf jmp_int; |
jmp_buf jmp_int; |
|
|
|
/* routines that don't return int */ |
/* routines that don't return int */ |
|
|
#ifdef ORDER |
extern char *__progname; |
extern int (*proc_compares[])(); |
|
#else |
|
extern int proc_compare(); |
|
#endif |
|
time_t time(); |
|
|
|
caddr_t get_process_info(); |
extern int (*proc_compares[])(const void *, const void *); |
|
int order_index; |
|
|
/* pointers to display routines */ |
/* pointers to display routines */ |
void (*d_loadave)() = i_loadave; |
void (*d_loadave) () = i_loadave; |
void (*d_procstates)() = i_procstates; |
void (*d_procstates) () = i_procstates; |
void (*d_cpustates)() = i_cpustates; |
void (*d_cpustates) () = i_cpustates; |
void (*d_memory)() = i_memory; |
void (*d_memory) () = i_memory; |
void (*d_message)() = i_message; |
void (*d_message) () = i_message; |
void (*d_header)() = i_header; |
void (*d_header) () = i_header; |
void (*d_process)() = i_process; |
void (*d_process) () = i_process; |
|
|
|
int displays = 0; /* indicates unspecified */ |
|
char do_unames = Yes; |
|
struct process_select ps; |
|
char dostates = No; |
|
char interactive = Maybe; |
|
char warnings = 0; |
|
double delay = Default_DELAY; |
|
char *order_name = NULL; |
|
int topn = Default_TOPN; |
|
int no_command = 1; |
|
|
int |
|
main(int argc, char *argv[]) |
|
{ |
|
int i; |
|
int active_procs; |
|
int change; |
|
|
|
struct system_info system_info; |
|
struct statics statics; |
|
caddr_t processes; |
|
|
|
static char tempbuf1[50]; |
|
static char tempbuf2[50]; |
|
sigset_t mask, oldmask; |
|
int topn = Default_TOPN; |
|
double delay = Default_DELAY; |
|
int displays = 0; /* indicates unspecified */ |
|
time_t curr_time; |
|
char *(*get_userid)() = username; |
|
char *uname_field = "USERNAME"; |
|
char *header_text; |
|
char *env_top; |
|
char **preset_argv; |
|
int preset_argc = 0; |
|
char **av; |
|
int ac; |
|
char dostates = No; |
|
char do_unames = Yes; |
|
char interactive = Maybe; |
|
char warnings = 0; |
|
#if Default_TOPN == Infinity |
#if Default_TOPN == Infinity |
char topn_specified = No; |
char topn_specified = No; |
#endif |
#endif |
char ch; |
|
char *iptr; |
|
char no_command = 1; |
|
struct timeval timeout; |
|
struct process_select ps; |
|
#ifdef ORDER |
|
char *order_name = NULL; |
|
int order_index = 0; |
|
#endif |
|
#ifndef FD_SET |
|
/* FD_SET and friends are not present: fake it */ |
|
typedef int fd_set; |
|
#define FD_ZERO(x) (*(x) = 0) |
|
#define FD_SET(f, x) (*(x) = f) |
|
#endif |
|
fd_set readfds; |
|
|
|
#ifdef ORDER |
/* |
static char command_chars[] = "\f qh?en#sdkriIuSo"; |
* these defines enumerate the "strchr"s of the commands in |
#else |
* command_chars |
static char command_chars[] = "\f qh?en#sdkriIuS"; |
*/ |
#endif |
|
/* these defines enumerate the "strchr"s of the commands in command_chars */ |
|
#define CMD_redraw 0 |
#define CMD_redraw 0 |
#define CMD_update 1 |
#define CMD_update 1 |
#define CMD_quit 2 |
#define CMD_quit 2 |
#define CMD_help1 3 |
#define CMD_help1 3 |
#define CMD_help2 4 |
#define CMD_help2 4 |
#define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ |
#define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ |
#define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ |
#define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ |
#define CMD_number1 6 |
#define CMD_number1 6 |
#define CMD_number2 7 |
#define CMD_number2 7 |
#define CMD_delay 8 |
#define CMD_delay 8 |
|
|
#define CMD_idletog2 13 |
#define CMD_idletog2 13 |
#define CMD_user 14 |
#define CMD_user 14 |
#define CMD_system 15 |
#define CMD_system 15 |
#ifdef ORDER |
|
#define CMD_order 16 |
#define CMD_order 16 |
#endif |
|
|
|
/* set the buffer for stdout */ |
void |
#ifdef DEBUG |
usage(void) |
setbuffer(stdout, NULL, 0); |
{ |
#else |
fprintf(stderr, |
setbuffer(stdout, stdoutbuf, Buffersize); |
"Top version %s\n" |
#endif |
"Usage: %s [-ISbinqu] [-d x] [-s x] [-o field] [-U username] [number]\n", |
|
version_string(), __progname); |
|
} |
|
|
/* get our name */ |
void |
if (argc > 0) |
parseargs(int ac, char **av) |
{ |
{ |
if ((myname = strrchr(argv[0], '/')) == 0) |
char *endp; |
{ |
int i; |
myname = argv[0]; |
|
} |
|
else |
|
{ |
|
myname++; |
|
} |
|
} |
|
|
|
/* initialize some selection options */ |
while ((i = getopt(ac, av, "SIbinqus:d:U:o:")) != -1) { |
ps.idle = Yes; |
switch (i) { |
ps.system = No; |
case 'u': /* toggle uid/username display */ |
ps.uid = -1; |
do_unames = !do_unames; |
ps.command = NULL; |
break; |
|
|
/* get preset options from the environment */ |
case 'U': /* display only username's processes */ |
if ((env_top = getenv("TOP")) != NULL) |
if ((ps.uid = userid(optarg)) == -1) { |
{ |
fprintf(stderr, "%s: unknown user\n", optarg); |
av = preset_argv = argparse(env_top, &preset_argc); |
exit(1); |
ac = preset_argc; |
} |
|
break; |
|
|
/* set the dummy argument to an explanatory message, in case |
case 'S': /* show system processes */ |
getopt encounters a bad argument */ |
ps.system = !ps.system; |
preset_argv[0] = "while processing environment"; |
break; |
} |
|
|
|
/* process options */ |
case 'I': /* show idle processes */ |
do { |
ps.idle = !ps.idle; |
/* if we're done doing the presets, then process the real arguments */ |
break; |
if (preset_argc == 0) |
|
{ |
|
ac = argc; |
|
av = argv; |
|
|
|
/* this should keep getopt happy... */ |
case 'i': /* go interactive regardless */ |
optind = 1; |
interactive = Yes; |
} |
break; |
|
|
while ((i = getopt(ac, av, "SIbinqus:d:U:o:")) != -1) |
case 'n': /* batch, or non-interactive */ |
{ |
case 'b': |
switch(i) |
interactive = No; |
{ |
break; |
case 'u': /* toggle uid/username display */ |
|
do_unames = !do_unames; |
|
break; |
|
|
|
case 'U': /* display only username's processes */ |
case 'd': /* number of displays to show */ |
if ((ps.uid = userid(optarg)) == -1) |
if ((i = atoiwi(optarg)) != Invalid && i != 0) { |
{ |
displays = i; |
fprintf(stderr, "%s: unknown user\n", optarg); |
break; |
exit(1); |
} |
} |
fprintf(stderr, |
break; |
"%s: warning: display count should be positive " |
|
"-- option ignored\n", |
|
__progname); |
|
warnings++; |
|
break; |
|
|
case 'S': /* show system processes */ |
case 's': |
ps.system = !ps.system; |
delay = strtod(optarg, &endp); |
break; |
|
|
|
case 'I': /* show idle processes */ |
if (delay > 0 && delay <= 1000000 && *endp == '\0') |
ps.idle = !ps.idle; |
break; |
break; |
|
|
|
case 'i': /* go interactive regardless */ |
fprintf(stderr, |
interactive = Yes; |
"%s: warning: delay should be a non-negative number" |
break; |
" -- using default\n", |
|
__progname); |
|
delay = Default_DELAY; |
|
warnings++; |
|
break; |
|
|
case 'n': /* batch, or non-interactive */ |
case 'q': /* be quick about it */ |
case 'b': |
/* only allow this if user is really root */ |
interactive = No; |
if (getuid() == 0) { |
break; |
/* be very un-nice! */ |
|
(void) nice(-20); |
|
break; |
|
} |
|
fprintf(stderr, |
|
"%s: warning: `-q' option can only be used by root\n", |
|
__progname); |
|
warnings++; |
|
break; |
|
|
case 'd': /* number of displays to show */ |
case 'o': /* select sort order */ |
if ((i = atoiwi(optarg)) == Invalid || i == 0) |
order_name = optarg; |
{ |
break; |
fprintf(stderr, |
|
"%s: warning: display count should be positive -- option ignored\n", |
|
myname); |
|
warnings++; |
|
} |
|
else |
|
{ |
|
displays = i; |
|
} |
|
break; |
|
|
|
case 's': |
default: |
{ |
usage(); |
char *endp; |
exit(1); |
|
|
delay = strtod(optarg, &endp); |
|
|
|
if (delay < 0 || delay >= 1000000 || *endp != '\0') |
|
{ |
|
fprintf(stderr, |
|
"%s: warning: delay should be a non-negative number -- using default\n", |
|
myname); |
|
delay = Default_DELAY; |
|
warnings++; |
|
} |
|
} |
} |
break; |
|
|
|
case 'q': /* be quick about it */ |
|
/* only allow this if user is really root */ |
|
if (getuid() == 0) |
|
{ |
|
/* be very un-nice! */ |
|
(void) nice(-20); |
|
} |
|
else |
|
{ |
|
fprintf(stderr, |
|
"%s: warning: `-q' option can only be used by root\n", |
|
myname); |
|
warnings++; |
|
} |
|
break; |
|
|
|
case 'o': /* select sort order */ |
|
#ifdef ORDER |
|
order_name = optarg; |
|
#else |
|
fprintf(stderr, |
|
"%s: this platform does not support arbitrary ordering. Sorry.\n", |
|
myname); |
|
warnings++; |
|
#endif |
|
break; |
|
|
|
default: |
|
fprintf(stderr, "\ |
|
Top version %s\n\ |
|
Usage: %s [-ISbinqu] [-d x] [-s x] [-o field] [-U username] [number]\n", |
|
version_string(), myname); |
|
exit(1); |
|
} |
|
} |
} |
|
|
/* get count of top processes to display (if any) */ |
/* get count of top processes to display (if any) */ |
if (optind < ac) |
if (optind < ac) { |
{ |
if ((topn = atoiwi(av[optind])) == Invalid) { |
if ((topn = atoiwi(av[optind])) == Invalid) |
fprintf(stderr, |
{ |
"%s: warning: process display count should " |
fprintf(stderr, |
"be non-negative -- using default\n", |
"%s: warning: process display count should be non-negative -- using default\n", |
__progname); |
myname); |
warnings++; |
warnings++; |
} |
} |
|
#if Default_TOPN == Infinity |
#if Default_TOPN == Infinity |
else |
else |
{ |
topn_specified = Yes; |
topn_specified = Yes; |
|
} |
|
#endif |
#endif |
} |
} |
|
} |
|
|
/* tricky: remember old value of preset_argc & set preset_argc = 0 */ |
struct system_info system_info; |
i = preset_argc; |
struct statics statics; |
preset_argc = 0; |
|
|
|
/* repeat only if we really did the preset arguments */ |
int |
} while (i != 0); |
main(int argc, char *argv[]) |
|
{ |
|
char *uname_field = "USERNAME", *header_text, *env_top; |
|
char *(*get_userid)() = username, **preset_argv, **av; |
|
int preset_argc = 0, ac, active_procs, i; |
|
sigset_t mask, oldmask; |
|
time_t curr_time; |
|
caddr_t processes; |
|
|
/* set constants for username/uid display correctly */ |
/* set the buffer for stdout */ |
if (!do_unames) |
#ifdef DEBUG |
{ |
setbuffer(stdout, NULL, 0); |
uname_field = " UID "; |
#else |
get_userid = itoa7; |
setbuffer(stdout, stdoutbuf, sizeof stdoutbuf); |
} |
#endif |
|
|
/* initialize the kernel memory interface */ |
/* initialize some selection options */ |
if (machine_init(&statics) == -1) |
ps.idle = Yes; |
{ |
ps.system = No; |
exit(1); |
ps.uid = -1; |
} |
ps.command = NULL; |
|
|
#ifdef ORDER |
/* get preset options from the environment */ |
/* determine sorting order index, if necessary */ |
if ((env_top = getenv("TOP")) != NULL) { |
if (order_name != NULL) |
av = preset_argv = argparse(env_top, &preset_argc); |
{ |
ac = preset_argc; |
if ((order_index = string_index(order_name, statics.order_names)) == -1) |
|
{ |
|
char **pp; |
|
|
|
fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", |
/* |
myname, order_name); |
* set the dummy argument to an explanatory message, in case |
fprintf(stderr, "\tTry one of these:"); |
* getopt encounters a bad argument |
pp = statics.order_names; |
*/ |
while (*pp != NULL) |
preset_argv[0] = "while processing environment"; |
{ |
|
fprintf(stderr, " %s", *pp++); |
|
} |
|
fputc('\n', stderr); |
|
exit(1); |
|
} |
} |
} |
/* process options */ |
#endif |
do { |
|
/* |
|
* if we're done doing the presets, then process the real |
|
* arguments |
|
*/ |
|
if (preset_argc == 0) { |
|
ac = argc; |
|
av = argv; |
|
optind = 1; |
|
} |
|
parseargs(ac, av); |
|
i = preset_argc; |
|
preset_argc = 0; |
|
} while (i != 0); |
|
|
#ifdef no_initialization_needed |
/* set constants for username/uid display correctly */ |
/* initialize the hashing stuff */ |
if (!do_unames) { |
if (do_unames) |
uname_field = " UID "; |
{ |
get_userid = itoa7; |
init_hash(); |
} |
} |
/* initialize the kernel memory interface */ |
#endif |
if (machine_init(&statics) == -1) |
|
exit(1); |
|
|
/* initialize termcap */ |
/* determine sorting order index, if necessary */ |
init_termcap(interactive); |
if (order_name != NULL) { |
|
if ((order_index = string_index(order_name, |
|
statics.order_names)) == -1) { |
|
char **pp; |
|
|
/* get the string to use for the process area header */ |
fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", |
header_text = format_header(uname_field); |
__progname, order_name); |
|
fprintf(stderr, "\tTry one of these:"); |
|
pp = statics.order_names; |
|
while (*pp != NULL) |
|
fprintf(stderr, " %s", *pp++); |
|
fputc('\n', stderr); |
|
exit(1); |
|
} |
|
} |
|
|
/* initialize display interface */ |
/* initialize termcap */ |
if ((max_topn = display_init(&statics)) == -1) |
init_termcap(interactive); |
{ |
|
fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); |
|
exit(4); |
|
} |
|
|
|
/* print warning if user requested more processes than we can display */ |
|
if (topn > max_topn) |
|
{ |
|
fprintf(stderr, |
|
"%s: warning: this terminal can only display %d processes.\n", |
|
myname, max_topn); |
|
warnings++; |
|
} |
|
|
|
/* adjust for topn == Infinity */ |
/* get the string to use for the process area header */ |
if (topn == Infinity) |
header_text = format_header(uname_field); |
{ |
|
/* |
/* initialize display interface */ |
* For smart terminals, infinity really means everything that can |
if ((max_topn = display_init(&statics)) == -1) { |
* be displayed, or Largest. |
fprintf(stderr, "%s: can't allocate sufficient memory\n", __progname); |
* On dumb terminals, infinity means every process in the system! |
exit(4); |
* We only really want to do that if it was explicitly specified. |
} |
* This is always the case when "Default_TOPN != Infinity". But if |
/* print warning if user requested more processes than we can display */ |
* topn wasn't explicitly specified and we are on a dumb terminal |
if (topn > max_topn) { |
* and the default is Infinity, then (and only then) we use |
fprintf(stderr, |
* "Nominal_TOPN" instead. |
"%s: warning: this terminal can only display %d processes.\n", |
*/ |
__progname, max_topn); |
|
warnings++; |
|
} |
|
/* adjust for topn == Infinity */ |
|
if (topn == Infinity) { |
|
/* |
|
* For smart terminals, infinity really means everything that can |
|
* be displayed, or Largest. |
|
* On dumb terminals, infinity means every process in the system! |
|
* We only really want to do that if it was explicitly specified. |
|
* This is always the case when "Default_TOPN != Infinity". But if |
|
* topn wasn't explicitly specified and we are on a dumb terminal |
|
* and the default is Infinity, then (and only then) we use |
|
* "Nominal_TOPN" instead. |
|
*/ |
#if Default_TOPN == Infinity |
#if Default_TOPN == Infinity |
topn = smart_terminal ? Largest : |
topn = smart_terminal ? Largest : |
(topn_specified ? Largest : Nominal_TOPN); |
(topn_specified ? Largest : Nominal_TOPN); |
#else |
#else |
topn = Largest; |
topn = Largest; |
#endif |
#endif |
} |
} |
|
/* set header display accordingly */ |
|
display_header(topn > 0); |
|
|
/* set header display accordingly */ |
/* determine interactive state */ |
display_header(topn > 0); |
if (interactive == Maybe) |
|
interactive = smart_terminal; |
|
|
/* determine interactive state */ |
/* if # of displays not specified, fill it in */ |
if (interactive == Maybe) |
if (displays == 0) |
{ |
displays = smart_terminal ? Infinity : 1; |
interactive = smart_terminal; |
|
} |
|
|
|
/* if # of displays not specified, fill it in */ |
/* |
if (displays == 0) |
* block interrupt signals while setting up the screen and the |
{ |
* handlers |
displays = smart_terminal ? Infinity : 1; |
*/ |
} |
sigemptyset(&mask); |
|
sigaddset(&mask, SIGINT); |
/* block interrupt signals while setting up the screen and the handlers */ |
sigaddset(&mask, SIGQUIT); |
sigemptyset(&mask); |
sigaddset(&mask, SIGTSTP); |
sigaddset(&mask, SIGINT); |
sigprocmask(SIG_BLOCK, &mask, &oldmask); |
sigaddset(&mask, SIGQUIT); |
init_screen(); |
sigaddset(&mask, SIGTSTP); |
(void) signal(SIGINT, leave); |
sigprocmask(SIG_BLOCK, &mask, &oldmask); |
(void) signal(SIGQUIT, leave); |
init_screen(); |
(void) signal(SIGTSTP, tstop); |
(void) signal(SIGINT, leave); |
|
(void) signal(SIGQUIT, leave); |
|
(void) signal(SIGTSTP, tstop); |
|
#ifdef SIGWINCH |
#ifdef SIGWINCH |
(void) signal(SIGWINCH, winch); |
(void) signal(SIGWINCH, winch); |
#endif |
#endif |
sigprocmask(SIG_SETMASK, &oldmask, NULL); |
sigprocmask(SIG_SETMASK, &oldmask, NULL); |
if (warnings) |
if (warnings) { |
{ |
fputs("....", stderr); |
fputs("....", stderr); |
fflush(stderr); /* why must I do this? */ |
fflush(stderr); /* why must I do this? */ |
sleep((unsigned) (3 * warnings)); |
sleep((unsigned)(3 * warnings)); |
fputc('\n', stderr); |
fputc('\n', stderr); |
} |
} |
|
|
|
restart: |
restart: |
|
|
/* |
/* |
* main loop -- repeat while display count is positive or while it |
* main loop -- repeat while display count is positive or while it |
* indicates infinity (by being -1) |
* indicates infinity (by being -1) |
*/ |
*/ |
|
while ((displays == -1) || (displays-- > 0)) { |
|
/* get the current stats */ |
|
get_system_info(&system_info); |
|
|
while ((displays == -1) || (displays-- > 0)) |
/* get the current set of processes */ |
{ |
processes = get_process_info(&system_info, &ps, |
/* get the current stats */ |
proc_compares[order_index]); |
get_system_info(&system_info); |
|
|
|
/* get the current set of processes */ |
/* display the load averages */ |
processes = |
(*d_loadave)(system_info.last_pid, system_info.load_avg); |
get_process_info(&system_info, |
|
&ps, |
|
#ifdef ORDER |
|
proc_compares[order_index]); |
|
#else |
|
proc_compare); |
|
#endif |
|
|
|
/* display the load averages */ |
/* display the current time */ |
(*d_loadave)(system_info.last_pid, |
/* this method of getting the time SHOULD be fairly portable */ |
system_info.load_avg); |
time(&curr_time); |
|
i_timeofday(&curr_time); |
|
|
/* display the current time */ |
/* display process state breakdown */ |
/* this method of getting the time SHOULD be fairly portable */ |
(*d_procstates)(system_info.p_total, system_info.procstates); |
time(&curr_time); |
|
i_timeofday(&curr_time); |
|
|
|
/* display process state breakdown */ |
/* display the cpu state percentage breakdown */ |
(*d_procstates)(system_info.p_total, |
if (dostates) { /* but not the first time */ |
system_info.procstates); |
(*d_cpustates) (system_info.cpustates); |
|
} else { |
|
/* we'll do it next time */ |
|
if (smart_terminal) |
|
z_cpustates(); |
|
else { |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
} |
|
dostates = Yes; |
|
} |
|
|
/* display the cpu state percentage breakdown */ |
/* display memory stats */ |
if (dostates) /* but not the first time */ |
(*d_memory) (system_info.memory); |
{ |
|
(*d_cpustates)(system_info.cpustates); |
|
} |
|
else |
|
{ |
|
/* we'll do it next time */ |
|
if (smart_terminal) |
|
{ |
|
z_cpustates(); |
|
} |
|
else |
|
{ |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
} |
|
dostates = Yes; |
|
} |
|
|
|
/* display memory stats */ |
/* handle message area */ |
(*d_memory)(system_info.memory); |
(*d_message) (); |
|
|
/* handle message area */ |
/* update the header area */ |
(*d_message)(); |
(*d_header) (header_text); |
|
|
/* update the header area */ |
if (topn > 0) { |
(*d_header)(header_text); |
/* determine number of processes to actually display */ |
|
/* |
if (topn > 0) |
* this number will be the smallest of: active |
{ |
* processes, number user requested, number current |
/* determine number of processes to actually display */ |
* screen accommodates |
/* this number will be the smallest of: active processes, |
*/ |
number user requested, number current screen accommodates */ |
active_procs = system_info.p_active; |
active_procs = system_info.p_active; |
if (active_procs > topn) |
if (active_procs > topn) |
active_procs = topn; |
{ |
if (active_procs > max_topn) |
active_procs = topn; |
active_procs = max_topn; |
} |
/* now show the top "n" processes. */ |
if (active_procs > max_topn) |
for (i = 0; i < active_procs; i++) |
{ |
(*d_process)(i, format_next_process(processes, |
active_procs = max_topn; |
get_userid)); |
} |
} else |
|
i = 0; |
|
|
/* now show the top "n" processes. */ |
/* do end-screen processing */ |
for (i = 0; i < active_procs; i++) |
u_endscreen(i); |
{ |
|
(*d_process)(i, format_next_process(processes, get_userid)); |
|
} |
|
} |
|
else |
|
{ |
|
i = 0; |
|
} |
|
|
|
/* do end-screen processing */ |
/* now, flush the output buffer */ |
u_endscreen(i); |
fflush(stdout); |
|
|
/* now, flush the output buffer */ |
/* only do the rest if we have more displays to show */ |
fflush(stdout); |
if (displays) { |
|
/* 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; |
|
if (!interactive) { |
|
/* set up alarm */ |
|
(void) signal(SIGALRM, onalrm); |
|
(void) alarm((unsigned) delay); |
|
|
/* only do the rest if we have more displays to show */ |
/* wait for the rest of it .... */ |
if (displays) |
pause(); |
{ |
} else { |
/* switch out for new display on smart terminals */ |
while (no_command) |
if (smart_terminal) |
if (rundisplay()) |
{ |
goto restart; |
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; |
|
if (!interactive) |
|
{ |
|
/* set up alarm */ |
|
(void) signal(SIGALRM, onalrm); |
|
(void) alarm((unsigned)delay); |
|
|
|
/* wait for the rest of it .... */ |
|
pause(); |
|
} |
|
else while (no_command) |
|
{ |
|
/* assume valid command unless told otherwise */ |
|
no_command = No; |
|
|
|
/* set up arguments for select with timeout */ |
quit(0); |
FD_ZERO(&readfds); |
/* NOTREACHED */ |
FD_SET(STDIN_FILENO, &readfds); /* for standard input */ |
return (0); |
timeout.tv_sec = (long)delay; |
} |
timeout.tv_usec = (long)((delay - timeout.tv_sec) * 1000000); |
|
|
|
if (leaveflag) { |
int |
end_screen(); |
rundisplay(void) |
exit(0); |
{ |
} |
static char tempbuf1[50], tempbuf2[50]; |
|
struct timeval timeout; |
|
fd_set readfds; |
|
sigset_t mask; |
|
char ch, *iptr; |
|
int change, i; |
|
static char command_chars[] = "\f qh?en#sdkriIuSo"; |
|
|
if (tstopflag) { |
/* |
/* move to the lower left */ |
* assume valid command unless told |
end_screen(); |
* otherwise |
fflush(stdout); |
*/ |
|
no_command = No; |
|
|
/* default the signal handler action */ |
/* |
(void) signal(SIGTSTP, SIG_DFL); |
* set up arguments for select with |
|
* timeout |
|
*/ |
|
FD_ZERO(&readfds); |
|
FD_SET(STDIN_FILENO, &readfds); |
|
timeout.tv_sec = (long) delay; |
|
timeout.tv_usec = (long) ((delay - timeout.tv_sec) * 1000000); |
|
|
/* unblock the signal and send ourselves one */ |
if (leaveflag) { |
sigemptyset(&mask); |
end_screen(); |
sigaddset(&mask, SIGTSTP); |
exit(0); |
sigprocmask(SIG_UNBLOCK, &mask, NULL); |
} |
(void) kill(0, SIGTSTP); |
if (tstopflag) { |
|
/* move to the lower left */ |
|
end_screen(); |
|
fflush(stdout); |
|
|
/* reset the signal handler */ |
/* |
(void) signal(SIGTSTP, tstop); |
* default the signal handler |
|
* action |
|
*/ |
|
(void) signal(SIGTSTP, SIG_DFL); |
|
|
/* reinit screen */ |
/* |
reinit_screen(); |
* unblock the signal and |
reset_display(); |
* send ourselves one |
tstopflag = 0; |
*/ |
goto restart; |
sigemptyset(&mask); |
} |
sigaddset(&mask, SIGTSTP); |
|
sigprocmask(SIG_UNBLOCK, &mask, NULL); |
|
(void) kill(0, SIGTSTP); |
|
|
if (winchflag) { |
/* reset the signal handler */ |
/* reascertain the screen dimensions */ |
(void) signal(SIGTSTP, tstop); |
get_screensize(); |
|
|
|
/* tell display to resize */ |
/* reinit screen */ |
max_topn = display_resize(); |
reinit_screen(); |
|
reset_display(); |
|
tstopflag = 0; |
|
return 1; |
|
} |
|
if (winchflag) { |
|
/* |
|
* reascertain the screen |
|
* dimensions |
|
*/ |
|
get_screensize(); |
|
|
/* reset the signal handler */ |
/* tell display to resize */ |
(void) signal(SIGWINCH, winch); |
max_topn = display_resize(); |
|
|
reset_display(); |
/* reset the signal handler */ |
winchflag = 0; |
(void) signal(SIGWINCH, winch); |
goto restart; |
|
} |
|
|
|
/* wait for either input or the end of the delay period */ |
reset_display(); |
if (select(STDIN_FILENO + 1, &readfds, (fd_set *)NULL, |
winchflag = 0; |
(fd_set *)NULL, &timeout) > 0) |
return 1; |
{ |
} |
int newval; |
/* |
char *errmsg; |
* wait for either input or the end |
|
* of the delay period |
/* something to read -- clear the message area first */ |
*/ |
clear_message(); |
if (select(STDIN_FILENO + 1, &readfds, (fd_set *) NULL, |
|
(fd_set *) NULL, &timeout) > 0) { |
|
char *errmsg; |
|
int newval; |
|
|
/* now read it and convert to command strchr */ |
clear_message(); |
/* (use "change" as a temporary to hold strchr) */ |
|
(void) read(0, &ch, 1); |
/* |
if ((iptr = strchr(command_chars, ch)) == NULL) |
* now read it and convert to |
{ |
* command strchr |
|
*/ |
|
(void) read(0, &ch, 1); |
|
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) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
no_command = Yes; |
no_command = Yes; |
} |
fflush(stdout); |
else |
return (0); |
{ |
} |
change = iptr - command_chars; |
|
if (overstrike && change > CMD_OSLIMIT) |
change = iptr - command_chars; |
{ |
if (overstrike && change > CMD_OSLIMIT) { |
/* error */ |
/* error */ |
new_message(MT_standout, |
new_message(MT_standout, |
" Command cannot be handled by this terminal"); |
" Command cannot be handled by this terminal"); |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
no_command = Yes; |
no_command = Yes; |
|
fflush(stdout); |
|
return (0); |
|
} |
|
|
|
switch (change) { |
|
case CMD_redraw: /* redraw screen */ |
|
reset_display(); |
|
break; |
|
|
|
case CMD_update: /* merely update display */ |
|
/* |
|
* is the load average high? |
|
*/ |
|
if (system_info.load_avg[0] > LoadMax) { |
|
/* yes, go home for visual feedback */ |
|
go_home(); |
|
fflush(stdout); |
} |
} |
else switch(change) |
break; |
{ |
|
case CMD_redraw: /* redraw screen */ |
case CMD_quit: /* quit */ |
|
quit(0); |
|
break; |
|
|
|
case CMD_help1: /* help */ |
|
case CMD_help2: |
|
reset_display(); |
|
clear(); |
|
show_help(); |
|
standout("Hit any key to continue: "); |
|
fflush(stdout); |
|
(void) read(0, &ch, 1); |
|
break; |
|
|
|
case CMD_errors: /* show errors */ |
|
if (error_count() == 0) { |
|
new_message(MT_standout, |
|
" Currently no errors to report."); |
|
if (putchar('\r') == EOF) |
|
exit(1); |
|
no_command = Yes; |
|
} else { |
reset_display(); |
reset_display(); |
break; |
|
|
|
case CMD_update: /* merely update display */ |
|
/* is the load average high? */ |
|
if (system_info.load_avg[0] > LoadMax) |
|
{ |
|
/* yes, go home for visual feedback */ |
|
go_home(); |
|
fflush(stdout); |
|
} |
|
break; |
|
|
|
case CMD_quit: /* quit */ |
|
quit(0); |
|
/*NOTREACHED*/ |
|
break; |
|
|
|
case CMD_help1: /* help */ |
|
case CMD_help2: |
|
reset_display(); |
|
clear(); |
clear(); |
show_help(); |
show_errors(); |
standout("Hit any key to continue: "); |
standout("Hit any key to continue: "); |
fflush(stdout); |
fflush(stdout); |
(void) read(0, &ch, 1); |
(void) read(0, &ch, 1); |
break; |
} |
|
break; |
case CMD_errors: /* show errors */ |
|
if (error_count() == 0) |
case CMD_number1: /* new number */ |
{ |
case CMD_number2: |
new_message(MT_standout, |
new_message(MT_standout, |
" Currently no errors to report."); |
"Number of processes to show: "); |
if (putchar('\r') == EOF) |
newval = readline(tempbuf1, 8, Yes); |
exit(1); |
if (newval > -1) { |
no_command = Yes; |
if (newval > max_topn) { |
} |
|
else |
|
{ |
|
reset_display(); |
|
clear(); |
|
show_errors(); |
|
standout("Hit any key to continue: "); |
|
fflush(stdout); |
|
(void) read(0, &ch, 1); |
|
} |
|
break; |
|
|
|
case CMD_number1: /* new number */ |
|
case CMD_number2: |
|
new_message(MT_standout, |
|
"Number of processes to show: "); |
|
newval = readline(tempbuf1, 8, Yes); |
|
if (newval > -1) |
|
{ |
|
if (newval > max_topn) |
|
{ |
|
new_message(MT_standout | MT_delayed, |
new_message(MT_standout | MT_delayed, |
" This terminal can only display %d processes.", |
" This terminal can only " |
max_topn); |
"display %d processes.", |
|
max_topn); |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
} |
} |
|
if (newval == 0) |
if (newval == 0) |
|
{ |
|
/* inhibit the header */ |
|
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; |
d_header = i_header; |
} |
|
topn = newval; |
|
} |
} |
break; |
topn = newval; |
|
} |
case CMD_delay: /* new seconds delay */ |
break; |
new_message(MT_standout, "Seconds to delay: "); |
|
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
case CMD_delay: /* new seconds delay */ |
{ |
new_message(MT_standout, "Seconds to delay: "); |
char *endp; |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
double newdelay = strtod(tempbuf2, &endp); |
char *endp; |
if (newdelay >= 0 && newdelay < 1000000 && *endp == '\0') |
double newdelay = strtod(tempbuf2, &endp); |
{ |
|
|
if (newdelay >= 0 && newdelay < 1000000 && |
|
*endp == '\0') |
delay = newdelay; |
delay = newdelay; |
} |
} |
} |
clear_message(); |
clear_message(); |
break; |
break; |
|
|
case CMD_displays: /* change display count */ |
case CMD_displays: /* change display count */ |
new_message(MT_standout, |
new_message(MT_standout, |
"Displays to show (currently %s): ", |
"Displays to show (currently %s): ", |
displays == -1 ? "infinite" : |
displays == -1 ? "infinite" : |
itoa(displays)); |
itoa(displays)); |
if ((i = readline(tempbuf1, 10, Yes)) > 0) |
if ((i = readline(tempbuf1, 10, Yes)) > 0) |
displays = i; |
{ |
else if (i == 0) |
displays = i; |
quit(0); |
} |
|
else if (i == 0) |
clear_message(); |
{ |
break; |
quit(0); |
|
} |
case CMD_kill: /* kill program */ |
clear_message(); |
new_message(0, "kill "); |
break; |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
|
if ((errmsg = kill_procs(tempbuf2)) != NULL) { |
case CMD_kill: /* kill program */ |
|
new_message(0, "kill "); |
|
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
|
{ |
|
if ((errmsg = kill_procs(tempbuf2)) != NULL) |
|
{ |
|
new_message(MT_standout, "%s", errmsg); |
new_message(MT_standout, "%s", errmsg); |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
no_command = Yes; |
no_command = Yes; |
} |
|
} |
} |
else |
} else |
{ |
clear_message(); |
clear_message(); |
break; |
} |
|
break; |
case CMD_renice: /* renice program */ |
|
new_message(0, "renice "); |
case CMD_renice: /* renice program */ |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
new_message(0, "renice "); |
if ((errmsg = renice_procs(tempbuf2)) != NULL) { |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
|
{ |
|
if ((errmsg = renice_procs(tempbuf2)) != NULL) |
|
{ |
|
new_message(MT_standout, "%s", errmsg); |
new_message(MT_standout, "%s", errmsg); |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
no_command = Yes; |
no_command = Yes; |
} |
|
} |
} |
else |
} else |
{ |
clear_message(); |
clear_message(); |
break; |
} |
|
break; |
|
|
|
case CMD_idletog: |
case CMD_idletog: |
case CMD_idletog2: |
case CMD_idletog2: |
ps.idle = !ps.idle; |
ps.idle = !ps.idle; |
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) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
break; |
break; |
|
|
case CMD_user: |
case CMD_user: |
new_message(MT_standout, |
new_message(MT_standout, |
"Username to show: "); |
"Username to show: "); |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { |
{ |
if (tempbuf2[0] == '+' && |
if (tempbuf2[0] == '+' && |
tempbuf2[1] == '\0') { |
tempbuf2[1] == '\0') |
|
{ |
|
ps.uid = -1; |
ps.uid = -1; |
} |
} else if ((i = userid(tempbuf2)) == -1) { |
else if ((i = userid(tempbuf2)) == -1) |
|
{ |
|
new_message(MT_standout, |
new_message(MT_standout, |
" %s: unknown user", tempbuf2); |
" %s: unknown user", tempbuf2); |
no_command = Yes; |
no_command = Yes; |
} |
} else |
else |
|
{ |
|
ps.uid = i; |
ps.uid = i; |
} |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
} else |
} |
clear_message(); |
else |
break; |
{ |
|
clear_message(); |
|
} |
|
break; |
|
|
|
case CMD_system: |
case CMD_system: |
ps.system = !ps.system; |
ps.system = !ps.system; |
new_message(MT_standout | MT_delayed, |
new_message(MT_standout | MT_delayed, |
" %sisplaying system processes.", |
" %sisplaying system processes.", |
ps.system ? "D" : "Not d"); |
ps.system ? "D" : "Not d"); |
break; |
break; |
|
|
#ifdef ORDER |
case CMD_order: |
case CMD_order: |
new_message(MT_standout, |
new_message(MT_standout, |
"Order to sort: "); |
"Order to sort: "); |
if (readline(tempbuf2, |
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
sizeof(tempbuf2), No) > 0) { |
{ |
if ((i = string_index(tempbuf2, |
if ((i = string_index(tempbuf2, statics.order_names)) == -1) |
statics.order_names)) == -1) { |
{ |
new_message(MT_standout, |
new_message(MT_standout, |
" %s: unrecognized sorting order", |
" %s: unrecognized sorting order", tempbuf2); |
tempbuf2); |
no_command = Yes; |
no_command = Yes; |
} |
} else |
else |
|
{ |
|
order_index = i; |
order_index = i; |
} |
|
if (putchar('\r') == EOF) |
|
exit(1); |
|
} |
|
else |
|
{ |
|
clear_message(); |
|
} |
|
break; |
|
#endif |
|
|
|
default: |
|
new_message(MT_standout, " BAD CASE IN SWITCH!"); |
|
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
} |
} else |
} |
clear_message(); |
|
break; |
|
|
/* flush out stuff that may have been written */ |
default: |
fflush(stdout); |
new_message(MT_standout, " BAD CASE IN SWITCH!"); |
|
if (putchar('\r') == EOF) |
|
exit(1); |
} |
} |
} |
|
} |
} |
} |
|
|
|
quit(0); |
/* flush out stuff that may have been written */ |
/*NOTREACHED*/ |
fflush(stdout); |
return(0); |
return 0; |
} |
} |
|
|
|
|
/* |
/* |
* reset_display() - reset all the display routine pointers so that entire |
* reset_display() - reset all the display routine pointers so that entire |
* screen will get redrawn. |
* screen will get redrawn. |
*/ |
*/ |
|
|
static void |
static void |
reset_display(void) |
reset_display(void) |
{ |
{ |
d_loadave = i_loadave; |
d_loadave = i_loadave; |
d_procstates = i_procstates; |
d_procstates = i_procstates; |
d_cpustates = i_cpustates; |
d_cpustates = i_cpustates; |
d_memory = i_memory; |
d_memory = i_memory; |
d_message = i_message; |
d_message = i_message; |
d_header = i_header; |
d_header = i_header; |
d_process = i_process; |
d_process = i_process; |
} |
} |
|
|
/* |
|
* signal handlers |
|
*/ |
|
|
|
void |
void |
leave(int unused) /* exit under normal conditions -- INT handler */ |
leave(int signo) |
{ |
{ |
leaveflag = 1; |
leaveflag = 1; |
} |
} |
|
|
void |
void |
tstop(int i) /* SIGTSTP handler */ |
tstop(int signo) |
{ |
{ |
tstopflag = 1; |
tstopflag = 1; |
} |
} |
|
|
#ifdef SIGWINCH |
#ifdef SIGWINCH |
void |
void |
winch(int i) /* SIGWINCH handler */ |
winch(int signo) |
{ |
{ |
winchflag = 1; |
winchflag = 1; |
} |
} |
#endif |
#endif |
|
|
void |
void |
quit(int status) /* exit under duress */ |
onalrm(int signo) |
{ |
{ |
end_screen(); |
|
exit(status); |
|
/*NOTREACHED*/ |
|
} |
} |
|
|
void |
void |
onalrm(int unused) /* SIGALRM handler */ |
quit(int ret) |
{ |
{ |
/* this is only used in batch mode to break out of the pause() */ |
end_screen(); |
/* return; */ |
exit(ret); |
} |
} |
|
|