ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/saidar/saidar.c
Revision: 1.38
Committed: Fri Dec 1 01:03:59 2006 UTC (17 years, 11 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.37: +16 -1 lines
Log Message:
Colour is only supported if ncurses is being used.

File Contents

# Content
1 /*
2 * i-scream libstatgrab
3 * http://www.i-scream.org
4 * Copyright (C) 2000-2004 i-scream
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * $Id: saidar.c,v 1.37 2006/12/01 00:38:39 tdb Exp $
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <sys/termios.h>
33 #include <signal.h>
34 #include <errno.h>
35 #include <statgrab.h>
36 #include <sys/times.h>
37 #include <limits.h>
38 #include <time.h>
39 #include <math.h>
40
41 #ifdef HAVE_NCURSES_H
42 #include <ncurses.h>
43 #define COLOR_SUPPORT
44 #else
45 #include <curses.h>
46 #endif
47
48 #define THRESHOLD_LOAD 1.0
49
50 #define THRESHOLD_WARN_ZMB 0
51
52 #define THRESHOLD_WARN_CPU 60.0
53 #define THRESHOLD_ALERT_CPU 90.0
54
55 #define THRESHOLD_WARN_SWAP 75.0
56 #define THRESHOLD_ALERT_SWAP 90.0
57
58 #define THRESHOLD_WARN_MEM 75.0
59 #define THRESHOLD_ALERT_MEM 90.0
60
61 #define THRESHOLD_WARN_DISK 75.0
62 #define THRESHOLD_ALERT_DISK 90.0
63
64 typedef struct{
65 sg_cpu_percents *cpu_percents;
66 sg_mem_stats *mem_stats;
67 sg_swap_stats *swap_stats;
68 sg_load_stats *load_stats;
69 sg_process_count *process_count;
70 sg_page_stats *page_stats;
71
72 sg_network_io_stats *network_io_stats;
73 int network_io_entries;
74
75 sg_disk_io_stats *disk_io_stats;
76 int disk_io_entries;
77
78 sg_fs_stats *fs_stats;
79 int fs_entries;
80
81 sg_host_info *host_info;
82 sg_user_stats *user_stats;
83 }stats_t;
84
85 stats_t stats;
86
87 char *size_conv(long long number){
88 char type[] = {'B', 'K', 'M', 'G', 'T'};
89 int x=0;
90 int sign=1;
91 static char string[10];
92
93 if(number < 0){
94 sign=-1;
95 number=-number;
96 }
97
98 for(;x<5;x++){
99 if( (number/1024) < (100)) {
100 break;
101 }
102 number = (number/1024);
103 }
104
105 number = number*sign;
106
107 snprintf(string, 10, "%lld%c", number, type[x]);
108 return string;
109
110 }
111
112 char *hr_uptime(time_t time){
113 int day = 0, hour = 0, min = 0;
114 static char uptime_str[25];
115 int sec = (int) time;
116
117 day = sec / (24*60*60);
118 sec = sec % (24*60*60);
119 hour = sec / (60*60);
120 sec = sec % (60*60);
121 min = sec / 60;
122 sec = sec % 60;
123
124 if(day){
125 snprintf(uptime_str, 25, "%dd %02d:%02d:%02d", day, hour, min, sec);
126 }else{
127 snprintf(uptime_str, 25, "%02d:%02d:%02d", hour, min, sec);
128 }
129 return uptime_str;
130 }
131
132 void display_headings(){
133 int line;
134
135 move(0,0);
136 printw("Hostname :");
137 move(0,27);
138 printw("Uptime : ");
139 move(0,54);
140 printw("Date : ");
141
142 /* Load */
143 move(2,0);
144 printw("Load 1 :");
145 move(3,0);
146 printw("Load 5 :");
147 move(4,0);
148 printw("Load 15 :");
149
150 /* CPU */
151 move(2,21);
152 printw("CPU Idle :");
153 move(3,21);
154 printw("CPU System:");
155 move(4,21);
156 printw("CPU User :");
157
158 /* Process */
159 move(2, 42);
160 printw("Running :");
161 move(3, 42);
162 printw("Sleeping :");
163 move(4, 42);
164 printw("Stopped :");
165 move(2, 62);
166 printw("Zombie :");
167 move(3, 62);
168 printw("Total :");
169 move(4, 62);
170 printw("No. Users :");
171
172 /* Mem */
173 move(6, 0);
174 printw("Mem Total :");
175 move(7, 0);
176 printw("Mem Used :");
177 move(8, 0);
178 printw("Mem Free :");
179
180 /* Swap */
181 move(6, 21);
182 printw("Swap Total:");
183 move(7, 21);
184 printw("Swap Used :");
185 move(8, 21);
186 printw("Swap Free :");
187
188 /* VM */
189 move(6, 42);
190 printw("Mem Used :");
191 move(7, 42);
192 printw("Swap Used :");
193 move(8, 42);
194 printw("Total Used:");
195
196 /* Paging */
197 move(6, 62);
198 printw("Paging in :");
199 move(7, 62);
200 printw("Paging out:");
201
202 /* Disk IO */
203 move(10,0);
204 printw("Disk Name");
205 move(10,15);
206 printw("Read");
207 move(10,28);
208 printw("Write");
209
210 line = 10;
211 if (stats.network_io_stats != NULL) {
212 /* Network IO */
213 move(line, 42);
214 printw("Network Interface");
215 move(line, 67);
216 printw("rx");
217 move(line, 77);
218 printw("tx");
219 line += 2 + stats.network_io_entries;
220 }
221
222 move(line, 42);
223 printw("Mount Point");
224 move(line, 65);
225 printw("Free");
226 move(line, 75);
227 printw("Used");
228
229 refresh();
230 }
231
232 void display_data(int colors){
233 char cur_time[20];
234 struct tm *tm_time;
235 time_t epoc_time;
236 int counter, line;
237 long long r,w;
238 long long rt, wt;
239 sg_disk_io_stats *disk_io_stat_ptr;
240 sg_network_io_stats *network_stat_ptr;
241 sg_fs_stats *disk_stat_ptr;
242 /* Size before it will start overwriting "uptime" */
243 char hostname[15];
244 char *ptr;
245
246 if (stats.host_info != NULL) {
247 move(0,12);
248 strncpy(hostname, stats.host_info->hostname, (sizeof(hostname) - 1));
249 /* strncpy does not NULL terminate.. If only strlcpy was on all platforms :) */
250 hostname[14] = '\0';
251 ptr=strchr(hostname, '.');
252 /* Some hosts give back a FQDN for hostname. To avoid this, we'll
253 * just blank out everything after the first "."
254 */
255 if (ptr != NULL){
256 *ptr = '\0';
257 }
258 if (colors) {
259 attron(COLOR_PAIR(1));
260 }
261 printw("%s", hostname);
262 move(0,36);
263 printw("%s", hr_uptime(stats.host_info->uptime));
264 epoc_time=time(NULL);
265 tm_time = localtime(&epoc_time);
266 strftime(cur_time, 20, "%Y-%m-%d %T", tm_time);
267 move(0,61);
268 printw("%s", cur_time);
269 if (colors) {
270 attroff(COLOR_PAIR(1));
271 }
272 }
273
274 if (stats.load_stats != NULL) {
275 /* Load */
276 if (colors) {
277 attron(COLOR_PAIR(6));
278 }
279 move(2,12);
280 if (colors && fabs(stats.load_stats->min1 - stats.load_stats->min5) > THRESHOLD_LOAD) {
281 attron(A_BOLD);
282 }
283 printw("%6.2f", stats.load_stats->min1);
284 if (colors) {
285 attroff(A_BOLD);
286 }
287 move(3,12);
288 if (colors && fabs(stats.load_stats->min5 - stats.load_stats->min15) > THRESHOLD_LOAD) {
289 attron(A_BOLD);
290 }
291 printw("%6.2f", stats.load_stats->min5);
292 if (colors) {
293 attroff(A_BOLD);
294 }
295 move(4,12);
296 if (colors && fabs(stats.load_stats->min1 - stats.load_stats->min15) > THRESHOLD_LOAD) {
297 attron(A_BOLD);
298 }
299 printw("%6.2f", stats.load_stats->min15);
300 if (colors) {
301 attroff(A_BOLD);
302 }
303 }
304
305 if (stats.cpu_percents != NULL) {
306 /* CPU */
307 move(2,33);
308 printw("%6.2f%%", stats.cpu_percents->idle);
309 move(3,33);
310 printw("%6.2f%%", (stats.cpu_percents->kernel + stats.cpu_percents->iowait + stats.cpu_percents->swap));
311 move(4,33);
312 if (colors && stats.cpu_percents->user + stats.cpu_percents->nice > THRESHOLD_ALERT_CPU) {
313 attron(A_STANDOUT);
314 attron(A_BOLD);
315 }
316 else if (colors && stats.cpu_percents->user + stats.cpu_percents->nice > THRESHOLD_WARN_CPU) {
317 attron(A_BOLD);
318 }
319 printw("%6.2f%%", (stats.cpu_percents->user + stats.cpu_percents->nice));
320 if(colors) {
321 attroff(A_BOLD);
322 attroff(A_STANDOUT);
323 attron(COLOR_PAIR(6));
324 }
325 }
326
327 if (stats.process_count != NULL) {
328 /* Process */
329 move(2, 54);
330 printw("%5d", stats.process_count->running);
331 move(2,74);
332 if (colors && stats.process_count->zombie > THRESHOLD_WARN_ZMB) {
333 attron(A_STANDOUT);
334 attron(A_BOLD);
335 }
336 printw("%5d", stats.process_count->zombie);
337 if(colors) {
338 attroff(A_STANDOUT);
339 attroff(A_BOLD);
340 }
341 move(3, 54);
342 printw("%5d", stats.process_count->sleeping);
343 move(3, 74);
344 printw("%5d", stats.process_count->total);
345 move(4, 54);
346 printw("%5d", stats.process_count->stopped);
347 }
348 if (stats.user_stats != NULL) {
349 move(4,74);
350 printw("%5d", stats.user_stats->num_entries);
351 }
352
353 if(colors) {
354 attroff(COLOR_PAIR(6));
355 attron(COLOR_PAIR(5));
356 }
357 if (stats.mem_stats != NULL) {
358 /* Mem */
359 move(6, 12);
360 printw("%7s", size_conv(stats.mem_stats->total));
361 move(7, 12);
362 printw("%7s", size_conv(stats.mem_stats->used));
363 move(8, 12);
364 printw("%7s", size_conv(stats.mem_stats->free));
365 }
366
367 if (stats.swap_stats != NULL) {
368 /* Swap */
369 move(6, 32);
370 printw("%8s", size_conv(stats.swap_stats->total));
371 move(7, 32);
372 printw("%8s", size_conv(stats.swap_stats->used));
373 move(8, 32);
374 printw("%8s", size_conv(stats.swap_stats->free));
375 }
376
377 /* VM */
378 if (stats.mem_stats != NULL && stats.mem_stats->total != 0) {
379 float f = 100.00 * (float)(stats.mem_stats->used)/stats.mem_stats->total;
380 if (colors && f > THRESHOLD_ALERT_MEM) {
381 attron(A_STANDOUT);
382 attron(A_BOLD);
383 }
384 else if (colors && f > THRESHOLD_WARN_MEM) {
385 attron(A_BOLD);
386 }
387 move(6, 54);
388 printw("%5.2f%%", f);
389 if (colors) {
390 attroff(A_STANDOUT);
391 attroff(A_BOLD);
392 attron(COLOR_PAIR(5));
393 }
394 }
395 if (stats.swap_stats != NULL && stats.swap_stats->total != 0) {
396 float f = 100.00 * (float)(stats.swap_stats->used)/stats.swap_stats->total;
397 if (colors && f > THRESHOLD_ALERT_SWAP) {
398 attron(A_STANDOUT);
399 attron(A_BOLD);
400 }
401 else if (colors && f > THRESHOLD_WARN_SWAP) {
402 attron(A_BOLD);
403 }
404 move(7, 54);
405 printw("%5.2f%%", f);
406 if (colors) {
407 attroff(A_STANDOUT);
408 attroff(A_BOLD);
409 attron(COLOR_PAIR(5));
410 }
411 }
412 if (stats.mem_stats != NULL && stats.swap_stats != NULL &&
413 stats.mem_stats->total != 0 && stats.swap_stats->total != 0) {
414 move(8, 54);
415 printw("%5.2f%%", (100.00 * (float)(stats.mem_stats->used+stats.swap_stats->used)/(stats.mem_stats->total+stats.swap_stats->total)));
416 }
417
418 if (stats.page_stats != NULL) {
419 /* Paging */
420 move(6, 74);
421 printw("%5d", (stats.page_stats->systime)? (stats.page_stats->pages_pagein / stats.page_stats->systime): stats.page_stats->pages_pagein);
422 move(7, 74);
423 printw("%5d", (stats.page_stats->systime)? (stats.page_stats->pages_pageout / stats.page_stats->systime) : stats.page_stats->pages_pageout);
424 }
425 if (colors) {
426 attroff(COLOR_PAIR(5));
427 }
428
429 line = 11;
430 if (stats.disk_io_stats != NULL) {
431 /* Disk IO */
432 disk_io_stat_ptr = stats.disk_io_stats;
433 r=0;
434 w=0;
435 for(counter=0;counter<stats.disk_io_entries;counter++){
436 char name[12];
437 strncpy(name, disk_io_stat_ptr->disk_name, sizeof(name));
438 name[sizeof(name)-1] = '\0'; /* strncpy doesn't terminate longer strings */
439 move(line, 0);
440 printw("%s", name);
441 move(line, 12);
442 rt = (disk_io_stat_ptr->systime)? (disk_io_stat_ptr->read_bytes/disk_io_stat_ptr->systime): disk_io_stat_ptr->read_bytes;
443 if(colors) {
444 attron(COLOR_PAIR(4));
445 }
446 printw("%7s", size_conv(rt));
447 r+=rt;
448 move(line, 26);
449 wt = (disk_io_stat_ptr->systime)? (disk_io_stat_ptr->write_bytes/disk_io_stat_ptr->systime): disk_io_stat_ptr->write_bytes;
450 printw("%7s", size_conv(wt));
451 w+=wt;
452 disk_io_stat_ptr++;
453 line++;
454 if(colors) {
455 attroff(COLOR_PAIR(4));
456 }
457 }
458 line++;
459 move(line, 0);
460 printw("Total");
461 move(line, 12);
462 if(colors) {
463 attron(COLOR_PAIR(4));
464 }
465 printw("%7s", size_conv(r));
466 move(line, 26);
467 printw("%7s", size_conv(w));
468 if(colors) {
469 attroff(COLOR_PAIR(4));
470 }
471 }
472
473 line = 11;
474 if (stats.network_io_stats != NULL) {
475 /* Network */
476 network_stat_ptr = stats.network_io_stats;
477 for(counter=0;counter<stats.network_io_entries;counter++){
478 char name[20];
479 strncpy(name, network_stat_ptr->interface_name, sizeof(name));
480 name[sizeof(name)-1] = '\0'; /* strncpy doesn't terminate longer strings */
481 move(line, 42);
482 printw("%s", name);
483 move(line, 62);
484 rt = (network_stat_ptr->systime)? (network_stat_ptr->rx / network_stat_ptr->systime): network_stat_ptr->rx;
485 if(colors) {
486 attron(COLOR_PAIR(4));
487 }
488 printw("%7s", size_conv(rt));
489 move(line, 72);
490 wt = (network_stat_ptr->systime)? (network_stat_ptr->tx / network_stat_ptr->systime): network_stat_ptr->tx;
491 printw("%7s", size_conv(wt));
492 network_stat_ptr++;
493 line++;
494 if(colors) {
495 attroff(COLOR_PAIR(4));
496 }
497 }
498 line += 2;
499 }
500
501 if (stats.fs_stats != NULL) {
502 /* Disk */
503 disk_stat_ptr = stats.fs_stats;
504 for(counter=0;counter<stats.fs_entries;counter++){
505 char name[20];
506 strncpy(name, disk_stat_ptr->mnt_point, sizeof(name));
507 name[sizeof(name)-1] = '\0'; /* strncpy doesn't terminate longer strings */
508 move(line, 42);
509 printw("%s", name);
510 move(line, 62);
511 if(colors) {
512 attron(COLOR_PAIR(2));
513 }
514 printw("%7s", size_conv(disk_stat_ptr->avail));
515 move(line, 73);
516 if(colors && 100.00 * ((float) disk_stat_ptr->used / (float) (disk_stat_ptr->used + disk_stat_ptr->avail)) > THRESHOLD_ALERT_DISK) {
517 attron(A_STANDOUT);
518 attron(A_BOLD);
519 } else if (colors && 100.00 * ((float) disk_stat_ptr->used / (float) (disk_stat_ptr->used + disk_stat_ptr->avail)) > THRESHOLD_WARN_DISK) {
520 attron(A_BOLD);
521 }
522 printw("%6.2f%%", 100.00 * ((float) disk_stat_ptr->used / (float) (disk_stat_ptr->used + disk_stat_ptr->avail)));
523 disk_stat_ptr++;
524 line++;
525 if(colors) {
526 attroff(COLOR_PAIR(2));
527 attroff(A_STANDOUT);
528 attroff(A_BOLD);
529 }
530 }
531 }
532
533 refresh();
534 }
535
536 void sig_winch_handler(int dummy){
537 clear();
538 display_headings();
539 display_data(0);
540 signal(SIGWINCH, sig_winch_handler);
541 }
542
543 int get_stats(){
544 stats.cpu_percents = sg_get_cpu_percents();
545 stats.mem_stats = sg_get_mem_stats();
546 stats.swap_stats = sg_get_swap_stats();
547 stats.load_stats = sg_get_load_stats();
548 stats.process_count = sg_get_process_count();
549 stats.page_stats = sg_get_page_stats_diff();
550 stats.network_io_stats = sg_get_network_io_stats_diff(&(stats.network_io_entries));
551 stats.disk_io_stats = sg_get_disk_io_stats_diff(&(stats.disk_io_entries));
552 stats.fs_stats = sg_get_fs_stats(&(stats.fs_entries));
553 stats.host_info = sg_get_host_info();
554 stats.user_stats = sg_get_user_stats();
555
556 return 1;
557 }
558
559 void version_num(char *progname){
560 fprintf(stderr, "%s version %s\n", progname, PACKAGE_VERSION);
561 fprintf(stderr, "\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
562 exit(1);
563 }
564
565 void usage(char *progname){
566 #ifdef COLOR_SUPPORT
567 fprintf(stderr, "Usage: %s [-d delay] [-c] [-v] [-h]\n\n", progname);
568 #else
569 fprintf(stderr, "Usage: %s [-d delay] [-v] [-h]\n\n", progname);
570 #endif
571 fprintf(stderr, " -d Sets the update time in seconds\n");
572 #ifdef COLOR_SUPPORT
573 fprintf(stderr, " -c Enables coloured output\n");
574 #endif
575 fprintf(stderr, " -v Prints version number\n");
576 fprintf(stderr, " -h Displays this help information.\n");
577 fprintf(stderr, "\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
578 exit(1);
579 }
580
581 int main(int argc, char **argv){
582 extern char *optarg;
583 int c;
584 int colouron = 0;
585
586 time_t last_update = 0;
587
588 WINDOW *window;
589
590 extern int errno;
591
592 int delay=2;
593
594 sg_init();
595 if(sg_drop_privileges() != 0){
596 fprintf(stderr, "Failed to drop setuid/setgid privileges\n");
597 return 1;
598 }
599
600 #ifdef COLOR_SUPPORT
601 while ((c = getopt(argc, argv, "d:cvh")) != -1){
602 #else
603 while ((c = getopt(argc, argv, "d:vh")) != -1){
604 #endif
605 switch (c){
606 case 'd':
607 delay = atoi(optarg);
608 if (delay < 1){
609 fprintf(stderr, "Time must be 1 second or greater\n");
610 exit(1);
611 }
612 break;
613 #ifdef COLOR_SUPPORT
614 case 'c':
615 colouron = 1;
616 break;
617 #endif
618 case 'v':
619 version_num(argv[0]);
620 break;
621 case 'h':
622 default:
623 usage(argv[0]);
624 return 1;
625 break;
626 }
627 }
628
629 signal(SIGWINCH, sig_winch_handler);
630 initscr();
631 #ifdef COLOR_SUPPORT
632 /* turn on colour */
633 if (colouron) {
634 if (has_colors()) {
635 start_color();
636 use_default_colors();
637 init_pair(1,COLOR_RED,-1);
638 init_pair(2,COLOR_GREEN,-1);
639 init_pair(3,COLOR_YELLOW,-1);
640 init_pair(4,COLOR_BLUE,-1);
641 init_pair(5,COLOR_MAGENTA,-1);
642 init_pair(6,COLOR_CYAN,-1);
643 } else {
644 fprintf(stderr, "Colour support disabled: your terminal does not support colour.");
645 colouron = 0;
646 }
647 }
648 #endif
649 nonl();
650 cbreak();
651 noecho();
652 timeout(delay * 1000);
653 window=newwin(0, 0, 0, 0);
654 clear();
655
656 if(!get_stats()){
657 fprintf(stderr, "Failed to get all the stats. Please check correct permissions\n");
658 endwin();
659 return 1;
660 }
661
662 display_headings();
663
664 for(;;){
665 time_t now;
666 int ch = getch();
667
668 if (ch == 'q'){
669 break;
670 }
671
672 /* To keep the numbers slightly accurate we do not want them
673 * updating more frequently than once a second.
674 */
675 now = time(NULL);
676 if ((now - last_update) >= 1) {
677 get_stats();
678 }
679 last_update = now;
680
681 display_data(colouron);
682 }
683
684 endwin();
685 return 0;
686 }