/*
* slmon
*
* Copyright (C) 2000, 2001, 2002 Krzysztof Luks <m00se@iq.pl>
*
* Some parts of this file are based on WMMon.app and GTop.
*
* WMMon.app is copyright (c) 1997, 1998 by Martijn Pieterse and
* Antoine Nulle.
*
* GTop is copyright (c) 1997,98 Radek Doulík.
*
* This program is distributed under the GPL license. For details see
* COPYING text.
*
* Author: Krzysztof Luks <m00se@iq.pl>
* Some changes contributed by Ryan Wood
*
* $Date: 2004/06/20 15:56:48 $
* $Revision: 1.8 $
*
*/
#include "draw.h"
#include <glibtop/netload.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*
* Clear screen using color n. This should be used instead of SLsmg_cls() to
* avoid strange transparency problems in gnome-terminal.
*/
void slmon_clear_screen(int col)
{
SLsmg_set_color(col);
SLsmg_fill_region(0, 0, SLtt_Screen_Rows, SLtt_Screen_Cols, ' ');
}
/*
* S-Lang initialistaion
*/
void init_slang(void)
{
SLtt_get_terminfo(); /* S-Lang initialization */
SLang_init_tty(-1, 0, 0);
SLsmg_init_smg();
SLtt_set_cursor_visibility(0);
SLtt_set_color(5, NULL, col_stat, col_stba); /* status line */
SLtt_set_color(6, NULL, col_norm, col_back); /* description */
SLtt_set_color(7, NULL, col_valu, col_back); /* value */
/* Gauge gradient values */
SLtt_set_color(10, NULL, col_gra1, col_back); /* 00 - 09 */
SLtt_set_color(11, NULL, col_gra2, col_back); /* 10 - 19 */
SLtt_set_color(12, NULL, col_gra3, col_back); /* 20 - 30 */
/* Too much inverse video look terribly ugly on monochrome terminals */
if (do_bold)
SLtt_set_mono(6, NULL, SLTT_BOLD_MASK);
else
SLtt_set_mono(6, NULL, 0);
SLtt_set_mono(7, NULL, 0);
SLtt_set_mono(10, NULL, 0);
SLtt_set_mono(11, NULL, 0);
SLtt_set_mono(12, NULL, 0);
if (height > SLtt_Screen_Rows)
height = SLtt_Screen_Rows;
else if (height < 20)
height = 20;
}
/*
* Draw gauge begining at (row, col).
*/
void draw_gauge(int row, int col, int value, char *caption, int align)
{
int i;
int color = 10;
SLsmg_gotorc(row, col);
SLsmg_erase_eol();
if (align == GAUGE_RIGHT) {
SLsmg_set_color(6);
SLsmg_printf("%s ", caption);
} else if (align == GAUGE_LEFT) {
SLsmg_set_color(7);
SLsmg_printf("%3d%% ", value);
}
SLsmg_set_color(7);
SLsmg_printf("[");
if (align == GAUGE_LEFT) {
SLsmg_gotorc(row, col + conf.gauge_len + 6); /* 6 == strlen("xxx% ["); */
SLsmg_set_color(7);
SLsmg_printf("]");
SLsmg_set_color(6);
SLsmg_printf(" %s", caption);
SLsmg_gotorc(row, col + 6); /* 6 == strlen("xxx% ["); */
} else if (align == GAUGE_RIGHT) {
SLsmg_gotorc(row, col + conf.gauge_len + strlen(caption) + 1);
SLsmg_set_color(7);
SLsmg_printf("]");
SLsmg_printf("%3d%% ", value);
SLsmg_gotorc(row, col + strlen(caption) + 2);
}
value *= conf.gauge_len;
value /= 100;
if (value > 100) /* Just in case someone tries to cheat us ;->> */
value = 100;
for (i = 0; i < value; i++) {
color = i / (conf.gauge_len / 3) + 10; /* Gauge colors: 10, 11, 12 */
if (color > 12) /* Let's try to be smart ;)) */
color = 12;
SLsmg_set_color(color);
SLsmg_printf("*");
}
}
/*
* Draw top and bottom status lines
*/
void draw_status(void)
{
time_t curtime; /* Current time */
struct tm *loctime; /* Local time */
char time_str[64];
struct utsname hi; /* host info */
int up_d, up_h, up_m, up_s; /* Uptime */
uname(&hi); /* get host information */
get_uptime(&up_d, &up_h, &up_m, &up_s);
curtime = time(NULL);
loctime = localtime(&curtime);
strftime(time_str, 64, "%a, %d %B %Y, %H:%M:%S", loctime);
/* Upper status line */
SLsmg_gotorc(0, 0);
SLsmg_set_color(5);
SLsmg_erase_eol();
SLsmg_printf("%s %s", PACKAGE, VERSION);
if (mode == MODE_H)
SLsmg_printf("\trspace: %d cspace: %d", rspace, cspace);
else if (mode == MODE_M)
SLsmg_printf("\tgauge length: %d ", conf.gauge_len);
SLsmg_gotorc(0, SLtt_Screen_Cols - strlen(time_str));
SLsmg_printf("%s", time_str); /* date/time */
/* Lower status line */
SLsmg_gotorc(height - 2, 0);
SLsmg_printf("%s %s %s %s, %d users", hi.nodename, hi.sysname,
hi.release, hi.machine, users());
SLsmg_erase_eol();
if (up_d > 0) {
SLsmg_gotorc(height - 2, SLtt_Screen_Cols - 21);
SLsmg_printf("Uptime: %3dd %02d:%02d:%02d", up_d, up_h, up_m,
up_s);
} else {
SLsmg_gotorc(height - 2, SLtt_Screen_Cols - 16);
SLsmg_printf("Uptime: %02d:%02d:%02d", up_h, up_m, up_s);
}
}
/*
* Draw histogram frame and caption
*/
void draw_histogram(char *caption)
{
int r = height;
int c = SLtt_Screen_Cols;
int r2 = rspace * 2;
int c2 = cspace * 2;
/* Box */
SLsmg_set_color(7);
SLsmg_draw_box(rspace, cspace, r - r2, c - c2);
/* If there is enouch space for the scale, than draw it */
if (cspace >= 4) {
SLsmg_gotorc(rspace, cspace - 4);
SLsmg_printf("100%%");
SLsmg_gotorc(r / 2, cspace - 4);
SLsmg_printf(" 50%%");
SLsmg_gotorc(r - rspace - 1, cspace - 4);
SLsmg_printf(" 0%%");
}
/* Caption */
if (caption != NULL) {
SLsmg_gotorc(rspace, (c / 2) - (strlen(caption) / 2) - 2);
SLsmg_printf("[ ");
SLsmg_set_color(6);
SLsmg_printf("%s", caption);
SLsmg_set_color(7);
SLsmg_printf(" ]");
}
}
/*
* Draw value inside histogram frame.
*/
void draw_histogram_value(int value, int pos)
{
value *= height - rspace * 2 - 3;
value /= 100;
SLsmg_set_color(7);
SLsmg_gotorc(height - value - rspace - 2, cspace + pos + 1);
SLsmg_draw_vline(value + 1);
}
/*
* Clear histogram except frame
*/
void clear_histogram(void)
{
int r2 = rspace * 2;
int c2 = cspace * 2;
SLsmg_set_color(7);
/* We have to be careful not to erase frame */
SLsmg_fill_region(rspace + 1, cspace + 1, height - r2 - 2,
SLtt_Screen_Cols - c2 - 2, ' ');
}
/*
* Print memory usage
*/
void print_mem(int r, int c)
{
u_int64_t m_free, m_total, m_used;
u_int64_t s_total, s_free, s_used;
glibtop_mem m;
glibtop_swap s;
glibtop_get_mem(&m);
glibtop_get_swap(&s);
m_free = m.free;
m_total = m.total;
m_used = m.used;
s_free = s.free;
s_total = s.total;
s_used = s.used;
SLsmg_set_color(6);
SLsmg_gotorc(r++, c);
SLsmg_printf("\tMemory:\t\t\tSwap:");
SLsmg_gotorc(r++, c);
SLsmg_erase_eol();
SLsmg_printf("Total:\t");
SLsmg_set_color(7);
SLsmg_printf("%12Ld \t\t%12Ld [%c]", m_total / unit_div[conf.mem],
s_total / unit_div[conf.mem], unit_name[conf.mem]);
SLsmg_gotorc(r++, c);
SLsmg_set_color(6);
SLsmg_erase_eol();
SLsmg_printf("Used:\t");
SLsmg_set_color(7);
SLsmg_printf("%12Ld \t\t%12Ld [%c]", m_used / unit_div[conf.mem],
s_used / unit_div[conf.mem], unit_name[conf.mem]);
SLsmg_gotorc(r++, c);
SLsmg_set_color(6);
SLsmg_erase_eol();
SLsmg_printf("Free:\t");
SLsmg_set_color(7);
SLsmg_printf("%12Ld \t\t%12Ld [%c]", m_free / unit_div[conf.mem],
s_free / unit_div[conf.mem], unit_name[conf.mem]);
}
/*
* Print keybindings
*/
void print_keys(int mode)
{
SLsmg_set_color(6);
SLsmg_gotorc(height - 1, 0);
SLsmg_erase_eol();
SLsmg_write_string("q: quit ?: help ");
switch (mode) {
case MODE_M:
SLsmg_write_string("u: mem unit U: fs unit up,down: fs scroll");
break;
case MODE_H:
SLsmg_write_string("h: histogram mode");
break;
case MODE_N:
SLsmg_write_string("u: net unit n: new interface d: delete interface");
break;
case MODE_P:
SLsmg_write_string("PgUp,PgDown,up,down: scroll, k:SIGTERM, K:spec signal");
break;
case MODE_X:
SLsmg_write_string("SPC,ENTER: leave help");
break;
}
}
/*
* Print machine's load average
*/
void print_ldavg(int r, int c)
{
glibtop_loadavg l;
glibtop_get_loadavg(&l);
}
/*
* Print filesystem information in df(1) like style
*/
void print_fs(int r, int c)
{
int i, gauge_tmp, j = 1;
int fs_count = 0, use;
double fs_size, fs_used, fs_avail;
double tmp1, tmp2;
char unit;
glibtop_mountlist ml;
glibtop_mountentry *me, *me_valid;
glibtop_fsusage f;
me = glibtop_get_mountlist(&ml, 0);
/* Alloc memory for all fileststems... */
me_valid =
(glibtop_mountentry *) malloc(ml.number *
sizeof(glibtop_mountentry));
/* ...but choose only those that have non-zero size... */
for (i = 0; i < ml.number; i++) {
glibtop_get_fsusage(&f, me[i].mountdir);
if (f.blocks)
me_valid[fs_count++] = me[i];
}
/* ...and free unused part. Dunno if there's a better way. */
me_valid = realloc(me_valid, fs_count * sizeof(glibtop_mountentry));
/* Check whether we didn't go beyond valid boundary */
if (conf.fs_first + conf.fs_max >= fs_count)
conf.fs_first =
conf.fs_max > fs_count ? 0 : fs_count - conf.fs_max;
/* back up gauge length */
gauge_tmp = conf.gauge_len;
conf.gauge_len = 12;
SLsmg_gotorc(r, c);
SLsmg_set_color(6);
/* print header */
SLsmg_printf("%-19s %-13s %-10s %-9s %-9s %-9s", "Percent Used",
"Mount point", "Type", "Size", "Used", "Avail");
for (i = conf.fs_first;
i < fs_count && i < conf.fs_max + conf.fs_first; i++) {
glibtop_get_fsusage(&f, me_valid[i].mountdir);
unit = unit_name[conf.fs + 1];
fs_size = (double) f.blocks;
fs_used = (double) (f.blocks - f.bfree);
fs_avail = (double) f.bavail;
use = (int) (fs_size - fs_avail) / fs_size * 100.0;
fs_size = (double) fs_size / 2.0 / unit_div[conf.fs];
fs_used = (double) fs_used / 2.0 / unit_div[conf.fs];
fs_avail = (double) fs_avail / 2.0 / unit_div[conf.fs];
SLsmg_gotorc(r + j, c);
draw_gauge(r + j, c, use, me_valid[i].mountdir, GAUGE_LEFT);
SLsmg_set_color(7);
SLsmg_gotorc(r + j, c + 34);
if (conf.fs > 1)
SLsmg_printf("%-8s %9.2f %9.2f %9.2f [%c]", me_valid[i].type,
fs_size, fs_used, fs_avail, unit);
else
SLsmg_printf("%-8s %9.0f %9.0f %9.0f [%c]", me_valid[i].type,
fs_size, fs_used, fs_avail, unit);
j++;
}
g_free(me);
g_free(me_valid);
conf.gauge_len = gauge_tmp;
/* if we haven't displayed all entries we need to draw a scrollbar */
if (conf.fs_max < fs_count) {
tmp1 = (double) conf.fs_first + conf.fs_max;
tmp2 = tmp1 / (double) fs_count;
tmp2 *= 100.0;
draw_scrollbar(r + 1, c + 77, conf.fs_max + 0, (int) tmp2);
}
}
int print_iface(int r, int c, char *name, unsigned long last_in, unsigned long last_out)
{
glibtop_netload nload;
unsigned long mtu, s, a, p_in, p_out, e_in, e_out, coll;
char add[20] = { 0 }, sub[20] = { 0 }, un;
double b_in, b_out, speed_in, speed_out, scale;
char un_in, un_out;
char flags[80] = { 0 };
glibtop_get_netload(&nload, name);
if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_UP))
strcat(flags, "flags: UP ");
else
strcat(flags, "flags: DOWN ");
if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_DEBUG))
strcat(flags, "DEBUG ");
if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_LOOPBACK))
strcat(flags, "LOOPBACK ");
if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_POINTOPOINT))
strcat(flags, "POINTOPOINT ");
if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_RUNNING))
strcat(flags, "RUNNING ");
if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_PROMISC))
strcat(flags, "PROMISC");
mtu = (unsigned long) nload.mtu; //
s = (unsigned long) nload.subnet; //
a = (unsigned long) nload.address; //
p_in = (unsigned long) nload.packets_in; //
p_out = (unsigned long) nload.packets_out; //
b_in = (double) nload.bytes_in / unit_div[conf.net]; //
b_out = (double) nload.bytes_out / unit_div[conf.net]; //
e_in = (unsigned long) nload.errors_in;
e_out = (unsigned long) nload.errors_out;
coll = (unsigned long) nload.collisions;
speed_in = (double) (nload.bytes_in - last_in);
speed_out = (double) (nload.bytes_out - last_out);
scale = (double) 1000000 / (update_time + 10000);
speed_in *= scale;
speed_out *= scale;
if ( speed_in >= 524288 ) {
speed_in /= 1048576;
un_in = 'M';
} else {
speed_in /= 1024;
un_in = 'k';
}
if ( speed_out >= 524288 ) {
speed_out /= 1048576;
un_out = 'M';
} else {
speed_out /= 1024;
un_out = 'k';
}
slmon_update_net_throughput(name, nload.bytes_in, nload.bytes_out);
un = unit_name[conf.net];
inet_ntop(AF_INET, &s, sub, 19);
inet_ntop(AF_INET, &a, add, 19);
SLsmg_gotorc(r, c);
SLsmg_set_color(7);
SLsmg_printf("%s", name);
SLsmg_gotorc(r, c + 8);
SLsmg_printf("%s", add);
SLsmg_gotorc(r, c + 26);
SLsmg_printf("%d", coll);
SLsmg_gotorc(r, c + 37);
if (conf.net == 0){
SLsmg_printf("%.lf%c", b_out, un);
SLsmg_gotorc(r, c + 47);
if (un_out == 'M')
SLsmg_set_color(15);
SLsmg_printf("%.2lf%c/s", speed_out, un_out);
SLsmg_set_color(7);
SLsmg_gotorc(r, c + 58);
SLsmg_printf("%.lf%c", b_in, un);
SLsmg_gotorc(r, c + 68);
if (un_in == 'M')
SLsmg_set_color(15);
SLsmg_printf("%.2lf%c/s", speed_in, un_in);
SLsmg_set_color(7);
} else {
SLsmg_printf("%.1lf%c", b_out, un);
SLsmg_gotorc(r, c + 47);
if (un_out == 'M')
SLsmg_set_color(15);
SLsmg_printf("%.2lf%c/s", speed_out, un_out);
SLsmg_set_color(7);
SLsmg_gotorc(r, c + 58);
SLsmg_printf("%.1lf%c", b_in, un);
SLsmg_gotorc(r, c + 68);
if (un_in == 'M')
SLsmg_set_color(15);
SLsmg_printf("%.2lf%c/s", speed_in, un_in);
SLsmg_set_color(7);
}
return 1; //height of status
}
/*
* Draw histogram mode
*/
void draw_mode_h(void)
{
char *capt;
capt = cpu_caption(cur_cpu);
draw_histogram_value(cpu_calc(cur_cpu), pos);
if (redraw == 1) {
draw_histogram(capt);
redraw = 0;
}
if (++pos >= SLtt_Screen_Cols - (2 * cspace) - 1) {
clear_histogram();
pos = 0;
}
free(capt);
}
/*
* Draw gauge mode
*/
void draw_mode_g(void)
{
int j;
char *capt;
SLsmg_gotorc(2, 0);
SLsmg_set_color(7);
SLsmg_forward(5); /* 5 == "xxx% " */
SLsmg_printf("0%%");
SLsmg_forward(conf.gauge_len - 4); /* 4 == "100%%" */
SLsmg_printf("100%%");
SLsmg_set_color(6);
SLsmg_printf(" Scale");
for (j = 0; j <= conf.cpus; j++) {
capt = cpu_caption(j);
draw_gauge(3 + j, 0, cpu_calc(j), capt, GAUGE_LEFT);
free(capt);
}
if (!(fnord % 2)) { /* Update these stats every other cycle */
print_mem(5 + j, 0);
print_ldavg(10 + j, 0);
print_fs(12 + j, 0);
}
}
/*
* Draw network mode
*/
void draw_mode_n(void)
{
struct slmon_net *net;
int num = 0, first;
if (conf.iface == NULL || conf.iface_count == 0) {
SLsmg_gotorc(5, (SLtt_Screen_Cols / 2) - 12);
SLsmg_set_color(7);
SLsmg_write_string("No interfaces specified.");
return;
}
net = conf.iface;
first = conf.iface_first;
/* clear the screen to avoid artefacts when scrolling */
SLsmg_set_color(7);
SLsmg_fill_region(1, 0, SLtt_Screen_Rows - 3, SLtt_Screen_Cols, ' ');
/* skip ifaces we don't want to see */
while(first > 0 && net != NULL) {
first--;
net = net->next;
}
/* print the remaining ones */
while(net != NULL) {
if(num + 3 > SLtt_Screen_Rows - 2)
break; /* no more space left on screen */
num += print_iface(2 + num, 1, net->name, net->last_in, net->last_out);
net = net->next;
}
/* draw scrollbar */
SLsmg_gotorc(1, 1);
SLsmg_set_color(6);
SLsmg_printf("INT IP Collisions Sent: k/s Recieved: k/s");
SLsmg_set_color(7);
draw_scrollbar(2, 0, SLtt_Screen_Rows - 4, (conf.iface_first * 100) / conf.iface_count);
}
/*
* Draw processes mode
* ps -e -o user,pid,pcpu,pmem,vsz,rsz,stat,cmd
*/
void draw_mode_p(void)
{
slmon_proc p;
int i, num;
double prct;
plist = slmon_get_proclist(&num);
if (plist) {
qsort(plist, num, sizeof(slmon_proc), conf.sort_func);
if (conf.proc_first + SLtt_Screen_Rows - 5 > num)
conf.proc_first = num - SLtt_Screen_Rows + 5;
if (conf.proc_curr >= num)
conf.proc_curr = num - 1;
if (conf.proc_first < 0)
conf.proc_first = 0;
if (conf.proc_curr < 0)
conf.proc_curr = 0;
SLsmg_set_color(6);
SLsmg_fill_region(1, 0, SLtt_Screen_Rows - 3, SLtt_Screen_Cols, ' ');
SLsmg_gotorc(1, 1);
SLsmg_printf("USER PID %%CPU %%MEM VSZ RSS STAT COMMAND");
if (SLtt_Screen_Rows - 5 < num) {
prct = (double) conf.proc_first + SLtt_Screen_Rows - 5;
prct /= (double) num;
prct *= 100.0;
draw_scrollbar(2, 0, SLtt_Screen_Rows - 5, (int) prct);
}
for (i = 0; i < num && i < SLtt_Screen_Rows - 5; i++) {
p = plist[i + conf.proc_first];
if(i + conf.proc_first == conf.proc_curr)
SLsmg_set_color(5);
else
SLsmg_set_color(7);
SLsmg_gotorc(2 + i, 1);
SLsmg_printf("%-8s %5d %2u.%1u %2u.%1u %5d %4d %-4c %s", p.user, p.pid, p.pcpu / 10, p.pcpu % 10, p.pmem / 10, p.pmem % 10, p.vsz, p.rss, p.state, p.args);
SLsmg_erase_eol();
}
free(plist);
}
}
void draw_mode_x(void)
{
SLsmg_set_color(7);
SLsmg_gotorc(1, (SLtt_Screen_Cols / 2) - 2);
SLsmg_printf("Help");
SLsmg_set_color(6);
SLsmg_gotorc(3, 1);
SLsmg_printf("Mode changing:");
SLsmg_set_color(7);
SLsmg_write_wrapped_string(HELP_MODE, 4, 1, SLtt_Screen_Rows - 2,
SLtt_Screen_Cols - 1, 0);
SLsmg_gotorc(10, 1);
SLsmg_set_color(6);
SLsmg_printf("Exiting:");
SLsmg_set_color(7);
SLsmg_write_wrapped_string(HELP_QUIT, 11, 1, SLtt_Screen_Rows - 2,
SLtt_Screen_Cols - 1, 0);
SLsmg_gotorc(13, 1);
SLsmg_set_color(6);
SLsmg_printf("Histogram mode:");
SLsmg_set_color(7);
SLsmg_write_wrapped_string(HELP_HIST, 14, 1, SLtt_Screen_Rows - 2,
SLtt_Screen_Cols - 1, 0);
SLsmg_gotorc(3, 36);
SLsmg_set_color(6);
SLsmg_printf("Proc mode:");
SLsmg_set_color(7);
SLsmg_write_wrapped_string(HELP_PROC, 4, 36, SLtt_Screen_Rows - 2,
SLtt_Screen_Cols - 1, 0);
SLsmg_gotorc(9, 36);
SLsmg_set_color(6);
SLsmg_printf("Net mode:");
SLsmg_set_color(7);
SLsmg_write_wrapped_string(HELP_NET, 10, 36, SLtt_Screen_Rows - 2,
SLtt_Screen_Cols - 1, 0);
SLsmg_gotorc(12, 36);
SLsmg_set_color(6);
SLsmg_printf("Main mode:");
SLsmg_set_color(7);
SLsmg_write_wrapped_string(HELP_MAIN, 13, 36, SLtt_Screen_Rows - 2,
SLtt_Screen_Cols - 1, 0);
}
/*
* Draw scrollbar
*/
void draw_scrollbar(int r, int c, int h, int prct)
{
int skip = (prct * h) / 100 - 1;
if (skip >= h)
skip = h - 1;
SLsmg_set_color(7);
SLsmg_gotorc(r, c);
SLsmg_draw_vline(h);
SLsmg_gotorc(r + skip, c);
SLsmg_printf("*");
}
void slmon_status_msg(char *format, ...)
{
va_list ptr;
SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
SLsmg_erase_eol();
va_start(ptr, format);
SLsmg_vprintf(format, ptr);
va_end(ptr);
SLsmg_refresh();
}
syntax highlighted by Code2HTML, v. 0.9.1