ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/saidar/saidar.c
Revision: 1.39
Committed: Fri Dec 1 14:21:17 2006 UTC (17 years, 11 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.38: +2 -4 lines
Log Message:
Sort out curses detection. It'll now detect ncurses before curses, and
cope with the header files being in include or include/ncurses. I think
this will work in every case.

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