/* * slmon * * Copyright (C) 2000, 2001, 2002 Krzysztof Luks * * 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 * Some changes contributed by Ryan Wood * * $Date: 2004/06/20 15:56:48 $ * $Revision: 1.8 $ * */ #include "draw.h" #include #include #include #include #include /* * 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(); }