#include <signal.h>
#include <curses.h>
#include <panel.h>
#include <string.h>
#include "top.h"
#define DISP_SIG SIGTERM
#define DISP_SIGNAME "TERM"
#define DISP_KEY_RESIZE (KEY_MAX + 1)
#define DISP_KEY_EXIT (KEY_MAX + 2)
static char *disp_lbuf;
static char *disp_sbuf;
static int disp_bufsize;
static char disp_ibuf[17];
static int disp_sig;
static const char *disp_signame;
static WINDOW *disp_dwin;
static PANEL *disp_dpan;
static unsigned disp_curline;
#define DISP_ILINE_CLEAR_DELAY 1
static int disp_iline;
static struct timeval disp_ilinetime;
static boolean_t disp_ilineclear;
static boolean_t
disp_p_skipl(void);
static boolean_t
disp_p_printl(const char *a_format, ...);
static boolean_t
disp_p_println(const char *a_format, ...);
static boolean_t
disp_p_vprintln(boolean_t a_newline, const char *a_format, va_list a_p);
static boolean_t
disp_p_wprintl(WINDOW *a_window, const char *a_format, ...);
static boolean_t
disp_p_vwprintln(WINDOW *a_window, boolean_t a_newline, const char *a_format,
va_list a_p);
static boolean_t
disp_p_mvwprintl(WINDOW *a_window, int a_y, int a_x, const char *a_format, ...);
static boolean_t
disp_p_mvwprintln(WINDOW *a_window, int a_y, int a_x, const char *a_format,
...);
static boolean_t
disp_p_vmvwprintln(WINDOW *a_window, boolean_t a_newline, int a_y, int a_x,
const char *a_format, va_list a_p);
static const char *
disp_p_iline_prompt(const char *a_format, ...);
static boolean_t
disp_p_iline_set(const char *a_format, ...);
static boolean_t
disp_p_iline_eset(boolean_t a_newline, const char *a_format, va_list a_p);
static boolean_t
disp_p_iline_vset(const char *a_format, va_list a_p);
static boolean_t
disp_p_init(void);
static boolean_t
disp_p_fini(void);
static void
disp_p_shutdown(int a_signal);
static boolean_t
disp_p_help(void);
static void
disp_p_sigwinch(int a_signal);
static boolean_t
disp_p_resize(void);
static boolean_t
disp_p_interp_c(void);
static boolean_t
disp_p_interp_ns(const char *a_name, int *r_int);
static boolean_t
disp_p_interp_Oo(const char *a_name, top_sort_key_t *r_key,
boolean_t *r_ascend);
static boolean_t
disp_p_interp_S(void);
static boolean_t
disp_p_interp_U(void);
boolean_t
disp_run(void)
{
boolean_t retval;
int c, i, y, x, ysize, xsize;
struct timeval curtime;
if (disp_p_init()
|| samp_init(disp_p_skipl, disp_p_printl, disp_p_println,
disp_p_vprintln, disp_p_iline_eset)) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&curtime, NULL);
for (;;) {
#ifdef TOP_DEPRECATED
AGAIN:
#endif
if (!isatty(0))
exit(1);
disp_curline = 0;
if (wmove(disp_dwin, 0, 0) == ERR
|| samp_run()) {
retval = TRUE;
goto RETURN;
}
getmaxyx(disp_dwin, ysize, xsize);
getyx(disp_dwin, y, x);
if (y < disp_iline) {
for (i = y + 1; i <= disp_iline && i < ysize; i++) {
if (wclrtoeol(disp_dwin) == ERR
|| wmove(disp_dwin, i, 0) == ERR) {
retval = TRUE;
goto RETURN;
}
}
getyx(disp_dwin, y, x);
}
if (y == disp_iline && y + 1 < ysize) {
if (wmove(disp_dwin, disp_iline + 1, 0) == ERR) {
retval = TRUE;
goto RETURN;
}
getyx(disp_dwin, y, x);
}
if (y > disp_iline) {
if (wclrtobot(disp_dwin) == ERR) {
retval = TRUE;
goto RETURN;
}
}
update_panels();
if (doupdate() == ERR) {
retval = TRUE;
goto RETURN;
}
GET_CHAR:
c = wgetch(disp_dwin);
gettimeofday(&curtime, NULL);
if (disp_ilineclear
&& disp_ilinetime.tv_sec + DISP_ILINE_CLEAR_DELAY
< curtime.tv_sec) {
if (disp_p_iline_set("")) {
retval = TRUE;
goto RETURN;
}
disp_ilineclear = FALSE;
}
switch (c) {
case 'c':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_interp_c()) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 'f':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
top_opt_f = !top_opt_f;
if (disp_p_iline_set(top_opt_f
? "Report shared library statistics"
: "Do not report shared library statistics"
)) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 'n':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_interp_ns("number of processes",
&top_opt_n)) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 'O':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_interp_Oo("secondary", &top_opt_O,
&top_opt_O_ascend)) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 'o':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_interp_Oo("primary", &top_opt_o,
&top_opt_o_ascend)) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case DISP_KEY_EXIT:
case 'q':
samp_fini();
retval = FALSE;
goto RETURN;
case 'r':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
top_opt_r = !top_opt_r;
if (disp_p_iline_set(top_opt_r
? "Report process memory object maps"
: "Do not report process memory object maps"
)) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 'S':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_interp_S()) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 's':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_interp_ns("update interval", &top_opt_s)) {
retval = TRUE;
goto RETURN;
}
wtimeout(disp_dwin, top_opt_s * 1000);
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 't':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
top_opt_t = !top_opt_t;
if (disp_p_iline_set(top_opt_t
? "Translate uid numbers to usernames"
: "Do not translate uid numbers to usernames")) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 'U':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_interp_U()) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
case 'w':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
top_opt_w = !top_opt_w;
if (disp_p_iline_set(top_opt_w
? "Display wide deltas"
: "Display narrow deltas")) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
#ifdef TOP_DEPRECATED
case 'x':
top_opt_x = !top_opt_x;
if (disp_p_iline_set(top_opt_x
? "Normal (non-compatibility) mode"
: "Compatibility mode")) {
retval = TRUE;
goto RETURN;
}
if (top_opt_x) {
top_opt_f = TRUE;
top_opt_r = TRUE;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
break;
#endif
case '\x0c':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_ilineclear) {
if (disp_p_iline_set("")) {
retval = TRUE;
goto RETURN;
}
disp_ilineclear = FALSE;
}
if (disp_p_resize()
|| redrawwin(disp_dwin) == ERR) {
retval = TRUE;
goto RETURN;
}
break;
case DISP_KEY_RESIZE:
if (disp_p_resize()) {
retval = TRUE;
goto RETURN;
}
break;
case '?':
#ifdef TOP_DEPRECATED
if (top_opt_x) {
goto AGAIN;
}
#endif
if (disp_p_help()) {
retval = TRUE;
goto RETURN;
}
case ERR:
break;
default:
goto GET_CHAR;
}
}
assert(0);
RETURN:
if (disp_p_fini()) {
retval = TRUE;
goto RETURN;
}
return retval;
}
static boolean_t
disp_p_skipl(void)
{
boolean_t retval;
int y, x, ysize, xsize;
getmaxyx(disp_dwin, ysize, xsize);
getyx(disp_dwin, y, x);
if (y + 1 < ysize) {
if (disp_iline != y) {
disp_iline = y;
if (disp_p_iline_set(disp_sbuf)) {
retval = TRUE;
goto RETURN;
}
}
if (wmove(disp_dwin, y + 1, 0) == ERR) {
retval = TRUE;
goto RETURN;
}
}
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_printl(const char *a_format, ...)
{
boolean_t retval;
va_list ap;
va_start(ap, a_format);
retval = disp_p_vwprintln(disp_dwin, FALSE, a_format, ap);
va_end(ap);
return retval;
}
static boolean_t
disp_p_println(const char *a_format, ...)
{
boolean_t retval;
va_list ap;
va_start(ap, a_format);
retval = disp_p_vwprintln(disp_dwin, TRUE, a_format, ap);
va_end(ap);
return retval;
}
static boolean_t
disp_p_vprintln(boolean_t a_newline, const char *a_format, va_list a_p)
{
return disp_p_vwprintln(disp_dwin, a_newline, a_format, a_p);
}
static boolean_t
disp_p_wprintl(WINDOW *a_window, const char *a_format, ...)
{
boolean_t retval;
va_list ap;
va_start(ap, a_format);
retval = disp_p_vwprintln(a_window, FALSE, a_format, ap);
va_end(ap);
return retval;
}
static boolean_t
disp_p_vwprintln(WINDOW *a_window, boolean_t a_newline, const char *a_format,
va_list a_p)
{
boolean_t retval;
int y, x, ysize, xsize, maxlen;
getmaxyx(a_window, ysize, xsize);
getyx(a_window, y, x);
if (disp_curline + 1 >= ysize) {
maxlen = 0;
assert(maxlen + 1 <= disp_bufsize);
} else if (y + 1 == ysize) {
maxlen = xsize - x - 1;
assert(maxlen + 1 <= disp_bufsize);
} else
#ifdef TOP_DBG
if (y < ysize)
#endif
{
maxlen = xsize - x;
assert(maxlen + 1 <= disp_bufsize);
}
#ifdef TOP_DBG
else {
assert(0);
}
#endif
if (maxlen > 0) {
if (wclrtoeol(a_window) == ERR) {
retval = TRUE;
goto RETURN;
}
if (vsnprintf(disp_lbuf, maxlen + 1, a_format, a_p) == -1
|| waddnstr(a_window, disp_lbuf, maxlen) == ERR) {
retval = TRUE;
goto RETURN;
}
}
if (a_newline) {
disp_curline++;
if (y + 1 < ysize) {
if (wmove(a_window, y + 1, 0) == ERR) {
retval = TRUE;
goto RETURN;
}
}
}
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_mvwprintl(WINDOW *a_window, int a_y, int a_x, const char *a_format, ...)
{
boolean_t retval;
va_list ap;
va_start(ap, a_format);
retval = disp_p_vmvwprintln(a_window, FALSE, a_y, a_x, a_format, ap);
va_end(ap);
return retval;
}
static boolean_t
disp_p_mvwprintln(WINDOW *a_window, int a_y, int a_x, const char *a_format, ...)
{
boolean_t retval;
va_list ap;
va_start(ap, a_format);
retval = disp_p_vmvwprintln(a_window, TRUE, a_y, a_x, a_format, ap);
va_end(ap);
return retval;
}
static boolean_t
disp_p_vmvwprintln(WINDOW *a_window, boolean_t a_newline, int a_y, int a_x,
const char *a_format, va_list a_p)
{
boolean_t retval;
int oldy, oldx, ysize, xsize;
getmaxyx(a_window, ysize, xsize);
if (a_y < ysize && a_x < xsize) {
getyx(a_window, oldy, oldx);
if (wmove(a_window, a_y, a_x) == ERR) {
retval = TRUE;
goto RETURN;
}
if (disp_p_vwprintln(a_window, a_newline, a_format, a_p)) {
wmove(a_window, oldy, oldx);
retval = TRUE;
goto RETURN;
}
}
retval = FALSE;
RETURN:
return retval;
}
static const char *
disp_p_iline_prompt(const char *a_format, ...)
{
const char * retval;
va_list ap;
boolean_t done, resized = FALSE, exited = FALSE;
int c, y, x, ysize, xsize, ilen, tcurline;
getmaxyx(disp_dwin, ysize, xsize);
tcurline = disp_curline;
va_start(ap, a_format);
if (disp_p_iline_vset(a_format, ap)) {
retval = NULL;
goto RETURN;
}
va_end(ap);
getyx(disp_dwin, y, x);
ilen = 0;
disp_ibuf[ilen] = '\0';
for (done = FALSE; done == FALSE;) {
if (y == disp_iline && x < xsize - 1) {
disp_curline = 0;
if (wmove(disp_dwin, y, x) == ERR
|| wclrtoeol(disp_dwin) == ERR
|| disp_p_wprintl(disp_dwin, "%s", disp_ibuf)) {
wmove(disp_dwin, y, x);
retval = NULL;
goto RETURN;
}
}
update_panels();
if (doupdate() == ERR) {
retval = NULL;
goto RETURN;
}
c = wgetch(disp_dwin);
switch (c) {
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case '_':
case '+': case '-':
if (ilen < sizeof(disp_ibuf) - 1) {
disp_ibuf[ilen] = c;
ilen++;
disp_ibuf[ilen] = '\0';
}
break;
case '\x08':
case '\x7f':
case KEY_BACKSPACE:
case KEY_DC:
if (ilen > 0) {
ilen--;
disp_ibuf[ilen] = '\0';
}
break;
case '\x0a':
case '\x0d':
case KEY_ENTER:
done = TRUE;
break;
case '\x07':
ilen = 0;
disp_ibuf[ilen] = '\0';
if (disp_p_iline_set("")) {
retval = NULL;
goto RETURN;
}
done = TRUE;
break;
case DISP_KEY_RESIZE:
if (disp_p_resize()) {
retval = NULL;
goto RETURN;
}
va_start(ap, a_format);
if (disp_p_iline_vset(a_format, ap)) {
retval = NULL;
goto RETURN;
}
va_end(ap);
getyx(disp_dwin, y, x);
resized = TRUE;
break;
case DISP_KEY_EXIT:
done = TRUE;
exited = TRUE;
break;
case '?':
if (disp_p_help()) {
retval = NULL;
goto RETURN;
}
case ERR:
default:
break;
}
}
strncat(disp_sbuf, disp_ibuf, disp_bufsize - strlen(disp_sbuf) - 1);
retval = disp_ibuf;
RETURN:
disp_curline = tcurline;
if (exited) {
if (ungetch(DISP_KEY_EXIT) == ERR) {
retval = NULL;
}
}
if (resized) {
if (ungetch(DISP_KEY_RESIZE) == ERR) {
retval = NULL;
}
}
return retval;
}
static boolean_t
disp_p_iline_set(const char *a_format, ...)
{
boolean_t retval;
va_list ap;
va_start(ap, a_format);
retval = disp_p_iline_vset(a_format, ap);
va_end(ap);
return retval;
}
static boolean_t
disp_p_iline_eset(boolean_t a_newline, const char *a_format, va_list a_p)
{
boolean_t retval;
int y, x;
getyx(disp_dwin, y, x);
if (disp_p_iline_vset(a_format, a_p)) {
retval = TRUE;
goto RETURN;
}
if (wmove(disp_dwin, y, x) == ERR) {
retval = TRUE;
goto RETURN;
}
gettimeofday(&disp_ilinetime, NULL);
disp_ilineclear = TRUE;
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_iline_vset(const char *a_format, va_list a_p)
{
boolean_t retval;
int ysize, xsize, tcurline;
getmaxyx(disp_dwin, ysize, xsize);
tcurline = disp_curline;
if (vsnprintf(disp_sbuf, disp_bufsize, a_format, a_p) == -1) {
retval = TRUE;
goto RETURN;
}
if (disp_iline < ysize) {
disp_curline = 0;
if (disp_p_mvwprintl(disp_dwin, disp_iline, 0, "%s",
disp_sbuf)) {
retval = TRUE;
goto RETURN;
}
update_panels();
if (doupdate() == ERR) {
retval = TRUE;
goto RETURN;
}
}
retval = FALSE;
RETURN:
disp_curline = tcurline;
return retval;
}
static boolean_t
disp_p_init(void)
{
boolean_t retval;
if (initscr() == NULL
|| cbreak() == ERR
|| noecho() == ERR
|| nonl() == ERR
|| intrflush(stdscr, FALSE) == ERR
|| meta(stdscr, TRUE) == ERR
|| keypad(stdscr, TRUE) == ERR) {
retval = TRUE;
goto RETURN;
}
signal(SIGINT, disp_p_shutdown);
signal(SIGQUIT, disp_p_shutdown);
signal(SIGWINCH, disp_p_sigwinch);
signal(SIGCONT, disp_p_resize);
if ((disp_dwin = newwin(0, 0, 0, 0)) == NULL) {
retval = TRUE;
goto RETURN;
}
wtimeout(disp_dwin, top_opt_s * 1000);
if ((disp_dpan = new_panel(disp_dwin)) == NULL) {
retval = TRUE;
goto RETURN;
}
disp_lbuf = (char *)malloc(COLS + 1);
if (disp_lbuf == NULL) {
retval = TRUE;
goto RETURN;
}
disp_sbuf = (char *)malloc(COLS + 1);
if (disp_sbuf == NULL) {
retval = TRUE;
goto RETURN;
}
disp_sbuf[0]='\0'; disp_lbuf[0]='\0';
disp_bufsize = COLS + 1;
disp_sig = DISP_SIG;
disp_signame = DISP_SIGNAME;
disp_iline = 0;
disp_ilineclear = FALSE;
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_fini(void)
{
boolean_t retval;
if (!isatty(0))
exit(1);
if (del_panel(disp_dpan) == ERR
|| delwin(disp_dwin) == ERR
|| endwin() == ERR) {
retval = TRUE;
goto RETURN;
}
free(disp_sbuf);
free(disp_lbuf);
retval = FALSE;
RETURN:
return retval;
}
static void
disp_p_shutdown(int a_signal)
{
ungetch(DISP_KEY_EXIT);
}
static boolean_t
disp_p_help(void)
{
boolean_t retval, again, resized = FALSE, exited = FALSE;
int c, y, tcurline;
WINDOW *hwin;
PANEL *hpan;
char opt_U_str[11];
tcurline = disp_curline;
disp_curline = 0;
if ((hwin = newwin(0, 0, 0, 0)) == NULL) {
retval = TRUE;
goto RETURN;
}
wtimeout(hwin, 1000);
if ((hpan = new_panel(hwin)) == NULL) {
retval = TRUE;
goto RETURN;
}
for (again = TRUE; again;) {
again = FALSE;
y = 0;
if (wattron(hwin, A_UNDERLINE) == ERR
|| disp_p_mvwprintl(hwin, y, 5, "State")
|| disp_p_mvwprintl(hwin, y, 12, "Command")
|| disp_p_mvwprintln(hwin, y, 27, "Description")
|| wattroff(hwin, A_UNDERLINE) == ERR) {
retval = TRUE;
goto RETURN;
}
y++;
if (top_opt_U == FALSE) {
opt_U_str[0] = '\0';
} else if (top_opt_t) {
struct passwd *pwd;
pwd = getpwuid((uid_t)top_opt_U_uid);
if (pwd == NULL) {
retval = TRUE;
goto RETURN;
}
snprintf(opt_U_str, sizeof(opt_U_str), "%s",
pwd->pw_name);
endpwent();
} else {
snprintf(opt_U_str, sizeof(opt_U_str), "%u",
top_opt_U_uid);
}
if (disp_p_mvwprintln(hwin, y++, 0, "\
? Display this help screen, regardless of context.")
|| disp_p_mvwprintln(hwin, y++, 0, "\
^L Redraw the screen.")
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10c c<mode> Set event counting mode to {a|d|e|n}.", top_opt_c)
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10s f Toggle shared library reporting.",
top_opt_f ? "on" : "off")
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10u n<nprocs> Only display <nprocs> processes.", top_opt_n)
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10s O<skey> Set secondary sort key to <skey> (see o<key>).",
top_sort_key_str(top_opt_O, top_opt_O_ascend))
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10s o<key> Set primary sort key to <key>: [+-]{command|cpu|pid",
top_sort_key_str(top_opt_o, top_opt_o_ascend))
|| disp_p_mvwprintln(hwin, y++, 0, "\
|prt|reg|rprvt|rshrd|rsize|th|time|uid|username|vprvt")
|| disp_p_mvwprintln(hwin, y++, 0, "\
|vsize}.")
|| disp_p_mvwprintln(hwin, y++, 0, "\
q Quit.")
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10s r Toggle process memory object map reporting.",
top_opt_r ? "on" : "off")
|| disp_p_mvwprintln(hwin, y++, 0, "\
S<sig>\\n<pid> Send signal <sig> to pid <pid>.")
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10u s<delay> Set the delay between updates to <delay> seconds.",
top_opt_s)
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10s t Toggle uid to username translation.",
top_opt_t ? "on" : "off")
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10s U<user> Only display processes owned by <user>, or all.",
opt_U_str)
|| disp_p_mvwprintln(hwin, y++, 0, "\
%10s w Toggle wide/narrow delta mode.",
top_opt_w ? "wide" : "narrow")
|| disp_p_mvwprintln(hwin, y++, 0, "\
")
|| disp_p_mvwprintl(hwin, y++, 0, "\
Press any key to continue...")) {
retval = TRUE;
goto RETURN;
}
update_panels();
if (doupdate() == ERR) {
retval = TRUE;
goto RETURN;
}
c = wgetch(hwin);
switch (c) {
case DISP_KEY_RESIZE:
again = TRUE;
resized = TRUE;
if (disp_p_resize()
|| wresize(hwin, LINES, COLS) == ERR
|| replace_panel(hpan, hwin) == ERR) {
retval = TRUE;
goto RETURN;
}
break;
case DISP_KEY_EXIT:
exited = TRUE;
break;
case ERR:
again = TRUE;
break;
default:
break;
}
}
if (del_panel(hpan) == ERR
|| delwin(hwin) == ERR) {
retval = TRUE;
goto RETURN;
}
update_panels();
if (doupdate() == ERR) {
retval = TRUE;
goto RETURN;
}
retval = FALSE;
RETURN:
disp_curline = tcurline;
if (exited) {
if (ungetch(DISP_KEY_EXIT) == ERR) {
retval = NULL;
}
}
if (resized) {
if (ungetch(DISP_KEY_RESIZE) == ERR) {
retval = TRUE;
}
}
return retval;
}
static void
disp_p_sigwinch(int a_signal)
{
if (ungetch(DISP_KEY_RESIZE) == ERR) {
_exit(1);
}
}
static boolean_t
disp_p_resize(void)
{
boolean_t retval;
struct winsize size;
char *p, *q;
if (ioctl(1, TIOCGWINSZ, &size) == -1
|| resizeterm(size.ws_row, size.ws_col) == ERR
|| (p = (char *)realloc(disp_lbuf, size.ws_col + 1)) == NULL
|| (q = (char *)realloc(disp_sbuf, size.ws_col + 1)) == NULL) {
retval = TRUE;
goto RETURN;
}
disp_lbuf = p;
disp_sbuf = q;
disp_bufsize = size.ws_col + 1;
if (wresize(disp_dwin, size.ws_row, size.ws_col) == ERR
|| replace_panel(disp_dpan, disp_dwin) == ERR) {
retval = TRUE;
goto RETURN;
}
redrawwin(disp_dwin);
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_interp_c(void)
{
boolean_t retval;
const char *s;
if ((s = disp_p_iline_prompt("mode [%c]: ", top_opt_c)) == NULL) {
retval = TRUE;
goto RETURN;
}
if (strlen(s) == 1 && (*s == 'a' || *s == 'd'
|| *s == 'e' || *s == 'n')) {
top_opt_c = s[0];
} else if (strlen(s) != 0) {
if (disp_p_iline_set( "Invalid mode: %s", s)) {
retval = TRUE;
goto RETURN;
}
}
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_interp_ns(const char *a_name, int *r_int)
{
boolean_t retval;
const char *s;
char *p;
unsigned n;
if ((s = disp_p_iline_prompt("%s [%u]: ", a_name, *r_int)) == NULL) {
retval = TRUE;
goto RETURN;
}
if (strlen(s) > 0) {
errno = 0;
n = strtoul(s, &p, 0);
if ((errno == EINVAL && n == 0)
|| (errno == ERANGE && n == ULONG_MAX)
|| *p != '\0'
|| n > TOP_MAX_NPROCS) {
if (disp_p_iline_set("Invalid %s: %s", a_name, s)) {
retval = TRUE;
goto RETURN;
}
} else {
*r_int = n;
}
}
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_interp_Oo(const char *a_name, top_sort_key_t *r_key, boolean_t *r_ascend)
{
boolean_t retval;
const char *s, *p;
boolean_t ascend;
if ((s = p = disp_p_iline_prompt("%s key [%s]: ", a_name,
top_sort_key_str(*r_key, *r_ascend))) == NULL) {
retval = TRUE;
goto RETURN;
}
if (strlen(p) > 0) {
if (*p == '+') {
ascend = TRUE;
p++;
} else if (*p == '-') {
ascend = FALSE;
p++;
} else {
ascend = FALSE;
}
*r_ascend = ascend;
if (strcmp(p, "command") == 0) {
*r_key = TOP_SORT_command;
} else if (strcmp(p, "cpu") == 0) {
*r_key = TOP_SORT_cpu;
} else if (strcmp(p, "pid") == 0) {
*r_key = TOP_SORT_pid;
} else if (strcmp(p, "prt") == 0) {
*r_key = TOP_SORT_prt;
} else if (strcmp(p, "reg") == 0) {
*r_key = TOP_SORT_reg;
} else if (strcmp(p, "rprvt") == 0) {
*r_key = TOP_SORT_rprvt;
} else if (strcmp(p, "rshrd") == 0) {
*r_key = TOP_SORT_rshrd;
} else if (strcmp(p, "rsize") == 0) {
*r_key = TOP_SORT_rsize;
} else if (strcmp(p, "th") == 0) {
*r_key = TOP_SORT_th;
} else if (strcmp(p, "time") == 0) {
*r_key = TOP_SORT_time;
} else if (strcmp(p, "uid") == 0) {
*r_key = TOP_SORT_uid;
} else if (strcmp(p, "username") == 0) {
*r_key = TOP_SORT_username;
} else if (strcmp(p, "vprvt") == 0) {
*r_key = TOP_SORT_vprvt;
} else if (strcmp(p, "vsize") == 0) {
*r_key = TOP_SORT_vsize;
} else {
if (disp_p_iline_set("Invalid key: %s", s)) {
retval = TRUE;
goto RETURN;
}
}
}
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_interp_S(void)
{
boolean_t retval;
const char *s, *signame = NULL;
char *p;
int pid, sig, error;
uid_t euid;
gid_t egid;
if (disp_signame != NULL) {
if ((s = disp_p_iline_prompt("signal [%s]: ", disp_signame))
== NULL) {
retval = TRUE;
goto RETURN;
}
} else {
if ((s = disp_p_iline_prompt("signal [%d]: ", disp_sig))
== NULL) {
retval = TRUE;
goto RETURN;
}
}
if (strlen(s) > 0) {
errno = 0;
sig = strtol(s, &p, 0);
if ((errno == EINVAL && sig == 0)
|| (errno == ERANGE && sig == LONG_MIN)
|| (errno == ERANGE && sig == LONG_MAX)
|| *p != '\0') {
if (strcmp(s, "HUP") == 0) {
sig = SIGHUP;
signame = "HUP";
} else if (strcmp(s, "INT") == 0) {
sig = SIGINT;
signame = "INT";
} else if (strcmp(s, "QUIT") == 0) {
sig = SIGQUIT;
signame = "QUIT";
} else if (strcmp(s, "ILL") == 0) {
sig = SIGILL;
signame = "ILL";
} else if (strcmp(s, "TRAP") == 0) {
sig = SIGTRAP;
signame = "TRAP";
} else if (strcmp(s, "ABRT") == 0) {
sig = SIGABRT;
signame = "ABRT";
} else if (strcmp(s, "IOT") == 0) {
sig = SIGIOT;
signame = "IOT";
} else if (strcmp(s, "EMT") == 0) {
sig = SIGEMT;
signame = "EMT";
} else if (strcmp(s, "FPE") == 0) {
sig = SIGFPE;
signame = "FPE";
} else if (strcmp(s, "KILL") == 0) {
sig = SIGKILL;
signame = "KILL";
} else if (strcmp(s, "BUS") == 0) {
sig = SIGBUS;
signame = "BUS";
} else if (strcmp(s, "SEGV") == 0) {
sig = SIGSEGV;
signame = "SEGV";
} else if (strcmp(s, "SYS") == 0) {
sig = SIGSYS;
signame = "SYS";
} else if (strcmp(s, "PIPE") == 0) {
sig = SIGPIPE;
signame = "PIPE";
} else if (strcmp(s, "ALRM") == 0) {
sig = SIGALRM;
signame = "ALRM";
} else if (strcmp(s, "TERM") == 0) {
sig = SIGTERM;
signame = "TERM";
} else if (strcmp(s, "URG") == 0) {
sig = SIGURG;
signame = "URG";
} else if (strcmp(s, "STOP") == 0) {
sig = SIGSTOP;
signame = "STOP";
} else if (strcmp(s, "TSTP") == 0) {
sig = SIGTSTP;
signame = "TSTP";
} else if (strcmp(s, "CONT") == 0) {
sig = SIGCONT;
signame = "CONT";
} else if (strcmp(s, "CHLD") == 0) {
sig = SIGCHLD;
signame = "CHLD";
} else if (strcmp(s, "TTIN") == 0) {
sig = SIGTTIN;
signame = "TTIN";
} else if (strcmp(s, "TTOU") == 0) {
sig = SIGTTOU;
signame = "TTOU";
} else if (strcmp(s, "IO") == 0) {
sig = SIGIO;
signame = "IO";
} else if (strcmp(s, "XCPU") == 0) {
sig = SIGXCPU;
signame = "XCPU";
} else if (strcmp(s, "XFSZ") == 0) {
sig = SIGXFSZ;
signame = "XFSZ";
} else if (strcmp(s, "VTALRM") == 0) {
sig = SIGVTALRM;
signame = "VTALRM";
} else if (strcmp(s, "PROF") == 0) {
sig = SIGPROF;
signame = "PROF";
} else if (strcmp(s, "WINCH") == 0) {
sig = SIGWINCH;
signame = "WINCH";
} else if (strcmp(s, "INFO") == 0) {
sig = SIGINFO;
signame = "INFO";
} else if (strcmp(s, "USR1") == 0) {
sig = SIGUSR1;
signame = "USR1";
} else if (strcmp(s, "USR2") == 0) {
sig = SIGUSR2;
signame = "USR2";
} else {
if (disp_p_iline_set("Invalid signal: %s",
s)) {
retval = TRUE;
goto RETURN;
}
retval = FALSE;
goto RETURN;
}
}
} else {
sig = disp_sig;
signame = disp_signame;
}
if (signame != NULL) {
if ((s = disp_p_iline_prompt("Send signal %s to pid: ",
signame)) == NULL) {
retval = TRUE;
goto RETURN;
}
} else {
if ((s = disp_p_iline_prompt("Send signal %u to pid: ", sig))
== NULL) {
retval = TRUE;
goto RETURN;
}
}
if (strlen(s) > 0) {
errno = 0;
pid = strtol(s, &p, 0);
if ((errno == EINVAL && pid == 0)
|| (errno == ERANGE && pid == LONG_MIN)
|| (errno == ERANGE && pid == LONG_MAX)
|| *p != '\0') {
if (disp_p_iline_set("Invalid pid: %s", s)) {
retval = TRUE;
goto RETURN;
}
retval = FALSE;
goto RETURN;
}
euid = geteuid();
egid = getegid();
if (seteuid(getuid()) == -1
|| setegid(getgid()) == -1) {
if (disp_p_iline_set("Missing setuid bit", s)) {
retval = TRUE;
goto RETURN;
}
retval = FALSE;
goto RETURN;
}
error = kill((pid_t)pid, sig);
if (seteuid(euid) == -1
|| setegid(egid) == -1) {
if (disp_p_iline_set(
"Error restoring setuid bit", s)) {
retval = TRUE;
goto RETURN;
}
retval = FALSE;
goto RETURN;
}
if (error == -1) {
switch (errno) {
case EINVAL:
if (disp_p_iline_set("Invalid signal: %d",
sig)) {
retval = TRUE;
goto RETURN;
}
break;
case ESRCH:
if (disp_p_iline_set("Invalid pid: %d", pid)) {
retval = TRUE;
goto RETURN;
}
break;
case EPERM:
if (disp_p_iline_set(
"Permission error signaling pid: %d",
pid)) {
retval = TRUE;
goto RETURN;
}
break;
default:
assert(0);
break;
}
retval = FALSE;
goto RETURN;
} else {
if (signame != NULL) {
if (disp_p_iline_set(
"Send signal %s to pid %d", signame, pid)) {
retval = TRUE;
goto RETURN;
}
} else {
if (disp_p_iline_set(
"Send signal %d to pid %d", sig, pid)) {
retval = TRUE;
goto RETURN;
}
}
disp_sig = sig;
disp_signame = signame;
}
} else {
if (disp_p_iline_set("Signal command canceled")) {
retval = TRUE;
goto RETURN;
}
}
retval = FALSE;
RETURN:
return retval;
}
static boolean_t
disp_p_interp_U(void)
{
boolean_t retval;
const char *s;
char *p;
unsigned uid;
struct passwd *pwd;
if ((s = disp_p_iline_prompt("user: ")) == NULL) {
retval = TRUE;
goto RETURN;
}
if (strlen(s) > 0) {
errno = 0;
uid = strtoul(s, &p, 0);
if ((errno == EINVAL && uid == 0)
|| (errno == ERANGE && uid == ULONG_MAX)
|| *p != '\0') {
pwd = getpwnam(s);
if (pwd != NULL) {
top_opt_U = TRUE;
top_opt_U_uid = pwd->pw_uid;
} else {
pwd = NULL;
}
} else {
pwd = getpwuid((uid_t)uid);
if (pwd != NULL) {
top_opt_U = TRUE;
top_opt_U_uid = (uid_t)uid;
}
}
endpwent();
if (pwd == NULL) {
if (disp_p_iline_set("Invalid user: %s", s)) {
retval = TRUE;
goto RETURN;
}
}
} else {
top_opt_U = FALSE;
}
retval = FALSE;
RETURN:
return retval;
}