2002-05-30 09:14:46 +05:30
|
|
|
|
/* top.c - Source file: show Linux processes */
|
2002-02-02 04:17:29 +05:30
|
|
|
|
/*
|
2002-06-27 05:26:49 +05:30
|
|
|
|
* Copyright (c) 2002, by: James C. Warner
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* All rights reserved. 8921 Hilloway Road
|
|
|
|
|
* Eden Prairie, Minnesota 55347 USA
|
|
|
|
|
* <warnerjc@worldnet.att.net>
|
|
|
|
|
*
|
2002-05-30 09:14:46 +05:30
|
|
|
|
* 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.
|
2002-02-02 04:17:29 +05:30
|
|
|
|
*/
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* For their contributions to this program, the author wishes to thank:
|
2002-10-03 04:10:32 +05:30
|
|
|
|
* Craig Small, <csmall@small.dropbear.id.au>
|
2002-10-07 03:04:17 +05:30
|
|
|
|
* Albert D. Cahalan, <albert@users.sf.net>
|
2002-06-19 05:15:30 +05:30
|
|
|
|
*/
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#include <sys/resource.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <curses.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include <errno.h>
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdarg.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include <term.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include <termios.h>
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <values.h>
|
2002-11-08 06:01:28 +05:30
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include "proc/devname.h"
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include "proc/procps.h"
|
|
|
|
|
#include "proc/readproc.h"
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include "proc/sig.h"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#ifdef USE_LIB_STA3
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include "proc/status.h"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#endif
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include "proc/sysinfo.h"
|
|
|
|
|
#include "proc/version.h"
|
|
|
|
|
#include "proc/whattime.h"
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#include "top.h"
|
|
|
|
|
|
|
|
|
|
/*###### Miscellaneous global stuff ####################################*/
|
|
|
|
|
|
|
|
|
|
/* The original and new terminal attributes */
|
|
|
|
|
static struct termios Savedtty,
|
|
|
|
|
Rawtty;
|
|
|
|
|
static int Ttychanged = 0;
|
|
|
|
|
|
2002-08-26 06:25:30 +05:30
|
|
|
|
/* Program name used in error messages and local 'rc' file name */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static char *Myname;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-08-26 06:25:30 +05:30
|
|
|
|
/* The Name of the local config file, dynamically constructed */
|
|
|
|
|
static char RCfile [OURPATHSZ];
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/* The run-time acquired page size */
|
|
|
|
|
static int Page_size;
|
|
|
|
|
|
2002-10-19 02:37:49 +05:30
|
|
|
|
/* SMP, Irix/Solaris mode, Linux 2.5.xx support */
|
|
|
|
|
static int Cpu_tot,
|
|
|
|
|
*Cpu_map;
|
|
|
|
|
/* assume no IO-wait stats, overridden if linux 2.5.41 */
|
2002-10-19 03:10:19 +05:30
|
|
|
|
static const char *States_fmts = STATES_line2x4;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/* Specific process id monitoring support */
|
|
|
|
|
static pid_t Monpids [MONPIDMAX] = { 0 };
|
|
|
|
|
static int Monpidsidx = 0;
|
|
|
|
|
|
|
|
|
|
/* A postponed error message */
|
|
|
|
|
static char Msg_delayed [SMLBUFSIZ];
|
|
|
|
|
static int Msg_awaiting = 0;
|
|
|
|
|
|
|
|
|
|
/* Configurable Display support ##################################*/
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
|
|
/* 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 persistent (in rcfile) */
|
2002-07-25 03:55:34 +05:30
|
|
|
|
static int Mode_altscr; /* 'A' - 'Alt' display mode (multi windows) */
|
|
|
|
|
/* next toggle physically alters a proc_t, it CANNOT be window based */
|
|
|
|
|
static int Mode_irixps = 1; /* 'I' - Irix vs. Solaris mode (SMP-only) */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static float Delay_time = DEF_DELAY; /* how long to sleep between updates */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* Global/Non-windows mode stuff that is NOT persistent */
|
|
|
|
|
static int No_ksyms = -1, /* set to '0' if ksym avail, '1' otherwise */
|
|
|
|
|
PSDBopen = 0, /* set to '1' if psdb opened (now postponed) */
|
|
|
|
|
Batch = 0, /* batch mode, collect no input, dumb output */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
Loops = -1, /* number of iterations, -1 loops forever */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
Secure_mode = 0; /* set if some functionality restricted */
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/* Some cap's stuff to reduce runtime calls --
|
|
|
|
|
to accomodate 'Batch' mode, they begin life as empty strings */
|
|
|
|
|
static char Cap_bold [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_clr_eol [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_clr_eos [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_clr_scr [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_curs_norm [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_curs_huge [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_home [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_norm [CAPBUFSIZ] = "",
|
|
|
|
|
Cap_reverse [CAPBUFSIZ] = "",
|
|
|
|
|
Caps_off [CAPBUFSIZ] = "";
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static int Cap_can_goto = 0;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
/* ////////////////////////////////////////////////////////////// */
|
|
|
|
|
/* Special Section: multiple windows/field groups ---------------*/
|
|
|
|
|
|
|
|
|
|
/* The pointers to 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],
|
|
|
|
|
*Curwin;
|
|
|
|
|
|
|
|
|
|
/* Frame oriented stuff that can't remain local to any 1 function
|
|
|
|
|
and/or that would be too cumbersome managed as parms */
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static unsigned Frame_maxtask; /* last known number of active tasks */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* ie. current 'size' of proc table */
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static unsigned Frame_running, /* state categories for this frame */
|
|
|
|
|
Frame_sleepin,
|
|
|
|
|
Frame_stopped,
|
|
|
|
|
Frame_zombied;
|
|
|
|
|
static float Frame_tscale; /* so we can '*' vs. '/' WHEN 'pcpu' */
|
|
|
|
|
static int Frame_srtflg, /* the subject window sort direction */
|
|
|
|
|
Frame_ctimes, /* the subject window's ctimes flag */
|
|
|
|
|
Frame_cmdlin; /* the subject window's cmdlin flag */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* ////////////////////////////////////////////////////////////// */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*###### Sort callbacks ################################################*/
|
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
/*
|
|
|
|
|
* These happen to be coded in the same order as the enum 'pflag'
|
2002-10-07 01:42:08 +05:30
|
|
|
|
* values. Note that 2 of these routines serve double duty --
|
|
|
|
|
* 2 columns each.
|
2002-10-02 05:40:30 +05:30
|
|
|
|
*/
|
2002-10-07 01:42:08 +05:30
|
|
|
|
_SC_NUMx(P_PID, pid)
|
|
|
|
|
_SC_NUMx(P_PPD, ppid)
|
|
|
|
|
_SC_NUMx(P_PGD, pgrp)
|
|
|
|
|
_SC_NUMx(P_UID, euid)
|
|
|
|
|
_SC_STRx(P_USR, euser)
|
|
|
|
|
_SC_STRx(P_GRP, egroup)
|
|
|
|
|
_SC_NUMx(P_TTY, tty)
|
|
|
|
|
_SC_NUMx(P_PRI, priority)
|
|
|
|
|
_SC_NUMx(P_NCE, nice)
|
|
|
|
|
_SC_NUMx(P_CPN, processor)
|
2002-09-13 17:12:44 +05:30
|
|
|
|
_SC_NUM1(P_CPU, pcpu)
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// also serves P_TM2 !
|
2002-09-13 17:12:44 +05:30
|
|
|
|
static int sort_P_TME (const proc_t **P, const proc_t **Q)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{
|
2002-09-13 17:12:44 +05:30
|
|
|
|
if (Frame_ctimes) {
|
|
|
|
|
if ( ((*P)->cutime + (*P)->cstime + (*P)->utime + (*P)->stime)
|
|
|
|
|
< ((*Q)->cutime + (*Q)->cstime + (*Q)->utime + (*Q)->stime) )
|
|
|
|
|
return SORT_lt;
|
|
|
|
|
if ( ((*P)->cutime + (*P)->cstime + (*P)->utime + (*P)->stime)
|
|
|
|
|
> ((*Q)->cutime + (*Q)->cstime + (*Q)->utime + (*Q)->stime) )
|
|
|
|
|
return SORT_gt;
|
|
|
|
|
} else {
|
|
|
|
|
if ( ((*P)->utime + (*P)->stime) < ((*Q)->utime + (*Q)->stime))
|
|
|
|
|
return SORT_lt;
|
|
|
|
|
if ( ((*P)->utime + (*P)->stime) > ((*Q)->utime + (*Q)->stime))
|
|
|
|
|
return SORT_gt;
|
|
|
|
|
}
|
|
|
|
|
return SORT_eq;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
_SC_NUM1(P_VRT, size)
|
|
|
|
|
_SC_NUM2(P_SWP, size, resident)
|
2002-11-08 06:01:28 +05:30
|
|
|
|
_SC_NUM1(P_RES, resident) // also serves P_MEM !
|
2002-09-13 17:12:44 +05:30
|
|
|
|
_SC_NUM1(P_COD, trs)
|
|
|
|
|
_SC_NUM1(P_DAT, drs)
|
|
|
|
|
_SC_NUM1(P_SHR, share)
|
|
|
|
|
_SC_NUM1(P_FLT, maj_flt)
|
|
|
|
|
_SC_NUM1(P_DRT, dt)
|
2002-10-07 01:42:08 +05:30
|
|
|
|
_SC_NUMx(P_STA, state)
|
2002-09-13 17:12:44 +05:30
|
|
|
|
|
|
|
|
|
static int sort_P_CMD (const proc_t **P, const proc_t **Q)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
{
|
|
|
|
|
/* if a process doesn't have a cmdline, we'll consider it a kernel thread
|
2002-11-08 06:01:28 +05:30
|
|
|
|
-- since displayed tasks are given special treatment, we must too */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (Frame_cmdlin && ((*P)->cmdline || (*Q)->cmdline)) {
|
2002-10-07 01:42:08 +05:30
|
|
|
|
if (!(*Q)->cmdline) return Frame_srtflg * -1;
|
|
|
|
|
if (!(*P)->cmdline) return Frame_srtflg;
|
|
|
|
|
return Frame_srtflg *
|
|
|
|
|
strncmp((*Q)->cmdline[0], (*P)->cmdline[0], (unsigned)Curwin->maxcmdln);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// this part also handles the compare if both are kernel threads
|
2002-10-07 01:42:08 +05:30
|
|
|
|
return Frame_srtflg * strcmp((*Q)->cmd, (*P)->cmd);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
_SC_NUM1(P_WCH, wchan)
|
|
|
|
|
_SC_NUM1(P_FLG, flags)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// *special* sort for prochlp() !
|
|
|
|
|
static int sort_HIST_t (const HIST_t *P, const HIST_t *Q)
|
|
|
|
|
{
|
|
|
|
|
return -1 * ( Q->pid - P->pid );
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*###### Tiny useful routine(s) ########################################*/
|
|
|
|
|
|
|
|
|
|
/*
|
2002-10-19 02:37:49 +05:30
|
|
|
|
* This routine isolates ALL user INPUT and ensures that we
|
2002-05-30 09:14:46 +05:30
|
|
|
|
* wont be mixing I/O from stdio and low-level read() requests */
|
|
|
|
|
static int chin (int ech, char *buf, unsigned cnt)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-05-30 09:14:46 +05:30
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
if (!ech)
|
|
|
|
|
rc = read(STDIN_FILENO, buf, cnt);
|
|
|
|
|
else {
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
|
|
|
|
|
rc = read(STDIN_FILENO, buf, cnt);
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty);
|
|
|
|
|
}
|
|
|
|
|
/* may be the beginning of a lengthy escape sequence */
|
|
|
|
|
tcflush(STDIN_FILENO, TCIFLUSH);
|
|
|
|
|
return rc; /* note: we do NOT produce a vaid 'string' */
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This routine simply formats whatever the caller wants and
|
|
|
|
|
* returns a pointer to the resulting 'const char' string... */
|
|
|
|
|
static const char *fmtmk (const char *fmts, ...)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-05-30 09:14:46 +05:30
|
|
|
|
static char buf[BIGBUFSIZ]; /* with help stuff, our buffer */
|
|
|
|
|
va_list va; /* requirements exceed 1k */
|
|
|
|
|
|
|
|
|
|
va_start(va, fmts);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
vsnprintf(buf, sizeof(buf), fmts, va);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
va_end(va);
|
|
|
|
|
return (const char *)buf;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
2002-10-02 05:40:30 +05:30
|
|
|
|
* This guy was originally designed just to trim the rc file lines and
|
|
|
|
|
* any 'open_psdb_message' result which arrived with an inappropriate
|
|
|
|
|
* newline (thanks to 'sysmap_mmap') -- but when tabs (^I) were found
|
|
|
|
|
* in some proc cmdlines, a choice was offered twix space or null. */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
static char *strim (int sp, char *str)
|
|
|
|
|
{
|
2002-10-10 03:02:33 +05:30
|
|
|
|
static const char ws[] = "\b\f\n\r\t\v";
|
2002-05-30 09:14:46 +05:30
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
if (sp)
|
|
|
|
|
while ((p = strpbrk(str, ws))) *p = ' ';
|
|
|
|
|
else
|
|
|
|
|
if ((p = strpbrk(str, ws))) *p = 0;
|
|
|
|
|
return str;
|
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
2002-10-02 05:40:30 +05:30
|
|
|
|
* This guy just facilitates Batch and protects against dumb ttys
|
|
|
|
|
* -- we'd 'inline' him but he's only called twice per frame,
|
|
|
|
|
* yet used in many other locations. */
|
2002-10-12 09:55:57 +05:30
|
|
|
|
static const char *tg2 (int x, int y)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-10-02 05:40:30 +05:30
|
|
|
|
return Cap_can_goto ? tgoto(cursor_address, x, y) : "";
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*###### Exit/Interrput routines #######################################*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The usual program end --
|
|
|
|
|
* called only by functions in this section. */
|
|
|
|
|
static void bye_bye (int eno, const char *str)
|
|
|
|
|
{
|
|
|
|
|
if (!Batch)
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(tg2(0, Screen_rows));
|
|
|
|
|
putp(Cap_curs_norm);
|
|
|
|
|
putp("\n");
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
#ifdef ATEOJ_REPORT
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"\nbye_bye's Summary report:"
|
|
|
|
|
"\n\tProgram"
|
2002-10-19 02:37:49 +05:30
|
|
|
|
"\n\t Linux version = %u.%u.%u"
|
2002-11-08 06:01:28 +05:30
|
|
|
|
"\n\t Page_size = %d, Cpu_tot = %d, sizeof(proc_t) = %u"
|
2002-10-02 05:40:30 +05:30
|
|
|
|
"\n\t %s, using Hertz = %u (%u bytes, %u-bit time)"
|
2002-08-26 06:25:30 +05:30
|
|
|
|
"\n\t sizeof(CPUS_t) = %u, sizeof(HIST_t) = %u (%u HIST_t's/Page)"
|
|
|
|
|
"\n\t CPU_FMTS_JUST1 = %s"
|
2002-10-07 01:42:08 +05:30
|
|
|
|
"\n\t CPU_FMTS_MULTI = %s"
|
|
|
|
|
"\n\tTerminal: %s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
"\n\t device = %s, ncurses = v%s"
|
|
|
|
|
"\n\t max_colors = %d, max_pairs = %d"
|
|
|
|
|
"\n\t Cap_can_goto = %s"
|
|
|
|
|
"\n\t Screen_cols = %d, Screen_rows = %d"
|
|
|
|
|
"\n\t Max_lines = %d"
|
|
|
|
|
"\n\tWindows and Curwin->"
|
|
|
|
|
"\n\t sizeof(WIN_t) = %u, GROUPSMAX = %d"
|
2002-08-26 06:25:30 +05:30
|
|
|
|
"\n\t winname = %s, grpname = %s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#ifdef CASEUP_HEXES
|
|
|
|
|
"\n\t winflags = %08X, maxpflgs = %d"
|
|
|
|
|
#else
|
|
|
|
|
"\n\t winflags = %08x, maxpflgs = %d"
|
|
|
|
|
#endif
|
|
|
|
|
"\n\t fieldscur = %s"
|
|
|
|
|
"\n\t winlines = %d, maxtasks = %d, maxcmdln = %d"
|
2002-09-13 17:12:44 +05:30
|
|
|
|
"\n\t sortindx = %d"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
"\n"
|
2002-10-19 02:37:49 +05:30
|
|
|
|
, LINUX_VERSION_MAJOR(linux_version_code)
|
|
|
|
|
, LINUX_VERSION_MINOR(linux_version_code)
|
|
|
|
|
, LINUX_VERSION_PATCH(linux_version_code)
|
2002-11-08 06:01:28 +05:30
|
|
|
|
, Page_size, Cpu_tot, sizeof(proc_t)
|
2002-08-26 06:25:30 +05:30
|
|
|
|
, procps_version, (unsigned)Hertz, sizeof(Hertz), sizeof(Hertz) * 8
|
|
|
|
|
, sizeof(CPUS_t), sizeof(HIST_t), Page_size / sizeof(HIST_t)
|
|
|
|
|
, CPU_FMTS_JUST1, CPU_FMTS_MULTI
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#ifdef PRETENDNOCAP
|
|
|
|
|
, "dumb"
|
|
|
|
|
#else
|
|
|
|
|
, termname()
|
|
|
|
|
#endif
|
|
|
|
|
, ttyname(STDOUT_FILENO), NCURSES_VERSION
|
|
|
|
|
, max_colors, max_pairs
|
|
|
|
|
, Cap_can_goto ? "yes" : "No!"
|
|
|
|
|
, Screen_cols, Screen_rows
|
|
|
|
|
, Max_lines
|
|
|
|
|
, sizeof(WIN_t), GROUPSMAX
|
|
|
|
|
, Curwin->winname, Curwin->grpname
|
|
|
|
|
, Curwin->winflags, Curwin->maxpflgs
|
|
|
|
|
, Curwin->fieldscur
|
|
|
|
|
, Curwin->winlines, Curwin->maxtasks, Curwin->maxcmdln
|
2002-09-13 17:12:44 +05:30
|
|
|
|
, Curwin->sortindx
|
2002-06-19 05:15:30 +05:30
|
|
|
|
);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
|
if (eno) perror(str);
|
|
|
|
|
else {
|
|
|
|
|
fputs(str, stderr);
|
|
|
|
|
eno = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
exit(eno);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Normal end of execution.
|
|
|
|
|
* catches:
|
|
|
|
|
* SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT and SIGTERM */
|
|
|
|
|
static void stop (int dont_care_sig)
|
|
|
|
|
{
|
2002-10-12 09:55:57 +05:30
|
|
|
|
(void)dont_care_sig;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
bye_bye(0, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Standard error handler to normalize the look of all err o/p */
|
|
|
|
|
static void std_err (const char *str)
|
|
|
|
|
{
|
|
|
|
|
static char buf[SMLBUFSIZ];
|
|
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
/* we'll use our own buffer so callers can still use fmtmk() and, yes the
|
|
|
|
|
leading tab is not the standard convention, but the standard is wrong
|
|
|
|
|
-- OUR msg won't get lost in screen clutter, like so many others! */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(buf, sizeof(buf), "\t%s: %s\n", Myname, str);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (!Ttychanged) {
|
|
|
|
|
fprintf(stderr, buf);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
/* not to worry, he'll change our exit code to 1 due to 'buf' */
|
|
|
|
|
bye_bye(0, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Suspend ourself.
|
|
|
|
|
* catches:
|
|
|
|
|
* SIGTSTP, SIGTTIN and SIGTTOU */
|
|
|
|
|
static void suspend (int dont_care_sig)
|
|
|
|
|
{
|
2002-10-12 09:55:57 +05:30
|
|
|
|
(void)dont_care_sig;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* reset terminal */
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(tg2(0, Screen_rows));
|
|
|
|
|
putp(Cap_curs_norm);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
fflush(stdout);
|
|
|
|
|
raise(SIGSTOP);
|
|
|
|
|
/* later, after SIGCONT... */
|
|
|
|
|
if (!Batch)
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
/*###### Misc Color/Display support ####################################*/
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make the appropriate caps/color strings and set some
|
|
|
|
|
* lengths which are used to distinguish twix the displayed
|
2002-10-19 02:37:49 +05:30
|
|
|
|
* columns and an actual printed row!
|
2002-05-30 09:14:46 +05:30
|
|
|
|
* note: we avoid the use of background color so as to maximize
|
|
|
|
|
* compatibility with the user's xterm settings */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static void capsmk (WIN_t *q)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/* macro to test if a basic (non-color) capability is valid
|
|
|
|
|
thanks: Floyd Davidson <floyd@ptialaska.net> */
|
|
|
|
|
#define tIF(s) s ? s : ""
|
|
|
|
|
static int capsdone = 0;
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* we must NOT disturb our 'empty' terminfo strings! */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
if (Batch) return;
|
|
|
|
|
|
|
|
|
|
/* these are the unchangeable puppies, so we only do 'em once */
|
|
|
|
|
if (!capsdone) {
|
|
|
|
|
strcpy(Cap_bold, tIF(enter_bold_mode));
|
|
|
|
|
strcpy(Cap_clr_eol, tIF(clr_eol));
|
|
|
|
|
strcpy(Cap_clr_eos, tIF(clr_eos));
|
|
|
|
|
strcpy(Cap_clr_scr, tIF(clear_screen));
|
|
|
|
|
strcpy(Cap_curs_huge, tIF(cursor_visible));
|
|
|
|
|
strcpy(Cap_curs_norm, tIF(cursor_normal));
|
|
|
|
|
strcpy(Cap_home, tIF(cursor_home));
|
|
|
|
|
strcpy(Cap_norm, tIF(exit_attribute_mode));
|
|
|
|
|
strcpy(Cap_reverse, tIF(enter_reverse_mode));
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(Caps_off, sizeof(Caps_off), "%s%s", Cap_norm, tIF(orig_pair));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
if (tgoto(cursor_address, 1, 1)) Cap_can_goto = 1;
|
|
|
|
|
capsdone = 1;
|
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* the key to NO run-time costs for configurable colors -- we spend a
|
|
|
|
|
little time with the user now setting up our terminfo strings, and
|
|
|
|
|
the job's done until he/she/it has a change-of-heart */
|
|
|
|
|
if (CHKw(q, Show_COLORS) && max_colors > 0) {
|
|
|
|
|
strcpy(q->capclr_sum, tparm(set_a_foreground, q->summclr));
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(q->capclr_msg, sizeof(q->capclr_msg), "%s%s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, tparm(set_a_foreground, q->msgsclr), Cap_reverse);
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(q->capclr_pmt, sizeof(q->capclr_pmt), "%s%s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, tparm(set_a_foreground, q->msgsclr), Cap_bold);
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(q->capclr_hdr, sizeof(q->capclr_hdr), "%s%s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, tparm(set_a_foreground, q->headclr), Cap_reverse);
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(q->capclr_rownorm, sizeof(q->capclr_rownorm), "%s%s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, Caps_off, tparm(set_a_foreground, q->taskclr));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
} else {
|
2002-06-19 05:15:30 +05:30
|
|
|
|
q->capclr_sum[0] = '\0';
|
|
|
|
|
strcpy(q->capclr_msg, Cap_reverse);
|
|
|
|
|
strcpy(q->capclr_pmt, Cap_bold);
|
|
|
|
|
strcpy(q->capclr_hdr, Cap_reverse);
|
|
|
|
|
strcpy(q->capclr_rownorm, Cap_norm);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* this guy's a composite, so we do him outside the if */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(q->capclr_rowhigh, sizeof(q->capclr_rowhigh), "%s%s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, q->capclr_rownorm, CHKw(q, Show_HIBOLD) ? Cap_bold : Cap_reverse);
|
|
|
|
|
q->len_rownorm = strlen(q->capclr_rownorm);
|
|
|
|
|
q->len_rowhigh = strlen(q->capclr_rowhigh);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
#undef tIF
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Show an error, but not right now.
|
|
|
|
|
* Due to the postponed opening of ksym, using open_psdb_message,
|
2002-09-13 17:12:44 +05:30
|
|
|
|
* if P_WCH had been selected and the program is restarted, the
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* message would otherwise be displayed prematurely.
|
|
|
|
|
* (old top handles that situation with typical inelegance) */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
static void msg_save (const char *fmts, ...)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-05-30 09:14:46 +05:30
|
|
|
|
char tmp[SMLBUFSIZ];
|
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
|
|
va_start(va, fmts);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
vsnprintf(tmp, sizeof(tmp), fmts, va);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
va_end(va);
|
|
|
|
|
/* we'll add some extra attention grabbers to whatever this is */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(Msg_delayed, sizeof(Msg_delayed), "\a*** %s ***", strim(0, tmp));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
Msg_awaiting = 1;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Show an error message (caller may include a '\a' for sound) */
|
|
|
|
|
static void show_msg (const char *str)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-10-19 02:37:49 +05:30
|
|
|
|
PUTP("%s%s %s %s%s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, tg2(0, Msg_row)
|
|
|
|
|
, Curwin->capclr_msg
|
2002-05-30 09:14:46 +05:30
|
|
|
|
, str
|
|
|
|
|
, Caps_off
|
|
|
|
|
, Cap_clr_eol);
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
sleep(MSG_SLEEP);
|
|
|
|
|
Msg_awaiting = 0;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Show an input prompt + larger cursor */
|
|
|
|
|
static void show_pmt (const char *str)
|
|
|
|
|
{
|
2002-10-19 02:37:49 +05:30
|
|
|
|
PUTP("%s%s%s: %s%s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, tg2(0, Msg_row)
|
|
|
|
|
, Curwin->capclr_pmt
|
2002-05-30 09:14:46 +05:30
|
|
|
|
, str
|
|
|
|
|
, Cap_curs_huge
|
|
|
|
|
, Caps_off);
|
|
|
|
|
fflush(stdout);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Show lines with specially formatted elements, but only output
|
|
|
|
|
* what will fit within the current screen width.
|
|
|
|
|
* Our special formatting consists of:
|
|
|
|
|
* "some text <_delimiter_> some more text <_delimiter_>...\n"
|
|
|
|
|
* Where <_delimiter_> is a single byte in the range of:
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* \01 through \10 (in decimalizee, 1 - 8)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
* and is used to select an 'attribute' from a capabilities table
|
|
|
|
|
* which is then applied to the *preceding* substring.
|
|
|
|
|
* Once recognized, the delimiter is replaced with a null character
|
|
|
|
|
* and viola, we've got a substring ready to output! Strings or
|
|
|
|
|
* substrings without delimiters will receive the Cap_norm attribute.
|
|
|
|
|
*
|
|
|
|
|
* Caution:
|
|
|
|
|
* This routine treats all non-delimiter bytes as displayable
|
|
|
|
|
* data subject to our screen width marching orders. If callers
|
|
|
|
|
* embed non-display data like tabs or terminfo strings in our
|
|
|
|
|
* glob, a line will truncate incorrectly at best. Worse case
|
|
|
|
|
* would be truncation of an embedded tty escape sequence.
|
|
|
|
|
*
|
|
|
|
|
* Tabs must always be avoided or our efforts are wasted and
|
|
|
|
|
* lines will wrap. To lessen but not eliminate the risk of
|
|
|
|
|
* terminfo string truncation, such non-display stuff should
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* be placed at the beginning of a "short" line.
|
|
|
|
|
* (and as for tabs, gimme 1 more color then no worries, mate) */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
static void show_special (const char *glob)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{ /* note: the following is for documentation only,
|
|
|
|
|
the real captab is now found in a group's WIN_t !
|
|
|
|
|
+------------------------------------------------------+
|
|
|
|
|
| char *captab[] = { : Cap's/Delim's |
|
|
|
|
|
| Cap_norm, Cap_norm, Cap_bold, = \00, \01, \02 |
|
|
|
|
|
| Sum_color, = \03 |
|
|
|
|
|
| Msg_color, Pmt_color, = \04, \05 |
|
|
|
|
|
| Hdr_color, = \06 |
|
|
|
|
|
| Row_color_high, = \07 |
|
|
|
|
|
| Row_color_norm }; = \10 [octal!] |
|
|
|
|
|
+------------------------------------------------------+ */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
char tmp[BIGBUFSIZ], *cap, *lin_end, *sub_beg, *sub_end;
|
|
|
|
|
int room;
|
|
|
|
|
|
|
|
|
|
/* handle multiple lines passed in a bunch */
|
|
|
|
|
while ((lin_end = strchr(glob, '\n'))) {
|
|
|
|
|
|
|
|
|
|
/* create a local copy we can extend and otherwise abuse */
|
|
|
|
|
memcpy(tmp, glob, (unsigned)(lin_end - glob));
|
|
|
|
|
/* zero terminate this part and prepare to parse substrings */
|
|
|
|
|
tmp[lin_end - glob] = '\0';
|
|
|
|
|
room = Screen_cols;
|
|
|
|
|
sub_beg = sub_end = tmp;
|
|
|
|
|
|
|
|
|
|
while (*sub_beg) {
|
|
|
|
|
switch (*sub_end) {
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 0: /* no end delim, captab makes normal */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
*(sub_end + 1) = '\0'; /* extend str end, then fall through */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 1: case 2: case 3: case 4:
|
|
|
|
|
case 5: case 6: case 7: case 8:
|
|
|
|
|
cap = Curwin->captab[(int)*sub_end];
|
2002-05-30 09:14:46 +05:30
|
|
|
|
*sub_end = '\0';
|
2002-10-19 02:37:49 +05:30
|
|
|
|
PUTP("%s%.*s%s", cap, room, sub_beg, Caps_off);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
room -= (sub_end - sub_beg);
|
|
|
|
|
sub_beg = ++sub_end;
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
default: /* nothin' special, just text */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
++sub_end;
|
|
|
|
|
}
|
|
|
|
|
if (0 >= room) break; /* skip substrings that won't fit */
|
|
|
|
|
} /* end: while 'subtrings' */
|
|
|
|
|
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(Cap_clr_eol);
|
|
|
|
|
putp("\n"); /* emulate truncated newline */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
glob = ++lin_end; /* point to next line (maybe) */
|
|
|
|
|
} /* end: while 'lines' */
|
|
|
|
|
|
|
|
|
|
/* if there's anything left in the glob (by virtue of no trailing '\n'),
|
|
|
|
|
it probably means caller wants to retain cursor position on this final
|
|
|
|
|
line -- ok then, we'll just do our 'fit-to-screen' thingy... */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
if (*glob) PUTP("%.*s", Screen_cols, glob);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
fflush(stdout);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/*###### Small Utility routines ########################################*/
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get a string from the user */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static char *ask4str (const char *prompt)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-05-30 09:14:46 +05:30
|
|
|
|
static char buf[GETBUFSIZ];
|
|
|
|
|
|
|
|
|
|
show_pmt(prompt);
|
|
|
|
|
memset(buf, '\0', sizeof(buf));
|
|
|
|
|
chin(1, buf, sizeof(buf) - 1);
|
|
|
|
|
putp(Cap_curs_norm);
|
|
|
|
|
return strim(0, buf);
|
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
|
|
|
|
* Get a float from the user */
|
|
|
|
|
static float get_float (const char *prompt)
|
|
|
|
|
{
|
|
|
|
|
char *line;
|
|
|
|
|
float f;
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (!(*(line = ask4str(prompt)))) return -1;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// note: we're not allowing negative floats
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (strcspn(line, ",.1234567890")) {
|
2002-05-30 09:14:46 +05:30
|
|
|
|
show_msg("\aNot valid");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
sscanf(line, "%f", &f);
|
|
|
|
|
return f;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
|
|
|
|
* Get an integer from the user */
|
|
|
|
|
static int get_int (const char *prompt)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-05-30 09:14:46 +05:30
|
|
|
|
char *line;
|
|
|
|
|
int n;
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (!(*(line = ask4str(prompt)))) return -1;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// note: we've got to allow negative ints (renice)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
if (strcspn(line, "-1234567890")) {
|
|
|
|
|
show_msg("\aNot valid");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
sscanf(line, "%d", &n);
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
|
|
|
|
* Do some scaling stuff.
|
|
|
|
|
* We'll interpret 'num' as one of the following types and
|
|
|
|
|
* try to format it to fit 'width'.
|
|
|
|
|
* SK_no (0) it's a byte count
|
|
|
|
|
* SK_Kb (1) it's kilobytes
|
|
|
|
|
* SK_Mb (2) it's megabytes
|
|
|
|
|
* SK_Gb (3) it's gigabytes */
|
2002-10-12 09:55:57 +05:30
|
|
|
|
static const char *scale_num (unsigned num, const int width, const unsigned type)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
{
|
2002-10-07 01:42:08 +05:30
|
|
|
|
/* kilobytes, megabytes, gigabytes, duh! */
|
|
|
|
|
static float scale[] = { 1024, 1024*1024, 1024*1024*1024, 0 };
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/* kilo, mega, giga, none */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#ifdef CASEUP_SCALE
|
2002-05-30 09:14:46 +05:30
|
|
|
|
static char nextup[] = { 'K', 'M', 'G', 0 };
|
|
|
|
|
#else
|
|
|
|
|
static char nextup[] = { 'k', 'm', 'g', 0 };
|
|
|
|
|
#endif
|
|
|
|
|
static char buf[TNYBUFSIZ];
|
2002-10-07 01:42:08 +05:30
|
|
|
|
float *dp;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
char *up;
|
|
|
|
|
|
|
|
|
|
/* try an unscaled version first... */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
if (width >= snprintf(buf, sizeof(buf), "%u", num)) return buf;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/* now try successively higher types until it fits */
|
|
|
|
|
for (up = nextup + type, dp = scale; *dp; ++dp, ++up) {
|
|
|
|
|
/* the most accurate version */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
if (width >= snprintf(buf, sizeof(buf), "%.1f%c", num / *dp, *up))
|
|
|
|
|
return buf;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/* the integer version */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
if (width >= snprintf(buf, sizeof(buf), "%d%c", (int)(num / *dp), *up))
|
|
|
|
|
return buf;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
|
|
|
|
/* well shoot, this outta' fit... */
|
2002-10-02 05:40:30 +05:30
|
|
|
|
return "?";
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
|
|
|
|
* Do some scaling stuff.
|
2002-11-08 06:01:28 +05:30
|
|
|
|
* format 'tics' to fit 'width'. */
|
2002-10-12 09:55:57 +05:30
|
|
|
|
static const char *scale_tics (TICS_t tics, const int width)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#ifdef CASEUP_SCALE
|
2002-10-07 01:42:08 +05:30
|
|
|
|
#define HH "%uH"
|
|
|
|
|
#define DD "%uD"
|
|
|
|
|
#define WW "%uW"
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#else
|
2002-10-07 01:42:08 +05:30
|
|
|
|
#define HH "%uh"
|
|
|
|
|
#define DD "%ud"
|
|
|
|
|
#define WW "%uw"
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#endif
|
|
|
|
|
static char buf[TNYBUFSIZ];
|
2002-11-08 06:01:28 +05:30
|
|
|
|
unsigned long nt; // narrow time, for speed on 32-bit
|
|
|
|
|
unsigned cc; // centiseconds
|
|
|
|
|
unsigned nn; // multi-purpose whatever
|
|
|
|
|
|
2002-11-09 07:30:52 +05:30
|
|
|
|
nt = (tics * 100ull) / Hertz;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
cc = nt % 100; // centiseconds past second
|
|
|
|
|
nt /= 100; // total seconds
|
|
|
|
|
nn = nt % 60; // seconds past the minute
|
|
|
|
|
nt /= 60; // total minutes
|
|
|
|
|
if (width >= snprintf(buf, sizeof(buf), "%lu:%02u.%02u", nt, nn, cc))
|
2002-10-19 02:37:49 +05:30
|
|
|
|
return buf;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn))
|
2002-10-19 02:37:49 +05:30
|
|
|
|
return buf;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
nn = nt % 60; // now minutes
|
|
|
|
|
nt /= 60; // now hours
|
|
|
|
|
if (width >= snprintf(buf, sizeof buf, "%lu,%02u", nt, nn))
|
2002-10-19 02:37:49 +05:30
|
|
|
|
return buf;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
nn = nt; // now also hours
|
|
|
|
|
if (width >= snprintf(buf, sizeof buf, HH, nn))
|
2002-10-19 02:37:49 +05:30
|
|
|
|
return buf;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
nn /= 24; // now days
|
|
|
|
|
if (width >= snprintf(buf, sizeof buf, DD, nn))
|
|
|
|
|
return buf;
|
|
|
|
|
nn /= 7; // now weeks
|
|
|
|
|
if (width >= snprintf(buf, sizeof buf, WW, nn))
|
|
|
|
|
return buf;
|
|
|
|
|
// well shoot, this outta' fit...
|
2002-10-02 05:40:30 +05:30
|
|
|
|
return "?";
|
2002-10-07 01:42:08 +05:30
|
|
|
|
|
|
|
|
|
#undef HH
|
|
|
|
|
#undef DD
|
|
|
|
|
#undef WW
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/*###### Library Alternatives ##########################################*/
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Handle our own memory stuff without the risk of leaving the
|
|
|
|
|
* user's terminal in an ugly state should things go sour. */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static void *alloc_c (unsigned numb)
|
|
|
|
|
{
|
|
|
|
|
void * p;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (!numb) ++numb;
|
|
|
|
|
if (!(p = calloc(1, numb)))
|
2002-10-02 05:40:30 +05:30
|
|
|
|
std_err("failed memory allocate");
|
2002-06-19 05:15:30 +05:30
|
|
|
|
return p;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static void *alloc_r (void *q, unsigned numb)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
void *p;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (!numb) ++numb;
|
|
|
|
|
if (!(p = realloc(q, numb)))
|
2002-10-02 05:40:30 +05:30
|
|
|
|
std_err("failed memory allocate");
|
2002-06-19 05:15:30 +05:30
|
|
|
|
return p;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
2002-10-19 02:37:49 +05:30
|
|
|
|
* This guy's modeled on libproc's 'five_cpu_numbers' function except
|
2002-10-02 05:40:30 +05:30
|
|
|
|
* we preserve all cpu data in our CPUS_t array which is organized
|
|
|
|
|
* as follows:
|
|
|
|
|
* cpus[0] thru cpus[n] == tics for each separate cpu
|
|
|
|
|
* cpus[Cpu_tot] == tics from the 1st /proc/stat line */
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static CPUS_t *cpus_refresh (CPUS_t *cpus)
|
2002-10-02 05:40:30 +05:30
|
|
|
|
{
|
|
|
|
|
static FILE *fp = NULL;
|
|
|
|
|
int i;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// enough for a /proc/stat CPU line (not the intr line)
|
2002-10-07 01:42:08 +05:30
|
|
|
|
char buf[SMLBUFSIZ];
|
2002-10-02 05:40:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/* by opening this file once, we'll avoid the hit on minor page faults
|
|
|
|
|
(sorry Linux, but you'll have to close it for us) */
|
2002-10-02 05:40:30 +05:30
|
|
|
|
if (!fp) {
|
|
|
|
|
if (!(fp = fopen("/proc/stat", "r")))
|
|
|
|
|
std_err(fmtmk("Failed /proc/stat open: %s", strerror(errno)));
|
|
|
|
|
/* note: we allocate one more CPUS_t than Cpu_tot so that the last slot
|
|
|
|
|
can hold tics representing the /proc/stat cpu summary (the first
|
|
|
|
|
line read) -- that slot supports our View_CPUSUM toggle */
|
|
|
|
|
cpus = alloc_c((1 + Cpu_tot) * sizeof(CPUS_t));
|
|
|
|
|
}
|
|
|
|
|
rewind(fp);
|
|
|
|
|
fflush(fp);
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// first value the last slot with the cpu summary line
|
2002-10-07 01:42:08 +05:30
|
|
|
|
if (!fgets(buf, sizeof(buf), fp)) std_err("failed /proc/stat read");
|
2002-10-06 22:16:06 +05:30
|
|
|
|
if (4 > sscanf(buf, CPU_FMTS_JUST1
|
2002-10-09 12:41:08 +05:30
|
|
|
|
, &cpus[Cpu_tot].u, &cpus[Cpu_tot].n, &cpus[Cpu_tot].s, &cpus[Cpu_tot].i, &cpus[Cpu_tot].w))
|
2002-10-02 05:40:30 +05:30
|
|
|
|
std_err("failed /proc/stat read");
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// and just in case we're 2.2.xx compiled without SMP support...
|
2002-10-19 02:37:49 +05:30
|
|
|
|
if (1 == Cpu_tot) memcpy(cpus, &cpus[1], sizeof(CPUS_t));
|
2002-10-02 05:40:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// now value each separate cpu's tics
|
2002-10-12 02:12:50 +05:30
|
|
|
|
for (i = 0; 1 < Cpu_tot && i < Cpu_tot; i++) {
|
2002-10-02 05:40:30 +05:30
|
|
|
|
#ifdef PRETEND4CPUS
|
|
|
|
|
rewind(fp);
|
2002-10-12 02:12:50 +05:30
|
|
|
|
#endif
|
2002-10-07 01:42:08 +05:30
|
|
|
|
if (!fgets(buf, sizeof(buf), fp)) std_err("failed /proc/stat read");
|
2002-10-06 22:16:06 +05:30
|
|
|
|
if (4 > sscanf(buf, CPU_FMTS_MULTI
|
2002-10-09 12:41:08 +05:30
|
|
|
|
, &cpus[i].u, &cpus[i].n, &cpus[i].s, &cpus[i].i, &cpus[i].w))
|
2002-10-02 05:40:30 +05:30
|
|
|
|
std_err("failed /proc/stat read");
|
|
|
|
|
}
|
|
|
|
|
return cpus;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*
|
|
|
|
|
* Refresh procs *Helper* function to eliminate yet one more need
|
|
|
|
|
* to loop through our darn proc_t table. He's responsible for:
|
|
|
|
|
* 1) calculating the elapsed time since the previous frame
|
|
|
|
|
* 2) counting the number of tasks in each state (run, sleep, etc)
|
|
|
|
|
* 3) maintaining the HIST_t's and priming the proc_t pcpu field
|
|
|
|
|
* 4) establishing the total number tasks for this frame */
|
|
|
|
|
static void prochlp (proc_t *this)
|
|
|
|
|
{
|
|
|
|
|
static HIST_t *hist_sav = NULL;
|
|
|
|
|
static HIST_t *hist_new = NULL;
|
|
|
|
|
static unsigned hist_siz = 0; // number of structs
|
|
|
|
|
static unsigned maxt_sav; // prior frame's max tasks
|
|
|
|
|
int i, lo, hi;
|
|
|
|
|
TICS_t tics;
|
|
|
|
|
|
|
|
|
|
if (!this) {
|
|
|
|
|
static struct timeval oldtimev;
|
|
|
|
|
struct timeval timev;
|
|
|
|
|
struct timezone timez;
|
|
|
|
|
HIST_t *hist_tmp;
|
|
|
|
|
float et;
|
|
|
|
|
|
|
|
|
|
gettimeofday(&timev, &timez);
|
|
|
|
|
et = (timev.tv_sec - oldtimev.tv_sec)
|
|
|
|
|
+ (float)(timev.tv_usec - oldtimev.tv_usec) / 1000000.0;
|
|
|
|
|
oldtimev.tv_sec = timev.tv_sec;
|
|
|
|
|
oldtimev.tv_usec = timev.tv_usec;
|
|
|
|
|
|
|
|
|
|
// if in Solaris mode, adjust our scaling for all cpus
|
|
|
|
|
Frame_tscale = 100.0f / ((float)Hertz * (float)et * (Mode_irixps ? 1 : Cpu_tot));
|
|
|
|
|
maxt_sav = Frame_maxtask;
|
|
|
|
|
Frame_maxtask = Frame_running = Frame_sleepin = Frame_stopped = Frame_zombied = 0;
|
|
|
|
|
|
|
|
|
|
// reuse memory each time around
|
|
|
|
|
hist_tmp = hist_sav;
|
|
|
|
|
hist_sav = hist_new;
|
|
|
|
|
hist_new = hist_tmp;
|
|
|
|
|
// prep for our binary search by sorting the last frame's HIST_t's
|
|
|
|
|
qsort(hist_sav, maxt_sav, sizeof(HIST_t), (QSORT_t)sort_HIST_t);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (this->state) {
|
|
|
|
|
case 'R':
|
|
|
|
|
Frame_running++;
|
|
|
|
|
break;
|
|
|
|
|
case 'S':
|
|
|
|
|
case 'D':
|
|
|
|
|
Frame_sleepin++;
|
|
|
|
|
break;
|
|
|
|
|
case 'T':
|
|
|
|
|
Frame_stopped++;
|
|
|
|
|
break;
|
|
|
|
|
case 'Z':
|
|
|
|
|
Frame_zombied++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Frame_maxtask+1 >= hist_siz) {
|
|
|
|
|
hist_siz = hist_siz * 5 / 4 + 100; // grow by at least 25%
|
|
|
|
|
hist_sav = alloc_r(hist_sav, sizeof(HIST_t) * hist_siz);
|
|
|
|
|
hist_new = alloc_r(hist_new, sizeof(HIST_t) * hist_siz);
|
|
|
|
|
}
|
|
|
|
|
/* calculate time in this process; the sum of user time (utime) and
|
|
|
|
|
system time (stime) -- but PLEASE dont waste time and effort on
|
|
|
|
|
calcs and saves that go unused, like the old top! */
|
|
|
|
|
hist_new[Frame_maxtask].pid = this->pid;
|
|
|
|
|
hist_new[Frame_maxtask].tics = tics = (this->utime + this->stime);
|
|
|
|
|
|
|
|
|
|
// find matching entry from previous frame and make ticks elapsed
|
|
|
|
|
lo = 0;
|
|
|
|
|
hi = maxt_sav - 1;
|
|
|
|
|
while (lo <= hi) {
|
|
|
|
|
i = (lo + hi) / 2;
|
|
|
|
|
if (this->pid < hist_sav[i].pid)
|
|
|
|
|
hi = i - 1;
|
|
|
|
|
else if (this->pid > hist_sav[i].pid)
|
|
|
|
|
lo = i + 1;
|
|
|
|
|
else {
|
|
|
|
|
tics -= hist_sav[i].tics;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* we're just saving elapsed tics, to be converted into %cpu if
|
|
|
|
|
this task wins it's displayable screen row lottery... */
|
|
|
|
|
this->pcpu = tics;
|
|
|
|
|
|
|
|
|
|
// shout this to the world with the final call (or us the next time in)
|
|
|
|
|
Frame_maxtask++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
/*
|
|
|
|
|
* This guy's modeled on libproc's 'readproctab' function except
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* we reuse and extend any prior proc_t's. He's been customized
|
|
|
|
|
* for our specific needs and to avoid the use of <stdarg.h> */
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static proc_t **procs_refresh (proc_t **table, int flags)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-11-08 06:01:28 +05:30
|
|
|
|
#define PTRsz sizeof(proc_t *)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#define ENTsz sizeof(proc_t)
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static unsigned savmax = 0; // first time, Bypass: (i)
|
|
|
|
|
proc_t *ptsk = (proc_t *)-1; // first time, Force: (ii)
|
|
|
|
|
unsigned curmax = 0; // every time (jeeze)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
PROCTAB* PT;
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
prochlp(NULL); // prep for a new frame
|
|
|
|
|
if (Monpidsidx)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
PT = openproc(flags | PROC_PID, Monpids);
|
2002-11-08 06:01:28 +05:30
|
|
|
|
else
|
2002-06-19 05:15:30 +05:30
|
|
|
|
PT = openproc(flags);
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// i) Allocated Chunks: *Existing* table; refresh + reuse
|
2002-06-19 05:15:30 +05:30
|
|
|
|
while (curmax < savmax) {
|
2002-11-08 09:04:20 +05:30
|
|
|
|
if (table[curmax]->cmdline) {
|
2002-10-19 02:37:49 +05:30
|
|
|
|
free(*table[curmax]->cmdline);
|
2002-11-08 09:04:20 +05:30
|
|
|
|
table[curmax]->cmdline = NULL;
|
|
|
|
|
}
|
2002-10-19 02:37:49 +05:30
|
|
|
|
if (!(ptsk = readproc(PT, table[curmax]))) break;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
prochlp(ptsk); // tally & complete this proc_t
|
2002-06-19 05:15:30 +05:30
|
|
|
|
++curmax;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// ii) Unallocated Chunks: *New* or *Existing* table; extend + fill
|
2002-06-19 05:15:30 +05:30
|
|
|
|
while (ptsk) {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// realloc as we go, keeping 'table' ahead of 'currmax++'
|
2002-10-19 02:37:49 +05:30
|
|
|
|
table = alloc_r(table, (curmax + 1) * PTRsz);
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// here, readproc will allocate the underlying proc_t stg
|
|
|
|
|
if ((ptsk = readproc(PT, NULL))) {
|
|
|
|
|
prochlp(ptsk); // tally & complete this proc_t
|
2002-10-19 02:37:49 +05:30
|
|
|
|
table[curmax++] = ptsk;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
closeproc(PT);
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// iii) Chunkless: make 'eot' entry, after ensuring proc_t exists
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (curmax >= savmax) {
|
2002-10-19 02:37:49 +05:30
|
|
|
|
table = alloc_r(table, (curmax + 1) * PTRsz);
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// here, we must allocate the underlying proc_t stg ourselves
|
2002-10-19 02:37:49 +05:30
|
|
|
|
table[curmax] = alloc_c(ENTsz);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
savmax = curmax + 1;
|
|
|
|
|
}
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// this frame's end, but not necessarily end of allocated space
|
2002-10-19 02:37:49 +05:30
|
|
|
|
table[curmax]->pid = -1;
|
|
|
|
|
return table;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
#undef PTRsz
|
|
|
|
|
#undef ENTsz
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
/*###### Startup routines ##############################################*/
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* No mater what *they* say, we handle the really really BIG and
|
|
|
|
|
* IMPORTANT stuff upon which all those lessor functions depend! */
|
|
|
|
|
static void before (char *me)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* setup our program name -- big! */
|
|
|
|
|
Myname = strrchr(me, '/');
|
|
|
|
|
if (Myname) ++Myname; else Myname = me;
|
|
|
|
|
|
|
|
|
|
/* establish cpu particulars -- even bigger! */
|
|
|
|
|
#ifdef PRETEND4CPUS
|
|
|
|
|
Cpu_tot = 4;
|
|
|
|
|
#else
|
2002-10-10 03:02:33 +05:30
|
|
|
|
Cpu_tot = smp_num_cpus;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#endif
|
|
|
|
|
Cpu_map = alloc_r(NULL, sizeof(int) * Cpu_tot);
|
|
|
|
|
for (i = 0; i < Cpu_tot; i++)
|
|
|
|
|
Cpu_map[i] = i;
|
2002-10-19 02:45:49 +05:30
|
|
|
|
if(linux_version_code > LINUX_VERSION(2, 5, 41))
|
2002-10-19 02:37:49 +05:30
|
|
|
|
States_fmts = STATES_line2x5;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
/* get virtual page size -- nearing huge! */
|
|
|
|
|
Page_size = getpagesize();
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
2002-09-13 17:12:44 +05:30
|
|
|
|
* Build the local RC file name then try to read both of 'em.
|
|
|
|
|
* 'SYS_RCFILE' contains two lines consisting of the secure
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* mode switch and an update interval. It's presence limits what
|
2002-09-13 17:12:44 +05:30
|
|
|
|
* ordinary users are allowed to do.
|
|
|
|
|
* '$HOME/RCfile' contains multiple lines - 2 global + 3 per window.
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* line 1: a shameless advertisement
|
2002-07-25 03:55:34 +05:30
|
|
|
|
* line 2: an id, Mode_altcsr, Mode_irixps, Delay_time and Curwin.
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* If running in secure mode via the /etc/rcfile,
|
|
|
|
|
* Delay_time will be ignored except for root.
|
|
|
|
|
* For each of the 4 windows:
|
|
|
|
|
* line a: contains w->winname, fieldscur
|
2002-09-13 17:12:44 +05:30
|
|
|
|
* line b: contains w->winflags, sortindx, maxtasks
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* line c: contains w->summclr, msgsclr, headclr, taskclr */
|
|
|
|
|
static void configs_read (void)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-10-10 03:02:33 +05:30
|
|
|
|
static const char err_rc[] = "bad rcfile, you should delete '%s'";
|
2002-10-21 10:20:41 +05:30
|
|
|
|
char fbuf[SMLBUFSIZ];
|
2002-06-19 05:15:30 +05:30
|
|
|
|
FILE *fp;
|
|
|
|
|
float delay = DEF_DELAY;
|
|
|
|
|
char id;
|
|
|
|
|
int i;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-21 10:20:41 +05:30
|
|
|
|
snprintf(RCfile, sizeof(RCfile), ".%src", Myname);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (getenv("HOME"))
|
2002-10-21 10:20:41 +05:30
|
|
|
|
snprintf(RCfile, sizeof(RCfile), "%s/.%src", getenv("HOME"), Myname);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-08-26 06:25:30 +05:30
|
|
|
|
fp = fopen(SYS_RCFILE, "r");
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (fp) {
|
|
|
|
|
fbuf[0] = '\0';
|
|
|
|
|
fgets(fbuf, sizeof(fbuf), fp); /* sys rc file, line #1 */
|
|
|
|
|
if (strchr(fbuf, 's')) Secure_mode = 1;
|
|
|
|
|
|
|
|
|
|
fbuf[0] = '\0';
|
|
|
|
|
fgets(fbuf, sizeof(fbuf), fp); /* sys rc file, line #2 */
|
|
|
|
|
fclose(fp);
|
|
|
|
|
sscanf(fbuf, "%f", &delay);
|
|
|
|
|
}
|
|
|
|
|
fp = fopen(RCfile, "r");
|
|
|
|
|
if (fp) {
|
|
|
|
|
fgets(fbuf, sizeof(fbuf), fp); /* ignore shameless advertisement */
|
|
|
|
|
if (5 != (fscanf(fp, "Id:%c, "
|
2002-07-25 03:55:34 +05:30
|
|
|
|
"Mode_altscr=%d, Mode_irixps=%d, Delay_time=%f, Curwin=%d\n"
|
2002-10-02 05:40:30 +05:30
|
|
|
|
, &id, &Mode_altscr, &Mode_irixps, &delay, &i)) || RCF_FILEID != id)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
std_err(fmtmk(err_rc, RCfile));
|
|
|
|
|
|
|
|
|
|
/* you saw that, right? (fscanf stickin' it to 'i') */
|
|
|
|
|
Curwin = Winstk[i];
|
|
|
|
|
for (i = 0; i < GROUPSMAX; i++) {
|
|
|
|
|
/* we won't check fscanf returns from here on out -- we'll be
|
|
|
|
|
hunky-dory with nothing in an rcfile except the 1st 2 lines */
|
|
|
|
|
fscanf(fp, "%s\tfieldscur=%s\n"
|
|
|
|
|
, Winstk[i]->winname, Winstk[i]->fieldscur);
|
2002-10-02 05:40:30 +05:30
|
|
|
|
if (WINNAMSIZ <= strlen(Winstk[i]->winname)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|| strlen(DEF_FIELDS) != strlen(Winstk[i]->fieldscur))
|
|
|
|
|
std_err(fmtmk(err_rc, RCfile));
|
2002-10-13 02:02:24 +05:30
|
|
|
|
fscanf(fp, "\twinflags=%d, sortindx=%u, maxtasks=%d \n"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, &Winstk[i]->winflags
|
2002-10-13 02:02:24 +05:30
|
|
|
|
, &Winstk[i]->sortindx
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, &Winstk[i]->maxtasks);
|
|
|
|
|
fscanf(fp, "\tsummclr=%d, msgsclr=%d, headclr=%d, taskclr=%d \n"
|
|
|
|
|
, &Winstk[i]->summclr
|
|
|
|
|
, &Winstk[i]->msgsclr
|
|
|
|
|
, &Winstk[i]->headclr
|
|
|
|
|
, &Winstk[i]->taskclr);
|
|
|
|
|
}
|
|
|
|
|
fclose(fp);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* lastly, establish the true runtime secure mode and delay time */
|
|
|
|
|
Secure_mode = getuid() ? Secure_mode : 0;
|
|
|
|
|
if (!Secure_mode || !getuid()) Delay_time = delay;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Parse command line arguments.
|
2002-05-30 09:14:46 +05:30
|
|
|
|
* Note: it's assumed that the rc file(s) have already been read
|
|
|
|
|
* and our job is to see if any of those options are to be
|
|
|
|
|
* overridden -- we'll force some on and negate others in our
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* best effort to honor the loser's (oops, user's) wishes... */
|
|
|
|
|
static void parse_args (char **args)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* differences between us and the former top:
|
2002-09-13 17:12:44 +05:30
|
|
|
|
-C (separate CPU states for SMP) is left to an rcfile
|
|
|
|
|
-p (pid monitoring) allows, not requires, a comma delimited list
|
2002-06-19 05:15:30 +05:30
|
|
|
|
-q (zero delay) eliminated as redundant, incomplete and inappropriate
|
|
|
|
|
use: "nice -n-10 top -d0" to achieve what was only claimed
|
2002-09-13 17:12:44 +05:30
|
|
|
|
-c,i,S act as toggles (not 'on' switches) for enhanced user flexibility
|
2002-06-19 05:15:30 +05:30
|
|
|
|
. no deprecated/illegal use of 'breakargv:' with goto
|
|
|
|
|
. bunched args are actually handled properly and none are ignored
|
|
|
|
|
. we tolerate NO whitespace and NO switches -- maybe too tolerant? */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
static const char usage[] =
|
2002-10-02 05:40:30 +05:30
|
|
|
|
" -hv | -bcisS -d delay -n iterations -p pid [,pid ...]";
|
2002-05-30 09:14:46 +05:30
|
|
|
|
float tmp_delay = MAXFLOAT;
|
|
|
|
|
char *p;
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
while (*args) {
|
|
|
|
|
char *cp = *(args++);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
while (*cp) {
|
|
|
|
|
switch (*cp) {
|
|
|
|
|
case '\0':
|
|
|
|
|
case '-':
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
Batch = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'c':
|
2002-06-19 05:15:30 +05:30
|
|
|
|
TOGw(Curwin, Show_CMDLIN);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
if (cp[1]) ++cp;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
else if (*args) cp = *args++;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
else std_err("-d requires argument");
|
|
|
|
|
/* a negative delay will be dealt with shortly... */
|
|
|
|
|
if (1 != sscanf(cp, "%f", &tmp_delay))
|
|
|
|
|
std_err(fmtmk("bad delay '%s'", cp));
|
|
|
|
|
break;
|
|
|
|
|
case 'h': case 'H':
|
|
|
|
|
case 'v': case 'V':
|
2002-10-02 05:40:30 +05:30
|
|
|
|
std_err(fmtmk("%s\nusage:\t%s%s"
|
2002-05-30 09:14:46 +05:30
|
|
|
|
, procps_version, Myname, usage));
|
|
|
|
|
case 'i':
|
2002-06-19 05:15:30 +05:30
|
|
|
|
TOGw(Curwin, Show_IDLEPS);
|
|
|
|
|
Curwin->maxtasks = 0;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
if (cp[1]) cp++;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
else if (*args) cp = *args++;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
else std_err("-n requires argument");
|
2002-08-26 06:25:30 +05:30
|
|
|
|
if (1 != sscanf(cp, "%d", &Loops) || 1 > Loops)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
std_err(fmtmk("bad iterations arg '%s'", cp));
|
|
|
|
|
break;
|
|
|
|
|
case 'p':
|
|
|
|
|
do {
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (cp[1]) cp++;
|
|
|
|
|
else if (*args) cp = *args++;
|
|
|
|
|
else std_err("-p argument missing");
|
2002-05-30 09:14:46 +05:30
|
|
|
|
if (Monpidsidx >= MONPIDMAX)
|
|
|
|
|
std_err(fmtmk("pid limit (%d) exceeded", MONPIDMAX));
|
|
|
|
|
if (1 != sscanf(cp, "%d", &Monpids[Monpidsidx])
|
|
|
|
|
|| 0 > Monpids[Monpidsidx])
|
|
|
|
|
std_err(fmtmk("bad pid '%s'", cp));
|
|
|
|
|
if (!Monpids[Monpidsidx])
|
|
|
|
|
Monpids[Monpidsidx] = getpid();
|
|
|
|
|
Monpidsidx++;
|
|
|
|
|
if (!(p = strchr(cp, ',')))
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
cp = p;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
} while (*cp);
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
Secure_mode = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'S':
|
2002-06-19 05:15:30 +05:30
|
|
|
|
TOGw(Curwin, Show_CTIMES);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
break;
|
|
|
|
|
default :
|
|
|
|
|
std_err(fmtmk("unknown argument '%c'\nusage:\t%s%s"
|
|
|
|
|
, *cp, Myname, usage));
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
} /* end: switch (*cp) */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* advance cp and jump over any numerical args used above */
|
2002-08-26 06:25:30 +05:30
|
|
|
|
if (*cp) cp += strspn(&cp[1], "- ,.1234567890") + 1;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
} /* end: while (*cp) */
|
|
|
|
|
} /* end: while (*args) */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/* fixup delay time, maybe... */
|
|
|
|
|
if (MAXFLOAT != tmp_delay) {
|
|
|
|
|
if (Secure_mode || 0 > tmp_delay)
|
|
|
|
|
msg_save("Delay time Not changed");
|
|
|
|
|
else
|
|
|
|
|
Delay_time = tmp_delay;
|
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up the terminal attributes */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static void whack_terminal (void)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-05-30 09:14:46 +05:30
|
|
|
|
struct termios newtty;
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* first the curses part... */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#ifdef PRETENDNOCAP
|
2002-10-02 05:40:30 +05:30
|
|
|
|
setupterm("dumb", STDOUT_FILENO, NULL);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#else
|
|
|
|
|
setupterm(NULL, STDOUT_FILENO, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
/* now our part... */
|
|
|
|
|
if (!Batch) {
|
|
|
|
|
if (-1 == tcgetattr(STDIN_FILENO, &Savedtty))
|
2002-10-02 05:40:30 +05:30
|
|
|
|
std_err("failed tty get");
|
2002-05-30 09:14:46 +05:30
|
|
|
|
newtty = Savedtty;
|
|
|
|
|
newtty.c_lflag &= ~ICANON;
|
|
|
|
|
newtty.c_lflag &= ~ECHO;
|
|
|
|
|
newtty.c_cc[VMIN] = 1;
|
|
|
|
|
newtty.c_cc[VTIME] = 0;
|
|
|
|
|
|
|
|
|
|
Ttychanged = 1;
|
|
|
|
|
if (-1 == tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtty)) {
|
|
|
|
|
putp(Cap_clr_scr);
|
2002-10-02 05:40:30 +05:30
|
|
|
|
std_err(fmtmk("failed tty set: %s", strerror(errno)));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
|
|
|
|
tcgetattr(STDIN_FILENO, &Rawtty);
|
|
|
|
|
putp(Cap_clr_scr);
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*###### Field Selection/Ordering routines #############################*/
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
/* These are our gosh darn 'Fields' !
|
2002-10-30 11:36:44 +05:30
|
|
|
|
They MUST be kept in sync with pflags !!
|
|
|
|
|
note: for integer data, the length modifiers found in .fmts may be
|
|
|
|
|
smaller than the true length found in the proc_t -- this plus
|
2002-11-08 06:01:28 +05:30
|
|
|
|
a cast if/when displayed provides some width protection. */
|
2002-09-13 17:12:44 +05:30
|
|
|
|
static FTAB_t Fieldstab[] = {
|
|
|
|
|
/* head fmts width scale sort desc
|
|
|
|
|
----------- ------- ------ ----- -------- ---------------------- */
|
2002-10-30 11:36:44 +05:30
|
|
|
|
{ " PID ", "%5u ", -1, -1, _SF(P_PID), "Process Id" },
|
|
|
|
|
{ " PPID ", "%5u ", -1, -1, _SF(P_PPD), "Parent Process Pid" },
|
|
|
|
|
{ " PGID ", "%5u ", -1, -1, _SF(P_PGD), "Process Group Id" },
|
|
|
|
|
{ " UID ", "%4u ", -1, -1, _SF(P_UID), "User Id" },
|
2002-09-13 17:12:44 +05:30
|
|
|
|
{ "USER ", "%-8.8s ", -1, -1, _SF(P_USR), "User Name" },
|
|
|
|
|
{ "GROUP ", "%-8.8s ", -1, -1, _SF(P_GRP), "Group Name" },
|
|
|
|
|
{ "TTY ", "%-8.8s ", 8, -1, _SF(P_TTY), "Controlling Tty" },
|
2002-10-30 11:36:44 +05:30
|
|
|
|
{ " PR ", "%3d ", -1, -1, _SF(P_PRI), "Priority" },
|
|
|
|
|
{ " NI ", "%3d ", -1, -1, _SF(P_NCE), "Nice value" },
|
|
|
|
|
{ "#C ", "%2u ", -1, -1, _SF(P_CPN), "Last used cpu (SMP)" },
|
2002-09-13 17:12:44 +05:30
|
|
|
|
{ "%CPU ", "%#4.1f ", -1, -1, _SF(P_CPU), "CPU usage" },
|
|
|
|
|
{ " TIME ", "%6.6s ", 6, -1, _SF(P_TME), "CPU Time" },
|
|
|
|
|
{ " TIME+ ", "%9.9s ", 9, -1, _SF(P_TME), "CPU Time, hundredths" },
|
|
|
|
|
{ "%MEM ", "%#4.1f ", -1, -1, _SF(P_RES), "Memory usage (RES)" },
|
|
|
|
|
{ " VIRT ", "%5.5s ", 5, SK_Kb, _SF(P_VRT), "Virtual Image (kb)" },
|
|
|
|
|
{ "SWAP ", "%4.4s ", 4, SK_Kb, _SF(P_SWP), "Swapped size (kb)" },
|
|
|
|
|
{ " RES ", "%4.4s ", 4, SK_Kb, _SF(P_RES), "Resident size (kb)" },
|
|
|
|
|
{ "CODE ", "%4.4s ", 4, SK_Kb, _SF(P_COD), "Code size (kb)" },
|
|
|
|
|
{ "DATA ", "%4.4s ", 4, SK_Kb, _SF(P_DAT), "Data+Stack size (kb)" },
|
|
|
|
|
{ " SHR ", "%4.4s ", 4, SK_Kb, _SF(P_SHR), "Shared Mem size (kb)" },
|
|
|
|
|
{ "nFLT ", "%4.4s ", 4, SK_no, _SF(P_FLT), "Page Fault count" },
|
|
|
|
|
{ "nDRT ", "%4.4s ", 4, SK_no, _SF(P_DRT), "Dirty Pages count" },
|
|
|
|
|
#ifdef USE_LIB_STA3
|
|
|
|
|
{ "STA ", "%3.3s ", -1, -1, _SF(P_STA), "Process Status" },
|
|
|
|
|
#else
|
|
|
|
|
{ "S ", "%c ", -1, -1, _SF(P_STA), "Process Status" },
|
|
|
|
|
#endif
|
|
|
|
|
/** next entry's special: '.head' will be formatted using table entry's own
|
|
|
|
|
'.fmts' plus runtime supplied conversion args! */
|
|
|
|
|
{ "Command ", "%-*.*s ", -1, -1, _SF(P_CMD), "Command line/name" },
|
|
|
|
|
{ "WCHAN ", "%-9.9s ", -1, -1, _SF(P_WCH), "Sleeping in Function" },
|
|
|
|
|
/** next entry's special: the 0's will be replaced with '.'! */
|
|
|
|
|
#ifdef CASEUP_HEXES
|
|
|
|
|
{ "Flags ", "%08lX ", -1, -1, _SF(P_FLG), "Task Flags <sched.h>" }
|
|
|
|
|
#else
|
|
|
|
|
{ "Flags ", "%08lx ", -1, -1, _SF(P_FLG), "Task Flags <sched.h>" }
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
2002-09-13 17:12:44 +05:30
|
|
|
|
* Display each field represented in the Fields Table along with its
|
|
|
|
|
* description and mark (with a leading asterisk) fields associated
|
|
|
|
|
* with upper case letter(s) in the passed 'fields string'.
|
2002-05-30 09:14:46 +05:30
|
|
|
|
*
|
|
|
|
|
* After all fields have been displayed, some extra explanatory
|
2002-09-13 17:12:44 +05:30
|
|
|
|
* text may also be output */
|
|
|
|
|
static void display_fields (const char *fields, const char *xtra)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#define yRSVD 3
|
2002-09-13 17:12:44 +05:30
|
|
|
|
const char *p;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
int i, cmax = Screen_cols / 2, rmax = Screen_rows - yRSVD;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-09 12:41:08 +05:30
|
|
|
|
/* we're relying on callers to first clear the screen and thus avoid screen
|
|
|
|
|
flicker if they're too lazy to handle their own asterisk (*) logic */
|
2002-05-30 09:14:46 +05:30
|
|
|
|
putp(Cap_bold);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
for (i = 0; i < MAXTBL(Fieldstab); ++i) {
|
|
|
|
|
int b = (NULL != strchr(fields, i + 'A'));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/* advance past any leading spaces */
|
|
|
|
|
for (p = Fieldstab[i].head; ' ' == *p; ++p)
|
|
|
|
|
;
|
2002-10-19 02:37:49 +05:30
|
|
|
|
PUTP("%s%s%c %c: %-10s = %s"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, tg2((i / rmax) * cmax, (i % rmax) + yRSVD)
|
2002-09-13 17:12:44 +05:30
|
|
|
|
, b ? Cap_bold : Cap_norm
|
2002-08-26 06:25:30 +05:30
|
|
|
|
, b ? '*' : ' '
|
|
|
|
|
, b ? i + 'A' : i + 'a'
|
2002-05-30 09:14:46 +05:30
|
|
|
|
, p
|
|
|
|
|
, Fieldstab[i].desc);
|
|
|
|
|
}
|
2002-09-13 17:12:44 +05:30
|
|
|
|
if (xtra) {
|
|
|
|
|
putp(Curwin->capclr_rownorm);
|
|
|
|
|
while ((p = strchr(xtra, '\n'))) {
|
|
|
|
|
++i;
|
2002-10-19 02:37:49 +05:30
|
|
|
|
PUTP("%s%.*s"
|
2002-09-13 17:12:44 +05:30
|
|
|
|
, tg2((i / rmax) * cmax, (i % rmax) + yRSVD)
|
2002-10-13 09:57:37 +05:30
|
|
|
|
, (int)(p - xtra)
|
|
|
|
|
, xtra);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
xtra = ++p;
|
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
|
|
|
|
putp(Caps_off);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
#undef yRSVD
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Change order of displayed fields. */
|
|
|
|
|
static void fields_reorder (void)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-10-10 03:02:33 +05:30
|
|
|
|
static const char prompt[] =
|
2002-10-02 05:40:30 +05:30
|
|
|
|
"Upper case letter moves field left, lower case right";
|
2002-05-30 09:14:46 +05:30
|
|
|
|
char c, *p;
|
|
|
|
|
int i;
|
|
|
|
|
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(Cap_clr_scr);
|
|
|
|
|
putp(Cap_curs_huge);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
display_fields(Curwin->fieldscur, FIELDS_xtra);
|
2002-10-21 10:20:41 +05:30
|
|
|
|
for (;;) {
|
2002-05-30 09:14:46 +05:30
|
|
|
|
show_special(fmtmk(FIELDS_current
|
2002-09-13 17:12:44 +05:30
|
|
|
|
, Cap_home, Curwin->fieldscur, Curwin->grpname, prompt));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
chin(0, &c, 1);
|
|
|
|
|
i = toupper(c) - 'A';
|
2002-09-13 17:12:44 +05:30
|
|
|
|
if (i < 0 || i >= MAXTBL(Fieldstab)) break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (((p = strchr(Curwin->fieldscur, i + 'A')))
|
|
|
|
|
|| ((p = strchr(Curwin->fieldscur, i + 'a')))) {
|
2002-05-30 09:14:46 +05:30
|
|
|
|
if (isupper(c)) p--;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (('\0' != p[1]) && (p >= Curwin->fieldscur)) {
|
2002-05-30 09:14:46 +05:30
|
|
|
|
c = p[0];
|
|
|
|
|
p[0] = p[1];
|
|
|
|
|
p[1] = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-10-21 10:20:41 +05:30
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
putp(Cap_curs_norm);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
/*
|
|
|
|
|
* Select sort field. */
|
|
|
|
|
static void fields_sort (void)
|
|
|
|
|
{
|
2002-10-10 03:02:33 +05:30
|
|
|
|
static const char prompt[] =
|
2002-09-13 17:12:44 +05:30
|
|
|
|
"Select sort field via field letter, type any other key to return";
|
|
|
|
|
char phoney[PFLAGSSIZ];
|
|
|
|
|
char c, *p;
|
2002-10-02 05:40:30 +05:30
|
|
|
|
int i, x;
|
2002-09-13 17:12:44 +05:30
|
|
|
|
|
|
|
|
|
strcpy(phoney, NUL_FIELDS);
|
2002-10-02 05:40:30 +05:30
|
|
|
|
x = i = Curwin->sortindx;
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(Cap_clr_scr);
|
|
|
|
|
putp(Cap_curs_huge);
|
2002-10-21 10:20:41 +05:30
|
|
|
|
for (;;) {
|
2002-09-13 17:12:44 +05:30
|
|
|
|
p = phoney + i;
|
|
|
|
|
*p = toupper(*p);
|
|
|
|
|
display_fields(phoney, SORT_xtra);
|
|
|
|
|
show_special(fmtmk(SORT_fields
|
|
|
|
|
, Cap_home, *p, Curwin->grpname, prompt));
|
|
|
|
|
chin(0, &c, 1);
|
|
|
|
|
i = toupper(c) - 'A';
|
|
|
|
|
if (i < 0 || i >= MAXTBL(Fieldstab)) break;
|
|
|
|
|
*p = tolower(*p);
|
2002-10-02 05:40:30 +05:30
|
|
|
|
x = i;
|
2002-10-21 10:20:41 +05:30
|
|
|
|
}
|
2002-10-02 05:40:30 +05:30
|
|
|
|
if ((p = strchr(Curwin->fieldscur, x + 'a')))
|
|
|
|
|
*p = x + 'A';
|
|
|
|
|
Curwin->sortindx = x;
|
2002-09-13 17:12:44 +05:30
|
|
|
|
putp(Cap_curs_norm);
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Toggle displayed fields. */
|
|
|
|
|
static void fields_toggle (void)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-10-10 03:02:33 +05:30
|
|
|
|
static const char prompt[] =
|
2002-09-13 17:12:44 +05:30
|
|
|
|
"Toggle fields via field letter, type any other key to return";
|
2002-05-30 09:14:46 +05:30
|
|
|
|
char c, *p;
|
|
|
|
|
int i;
|
|
|
|
|
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(Cap_clr_scr);
|
|
|
|
|
putp(Cap_curs_huge);
|
2002-10-21 10:20:41 +05:30
|
|
|
|
for (;;) {
|
2002-09-13 17:12:44 +05:30
|
|
|
|
display_fields(Curwin->fieldscur, FIELDS_xtra);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
show_special(fmtmk(FIELDS_current
|
2002-09-13 17:12:44 +05:30
|
|
|
|
, Cap_home, Curwin->fieldscur, Curwin->grpname, prompt));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
chin(0, &c, 1);
|
|
|
|
|
i = toupper(c) - 'A';
|
2002-09-13 17:12:44 +05:30
|
|
|
|
if (i < 0 || i >= MAXTBL(Fieldstab)) break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if ((p = strchr(Curwin->fieldscur, i + 'A')))
|
2002-05-30 09:14:46 +05:30
|
|
|
|
*p = i + 'a';
|
2002-06-19 05:15:30 +05:30
|
|
|
|
else if ((p = strchr(Curwin->fieldscur, i + 'a')))
|
2002-05-30 09:14:46 +05:30
|
|
|
|
*p = i + 'A';
|
2002-10-21 10:20:41 +05:30
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
putp(Cap_curs_norm);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/*###### Windows/Field Groups support #################################*/
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Set the number of fields/columns to display;
|
|
|
|
|
* Create the field columns heading; and then
|
|
|
|
|
* Set maximum cmdline length. */
|
|
|
|
|
static void win_colsheads (WIN_t *q)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
const char *h;
|
|
|
|
|
int i, needpsdb = 0;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* build window's procflags array and establish a tentative maxpflgs */
|
2002-10-02 05:40:30 +05:30
|
|
|
|
for (i = 0, q->maxpflgs = 0; q->fieldscur[i]; i++) {
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (isupper(q->fieldscur[i]))
|
|
|
|
|
q->procflags[q->maxpflgs++] = q->fieldscur[i] - 'A';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* build a preliminary columns header not to exceed screen width
|
|
|
|
|
(and account for a possible leading window number) */
|
2002-07-25 03:55:34 +05:30
|
|
|
|
if (Mode_altscr) strcpy(q->columnhdr, " "); else q->columnhdr[0] = '\0';
|
2002-06-19 05:15:30 +05:30
|
|
|
|
for (i = 0; i < q->maxpflgs; i++) {
|
|
|
|
|
h = Fieldstab[q->procflags[i]].head;
|
|
|
|
|
/* oops, won't fit -- we're outta here... */
|
|
|
|
|
if (Screen_cols < (int)(strlen(q->columnhdr) + strlen(h))) break;
|
|
|
|
|
strcat(q->columnhdr, h);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* establish the final maxpflgs and prepare to grow the command
|
|
|
|
|
column heading via maxcmdln -- it may be a fib if P_CMD wasn't
|
|
|
|
|
encountered, but that's ok because it won't be displayed anyway */
|
|
|
|
|
q->maxpflgs = i;
|
|
|
|
|
q->maxcmdln = Screen_cols
|
|
|
|
|
- (strlen(q->columnhdr) - strlen(Fieldstab[P_CMD].head)) - 1;
|
|
|
|
|
|
|
|
|
|
/* now we can build the true run-time columns header and format the
|
2002-11-08 06:01:28 +05:30
|
|
|
|
command column heading if P_CMD is really being displayed -- the
|
|
|
|
|
task display guy is aware of the addition of winnum to the header */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
snprintf(q->columnhdr, sizeof(q->columnhdr), "%s"
|
|
|
|
|
, Mode_altscr ? fmtmk("%d", q->winnum) : "");
|
2002-06-19 05:15:30 +05:30
|
|
|
|
for (i = 0; i < q->maxpflgs; i++) {
|
|
|
|
|
h = Fieldstab[q->procflags[i]].head;
|
2002-09-13 17:12:44 +05:30
|
|
|
|
/* are we gonna' need the kernel symbol table? */
|
|
|
|
|
if (P_WCH == q->procflags[i]) needpsdb = 1;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (P_CMD == q->procflags[i])
|
|
|
|
|
strcat(q->columnhdr
|
|
|
|
|
, fmtmk(Fieldstab[P_CMD].fmts, q->maxcmdln, q->maxcmdln, h));
|
|
|
|
|
else
|
|
|
|
|
strcat(q->columnhdr, h);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do we need the kernel symbol table (and is it already open?) */
|
|
|
|
|
if (needpsdb) {
|
|
|
|
|
if (-1 == No_ksyms) {
|
|
|
|
|
No_ksyms = 0;
|
|
|
|
|
if (open_psdb_message(NULL, msg_save))
|
|
|
|
|
/* why so counter-intuitive, couldn't open_psdb_message
|
|
|
|
|
mirror sysmap_mmap -- that func does all the work anyway? */
|
|
|
|
|
No_ksyms = 1;
|
|
|
|
|
else
|
|
|
|
|
PSDBopen = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-19 02:37:49 +05:30
|
|
|
|
/*
|
|
|
|
|
* Tell caller if a specific pflag is 'exposing itself' (whoa!) */
|
|
|
|
|
static inline int win_fldviz (WIN_t *q, PFLG_t flg)
|
|
|
|
|
{
|
|
|
|
|
PFLG_t *p = q->procflags + q->maxpflgs - 1;
|
|
|
|
|
|
|
|
|
|
while (*p != flg && q->procflags < p) --p;
|
|
|
|
|
return *p == flg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/*
|
|
|
|
|
* Value a window's name and make the associated group name. */
|
|
|
|
|
static void win_names (WIN_t *q, const char *name)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
sprintf(q->winname, "%.*s", WINNAMSIZ -1, name);
|
2002-06-27 05:26:49 +05:30
|
|
|
|
sprintf(q->grpname, "%d:%.*s", q->winnum, WINNAMSIZ -1, name);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Display a window/field group (ie. make it "current"). */
|
2002-10-09 12:41:08 +05:30
|
|
|
|
static void win_select (char ch)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-10-10 03:02:33 +05:30
|
|
|
|
static const char prompt[] = "Choose field group (1 - 4)";
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/* if there's no ch, it means we're supporting the external interface,
|
2002-06-19 05:15:30 +05:30
|
|
|
|
so we must try to get our own darn ch by begging the user... */
|
|
|
|
|
if (!ch) {
|
|
|
|
|
show_pmt(prompt);
|
|
|
|
|
chin(0, (char *)&ch, 1);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
switch (ch) {
|
|
|
|
|
case 'a': /* we don't carry 'a' / 'w' in our */
|
2002-06-27 05:26:49 +05:30
|
|
|
|
Curwin = Curwin->next; /* pmt - they're here for a good */
|
|
|
|
|
break; /* friend of ours -- wins_colors. */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
case 'w': /* (however those letters work via */
|
2002-06-27 05:26:49 +05:30
|
|
|
|
Curwin = Curwin->prev; /* the pmt too but gee, end-loser */
|
|
|
|
|
break; /* should just press the darn key) */
|
|
|
|
|
case '1': case '2':
|
|
|
|
|
case '3': case '4':
|
|
|
|
|
Curwin = Winstk[ch - '1'];
|
2002-06-19 05:15:30 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Just warn the user when a command can't be honored. */
|
|
|
|
|
static int win_warn (void)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
{
|
2002-10-02 05:40:30 +05:30
|
|
|
|
show_msg(fmtmk("\aCommand disabled, activate %s with '-' or '_'"
|
|
|
|
|
, Curwin->grpname));
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* we gotta' return false 'cause we're somewhat well known within
|
|
|
|
|
macro society, by way of that sassy little tertiary operator... */
|
|
|
|
|
return 0;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Change colors *Helper* function to save/restore settings;
|
|
|
|
|
* ensure colors will show; and rebuild the terminfo strings. */
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static void winsclrhlp (WIN_t *q, int save)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static int flgssav, summsav, msgssav, headsav, tasksav;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (save) {
|
|
|
|
|
flgssav = q->winflags; summsav = q->summclr;
|
|
|
|
|
msgssav = q->msgsclr; headsav = q->headclr; tasksav = q->taskclr;
|
|
|
|
|
SETw(q, Show_COLORS);
|
|
|
|
|
} else {
|
|
|
|
|
q->winflags = flgssav; q->summclr = summsav;
|
|
|
|
|
q->msgsclr = msgssav; q->headclr = headsav; q->taskclr = tasksav;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
capsmk(q);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Change colors used in display */
|
|
|
|
|
static void wins_colors (void)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#define kbdABORT 'q'
|
|
|
|
|
#define kbdAPPLY '\n'
|
|
|
|
|
int clr = Curwin->taskclr, *pclr = &Curwin->taskclr;
|
|
|
|
|
char ch, tgt = 'T';
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (0 >= max_colors) {
|
|
|
|
|
show_msg("\aNo colors to map!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-11-08 06:01:28 +05:30
|
|
|
|
winsclrhlp(Curwin, 1);
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(Cap_clr_scr);
|
|
|
|
|
putp(Cap_curs_huge);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
do {
|
2002-10-19 02:37:49 +05:30
|
|
|
|
putp(Cap_home);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* this string is well above ISO C89's minimum requirements! */
|
|
|
|
|
show_special(fmtmk(COLOR_help
|
2002-10-19 02:37:49 +05:30
|
|
|
|
, procps_version, Curwin->grpname
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, CHKw(Curwin, Show_HIBOLD) ? "On" : "Off"
|
|
|
|
|
, CHKw(Curwin, Show_COLORS) ? "On" : "Off"
|
|
|
|
|
, tgt, clr, Curwin->winname));
|
|
|
|
|
chin(0, &ch, 1);
|
|
|
|
|
switch (ch) {
|
|
|
|
|
case 'S':
|
|
|
|
|
pclr = &Curwin->summclr;
|
|
|
|
|
clr = *pclr;
|
|
|
|
|
tgt = ch;
|
|
|
|
|
break;
|
|
|
|
|
case 'M':
|
|
|
|
|
pclr = &Curwin->msgsclr;
|
|
|
|
|
clr = *pclr;
|
|
|
|
|
tgt = ch;
|
|
|
|
|
break;
|
|
|
|
|
case 'H':
|
|
|
|
|
pclr = &Curwin->headclr;
|
|
|
|
|
clr = *pclr;
|
|
|
|
|
tgt = ch;
|
|
|
|
|
break;
|
|
|
|
|
case 'T':
|
|
|
|
|
pclr = &Curwin->taskclr;
|
|
|
|
|
clr = *pclr;
|
|
|
|
|
tgt = ch;
|
|
|
|
|
break;
|
|
|
|
|
case '0': case '1': case '2': case '3':
|
|
|
|
|
case '4': case '5': case '6': case '7':
|
|
|
|
|
clr = ch - '0';
|
|
|
|
|
*pclr = clr;
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
TOGw(Curwin, Show_HIBOLD);
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
TOGw(Curwin, Show_COLORS);
|
|
|
|
|
break;
|
|
|
|
|
case 'a':
|
|
|
|
|
case 'w':
|
|
|
|
|
win_select(ch);
|
2002-11-08 06:01:28 +05:30
|
|
|
|
winsclrhlp(Curwin, 1);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
clr = Curwin->taskclr, pclr = &Curwin->taskclr;
|
|
|
|
|
tgt = 'T';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
capsmk(Curwin);
|
|
|
|
|
} while (kbdAPPLY != ch && kbdABORT != ch);
|
|
|
|
|
|
|
|
|
|
if (kbdABORT == ch)
|
2002-11-08 06:01:28 +05:30
|
|
|
|
winsclrhlp(Curwin, 0);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
putp(Cap_curs_norm);
|
|
|
|
|
|
|
|
|
|
#undef kbdABORT
|
|
|
|
|
#undef kbdAPPLY
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Manipulate flag(s) for all our windows. */
|
|
|
|
|
static void wins_reflag (int what, int flg)
|
|
|
|
|
{
|
|
|
|
|
WIN_t *w;
|
|
|
|
|
|
|
|
|
|
w = Curwin;
|
|
|
|
|
do {
|
|
|
|
|
switch (what) {
|
2002-06-27 05:26:49 +05:30
|
|
|
|
case Flags_TOG:
|
2002-06-19 05:15:30 +05:30
|
|
|
|
TOGw(w, flg);
|
|
|
|
|
break;
|
2002-06-27 05:26:49 +05:30
|
|
|
|
case Flags_SET: /* Ummmm, i can't find anybody */
|
2002-10-02 05:40:30 +05:30
|
|
|
|
SETw(w, flg); /* who uses Flags_set ... */
|
|
|
|
|
break;
|
2002-06-27 05:26:49 +05:30
|
|
|
|
case Flags_OFF:
|
2002-06-19 05:15:30 +05:30
|
|
|
|
OFFw(w, flg);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-10-02 05:40:30 +05:30
|
|
|
|
/* a flag with special significance -- user wants to rebalance
|
|
|
|
|
display so we gotta' 'off' one number then force on two flags... */
|
|
|
|
|
if (EQUWINS_cwo == flg) {
|
2002-06-19 05:15:30 +05:30
|
|
|
|
w->maxtasks = 0;
|
|
|
|
|
SETw(w, Show_IDLEPS | VISIBLE_tsk);
|
2002-10-02 05:40:30 +05:30
|
|
|
|
}
|
|
|
|
|
w = w->next;
|
|
|
|
|
} while (w != Curwin);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set the screen dimensions and call the real workhorse.
|
|
|
|
|
* (also) catches:
|
|
|
|
|
* SIGWINCH and SIGCONT */
|
|
|
|
|
static void wins_resize (int dont_care_sig)
|
|
|
|
|
{
|
|
|
|
|
struct winsize wz;
|
|
|
|
|
WIN_t *w;
|
|
|
|
|
|
2002-10-12 11:06:52 +05:30
|
|
|
|
(void)dont_care_sig;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
Screen_cols = columns;
|
|
|
|
|
Screen_rows = lines;
|
|
|
|
|
if (-1 != (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wz))) {
|
|
|
|
|
Screen_cols = wz.ws_col;
|
|
|
|
|
Screen_rows = wz.ws_row;
|
|
|
|
|
}
|
2002-10-21 10:20:41 +05:30
|
|
|
|
/* we might disappoint some folks (but they'll deserve it) */
|
|
|
|
|
if (SCREENMAX < Screen_cols) Screen_cols = SCREENMAX;
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
w = Curwin;
|
|
|
|
|
do {
|
|
|
|
|
win_colsheads(w);
|
|
|
|
|
w = w->next;
|
|
|
|
|
} while (w != Curwin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up the raw/incomplete field group windows --
|
|
|
|
|
* they'll be finished off after startup completes.
|
2002-10-02 05:40:30 +05:30
|
|
|
|
* [ and very likely that will override most/all of our efforts ]
|
|
|
|
|
* [ --- life-is-NOT-fair --- ] */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
static void windows_stage1 (void)
|
|
|
|
|
{
|
|
|
|
|
static struct {
|
|
|
|
|
const char *name;
|
|
|
|
|
const char *flds;
|
2002-09-13 17:12:44 +05:30
|
|
|
|
const int sort;
|
|
|
|
|
const int clrs[4]; /* summ, msgs, heads, task */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
} wtab[] = {
|
2002-10-12 05:00:29 +05:30
|
|
|
|
{ "Def", DEF_FIELDS, P_CPU,
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{ COLOR_RED, COLOR_RED, COLOR_YELLOW, COLOR_RED } },
|
2002-10-12 05:00:29 +05:30
|
|
|
|
{ "Job", JOB_FIELDS, P_PID,
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{ COLOR_CYAN, COLOR_CYAN, COLOR_WHITE, COLOR_CYAN } },
|
2002-09-13 17:12:44 +05:30
|
|
|
|
{ "Mem", MEM_FIELDS, P_MEM,
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{ COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLUE, COLOR_MAGENTA } },
|
2002-09-13 17:12:44 +05:30
|
|
|
|
{ "Usr", USR_FIELDS, P_USR,
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{ COLOR_YELLOW, COLOR_YELLOW, COLOR_GREEN, COLOR_YELLOW } },
|
|
|
|
|
};
|
|
|
|
|
WIN_t *w;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
int i;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
/* get all our window structs in one big chunk */
|
|
|
|
|
w = alloc_c(sizeof(WIN_t) * GROUPSMAX);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < GROUPSMAX; i++) {
|
|
|
|
|
Winstk[i] = w;
|
2002-06-27 05:26:49 +05:30
|
|
|
|
w->winnum = i + 1;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
strcpy(w->winname, wtab[i].name);
|
|
|
|
|
strcpy(w->fieldscur, wtab[i].flds);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
w->sortindx = wtab[i].sort;
|
|
|
|
|
w->winflags = DEF_WINFLGS;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
w->summclr = wtab[i].clrs[0];
|
|
|
|
|
w->msgsclr = wtab[i].clrs[1];
|
|
|
|
|
w->headclr = wtab[i].clrs[2];
|
|
|
|
|
w->taskclr = wtab[i].clrs[3];
|
2002-06-19 05:15:30 +05:30
|
|
|
|
w->captab[0] = Cap_norm;
|
|
|
|
|
w->captab[1] = Cap_norm;
|
|
|
|
|
w->captab[2] = Cap_bold;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
w->captab[3] = w->capclr_sum;
|
|
|
|
|
w->captab[4] = w->capclr_msg;
|
|
|
|
|
w->captab[5] = w->capclr_pmt;
|
|
|
|
|
w->captab[6] = w->capclr_hdr;
|
|
|
|
|
w->captab[7] = w->capclr_rowhigh;
|
|
|
|
|
w->captab[8] = w->capclr_rownorm;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
w->next = w + 1;
|
|
|
|
|
w->prev = w - 1;
|
|
|
|
|
++w;
|
|
|
|
|
}
|
|
|
|
|
/* fixup the circular chains... */
|
2002-06-27 05:26:49 +05:30
|
|
|
|
Winstk[3]->next = Winstk[0];
|
|
|
|
|
Winstk[0]->prev = Winstk[3];
|
2002-06-19 05:15:30 +05:30
|
|
|
|
Curwin = Winstk[0];
|
2002-07-25 03:55:34 +05:30
|
|
|
|
Mode_altscr = 0;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This guy just completes the field group windows after the
|
|
|
|
|
* rcfiles have been read and command line arguments parsed
|
|
|
|
|
* (he's also key to the success of that darn Batch mode). */
|
|
|
|
|
static void windows_stage2 (void)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (Batch) {
|
2002-07-25 03:55:34 +05:30
|
|
|
|
Mode_altscr = 0;
|
2002-10-02 05:40:30 +05:30
|
|
|
|
OFFw(Curwin, Show_COLORS | Show_HICOLS | Show_HIROWS);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
wins_resize(0);
|
|
|
|
|
for (i = 0; i < GROUPSMAX; i++) {
|
|
|
|
|
win_names(Winstk[i], Winstk[i]->winname);
|
|
|
|
|
capsmk(Winstk[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*###### Main Screen routines ##########################################*/
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
/*
|
2002-11-08 06:01:28 +05:30
|
|
|
|
* Process keyboard input during the main loop */
|
|
|
|
|
static void do_key (unsigned c)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// standardized 'secure mode' errors
|
|
|
|
|
static const char err_secure[] = "\aUnavailable in secure mode";
|
|
|
|
|
#ifdef WARN_NOT_SMP
|
|
|
|
|
// standardized 'smp' errors
|
|
|
|
|
static const char err_smp[] = "\aSorry, only 1 cpu detected";
|
|
|
|
|
#endif
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
switch (c) {
|
|
|
|
|
case '1':
|
|
|
|
|
#ifdef WARN_NOT_SMP
|
|
|
|
|
if (Cpu_tot > 1) TOGw(Curwin, View_CPUSUM);
|
|
|
|
|
else show_msg(err_smp);
|
|
|
|
|
#else
|
|
|
|
|
TOGw(Curwin, View_CPUSUM);
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'a':
|
|
|
|
|
if (Mode_altscr) Curwin = Curwin->next;
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'A':
|
|
|
|
|
Mode_altscr = !Mode_altscr;
|
|
|
|
|
wins_resize(0);
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'b':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
if (!CHKw(Curwin, Show_HICOLS) && !CHKw(Curwin, Show_HIROWS))
|
|
|
|
|
show_msg("\aNothing to highlight!");
|
|
|
|
|
else {
|
|
|
|
|
TOGw(Curwin, Show_HIBOLD);
|
|
|
|
|
capsmk(Curwin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'c':
|
|
|
|
|
VIZTOGc(Show_CMDLIN);
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'd':
|
|
|
|
|
case 's':
|
|
|
|
|
if (Secure_mode)
|
|
|
|
|
show_msg(err_secure);
|
|
|
|
|
else {
|
|
|
|
|
float tmp =
|
|
|
|
|
get_float(fmtmk("Change delay from %.1f to", Delay_time));
|
|
|
|
|
if (-1 < tmp) Delay_time = tmp;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-11-08 06:01:28 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'f':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
fields_toggle();
|
|
|
|
|
win_colsheads(Curwin);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'F':
|
|
|
|
|
case 'O':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
fields_sort();
|
|
|
|
|
win_colsheads(Curwin);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-10-13 13:53:50 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'g':
|
|
|
|
|
if (Mode_altscr) {
|
|
|
|
|
char tmp[GETBUFSIZ];
|
|
|
|
|
strcpy(tmp, ask4str(fmtmk("Rename window '%s' to (1-3 chars)"
|
|
|
|
|
, Curwin->winname)));
|
|
|
|
|
if (tmp[0]) win_names(Curwin, tmp);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'G':
|
|
|
|
|
win_select(0);
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'h':
|
|
|
|
|
case '?':
|
|
|
|
|
{ char ch;
|
|
|
|
|
putp(Cap_clr_scr);
|
|
|
|
|
putp(Cap_curs_huge);
|
|
|
|
|
/* this string is well above ISO C89's minimum requirements! */
|
|
|
|
|
show_special(fmtmk(KEYS_help
|
|
|
|
|
, procps_version
|
|
|
|
|
, Curwin->grpname
|
|
|
|
|
, CHKw(Curwin, Show_CTIMES) ? "On" : "Off"
|
|
|
|
|
, Delay_time
|
|
|
|
|
, Secure_mode ? "On" : "Off"
|
|
|
|
|
, Secure_mode ? "" : KEYS_help_unsecured));
|
|
|
|
|
chin(0, &ch, 1);
|
|
|
|
|
if ('?' == ch || 'h' == ch) {
|
|
|
|
|
do {
|
|
|
|
|
putp(Cap_clr_scr);
|
|
|
|
|
show_special(fmtmk(WINDOWS_help
|
|
|
|
|
, Curwin->grpname
|
|
|
|
|
, Winstk[0]->winname
|
|
|
|
|
, Winstk[1]->winname
|
|
|
|
|
, Winstk[2]->winname
|
|
|
|
|
, Winstk[3]->winname));
|
|
|
|
|
chin(0, &ch, 1);
|
|
|
|
|
win_select(ch);
|
|
|
|
|
} while ('\n' != ch);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-11-08 06:01:28 +05:30
|
|
|
|
putp(Cap_curs_norm);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-11-08 06:01:28 +05:30
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'i':
|
|
|
|
|
VIZTOGc(Show_IDLEPS);
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'I':
|
|
|
|
|
#ifdef WARN_NOT_SMP
|
|
|
|
|
if (Cpu_tot > 1) {
|
|
|
|
|
Mode_irixps = !Mode_irixps;
|
|
|
|
|
show_msg(fmtmk("Irix mode %s", Mode_irixps ? "On" : "Off"));
|
|
|
|
|
} else
|
|
|
|
|
show_msg(err_smp);
|
|
|
|
|
#else
|
|
|
|
|
Mode_irixps = !Mode_irixps;
|
|
|
|
|
show_msg(fmtmk("Irix mode %s", Mode_irixps ? "On" : "Off"));
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'k':
|
|
|
|
|
if (Secure_mode) {
|
|
|
|
|
show_msg(err_secure);
|
|
|
|
|
} else {
|
|
|
|
|
int sig, pid = get_int("PID to kill");
|
|
|
|
|
if (0 < pid) {
|
|
|
|
|
sig = signal_name_to_number(
|
|
|
|
|
ask4str(fmtmk("Kill PID %d with signal [%i]"
|
|
|
|
|
, pid, DEF_SIGNAL)));
|
|
|
|
|
if (-1 == sig) sig = DEF_SIGNAL;
|
|
|
|
|
if (sig && kill(pid, sig))
|
|
|
|
|
show_msg(fmtmk("\aKill of PID '%d' with '%d' failed: %s"
|
|
|
|
|
, pid, sig, strerror(errno)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'l':
|
|
|
|
|
TOGw(Curwin, View_LOADAV);
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
case 'm':
|
|
|
|
|
TOGw(Curwin, View_MEMORY);
|
|
|
|
|
break;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
case 'n':
|
|
|
|
|
case '#':
|
|
|
|
|
if (VIZCHKc) {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
int num =
|
|
|
|
|
get_int(fmtmk("Maximum tasks = %d, change to (0 is unlimited)"
|
|
|
|
|
, Curwin->maxtasks));
|
|
|
|
|
if (-1 < num) Curwin->maxtasks = num;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'o':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
fields_reorder();
|
|
|
|
|
win_colsheads(Curwin);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
case 'q':
|
|
|
|
|
stop(0);
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 'r':
|
|
|
|
|
if (Secure_mode)
|
2002-10-02 05:40:30 +05:30
|
|
|
|
show_msg(err_secure);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
else {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
int val, pid = get_int("PID to renice");
|
|
|
|
|
if (0 < pid) {
|
|
|
|
|
val = get_int(fmtmk("Renice PID %d to value", pid));
|
|
|
|
|
if (setpriority(PRIO_PROCESS, (unsigned)pid, val))
|
|
|
|
|
show_msg(fmtmk("\aRenice of PID %d to %d failed: %s"
|
|
|
|
|
, pid, val, strerror(errno)));
|
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'R':
|
|
|
|
|
VIZTOGc(Qsrt_NORMAL);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'S':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
TOGw(Curwin, Show_CTIMES);
|
|
|
|
|
show_msg(fmtmk("Cumulative time %s"
|
|
|
|
|
, CHKw(Curwin, Show_CTIMES) ? "On" : "Off"));
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 't':
|
|
|
|
|
TOGw(Curwin, View_STATES);
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 'u':
|
|
|
|
|
if (VIZCHKc)
|
|
|
|
|
strcpy(Curwin->colusrnam, ask4str("Which user (blank for all)"));
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
case 'w':
|
|
|
|
|
if (Mode_altscr) Curwin = Curwin->prev;
|
|
|
|
|
break;
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 'W':
|
|
|
|
|
{ FILE *fp = fopen(RCfile, "w"); int i;
|
|
|
|
|
if (fp) {
|
|
|
|
|
fprintf(fp, "RCfile for \"%s with windows\"\t\t# shameless braggin'\n"
|
|
|
|
|
, Myname);
|
|
|
|
|
fprintf(fp, "Id:%c, "
|
2002-08-26 06:25:30 +05:30
|
|
|
|
"Mode_altscr=%d, Mode_irixps=%d, Delay_time=%.3f, Curwin=%d\n"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, RCF_FILEID
|
2002-07-25 03:55:34 +05:30
|
|
|
|
, Mode_altscr, Mode_irixps, Delay_time, Curwin - Winstk[0]);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
for (i = 0; i < GROUPSMAX; i++) {
|
|
|
|
|
fprintf(fp, "%s\tfieldscur=%s\n"
|
|
|
|
|
, Winstk[i]->winname, Winstk[i]->fieldscur);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
fprintf(fp, "\twinflags=%d, sortindx=%d, maxtasks=%d\n"
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, Winstk[i]->winflags
|
2002-09-13 17:12:44 +05:30
|
|
|
|
, Winstk[i]->sortindx
|
2002-06-19 05:15:30 +05:30
|
|
|
|
, Winstk[i]->maxtasks);
|
|
|
|
|
fprintf(fp, "\tsummclr=%d, msgsclr=%d, headclr=%d, taskclr=%d\n"
|
|
|
|
|
, Winstk[i]->summclr
|
|
|
|
|
, Winstk[i]->msgsclr
|
|
|
|
|
, Winstk[i]->headclr
|
|
|
|
|
, Winstk[i]->taskclr);
|
|
|
|
|
}
|
|
|
|
|
fclose(fp);
|
|
|
|
|
show_msg(fmtmk("Wrote configuration to '%s'", RCfile));
|
|
|
|
|
} else
|
|
|
|
|
show_msg(fmtmk("\aFailed '%s' open: %s", RCfile, strerror(errno)));
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 'x':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
TOGw(Curwin, Show_HICOLS);
|
|
|
|
|
capsmk(Curwin);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 'y':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
TOGw(Curwin, Show_HIROWS);
|
|
|
|
|
capsmk(Curwin);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 'z':
|
|
|
|
|
if (VIZCHKc) {
|
|
|
|
|
TOGw(Curwin, Show_COLORS);
|
|
|
|
|
capsmk(Curwin);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
case 'Z':
|
|
|
|
|
wins_colors();
|
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
case '-':
|
2002-11-08 06:01:28 +05:30
|
|
|
|
if (Mode_altscr) TOGw(Curwin, VISIBLE_tsk);
|
2002-09-13 17:12:44 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
case '_':
|
2002-11-08 06:01:28 +05:30
|
|
|
|
if (Mode_altscr) wins_reflag(Flags_TOG, VISIBLE_tsk);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
case '=':
|
2002-09-13 17:12:44 +05:30
|
|
|
|
Curwin->maxtasks = 0;
|
|
|
|
|
SETw(Curwin, Show_IDLEPS | VISIBLE_tsk);
|
|
|
|
|
Monpidsidx = 0;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
case '+':
|
2002-11-08 06:01:28 +05:30
|
|
|
|
if (Mode_altscr) SETw(Curwin, EQUWINS_cwo);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
case '<':
|
|
|
|
|
if (VIZCHKc) {
|
2002-10-13 23:53:22 +05:30
|
|
|
|
PFLG_t *p = Curwin->procflags + Curwin->maxpflgs - 1;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
while (*p != Curwin->sortindx) --p;
|
2002-10-13 23:53:22 +05:30
|
|
|
|
if (--p >= Curwin->procflags)
|
2002-09-13 17:12:44 +05:30
|
|
|
|
Curwin->sortindx = *p;
|
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
break;
|
|
|
|
|
|
2002-09-13 17:12:44 +05:30
|
|
|
|
case '>':
|
|
|
|
|
if (VIZCHKc) {
|
2002-10-13 23:53:22 +05:30
|
|
|
|
PFLG_t *p = Curwin->procflags;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
while (*p != Curwin->sortindx) ++p;
|
2002-10-13 23:53:22 +05:30
|
|
|
|
if (++p < Curwin->procflags + Curwin->maxpflgs)
|
2002-09-13 17:12:44 +05:30
|
|
|
|
Curwin->sortindx = *p;
|
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-02 05:40:30 +05:30
|
|
|
|
case '\n': /* just ignore these, they'll have the effect */
|
|
|
|
|
case ' ': /* of refreshing display after waking us up ! */
|
2002-09-13 17:12:44 +05:30
|
|
|
|
break;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
default:
|
|
|
|
|
show_msg("\aUnknown command - try 'h' for help");
|
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*
|
|
|
|
|
* State display *Helper* function to calc and display the state
|
|
|
|
|
* percentages for a single cpu. In this way, we can support
|
|
|
|
|
* the following environments without the usual code bloat.
|
|
|
|
|
* 1) single cpu machines
|
|
|
|
|
* 2) modest smp boxes with room for each cpu's percentages
|
|
|
|
|
* 3) massive smp guys leaving little or no room for process
|
|
|
|
|
* display and thus requiring the cpu summary toggle */
|
|
|
|
|
static void summaryhlp (CPUS_t *cpu, const char *pfx)
|
|
|
|
|
{
|
|
|
|
|
/* we'll trim to zero if we get negative time ticks,
|
|
|
|
|
which has happened with some SMP kernels (pre-2.4?) */
|
|
|
|
|
#define TRIMz(x) ((tz = (STIC_t)x) < 0 ? 0 : tz)
|
|
|
|
|
STIC_t u_frme, s_frme, n_frme, i_frme, w_frme, tot_frme, tz;
|
|
|
|
|
float scale;
|
|
|
|
|
|
|
|
|
|
u_frme = TRIMz(cpu->u - cpu->u_sav);
|
|
|
|
|
s_frme = TRIMz(cpu->s - cpu->s_sav);
|
|
|
|
|
n_frme = TRIMz(cpu->n - cpu->n_sav);
|
|
|
|
|
i_frme = TRIMz(cpu->i - cpu->i_sav);
|
|
|
|
|
w_frme = TRIMz(cpu->w - cpu->w_sav);
|
|
|
|
|
tot_frme = u_frme + s_frme + n_frme + i_frme + w_frme;
|
|
|
|
|
if (1 > tot_frme) tot_frme = 1;
|
|
|
|
|
scale = 100.0 / (float)tot_frme;
|
|
|
|
|
|
|
|
|
|
/* display some kinda' cpu state percentages
|
|
|
|
|
(who or what is explained by the passed prefix) */
|
|
|
|
|
show_special(fmtmk(States_fmts
|
|
|
|
|
, pfx
|
|
|
|
|
, (float)u_frme * scale
|
|
|
|
|
, (float)s_frme * scale
|
|
|
|
|
, (float)n_frme * scale
|
|
|
|
|
, (float)i_frme * scale
|
|
|
|
|
, (float)w_frme * scale));
|
|
|
|
|
Msg_row += 1;
|
|
|
|
|
|
|
|
|
|
// remember for next time around
|
|
|
|
|
cpu->u_sav = cpu->u;
|
|
|
|
|
cpu->s_sav = cpu->s;
|
|
|
|
|
cpu->n_sav = cpu->n;
|
|
|
|
|
cpu->i_sav = cpu->i;
|
|
|
|
|
cpu->w_sav = cpu->w;
|
|
|
|
|
|
|
|
|
|
#undef TRIMz
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-30 09:14:46 +05:30
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Begin a new frame by:
|
|
|
|
|
* 1) Refreshing the all important proc table
|
|
|
|
|
* 2) Displaying uptime and load average (maybe)
|
2002-11-08 06:01:28 +05:30
|
|
|
|
* 3) Displaying task/cpu states (maybe)
|
|
|
|
|
* 4) Displaying memory & swap usage (maybe)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* and then, returning a pointer to the pointers to the proc_t's! */
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static proc_t **summary_show (void)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
{
|
|
|
|
|
static proc_t **p_table = NULL;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static CPUS_t *smpcpu = NULL;
|
2002-10-19 02:37:49 +05:30
|
|
|
|
int p_flags = PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS;
|
|
|
|
|
WIN_t *w;
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// let's try to minimize the cost of this frame (cross your fingers)
|
2002-10-19 02:37:49 +05:30
|
|
|
|
w = Curwin;
|
|
|
|
|
do {
|
|
|
|
|
if (!Mode_altscr || CHKw(w, VISIBLE_tsk)) {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
if ( CHKw(w, Show_CMDLIN)
|
|
|
|
|
&& win_fldviz(w, P_CMD) ) p_flags |= PROC_FILLCOM;
|
|
|
|
|
if (win_fldviz(w, P_USR)) p_flags |= PROC_FILLUSR;
|
|
|
|
|
if (win_fldviz(w, P_GRP)) p_flags |= PROC_FILLGRP;
|
2002-10-19 02:37:49 +05:30
|
|
|
|
}
|
|
|
|
|
if (Mode_altscr) w = w->next;
|
|
|
|
|
} while (w != Curwin);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 09:04:20 +05:30
|
|
|
|
// whoa first time, gotta' prime the pump...
|
2002-05-30 09:14:46 +05:30
|
|
|
|
if (!p_table) {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
p_table = procs_refresh(NULL, p_flags);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
putp(Cap_clr_scr);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
sleep(1);
|
|
|
|
|
} else
|
2002-06-19 05:15:30 +05:30
|
|
|
|
putp(Batch ? "\n\n" : Cap_home);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
p_table = procs_refresh(p_table, p_flags);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*
|
|
|
|
|
** Display Uptime and Loadavg */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (CHKw(Curwin, View_LOADAV)) {
|
2002-07-25 03:55:34 +05:30
|
|
|
|
if (!Mode_altscr)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
show_special(fmtmk(LOADAV_line, Myname, sprint_uptime()));
|
|
|
|
|
else
|
|
|
|
|
show_special(fmtmk(CHKw(Curwin, VISIBLE_tsk)
|
|
|
|
|
? LOADAV_line_alt
|
|
|
|
|
: LOADAV_line
|
|
|
|
|
, Curwin->grpname, sprint_uptime()));
|
|
|
|
|
Msg_row += 1;
|
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*
|
|
|
|
|
** Display Task and Cpu(s) States */
|
|
|
|
|
if (CHKw(Curwin, View_STATES)) {
|
|
|
|
|
show_special(fmtmk(STATES_line1
|
|
|
|
|
, Frame_maxtask, Frame_running, Frame_sleepin
|
|
|
|
|
, Frame_stopped, Frame_zombied));
|
|
|
|
|
Msg_row += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smpcpu = cpus_refresh(smpcpu);
|
|
|
|
|
|
|
|
|
|
if (CHKw(Curwin, View_CPUSUM)) {
|
|
|
|
|
// display just the 1st /proc/stat line
|
|
|
|
|
summaryhlp(&smpcpu[Cpu_tot], "Cpu(s):");
|
|
|
|
|
} else {
|
|
|
|
|
int i;
|
|
|
|
|
char tmp[SMLBUFSIZ];
|
|
|
|
|
// display each cpu's states separately
|
|
|
|
|
for (i = 0; i < Cpu_tot; i++) {
|
|
|
|
|
snprintf(tmp, sizeof(tmp), " Cpu%-2d:", Mode_irixps ? i : Cpu_map[i]);
|
|
|
|
|
summaryhlp(&smpcpu[i], tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*
|
|
|
|
|
** Display Memory and Swap stats */
|
|
|
|
|
meminfo();
|
|
|
|
|
if (CHKw(Curwin, View_MEMORY)) {
|
|
|
|
|
show_special(fmtmk(MEMORY_line1
|
|
|
|
|
, kb_main_total, kb_main_used, kb_main_free, kb_main_buffers));
|
|
|
|
|
show_special(fmtmk(MEMORY_line2
|
|
|
|
|
, kb_swap_total, kb_swap_used, kb_swap_free, kb_main_cached));
|
|
|
|
|
Msg_row += 2;
|
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
SETw(Curwin, NEWFRAM_cwo);
|
|
|
|
|
return p_table;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Task display *Helper* function to handle highlighted
|
|
|
|
|
* column transitions. */
|
|
|
|
|
static void taskhlp (WIN_t *q, int a, int c, int *p, char *b, const char *f, ...)
|
|
|
|
|
{ // q = duh, a = status, c = hicol, p = pad, b = buf, f = fmt
|
|
|
|
|
char tmp[COLBUFSIZ];
|
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
|
|
va_start(va, f);
|
|
|
|
|
/* this conditional is for piece-of-mind only -- it should NOT be needed
|
|
|
|
|
given the macro employed to call us (only when the target column
|
|
|
|
|
is the current sort field and Show_HICOLS is on) */
|
|
|
|
|
if (!c) {
|
|
|
|
|
vsprintf(b, f, va);
|
|
|
|
|
} else {
|
|
|
|
|
vsnprintf(tmp, sizeof(tmp), f, va);
|
|
|
|
|
sprintf(b, "%s%s", q->capclr_rowhigh, tmp);
|
|
|
|
|
*p += q->len_rowhigh;
|
|
|
|
|
if (!CHKw(q, Show_HIROWS) || 'R' != a) {
|
|
|
|
|
strcat(b, q->capclr_rownorm);
|
|
|
|
|
*p += q->len_rownorm;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
va_end(va);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Display information for a single task row. */
|
|
|
|
|
static void task_show (WIN_t *q, proc_t *task)
|
|
|
|
|
{
|
|
|
|
|
/* the following macro is our means to 'inline' emitting a column -- that's
|
|
|
|
|
far and away the most frequent and costly part of top's entire job! */
|
|
|
|
|
#define MKCOL(q,a,c,p,b,f,v...) do{ \
|
|
|
|
|
if (!c) \
|
|
|
|
|
snprintf(b, sizeof(b), f, ## v); \
|
|
|
|
|
else taskhlp(q, a, c, p, b, f, ## v); } while(0)
|
|
|
|
|
char rbuf[ROWBUFSIZ];
|
|
|
|
|
int j, x, pad;
|
|
|
|
|
|
|
|
|
|
/* since win_colsheads adds a number to the window's column header,
|
|
|
|
|
we must begin a row with that in mind... */
|
|
|
|
|
if ((pad = Mode_altscr)) strcpy(rbuf, " "); else rbuf[0] = '\0';
|
|
|
|
|
|
|
|
|
|
for (x = 0; x < q->maxpflgs; x++) {
|
|
|
|
|
char cbuf[COLBUFSIZ];
|
|
|
|
|
char a = task->state; // we'll use local var's so
|
|
|
|
|
PFLG_t i = q->procflags[x]; // gcc doesn't reinvent the
|
|
|
|
|
const char *f = Fieldstab[i].fmts; // wheel - yields a cryptic
|
|
|
|
|
unsigned s = Fieldstab[i].scale; // call, but saves a bunch
|
|
|
|
|
unsigned w = Fieldstab[i].width; // of generated code...
|
|
|
|
|
int c = (CHKw(q, Show_HICOLS) && q->sortindx == i);
|
|
|
|
|
|
|
|
|
|
cbuf[0] = '\0';
|
|
|
|
|
switch (i) {
|
|
|
|
|
case P_CMD:
|
|
|
|
|
{ char *cmdptr, cmdnam[ROWBUFSIZ];
|
|
|
|
|
|
|
|
|
|
if (!CHKw(q, Show_CMDLIN))
|
|
|
|
|
cmdptr = task->cmd;
|
|
|
|
|
else {
|
|
|
|
|
cmdnam[0] = '\0';
|
|
|
|
|
if (task->cmdline) {
|
|
|
|
|
j = 0;
|
|
|
|
|
do {
|
|
|
|
|
/* during a kernel build, parts of the make will create
|
|
|
|
|
cmdlines in excess of 3000 bytes but *without* the
|
|
|
|
|
intervening nulls -- so we must limit our strcat... */
|
|
|
|
|
strcat(cmdnam
|
|
|
|
|
, fmtmk("%.*s ", q->maxcmdln, task->cmdline[j++]));
|
|
|
|
|
if (q->maxcmdln < (int)strlen(cmdnam)) break;
|
|
|
|
|
} while (task->cmdline[j]);
|
|
|
|
|
/* whoa, gnome's xscreensaver had a ^I in his cmdline
|
|
|
|
|
creating a line wrap when the window was maximized &
|
|
|
|
|
the tab came into view -- so whack those suckers... */
|
|
|
|
|
strim(1, cmdnam);
|
|
|
|
|
} else {
|
|
|
|
|
/* if cmdline is absent, consider it a kernel thread and
|
|
|
|
|
display it uniquely (need sort callback's complicity) */
|
|
|
|
|
strcpy(cmdnam, fmtmk(CMDLINE_FMTS, task->cmd));
|
|
|
|
|
}
|
|
|
|
|
cmdptr = cmdnam;
|
|
|
|
|
}
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, q->maxcmdln, q->maxcmdln, cmdptr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case P_COD:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_num(PAGES_2K(task->trs), w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_CPN:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (unsigned)task->processor);
|
|
|
|
|
break;
|
|
|
|
|
case P_CPU:
|
|
|
|
|
{ float u = (float)task->pcpu * Frame_tscale;
|
|
|
|
|
|
|
|
|
|
if (99.9 < u) u = 99.9;
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, u);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case P_DAT:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_num(PAGES_2K(task->drs), w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_DRT:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_num((unsigned)task->dt, w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_FLG:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (long)task->flags);
|
|
|
|
|
for (j = 0; cbuf[j]; j++) if ('0' == cbuf[j]) cbuf[j] = '.';
|
|
|
|
|
break;
|
|
|
|
|
case P_FLT:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_num(task->maj_flt, w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_GRP:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, task->egroup);
|
|
|
|
|
break;
|
|
|
|
|
case P_MEM:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f
|
|
|
|
|
, (float)PAGES_2K(task->resident) * 100 / kb_main_total);
|
|
|
|
|
break;
|
|
|
|
|
case P_NCE:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (int)task->nice);
|
|
|
|
|
break;
|
|
|
|
|
case P_PGD:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (unsigned)task->pgrp);
|
|
|
|
|
break;
|
|
|
|
|
case P_PID:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (unsigned)task->pid);
|
|
|
|
|
break;
|
|
|
|
|
case P_PPD:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (unsigned)task->ppid);
|
|
|
|
|
break;
|
|
|
|
|
case P_PRI:
|
|
|
|
|
if (-99 > task->priority || +99 < task->priority)
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, " RT ");
|
|
|
|
|
else
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (int)task->priority);
|
|
|
|
|
break;
|
|
|
|
|
case P_RES:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_num(PAGES_2K(task->resident), w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_SHR:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_num(PAGES_2K(task->share), w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_STA:
|
|
|
|
|
#ifdef USE_LIB_STA3
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, status(task));
|
|
|
|
|
#else
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, task->state);
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case P_SWP:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f
|
|
|
|
|
, scale_num(PAGES_2K(task->size - task->resident), w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_TME:
|
|
|
|
|
case P_TM2:
|
|
|
|
|
{ TICS_t t;
|
|
|
|
|
|
|
|
|
|
t = task->utime + task->stime;
|
|
|
|
|
if (CHKw(q, Show_CTIMES))
|
|
|
|
|
t += (task->cutime + task->cstime);
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_tics(t, w));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case P_TTY:
|
|
|
|
|
{ char tmp[TNYBUFSIZ];
|
|
|
|
|
|
|
|
|
|
dev_to_tty(tmp, (int)w, task->tty, task->pid, ABBREV_DEV);
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, tmp);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case P_UID:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, (unsigned)task->euid);
|
|
|
|
|
break;
|
|
|
|
|
case P_USR:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, task->euser);
|
|
|
|
|
break;
|
|
|
|
|
case P_VRT:
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, scale_num(PAGES_2K(task->size), w, s));
|
|
|
|
|
break;
|
|
|
|
|
case P_WCH:
|
|
|
|
|
if (No_ksyms) {
|
|
|
|
|
#ifdef CASEUP_HEXES
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, "%08lX ", (long)task->wchan);
|
|
|
|
|
#else
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, "%08lx ", (long)task->wchan);
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
MKCOL(q, a, c, &pad, cbuf, f, wchan(task->wchan));
|
|
|
|
|
}
|
|
|
|
|
break;
|
2002-10-19 02:37:49 +05:30
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
} /* end: switch 'procflag' */
|
|
|
|
|
|
|
|
|
|
strcat(rbuf, cbuf);
|
|
|
|
|
} /* end: for 'maxpflgs' */
|
|
|
|
|
|
|
|
|
|
// This row buffer could be stuffed with parameterized strings...
|
|
|
|
|
PUTP("\n%s%.*s%s%s", (CHKw(q, Show_HIROWS) && 'R' == task->state)
|
|
|
|
|
? q->capclr_rowhigh : q->capclr_rownorm
|
|
|
|
|
, Screen_cols + pad
|
|
|
|
|
, rbuf
|
|
|
|
|
, Caps_off
|
|
|
|
|
, Cap_clr_eol);
|
|
|
|
|
|
|
|
|
|
#undef MKCOL
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
* Squeeze as many tasks as we can into a single window,
|
|
|
|
|
* after sorting the passed proc table. */
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static void window_show (proc_t **ppt, WIN_t *q, int *lscr)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{
|
|
|
|
|
#ifdef SORT_SUPRESS
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// the 1 flag that DOES and 2 flags that MAY impact our proc table qsort
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#define srtMASK ~( Qsrt_NORMAL | Show_CMDLIN | Show_CTIMES )
|
2002-09-13 17:12:44 +05:30
|
|
|
|
static PFLG_t sav_indx = 0;
|
|
|
|
|
static int sav_flgs = -1;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#endif
|
|
|
|
|
int i, lwin;
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*
|
|
|
|
|
** Display Column Headings -- and distract 'em while we sort (maybe) */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
PUTP("\n%s%s%s%s", q->capclr_hdr, q->columnhdr, Caps_off, Cap_clr_eol);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
#ifdef SORT_SUPRESS
|
|
|
|
|
if (CHKw(Curwin, NEWFRAM_cwo)
|
2002-09-13 17:12:44 +05:30
|
|
|
|
|| sav_indx != q->sortindx
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|| sav_flgs != (q->winflags & srtMASK)) {
|
2002-09-13 17:12:44 +05:30
|
|
|
|
sav_indx = q->sortindx;
|
2002-06-19 05:15:30 +05:30
|
|
|
|
sav_flgs = (q->winflags & srtMASK);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
#endif
|
2002-11-08 06:01:28 +05:30
|
|
|
|
if (CHKw(q, Qsrt_NORMAL)) Frame_srtflg = 1; // this one's always needed!
|
2002-10-07 01:42:08 +05:30
|
|
|
|
else Frame_srtflg = -1;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
Frame_ctimes = CHKw(q, Show_CTIMES); // this and next, only maybe
|
2002-06-19 05:15:30 +05:30
|
|
|
|
Frame_cmdlin = CHKw(q, Show_CMDLIN);
|
2002-11-08 09:04:20 +05:30
|
|
|
|
qsort(ppt, Frame_maxtask, sizeof(proc_t *), Fieldstab[q->sortindx].sort);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#ifdef SORT_SUPRESS
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// account for column headings
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (!Batch) (*lscr)++;
|
|
|
|
|
lwin = 1;
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
|
|
while ( -1 != ppt[i]->pid && *lscr < Max_lines
|
|
|
|
|
&& (!q->winlines || (lwin <= q->winlines)) ) {
|
|
|
|
|
if ((CHKw(q, Show_IDLEPS)
|
|
|
|
|
|| ('S' != ppt[i]->state && 'Z' != ppt[i]->state))
|
|
|
|
|
&& ((!q->colusrnam[0])
|
|
|
|
|
|| (!strcmp(q->colusrnam, ppt[i]->euser)) ) ) {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*
|
|
|
|
|
** Display a process Row */
|
|
|
|
|
task_show(q, ppt[i]);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
if (!Batch) (*lscr)++;
|
|
|
|
|
++lwin;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
++i;
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// for this frame that window's toast, cleanup for next time
|
2002-06-19 05:15:30 +05:30
|
|
|
|
q->winlines = 0;
|
|
|
|
|
OFFw(Curwin, FLGSOFF_cwo);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
#ifdef SORT_SUPRESS
|
|
|
|
|
#undef srtMASK
|
|
|
|
|
#endif
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/*###### Entry point plus two ##########################################*/
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/*
|
|
|
|
|
* This guy's just a *Helper* function who apportions the
|
2002-11-08 06:01:28 +05:30
|
|
|
|
* remaining amount of screen real estate under multiple windows */
|
|
|
|
|
static void framehlp (int wix, int max)
|
2002-05-30 09:14:46 +05:30
|
|
|
|
{
|
2002-06-19 05:15:30 +05:30
|
|
|
|
int i, rsvd, size, wins;
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// calc remaining number of visible windows + total 'user' lines
|
2002-06-19 05:15:30 +05:30
|
|
|
|
for (i = wix, rsvd = 0, wins = 0; i < GROUPSMAX; i++) {
|
|
|
|
|
if (CHKw(Winstk[i], VISIBLE_tsk)) {
|
|
|
|
|
rsvd += Winstk[i]->maxtasks;
|
|
|
|
|
++wins;
|
|
|
|
|
if (max <= rsvd) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!wins) wins = 1;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// set aside 'rsvd' & deduct 1 line/window for the columns heading
|
2002-06-19 05:15:30 +05:30
|
|
|
|
size = (max - wins) - rsvd;
|
|
|
|
|
if (0 <= size) size = max;
|
|
|
|
|
size = (max - wins) / wins;
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
/* for remaining windows, set WIN_t winlines to either the user's
|
|
|
|
|
maxtask (1st choice) or our 'foxized' size calculation
|
|
|
|
|
(foxized adj. - 'fair and balanced') */
|
2002-06-19 05:15:30 +05:30
|
|
|
|
for (i = wix ; i < GROUPSMAX; i++) {
|
|
|
|
|
if (CHKw(Winstk[i], VISIBLE_tsk)) {
|
|
|
|
|
Winstk[i]->winlines =
|
|
|
|
|
Winstk[i]->maxtasks ? Winstk[i]->maxtasks : size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Initiate the Frame Display Update cycle at someone's whim!
|
|
|
|
|
* This routine doesn't do much, mostly he just calls others.
|
|
|
|
|
*
|
|
|
|
|
* (Whoa, wait a minute, we DO caretake that Msg_row guy and)
|
|
|
|
|
* (we CALCULATE that IMPORTANT Max_lines thingy so that the)
|
|
|
|
|
* (*subordinate* functions invoked know WHEN the user's had)
|
|
|
|
|
* (ENOUGH already. And at Frame End, it SHOULD be apparent)
|
|
|
|
|
* (WE am d'MAN -- clearing UNUSED screen LINES and ensuring)
|
|
|
|
|
* (the CURSOR is STUCK in just the RIGHT place, know what I)
|
|
|
|
|
* (mean? Huh, "doesn't DO MUCH"! Never, EVER think or say)
|
|
|
|
|
* (THAT about THIS function again, Ok? Good that's better.)
|
|
|
|
|
*
|
|
|
|
|
* (ps. we ARE the UNEQUALED justification KING of COMMENTS!)
|
|
|
|
|
* (No, I don't mean significance/relevance, only alignment.)
|
|
|
|
|
*
|
|
|
|
|
* (What's that? Are you sure? Old main's REALLY GOOD too?)
|
|
|
|
|
* (You say he even JUSTIFIES comments in his FUNCTION BODY?)
|
|
|
|
|
* (Jeeze, how COULD I have known? That sob's NOT IN SCOPE!)
|
|
|
|
|
*/
|
2002-11-08 06:01:28 +05:30
|
|
|
|
static void frame_make (void)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
{
|
|
|
|
|
proc_t **ppt;
|
|
|
|
|
int i, scrlins;
|
|
|
|
|
|
|
|
|
|
Msg_row = scrlins = 0;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
ppt = summary_show();
|
2002-06-19 05:15:30 +05:30
|
|
|
|
Max_lines = (Screen_rows - Msg_row) - 1;
|
|
|
|
|
|
|
|
|
|
if (CHKw(Curwin, EQUWINS_cwo))
|
2002-06-27 05:26:49 +05:30
|
|
|
|
wins_reflag(Flags_OFF, EQUWINS_cwo);
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// sure hope each window's columns header begins with a newline...
|
2002-06-19 05:15:30 +05:30
|
|
|
|
putp(tg2(0, Msg_row));
|
|
|
|
|
|
2002-07-25 03:55:34 +05:30
|
|
|
|
if (!Mode_altscr) {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// only 1 window to show so, piece o' cake
|
2002-06-19 05:15:30 +05:30
|
|
|
|
Curwin->winlines = Curwin->maxtasks;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
window_show(ppt, Curwin, &scrlins);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
} else {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// maybe NO window is visible but assume, pieces o' cakes
|
2002-06-19 05:15:30 +05:30
|
|
|
|
for (i = 0 ; i < GROUPSMAX; i++) {
|
|
|
|
|
if (CHKw(Winstk[i], VISIBLE_tsk)) {
|
2002-11-08 06:01:28 +05:30
|
|
|
|
framehlp(i, Max_lines - scrlins);
|
|
|
|
|
window_show(ppt, Winstk[i], &scrlins);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
}
|
|
|
|
|
if (Max_lines <= scrlins) break;
|
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
}
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/* clear to end-of-screen (critical if last window is 'idleps off'),
|
|
|
|
|
then put the cursor in-its-place, and rid us of any prior frame's msg
|
|
|
|
|
(main loop must iterate such that we're always called before sleep) */
|
2002-10-19 02:37:49 +05:30
|
|
|
|
PUTP("%s%s%s", Cap_clr_eos, tg2(0, Msg_row), Cap_clr_eol);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
fflush(stdout);
|
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/*
|
|
|
|
|
* Darling, you DO look simply MARVELOUS -- have you been dieting?
|
|
|
|
|
* Or maybe it's because YOU and WINDOWS seem such a HAPPY couple.
|
|
|
|
|
*
|
|
|
|
|
* Of course NO. Not THOSE deathly BLUE WINDOWS! I mean your 'A'
|
|
|
|
|
* mode (alt display) windows. Yes, yes those completely OPTIONAL
|
|
|
|
|
* ones. We ALL know you'd NEVER FORCE that interface on ANY user
|
|
|
|
|
* - unlike You-Know-Who! Well I've got to run. But you're doing
|
|
|
|
|
* it just SPLENDIDLY! You go right on doing it EXACTLY the SAME!
|
|
|
|
|
*/
|
|
|
|
|
int main (int dont_care_argc, char **argv)
|
2002-08-26 06:25:30 +05:30
|
|
|
|
{
|
2002-10-12 09:55:57 +05:30
|
|
|
|
(void)dont_care_argc;
|
2002-08-26 06:25:30 +05:30
|
|
|
|
before(*argv);
|
|
|
|
|
/*
|
2002-06-19 05:15:30 +05:30
|
|
|
|
Ok, she's gone now. Don't you mind her, she means well but yes, she is
|
|
|
|
|
a bit of a busy-body. Always playing the matchmaker role, trying to do
|
|
|
|
|
away with unmarried windows and bachelors. So, back to business buddy!
|
|
|
|
|
|
|
|
|
|
You're hungry, you said? How'd you like a sandwich? No, no, no -- not
|
|
|
|
|
the usual slopped together, hacked up illogic. I'm talkin' a carefully
|
|
|
|
|
reasoned, artfully crafted, extremely capable, well behaved executable!
|
|
|
|
|
|
2002-11-08 06:01:28 +05:30
|
|
|
|
Well then, here, try THIS sandwich: */
|
|
|
|
|
// +-------------+
|
|
|
|
|
windows_stage1(); // top (sic) slice
|
|
|
|
|
configs_read(); // > spread etc, <
|
|
|
|
|
parse_args(&argv[1]); // > lean stuff, <
|
|
|
|
|
whack_terminal(); // > onions etc. <
|
|
|
|
|
windows_stage2(); // as bottom slice
|
|
|
|
|
// +-------------+
|
2002-05-30 09:14:46 +05:30
|
|
|
|
signal(SIGALRM, stop);
|
|
|
|
|
signal(SIGHUP, stop);
|
|
|
|
|
signal(SIGINT, stop);
|
|
|
|
|
signal(SIGPIPE, stop);
|
|
|
|
|
signal(SIGQUIT, stop);
|
|
|
|
|
signal(SIGTERM, stop);
|
|
|
|
|
signal(SIGTSTP, suspend);
|
|
|
|
|
signal(SIGTTIN, suspend);
|
|
|
|
|
signal(SIGTTOU, suspend);
|
2002-06-19 05:15:30 +05:30
|
|
|
|
signal(SIGCONT, wins_resize);
|
|
|
|
|
signal(SIGWINCH, wins_resize);
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-10-21 10:20:41 +05:30
|
|
|
|
for (;;) {
|
2002-05-30 09:14:46 +05:30
|
|
|
|
struct timeval tv;
|
|
|
|
|
fd_set fs;
|
|
|
|
|
char c;
|
2002-11-08 06:01:28 +05:30
|
|
|
|
// This is it?
|
|
|
|
|
frame_make(); // Impossible!
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
|
|
|
|
if (Msg_awaiting) show_msg(Msg_delayed);
|
|
|
|
|
if (0 < Loops) --Loops;
|
|
|
|
|
if (!Loops) stop(0);
|
|
|
|
|
|
|
|
|
|
if (Batch)
|
|
|
|
|
sleep((unsigned)Delay_time);
|
2002-11-08 06:01:28 +05:30
|
|
|
|
else { // Linux reports time not slept,
|
|
|
|
|
tv.tv_sec = Delay_time; // so we must reinit every time.
|
2002-05-30 09:14:46 +05:30
|
|
|
|
tv.tv_usec = (Delay_time - (int)Delay_time) * 1000000;
|
|
|
|
|
FD_ZERO(&fs);
|
|
|
|
|
FD_SET(STDIN_FILENO, &fs);
|
|
|
|
|
if (0 < select(STDIN_FILENO+1, &fs, NULL, NULL, &tv)
|
|
|
|
|
&& 0 < chin(0, &c, 1))
|
|
|
|
|
do_key((unsigned)c);
|
|
|
|
|
}
|
2002-10-21 10:20:41 +05:30
|
|
|
|
}
|
2002-05-30 09:14:46 +05:30
|
|
|
|
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/*
|
2002-11-08 06:01:28 +05:30
|
|
|
|
(listen before we return, aren't you sort of sad for old 'frame_make'?)
|
2002-06-19 05:15:30 +05:30
|
|
|
|
(so, uh, why don't we just move this main guy to near the beginning of)
|
|
|
|
|
(the C source file. then that poor old function would be sure to have)
|
|
|
|
|
(at least a chance at scopin' us out, ya know what i mean? so what do)
|
|
|
|
|
(ya think? all things considered, would that be a proper thing to do?)
|
|
|
|
|
|
|
|
|
|
Now there's an EXCELLENT idea! After all, SOME programmers DO code the
|
|
|
|
|
main function ANY OLD PLACE they feel like. And in doing THAT, they're
|
|
|
|
|
helping to keep those that FOLLOW out of mischief, busy HUNTING for the
|
|
|
|
|
<bleepin'> thing. Further, by moving it we can contribute to PROTOTYPE
|
|
|
|
|
PROLIFERATION for every function main calls. Don't you KNOW that those
|
|
|
|
|
declarations OFTEN LINGER, usually long AFTER the REAL definitions have
|
|
|
|
|
DISAPPEARED, since programs do evolve? Yep that's a GREAT idea you got
|
|
|
|
|
there, NICE GOING! But, here's an opposing view: ANYONE who'd put main
|
|
|
|
|
ANYWHERE such that its LOCATION cannot be REACHED with JUST 1 KEYSTROKE
|
|
|
|
|
better turn in their Coding_Badge and Pocket_Protector then -- BE GONE!
|
|
|
|
|
The main function has only ONE proper HOME: always the LAST function in
|
|
|
|
|
that C Listing. End-of-Story, No-More-Discussion, so BE QUIET already!
|
|
|
|
|
|
|
|
|
|
\---------------------------------------------------------------------/
|
|
|
|
|
Sheeesh, didn't that dufus know the return statement can't be executed,
|
2002-06-27 05:26:49 +05:30
|
|
|
|
or we end via that stop() function? Oh Lordy, I is DROWNING in morons;
|
|
|
|
|
they done REACHED clear up to my OUTER braces! We's surely DOOMED now!
|
2002-06-19 05:15:30 +05:30
|
|
|
|
/---------------------------------------------------------------------\
|
|
|
|
|
*/
|
2002-05-30 09:14:46 +05:30
|
|
|
|
return 0;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|