Files
s390-tools/hyptop/hyptop.c
Mete Durlu 617a8248e8 hyptop: Add option to show omitted fields on formatted output
Fields without a valid value are normally excluded from formatted output
of hyptop. Add "--all" option to force hyptop to display those fields
with null values.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2025-12-10 14:40:51 +01:00

395 lines
7.0 KiB
C

/*
* hyptop - Show hypervisor performance data on System z
*
* Main & init functions
*
* Copyright IBM Corp. 2010, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <ncurses.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include "lib/util_fmt.h"
#include "dg_debugfs.h"
#include "helper.h"
#include "hyptop.h"
#include "opts.h"
#include "sd.h"
#include "win_cpu_types.h"
#ifdef WITH_HYPFS
#include "dg_hypfs.h"
#endif
/*
* Globals for the whole program
*/
struct hyptop_globals g;
/*
* Get current terminal size and tell curses about it
*/
static void l_term_size_get(void)
{
struct winsize ws;
g.c.col_cnt = 80;
g.c.row_cnt = 24;
if (ioctl(1, TIOCGWINSZ, &ws) != -1) {
if ((ws.ws_col != 0) && (ws.ws_row != 0)) {
g.c.col_cnt = ws.ws_col;
g.c.row_cnt = ws.ws_row;
}
}
resizeterm(g.c.row_cnt, g.c.col_cnt);
}
/*
* Process input
*/
static enum hyptop_win_action l_process_input(struct hyptop_win *win)
{
int c;
/* Skip all resize events */
while ((c = wgetch(stdscr)) == KEY_RESIZE) {}
return win->process_input(win, c);
}
/*
* Process input with timeout
*/
static enum hyptop_win_action l_process_input_timeout(time_t time_s,
long time_us)
{
struct timeval tv;
fd_set fds;
int rc;
while (1) {
FD_ZERO(&fds);
FD_SET(0, &fds);
tv.tv_sec = time_s;
tv.tv_usec = time_us;
rc = select(1, &fds, NULL, NULL, &tv);
switch (rc) {
case 0:
/* Timeout */
return WIN_KEEP;
case 1:
/* Input */
if (l_process_input(g.w.cur) == WIN_SWITCH)
return WIN_SWITCH;
continue;
case -1:
if (errno != EINTR)
ERR_EXIT_ERRNO("Select call failed");
/* Signal: Resize */
hyptop_update_term();
continue;
default:
assert(0);
}
}
}
/*
* Sleep
*/
static enum hyptop_win_action l_sleep(time_t time_s, long time_us)
{
struct timespec ts;
ts.tv_sec = time_s;
ts.tv_nsec = util_usecs_to_nsecs(time_us);
nanosleep(&ts, NULL);
return WIN_KEEP;
}
/*
* External process input with timeout funciton
*/
enum hyptop_win_action hyptop_process_input_timeout(void)
{
enum hyptop_win_action rc;
if (g.o.batch_mode_specified) {
opts_iterations_next();
rc = l_sleep(g.o.delay_s, g.o.delay_us);
} else {
rc = l_process_input_timeout(g.o.delay_s, g.o.delay_us);
opts_iterations_next();
}
return rc;
}
/*
* External process input funciton
*/
enum hyptop_win_action hyptop_process_input(void)
{
return l_process_input_timeout(-1U, 0);
}
/*
* Signal handler for exiting hyptop
*/
static void l_sig_exit(int sig)
{
(void) sig;
hyptop_exit(0);
}
/*
* Install signal handler
*/
static void l_sig_handler_init(void)
{
struct sigaction sigact;
/* Ignore signals SIGUSR1 and SIGUSR2 */
if (sigemptyset(&sigact.sa_mask) < 0)
goto fail;
sigact.sa_flags = 0;
sigact.sa_handler = SIG_IGN;
if (sigaction(SIGUSR1, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGUSR2, &sigact, NULL) < 0)
goto fail;
/* Exit on SIGINT, SIGTERM, SIGHUP, ... */
if (sigemptyset(&sigact.sa_mask) < 0)
goto fail;
sigact.sa_handler = l_sig_exit;
if (sigaction(SIGINT, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGTERM, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGHUP, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGQUIT, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGALRM, &sigact, NULL) < 0)
goto fail;
if (sigaction(SIGPIPE, &sigact, NULL) < 0)
goto fail;
return;
fail:
ERR_EXIT_ERRNO("Could not initialize signal handler");
}
/*
* Start curses
*/
static int l_initscr(void)
{
if (!initscr())
return ERR;
g.c.initialized = 1;
atexit(hyptop_text_mode);
return 0;
}
/*
* Check if terminal is able to run hyptop in curses mode
*/
static void l_term_check(void)
{
char *term_str = getenv("TERM");
if (!term_str)
ERR_EXIT("Please set TERM environment variable or "
"try \"--batch_mode\"\n");
/* S390 line mode terminals normally have TERM=dumb */
if (strcmp(term_str, "dumb") == 0)
ERR_EXIT("Terminal of type \"dumb\" is not supported,"
" try \"--batch_mode\"\n");
}
/*
* Init util_fmt if --format is specified on the command line.
*/
static void l_fmt_init(void)
{
unsigned int flags = FMT_WARN;
if (!g.o.format_specified)
return;
if (g.o.format == FMT_CSV)
flags |= FMT_QUOTEALL;
if (g.o.format == FMT_CSV || g.o.format_all)
flags |= FMT_KEEPINVAL;
if (g.o.format == FMT_JSON || g.o.format == FMT_JSONSEQ)
flags |= FMT_HANDLEINT;
util_fmt_init(stdout, g.o.format, flags, 1);
}
/*
* Init curses
*/
static void l_term_init(void)
{
if (g.o.batch_mode_specified)
return;
l_term_check();
if (l_initscr() == ERR)
goto fail;
if (noecho() == ERR)
goto fail;
if (nodelay(stdscr, TRUE) == ERR)
goto fail;
if (cbreak() == ERR) /* Line buffering disabled. pass on everything */
goto fail;
if (keypad(stdscr, TRUE) == ERR)
goto fail;
curs_set(0); /* prevent cursor from blinking */
l_term_size_get();
l_sig_handler_init();
return;
fail:
ERR_EXIT("Could not initialize curses, try \"--batch_mode\"\n");
}
/*
* Initialize data gatherer
*/
#ifdef WITH_HYPFS
static void l_dg_init(void)
{
if (dg_debugfs_init(0) == 0)
return;
if (dg_hypfs_init() == 0)
return;
ERR_EXIT("Could not initialize data gatherer\n");
}
#else
static void l_dg_init(void)
{
dg_debugfs_init(1);
}
#endif
/*
* Windows event loop
*/
static void l_event_loop(void)
{
while (1)
g.w.cur->run(g.w.cur);
}
/*
* Clear terminal and write new window content to it
*/
static void l_update_term_curses(void)
{
/* Init screen */
l_term_size_get();
curs_set(0); /* pervent cursor from blinking */
move(0, 0);
erase();
hyptop_printf_init();
/* Write window to screen */
g.w.cur->update_term(g.w.cur);
refresh();
}
/*
* Write window content in line mode
*/
static void l_update_term_batch(void)
{
g.w.cur->update_term(g.w.cur);
}
/*
* Update terminal with new window content
*/
void hyptop_update_term(void)
{
if (g.o.batch_mode_specified)
l_update_term_batch();
else
l_update_term_curses();
}
/*
* Switch to new window "win"
*/
enum hyptop_win_action win_switch(struct hyptop_win *win)
{
assert(g.w.prev_cnt < sizeof(g.w.prev) / sizeof(void *));
g.w.prev[g.w.prev_cnt] = g.w.cur;
g.w.prev_cnt++;
g.w.cur = win;
return WIN_SWITCH;
}
/*
* Switch back to previous window
*/
enum hyptop_win_action win_back(void)
{
g.w.prev_cnt--;
g.w.cur = g.w.prev[g.w.prev_cnt];
return WIN_SWITCH;
}
/*
* Switch to text mode
*/
void hyptop_text_mode(void)
{
if (!g.c.initialized)
return;
g.c.initialized = 0;
clear();
refresh();
endwin();
}
/*
* Exit hyptop
*/
void __noreturn hyptop_exit(int rc)
{
hyptop_text_mode();
exit(rc);
}
/*
* Initialize all modules and start first window
*/
int main(int argc, char *argv[])
{
opts_parse(argc, argv);
l_fmt_init();
hyptop_helper_init();
sd_init();
l_dg_init();
opt_verify_systems();
l_term_init();
win_sys_list_init();
win_sys_init();
g.win_cpu_types = win_cpu_types_new();
l_event_loop();
return 0;
}