/* top.c - Source file: show Linux processes */
/*
* Copyright (c) 2002-2022, by: Jim Warner <james.warner@comcast.net
*
* This file may be used subject to the terms and conditions of the
* GNU Library General Public License Version 2, or any later version
* at your option, as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*/
/* For contributions to this program, the author wishes to thank:
* Craig Small, <csmall@dropbear.xyz>
* Albert D. Cahalan, <albert@users.sf.net>
* Sami Kerola, <kerolasa@iki.fi>
*/
#include <ctype.h>
#include <curses.h>
#include <errno.h>
#include <fcntl.h>
#include <float.h>
#include <getopt.h>
#include <limits.h>
#include <pwd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <term.h> // foul sob, defines all sorts of stuff...
#undef raw
#undef tab
#undef TTY
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/select.h> // also available via <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h> // also available via <stdlib.h>
#include "fileutils.h"
#include "signals.h"
#include "nls.h"
#include "meminfo.h"
#include "misc.h"
#include "pids.h"
#include "stat.h"
#include "top.h"
#include "top_nls.h"
/*###### Miscellaneous global stuff ####################################*/
/* The original and new terminal definitions
(only set when not in 'Batch' mode) */
static struct termios Tty_original, // our inherited terminal definition
#ifdef TERMIOS_ONLY
Tty_tweaked, // for interactive 'line' input
#endif
Tty_raw; // for unsolicited input
static int Ttychanged = 0;
/* Last established cursor state/shape */
static const char *Cursor_state = "";
/* Program name used in error messages and local 'rc' file name */
static char *Myname;
/* Our constant sigset, so we need initialize it but once */
static sigset_t Sigwinch_set;
/* The 'local' config file support */
static char Rc_name [OURPATHSZ];
static RCF_t Rc = DEF_RCFILE;
static int Rc_questions;
static int Rc_compatibilty;
/* SMP, Irix/Solaris mode, Linux 2.5.xx support (and beyond) */
static long Hertz;
static int Cpu_cnt;
static float Cpu_pmax;
static const char *Cpu_States_fmts;
/* Specific process id monitoring support */
static int Monpids [MONPIDMAX+1] = { 0 };
static int Monpidsidx = 0;
/* Current screen dimensions.
note: the number of processes displayed is tracked on a per window
basis (see the WIN_t). Max_lines is the total number of
screen rows after deducting summary information overhead. */
/* Current terminal screen size. */
static int Screen_cols, Screen_rows, Max_lines;
/* These 'SCREEN_ROWS', 'BOT_ and 'Bot_' guys are used
in managing the special separate bottom 'window' ... */
#define SCREEN_ROWS ( Screen_rows - Bot_rsvd )
#define BOT_ITEMMAX 10 // Bot_item array's max size
#define BOT_MSGSMAX 10 // total entries for Msg_tab
#define BOT_UNFOCUS -1 // tab focus not established
// negative 'item' values won't be seen by build_headers() ...
#define BOT_DELIMIT -1 // fencepost with item array
#define BOT_ITEM_NS -2 // data for namespaces req'd
#define BOT_MSG_LOG -3 // show the most recent msgs
// next 4 are used when toggling window contents
#define BOT_SEP_CMA ','
#define BOT_SEP_SLS '/'
#define BOT_SEP_SMI ';'
#define BOT_SEP_SPC ' '
// 1 for horizontal separator
#define BOT_RSVD 1
#define BOT_KEEP Bot_show_func = NULL
#define BOT_TOSS do { Bot_show_func = NULL; Bot_item[0] = BOT_DELIMIT; \
Bot_task = Bot_rsvd = Bot_what = 0; \
Bot_indx = BOT_UNFOCUS; \
} while(0)
static int Bot_task,
Bot_what,
Bot_rsvd,
Bot_indx = BOT_UNFOCUS,
Bot_item[BOT_ITEMMAX] = { BOT_DELIMIT };
static char Bot_sep,
*Bot_head,
Bot_buf[BOTBUFSIZ]; // the 'environ' can be huge
typedef int(*BOT_f)(const void *, const void *);
static BOT_f Bot_focus_func;
static void(*Bot_show_func)(void);
/* This is really the number of lines needed to display the summary
information (0 - nn), but is used as the relative row where we
stick the cursor between frames. */
static int Msg_row;
/* Global/Non-windows mode stuff that is NOT persistent */
static int Batch = 0, // batch mode, collect no input, dumb output
Loops = -1, // number of iterations, -1 loops forever
Secure_mode = 0, // set if some functionality restricted
Width_mode = 0, // set w/ 'w' - potential output override
Thread_mode = 0; // set w/ 'H' - show threads vs. tasks
/* Unchangeable cap's stuff built just once (if at all) and
thus NOT saved in a WIN_t's RCW_t. To accommodate 'Batch'
mode, they begin life as empty strings so the overlying
logic need not change ! */
static char Cap_clr_eol [CAPBUFSIZ] = "", // global and/or static vars
Cap_nl_clreos [CAPBUFSIZ] = "", // are initialized to zeros!
Cap_clr_scr [CAPBUFSIZ] = "", // the assignments used here
Cap_curs_norm [CAPBUFSIZ] = "", // cost nothing but DO serve
Cap_curs_huge [CAPBUFSIZ] = "", // to remind people of those
Cap_curs_hide [CAPBUFSIZ] = "", // batch requirements!
Cap_clr_eos [CAPBUFSIZ] = "",
Cap_home [CAPBUFSIZ] = "",
Cap_norm [CAPBUFSIZ] = "",
Cap_reverse [CAPBUFSIZ] = "",
Caps_off [CAPBUFSIZ] = "",
Caps_endline [SMLBUFSIZ] = "";
#ifndef RMAN_IGNORED
static char Cap_rmam [CAPBUFSIZ] = "",
Cap_smam [CAPBUFSIZ] = "";
/* set to 1 if writing to the last column would be troublesome
(we don't distinguish the lowermost row from the other rows) */
static int Cap_avoid_eol = 0;
#endif
static int Cap_can_goto = 0;
/* Some optimization stuff, to reduce output demands...
The Pseudo_ guys are managed by adj_geometry and frame_make. They
are exploited in a macro and represent 90% of our optimization.
The Stdout_buf is transparent to our code and regardless of whose
buffer is used, stdout is flushed at frame end or if interactive. */
static char *Pseudo_screen;
static int Pseudo_row = PROC_XTRA;
static size_t Pseudo_size;
#ifndef OFF_STDIOLBF
// less than stdout's normal buffer but with luck mostly '\n' anyway
static char Stdout_buf[2048];
#endif
/* Our four WIN_t's, and which of those is considered the 'current'
window (ie. which window is associated with any summ info displayed
and to which window commands are directed) */
static WIN_t Winstk [GROUPSMAX];
static WIN_t *Curwin;
/* Frame oriented stuff that can't remain local to any 1 function
and/or that would be too cumbersome managed as parms,
and/or that are simply more efficiently handled as globals
[ 'Frames_...' (plural) stuff persists beyond 1 frame ]
[ or are used in response to async signals received ! ] */
static volatile int Frames_s