ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.15
Committed: Thu Apr 10 12:31:19 2003 UTC (21 years, 7 months ago) by pajs
Content type: text/plain
Branch: MAIN
CVS Tags: IDAR_1_1
Changes since 1.14: +100 -73 lines
Log Message:
Proper resize support by catching SIGWINCH. Done some tiding. Added the ability
to do process stats (r).

Changed the megabytes units to have 2d.p. so it would show more than units of
100k/sec.

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org.uk
4 * Copyright (C) 2000-2002 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
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <ukcprog.h>
32 #include <netinet/in.h>
33 #include <netdb.h>
34 #include <sys/termios.h>
35 #include <signal.h>
36 #include <errno.h>
37
38 #include <libxml/xmlmemory.h>
39 #include <libxml/parser.h>
40 #include "genmergesort.h"
41
42 #ifdef HAVE_NCURSES_H
43 #include <ncurses.h>
44 #else
45 #include <curses.h>
46 #endif
47
48 struct host_line_t{
49 char *hostname;
50 int line;
51
52 struct host_line_t *next;
53 };
54 typedef struct host_line_t host_line_list_t;
55
56 struct diskio_data_t{
57 char *name;
58
59 long long read;
60 long long write;
61
62 struct diskio_data_t *next;
63 };
64 typedef struct diskio_data_t diskio_data_list_t;
65
66 struct network_data_t{
67 char *name;
68
69 long long rx;
70 long long tx;
71
72 struct network_data_t *next;
73 };
74 typedef struct network_data_t network_data_list_t;
75
76 /*
77 struct disk_data_t{
78 char *name;
79 char *mount_pnt;
80
81 long long total_space;
82 long long total_used;
83 long long total_avail;
84 // Other data we are less intrested in are not stored
85
86 struct disk_data_t *next;
87 };
88 typedef struct disk_data_t disk_data_list_t;
89 */
90 #define MAXHOSTNAMESIZE 10
91 struct machine_data_t{
92
93 char *name;
94
95 char sysname[MAXHOSTNAMESIZE+1];
96
97 double cpu_user;
98 double cpu_idle;
99 double cpu_iowait;
100 double cpu_kernel;
101 double cpu_swap;
102 double cpu_used; /* 100 - idle */
103
104 long long memory_total;
105 long long memory_free;
106 long long memory_used;
107 double memory_used_pecent;
108
109 long long swap_total;
110 long long swap_free;
111 long long swap_used;
112 double swap_used_pecent;
113
114 int pages_in;
115 int pages_out;
116
117 double load_1;
118 double load_5;
119 double load_15;
120
121 int processes_total;
122 int processes_sleeping;
123 int processes_cpu;
124 int processes_zombie;
125 int processes_stopped;
126
127 network_data_list_t *network_data_list;
128 long long network_io_total_tx;
129 long long network_io_total_rx;
130 long long network_io_total;
131
132 diskio_data_list_t *diskio_data_list;
133 long long disk_io_total_write;
134 long long disk_io_total_read;
135 long long disk_io_total;
136
137 /* Maybe in the future */
138 /*
139 disk_data_list_t disk_data_list;
140 double disk_total_used;
141 */
142
143 struct machine_data_t *next;
144 };
145
146 typedef struct machine_data_t machine_data_list_t;
147
148 #define SORTBYMAXNAME 128
149 typedef struct{
150 int maxx;
151 int maxy;
152
153 char units;
154
155 int cpu_user;
156 int cpu_idle;
157 int cpu_iowait;
158 int cpu_kernel;
159 int cpu_swap;
160 int cpu_used;
161
162 int memory_total;
163 int memory_free;
164 int memory_used;
165 int memory_used_pecent;
166
167 int swap_total;
168 int swap_free;
169 int swap_used;
170 int swap_used_pecent;
171
172 int load_1;
173 int load_5;
174 int load_15;
175
176 int pages_in;
177 int pages_out;
178
179 int processes;
180
181 int network_io_total_tx;
182 int network_io_total_rx;
183 int network_all_stats;
184
185 int disk_io_total_write;
186 int disk_io_total_read;
187 int disk_io_all_stats;
188
189 int disk_total_used;
190 int disk_all_stats;
191
192 char sortby[SORTBYMAXNAME];
193 }display_config_t;
194
195 GENERIC_MERGE_SORT(static, sort_machine_stats, machine_data_list_t, next)
196
197 #define MKCMP(x) int cmp_##x(machine_data_list_t *a, machine_data_list_t *b){return ((a->x) == (b->x)? 0 : (((a->x) > (b->x))? -1 : 1));}
198
199
200 int (*sortby_ptr)(machine_data_list_t *a, machine_data_list_t *b);
201
202 MKCMP(cpu_used)
203 MKCMP(load_1)
204 MKCMP(network_io_total)
205 MKCMP(network_io_total_tx)
206 MKCMP(network_io_total_rx)
207 MKCMP(disk_io_total)
208 MKCMP(disk_io_total_write)
209 MKCMP(disk_io_total_read)
210 MKCMP(memory_used_pecent)
211 MKCMP(swap_used_pecent)
212
213 #define CPU_USED "CPU used"
214 #define LOAD "Load (1)"
215 #define NETIORX "total Network RX for all interfaces"
216 #define NETIOTX "total Network TX for all interfaces"
217 #define NETIO "total Network IO for all interfaces (rx+tx)"
218 #define MEM "Memory usage"
219 #define SWAP "Swap usage"
220 #define DISKIOR "DiskIO reads"
221 #define DISKIOW "DiskIO writes"
222 #define DISKIO "Total DiskIO (reads+writes)"
223
224 int sig_winch=0;
225
226 #ifndef HAVE_ATOLL
227 long long int atoll (const char *nptr){
228 return strtoll (nptr, (char **) NULL, 10);
229 }
230 #endif
231
232 #ifndef HAVE_STRLCPY
233 /*
234 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
235 * All rights reserved.
236 *
237 * Redistribution and use in source and binary forms, with or without
238 * modification, are permitted provided that the following conditions
239 * are met:
240 * 1. Redistributions of source code must retain the above copyright
241 * notice, this list of conditions and the following disclaimer.
242 * 2. Redistributions in binary form must reproduce the above copyright
243 * notice, this list of conditions and the following disclaimer in the
244 * documentation and/or other materials provided with the distribution.
245 * 3. The name of the author may not be used to endorse or promote products
246 * derived from this software without specific prior written permission.
247 *
248 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
249 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
250 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
251 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
252 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
253 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
254 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
255 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
256 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
257 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258 */
259
260 /*
261 * Copy src to string dst of size siz. At most siz-1 characters
262 * will be copied. Always NUL terminates (unless siz == 0).
263 * Returns strlen(src); if retval >= siz, truncation occurred.
264 */
265 size_t
266 strlcpy(dst, src, siz)
267 char *dst;
268 const char *src;
269 size_t siz;
270 {
271 register char *d = dst;
272 register const char *s = src;
273 register size_t n = siz;
274
275 /* Copy as many bytes as will fit */
276 if (n != 0 && --n != 0) {
277 do {
278 if ((*d++ = *s++) == 0)
279 break;
280 } while (--n != 0);
281 }
282
283 /* Not enough room in dst, add NUL and traverse rest of src */
284 if (n == 0) {
285 if (siz != 0)
286 *d = '\0'; /* NUL-terminate dst */
287 while (*s++)
288 ;
289 }
290
291 return(s - src - 1); /* count does not include NUL */
292 }
293
294 #endif
295
296
297 FILE *create_tcp_connection(char *hostname, int port){
298 int sock;
299 struct sockaddr_in addr;
300 struct in_addr haddr;
301 FILE *f;
302
303 if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){
304 return NULL;
305 }
306
307 if((get_host_addr(hostname, &haddr))!=0){
308 close(sock);
309 return NULL;
310 }
311
312 memset(&addr, 0, sizeof(addr));
313 addr.sin_family = AF_INET;
314 memcpy(&addr.sin_addr, &haddr, sizeof(haddr));
315 addr.sin_port = htons(port);
316
317 if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){
318 close(sock);
319 return NULL;
320 }
321
322 if((f=fdopen(sock, "r+"))==NULL){
323 close(sock);
324 return NULL;
325 }
326
327 return f;
328 }
329
330 int tcp_comm(FILE *f, char *send, char **response, char *expected){
331
332 if(send!=NULL){
333 fprintf(f, "%s\n", send);
334 }
335 fflush(f);
336 *response=fpgetline(f);
337 fseek(f, 0, SEEK_CUR);
338
339 if( (*response==NULL) || (strcmp(*response, "ERROR")==0) ) return -1;
340
341 if(expected==NULL) return 0;
342
343 if((strcmp(expected, *response))==0) return 0;
344
345 return -1;
346 }
347
348 /* Takes a xml char * and a machine_data_list_t. This will parse
349 * the xml and put it into the correct entry of the machine_data
350 * linked list. This will return the number of entries in the linked
351 * list, or -1 on a error.
352 */
353 int parse_xml(char *xml, machine_data_list_t **md){
354 xmlDocPtr doc;
355 xmlNodePtr cur;
356 xmlNodePtr ele;
357 xmlAttr *list;
358
359 static int num_hosts=0;
360
361 machine_data_list_t *machine_data_list=*md;
362
363 int found_host=0;
364
365 char *hostname=NULL;
366 network_data_list_t *network_data_list=NULL;
367 network_data_list_t *ndl_ptr=NULL;
368 diskio_data_list_t *diskio_data_list=NULL;
369 diskio_data_list_t *didl_ptr=NULL;
370 char *tmp;
371
372 doc=xmlParseDoc(xml);
373 if(doc==NULL) return -1;
374
375 cur = xmlDocGetRootElement(doc);
376 if(cur==NULL){
377 xmlFreeDoc(doc);
378 return -1;
379 }
380
381
382 /* Get the hostname */
383 list=cur->properties;
384 while(list!=NULL){
385 if((xmlStrcmp(list->name, (const xmlChar *) "machine_name"))==0){
386 hostname = xmlNodeGetContent(list->children);
387 if(hostname==NULL){
388 return -1;
389 }
390 }
391 list=list->next;
392 }
393 if(hostname==NULL){
394 return -1;
395 }
396
397 /* Get machine_data for host.. Or create if it doesn't have one */
398 while(machine_data_list!=NULL){
399 if((strncmp(machine_data_list->name, hostname, strlen(hostname)))==0){
400 found_host=1;
401 break;
402 }
403 machine_data_list=machine_data_list->next;
404 }
405
406 if(!found_host){
407 /* We didn't find this host, but we should be at the end of the list */
408 machine_data_list=malloc(sizeof(machine_data_list_t));
409 if(machine_data_list==NULL) return -1;
410 machine_data_list->next=(*md);
411 machine_data_list->name=hostname;
412 machine_data_list->network_data_list=NULL;
413 machine_data_list->diskio_data_list=NULL;
414 *md=machine_data_list;
415 num_hosts++;
416 }
417
418 /* Now we want to pull out the data */
419
420 cur = cur->xmlChildrenNode;
421 while(cur != NULL) {
422 ele=cur->xmlChildrenNode;
423 while(ele != NULL){
424
425 /* CPU Stats */
426 if(!xmlStrcmp(cur->name, (const xmlChar *) "cpu")){
427 tmp=xmlNodeGetContent(ele);
428 if(!xmlStrcmp(ele->name, (const xmlChar *) "user")){
429 machine_data_list->cpu_user=atof(tmp);
430 }
431 if(!xmlStrcmp(ele->name, (const xmlChar *) "kernel")){
432 machine_data_list->cpu_kernel=atof(tmp);
433 }
434 if(!xmlStrcmp(ele->name, (const xmlChar *) "idle")){
435 machine_data_list->cpu_idle=atof(tmp);
436 }
437 if(!xmlStrcmp(ele->name, (const xmlChar *) "iowait")){
438 machine_data_list->cpu_iowait=atof(tmp);
439 }
440 if(!xmlStrcmp(ele->name, (const xmlChar *) "swap")){
441 machine_data_list->cpu_iowait=atof(tmp);
442 }
443
444 if(tmp!=NULL) xmlFree(tmp);
445 }
446
447 /* Memory Stats */
448 if(!xmlStrcmp(cur->name, (const xmlChar *) "memory")){
449 tmp=xmlNodeGetContent(ele);
450 if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
451 machine_data_list->memory_total=atoll(tmp);
452 }
453 if(!xmlStrcmp(ele->name, (const xmlChar *) "free")){
454 machine_data_list->memory_free=atoll(tmp);
455 }
456 if(!xmlStrcmp(ele->name, (const xmlChar *) "used")){
457 machine_data_list->memory_used=atoll(tmp);
458 }
459
460 if(tmp!=NULL) xmlFree(tmp);
461 }
462
463 /* Load Stats */
464 if(!xmlStrcmp(cur->name, (const xmlChar *) "load")){
465 tmp=xmlNodeGetContent(ele);
466 if(!xmlStrcmp(ele->name, (const xmlChar *) "load1")){
467 machine_data_list->load_1=atof(tmp);
468 }
469 if(!xmlStrcmp(ele->name, (const xmlChar *) "load5")){
470 machine_data_list->load_5=atof(tmp);
471 }
472 if(!xmlStrcmp(ele->name, (const xmlChar *) "load15")){
473 machine_data_list->load_15=atof(tmp);
474 }
475
476 if(tmp!=NULL) xmlFree(tmp);
477 }
478
479 /* swap stats */
480 if(!xmlStrcmp(cur->name, (const xmlChar *) "swap")){
481 tmp=xmlNodeGetContent(ele);
482 if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
483 machine_data_list->swap_total=atoll(tmp);
484 }
485 if(!xmlStrcmp(ele->name, (const xmlChar *) "free")){
486 machine_data_list->swap_free=atoll(tmp);
487 }
488 if(!xmlStrcmp(ele->name, (const xmlChar *) "used")){
489 machine_data_list->swap_used=atoll(tmp);
490 }
491
492 if(tmp!=NULL) xmlFree(tmp);
493 }
494
495 /* Process stat */
496 if(!xmlStrcmp(cur->name, (const xmlChar *) "processes")){
497 tmp=xmlNodeGetContent(ele);
498 if(!xmlStrcmp(ele->name, (const xmlChar *) "sleeping")){
499 machine_data_list->processes_sleeping=atoi(tmp);
500 }
501 if(!xmlStrcmp(ele->name, (const xmlChar *) "cpu")){
502 machine_data_list->processes_cpu=atoi(tmp);
503 }
504 if(!xmlStrcmp(ele->name, (const xmlChar *) "zombie")){
505 machine_data_list->processes_zombie=atoi(tmp);
506 }
507 if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
508 machine_data_list->processes_total=atoi(tmp);
509 }
510
511 if(tmp!=NULL) xmlFree(tmp);
512 }
513
514 /* paging stats */
515 if(!xmlStrcmp(cur->name, (const xmlChar *) "pages")){
516 tmp=xmlNodeGetContent(ele);
517 if(!xmlStrcmp(ele->name, (const xmlChar *) "pageins")){
518 machine_data_list->pages_in=atoi(tmp);
519 }
520 if(!xmlStrcmp(ele->name, (const xmlChar *) "pageouts")){
521 machine_data_list->pages_out=atoi(tmp);
522 }
523
524 if(tmp!=NULL) xmlFree(tmp);
525 }
526
527 /* OS stats */
528 if(!xmlStrcmp(cur->name, (const xmlChar *) "os")){
529 tmp=xmlNodeGetContent(ele);
530 if(!xmlStrcmp(ele->name, (const xmlChar *) "sysname")){
531 strlcpy(machine_data_list->sysname, tmp, MAXHOSTNAMESIZE+1);
532 }
533 if(tmp!=NULL) xmlFree(tmp);
534 }
535
536 /* Network stats */
537 /* Needs to connect current stat to a previous one. Or create it if new */
538 /* Get name.. Walk list. If match, copy rx/tx values. Else malloc, add to list */
539 if(!xmlStrcmp(cur->name, (const xmlChar *) "net")){
540
541 list=ele->properties;
542 if(list==NULL) continue;
543 network_data_list=malloc(sizeof(network_data_list_t));
544 if(network_data_list==NULL) return -1;
545 while(list!=NULL){
546 tmp=xmlNodeGetContent(list->children);
547 if(!xmlStrcmp(list->name, (const xmlChar *) "name")){
548 network_data_list->name=strdup(tmp);
549 }
550 if(!xmlStrcmp(list->name, (const xmlChar *) "rx")){
551 network_data_list->rx=atoll(tmp);
552 }
553 if(!xmlStrcmp(list->name, (const xmlChar *) "tx")){
554 network_data_list->tx=atoll(tmp);
555 }
556
557 xmlFree(tmp);
558 list=list->next;
559 }
560 if(network_data_list->name==NULL) continue;
561 found_host=0;
562 ndl_ptr=machine_data_list->network_data_list;
563 while(ndl_ptr!=NULL){
564 if(!strcmp(ndl_ptr->name, network_data_list->name)){
565 found_host=1;
566 break;
567 }
568 ndl_ptr=ndl_ptr->next;
569 }
570 if(found_host){
571 ndl_ptr->rx=network_data_list->rx;
572 ndl_ptr->tx=network_data_list->tx;
573 free(network_data_list->name);
574 free(network_data_list);
575 }else{
576 network_data_list->next=machine_data_list->network_data_list;
577 machine_data_list->network_data_list=network_data_list;
578 }
579 }
580
581 /* Disk IO stats */
582 if(!xmlStrcmp(cur->name, (const xmlChar *) "diskio")){
583
584 list=ele->properties;
585 if(list==NULL) continue;
586 diskio_data_list=malloc(sizeof(diskio_data_list_t));
587 if(diskio_data_list==NULL) return -1;
588 while(list!=NULL){
589 tmp=xmlNodeGetContent(list->children);
590 if(!xmlStrcmp(list->name, (const xmlChar *) "name")){
591 diskio_data_list->name=strdup(tmp);
592 }
593 if(!xmlStrcmp(list->name, (const xmlChar *) "rbytes")){
594 diskio_data_list->read=atoll(tmp);
595 }
596 if(!xmlStrcmp(list->name, (const xmlChar *) "wbytes")){
597 diskio_data_list->write=atoll(tmp);
598 }
599
600 xmlFree(tmp);
601 list=list->next;
602 }
603 if(diskio_data_list->name==NULL) continue;
604 found_host=0;
605 didl_ptr=machine_data_list->diskio_data_list;
606 while(didl_ptr!=NULL){
607 if(!strcmp(didl_ptr->name, diskio_data_list->name)){
608 found_host=1;
609 break;
610 }
611 didl_ptr=didl_ptr->next;
612 }
613 if(found_host){
614 didl_ptr->read=diskio_data_list->read;
615 didl_ptr->write=diskio_data_list->write;
616 free(diskio_data_list->name);
617 free(diskio_data_list);
618 }else{
619 diskio_data_list->next=machine_data_list->diskio_data_list;
620 machine_data_list->diskio_data_list=diskio_data_list;
621 }
622 }
623
624
625
626 ele=ele->next;
627 }
628 cur=cur->next;
629 }
630
631 /* Append data we want thats not stored in the server */
632 machine_data_list->cpu_used=100.00-machine_data_list->cpu_idle;
633 machine_data_list->memory_used_pecent=((double)machine_data_list->memory_used / (double)machine_data_list->memory_total) * 100.00;
634 machine_data_list->swap_used_pecent=((double)machine_data_list->swap_used / (double)machine_data_list->swap_total) * 100.00;
635
636 ndl_ptr=machine_data_list->network_data_list;
637 machine_data_list->network_io_total_tx=0;
638 machine_data_list->network_io_total_rx=0;
639 while(ndl_ptr!=NULL){
640 machine_data_list->network_io_total_tx+=ndl_ptr->tx;
641 machine_data_list->network_io_total_rx+=ndl_ptr->rx;
642 ndl_ptr=ndl_ptr->next;
643 }
644 machine_data_list->network_io_total=machine_data_list->network_io_total_rx+machine_data_list->network_io_total_tx;
645
646 didl_ptr=machine_data_list->diskio_data_list;
647 machine_data_list->disk_io_total_read=0;
648 machine_data_list->disk_io_total_write=0;
649 while(didl_ptr!=NULL){
650 machine_data_list->disk_io_total_read+=didl_ptr->read;
651 machine_data_list->disk_io_total_write+=didl_ptr->write;
652 didl_ptr=didl_ptr->next;
653 }
654 machine_data_list->disk_io_total=machine_data_list->disk_io_total_read+machine_data_list->disk_io_total_write;
655
656 xmlFreeDoc(doc);
657
658 return num_hosts;
659
660
661 }
662
663 void display(machine_data_list_t *machine_data_list, display_config_t *display_config, int *title){
664 int line_num=4;
665 int counter;
666 int x=1;
667
668 if(*title){
669 clear();
670 move (display_config->maxy-3, 1);
671 printw("Sorting by %-64s", display_config->sortby);
672 move (display_config->maxy-2, 1);
673 if(display_config->units == 'b'){
674 printw("Units are measured in bytes/sec");
675 }
676 if(display_config->units == 'k'){
677 printw("Units are measured in kilobytes/sec");
678 }
679 if(display_config->units == 'm'){
680 printw("Units are measured in megabytes/sec");
681 }
682
683 move(1,1);
684 printw("%-11s", "Hostname");
685 x=x+11+1;
686 if(display_config->cpu_used && (display_config->maxx > x+6)){
687 move(1,x);
688 printw("%5s", "CPU");
689 move(2,x);
690 printw("%5s", "used%");
691 x+=6;
692 }
693 if(display_config->load_1 && (display_config->maxx > x+6)){
694 move(1,x);
695 printw("%5s", "Load");
696 move(2,x);
697 printw("%5s", "(1m)");
698 x+=6;
699 }
700
701 if(display_config->pages_in && (display_config->maxx > x+6)){
702 move(1,x);
703 printw("%5s", "Page");
704 move(2,x);
705 printw("%5s", "ins");
706 x+=6;
707 }
708
709 if(display_config->pages_out && (display_config->maxx > x+6)){
710 move(1,x);
711 printw("%5s", "Page");
712 move(2,x);
713 printw("%5s", "outs");
714 x+=6;
715 }
716
717 if(display_config->memory_used_pecent && (display_config->maxx > x+6)){
718 move(1,x);
719 printw("%5s", "Mem");
720 move(2,x);
721 printw("%5s", "used");
722 x+=6;
723 }
724
725 if(display_config->swap_used_pecent && (display_config->maxx > x+6)){
726 move(1,x);
727 printw("%5s", "Swap");
728 move(2,x);
729 printw("%5s", "used");
730 x+=6;
731 }
732
733 if(display_config->network_io_total_rx){
734 if(display_config->units=='b' && (display_config->maxx > x+9)){
735 move(1,x);
736 printw("%8s", "Net");
737 move(2,x);
738 printw("%8s", "rx");
739 x+=9;
740 }
741
742 if(display_config->units=='k' && (display_config->maxx > x+6)){
743 move(1,x);
744 printw("%5s", "Net");
745 move(2,x);
746 printw("%5s", "rx");
747 x+=6;
748 }
749
750 if(display_config->units=='m' && (display_config->maxx > x+6)){
751 move(1,x);
752 printw("%5s", "Net");
753 move(2,x);
754 printw("%5s", "rx");
755 x+=6;
756 }
757
758 }
759
760 if(display_config->network_io_total_tx){
761 if(display_config->units=='b' && (display_config->maxx > x+9)){
762 move(1,x);
763 printw("%8s", "Net");
764 move(2,x);
765 printw("%8s", "tx");
766 x+=9;
767 }
768
769 if(display_config->units=='k' && (display_config->maxx > x+6)){
770 move(1,x);
771 printw("%5s", "Net");
772 move(2,x);
773 printw("%5s", "tx");
774 x+=6;
775 }
776
777 if(display_config->units=='m' && (display_config->maxx > x+6)){
778 move(1,x);
779 printw("%5s", "Net");
780 move(2,x);
781 printw("%5s", "tx");
782 x+=6;
783 }
784
785 }
786
787 if(display_config->disk_io_total_read){
788 if(display_config->units=='b' && (display_config->maxx > x+10)){
789 move(1,x);
790 printw("%9s", "Disk");
791 move(2,x);
792 printw("%9s", "read");
793 x+=10;
794 }
795
796 if(display_config->units=='k' && (display_config->maxx > x+7)){
797 move(1,x);
798 printw("%6s", "Disk");
799 move(2,x);
800 printw("%6s", "read");
801 x+=7;
802 }
803
804 if(display_config->units=='m' && (display_config->maxx > x+7)){
805 move(1,x);
806 printw("%6s", "Disk");
807 move(2,x);
808 printw("%6s", "read");
809 x+=7;
810 }
811
812 }
813
814 if(display_config->disk_io_total_read){
815 if(display_config->units=='b' && (display_config->maxx > x+10)){
816 move(1,x);
817 printw("%9s", "Disk");
818 move(2,x);
819 printw("%9s", "write");
820 x+=10;
821 }
822
823 if(display_config->units=='k' && (display_config->maxx > x+7)){
824 move(1,x);
825 printw("%6s", "Disk");
826 move(2,x);
827 printw("%6s", "write");
828 x+=7;
829 }
830
831 if(display_config->units=='m' && (display_config->maxx > x+7)){
832 move(1,x);
833 printw("%6s", "Disk");
834 move(2,x);
835 printw("%6s", "write");
836 x+=7;
837 }
838
839 }
840
841 if(display_config->processes && (display_config->maxx > x+25)){
842 move(1,x);
843 printw("%-24s", " Number of Process");
844 move(2,x);
845 printw("%-24s", " Run Slep Zomb Stop Tot");
846 x+=25;
847 }
848
849 *title=0;
850 }
851
852 /* Counter starts at 8, for padding (eg, headers, borders etc) */
853 for(counter=8;counter<display_config->maxy;counter++){
854 if(machine_data_list==NULL) break;
855 move(line_num++, 1);
856 printw("%-11s", machine_data_list->sysname);
857 x=13;
858
859 if(display_config->cpu_used && (display_config->maxx > x+6)){
860 printw(" %5.1f", machine_data_list->cpu_used);
861 x+=6;
862 }
863 if(display_config->load_1 && (display_config->maxx > x+6)){
864 printw(" %5.1f", machine_data_list->load_1);
865 x+=6;
866 }
867 if(display_config->pages_in && (display_config->maxx > x+6)){
868 printw(" %5d", machine_data_list->pages_in);
869 x+=6;
870 }
871 if(display_config->pages_out && (display_config->maxx > x+6)){
872 printw(" %5d", machine_data_list->pages_out);
873 x+=6;
874 }
875 if(display_config->memory_used_pecent && (display_config->maxx > x+6)){
876 printw(" %5.1f", machine_data_list->memory_used_pecent);
877 x+=6;
878 }
879 if(display_config->swap_used_pecent && (display_config->maxx > x+6)){
880 printw(" %5.1f", machine_data_list->swap_used_pecent);
881 x+=6;
882 }
883
884 if(display_config->network_io_total_rx){
885 if(display_config->units=='b' && (display_config->maxx > x+9)){
886 printw(" %8lld", machine_data_list->network_io_total_rx);
887 x+=9;
888 }
889 if(display_config->units=='k' && (display_config->maxx > x+6)){
890 printw(" %5lld", machine_data_list->network_io_total_rx/1024);
891 x+=6;
892 }
893 if(display_config->units=='m' && (display_config->maxx > x+6)){
894 printw(" %5.2f", (double)(machine_data_list->network_io_total_rx/(1024.00*1024.00)));
895 x+=6;
896 }
897 }
898
899 if(display_config->network_io_total_tx){
900 if(display_config->units=='b' && (display_config->maxx > x+9)){
901 printw(" %8lld", machine_data_list->network_io_total_tx);
902 x+=9;
903 }
904 if(display_config->units=='k' && (display_config->maxx > x+6)){
905 printw(" %5lld", machine_data_list->network_io_total_tx/1024);
906 x+=6;
907 }
908 if(display_config->units=='m' && (display_config->maxx > x+6)){
909 printw(" %5.2f", (double)(machine_data_list->network_io_total_tx/(1024.00*1024.00)));
910 x+=6;
911 }
912 }
913
914 if(display_config->disk_io_total_read){
915 if(display_config->units=='b' && (display_config->maxx > x+10)){
916 printw(" %9lld", machine_data_list->disk_io_total_read);
917 x+=10;
918 }
919 if(display_config->units=='k' && (display_config->maxx > x+7)){
920 printw(" %6lld", machine_data_list->disk_io_total_read/1024);
921 x+=7;
922 }
923 if(display_config->units=='m' && (display_config->maxx > x+7)){
924 printw(" %6.2f", (double)(machine_data_list->disk_io_total_read/(1024.00*1024.00)));
925 x+=7;
926 }
927 }
928
929 if(display_config->disk_io_total_write){
930 if(display_config->units=='b' && (display_config->maxx > x+10)){
931 printw(" %9lld", machine_data_list->disk_io_total_write);
932 x+=10;
933 }
934 if(display_config->units=='k' && (display_config->maxx > x+7)){
935 printw(" %6lld", machine_data_list->disk_io_total_write/1024);
936 x+=7;
937 }
938 if(display_config->units=='m' && (display_config->maxx > x+7)){
939 printw(" %6.2f", (double)(machine_data_list->disk_io_total_write/(1024.00*1024.00)));
940 x+=7;
941 }
942 }
943 if(display_config->processes && display_config->maxx > x+25){
944 printw(" %4d %4d %4d %4d %4d", machine_data_list->processes_cpu, \
945 machine_data_list->processes_sleeping, \
946 machine_data_list->processes_zombie, \
947 machine_data_list->processes_stopped, \
948 machine_data_list->processes_total);
949 x+=25;
950 }
951
952 machine_data_list=machine_data_list->next;
953 }
954
955
956 refresh();
957
958 }
959
960 void sig_winch_handler(int sig){
961
962 sig_winch=1;
963 signal(SIGWINCH, sig_winch_handler);
964 }
965
966 int main(int argc, char **argv){
967 WINDOW *window;
968 fd_set infds;
969 struct winsize size;
970
971 FILE *control;
972 FILE *data;
973
974 char *machine_list=NULL;
975 char *response=NULL;
976
977 char *servername;
978 int server_control_port;
979 int server_data_port;
980
981 machine_data_list_t *machine_data_list=NULL;
982
983 int num_hosts;
984 int title=1;
985
986 int cmdopt;
987 extern int optind;
988 extern char *optarg;
989
990 extern int errno;
991
992 display_config_t display_config;
993 char ch;
994
995 int data_fileno, stdin_fileno, biggest_fileno;
996
997 sortby_ptr=NULL;
998
999 /* What to display defaults */
1000 display_config.units='b';
1001
1002 display_config.cpu_user=0;
1003 display_config.cpu_idle=0;
1004 display_config.cpu_iowait=0;
1005 display_config.cpu_kernel=0;
1006 display_config.cpu_swap=0;
1007 display_config.cpu_used=1;
1008
1009 display_config.memory_total=0;
1010 display_config.memory_free=0;
1011 display_config.memory_used=0;
1012 display_config.memory_used_pecent=1;
1013
1014 display_config.swap_total=0;
1015 display_config.swap_free=0;
1016 display_config.swap_used=0;
1017 display_config.swap_used_pecent=1;
1018
1019 display_config.load_1=1;
1020 display_config.load_5=0;
1021 display_config.load_15=0;
1022
1023 display_config.pages_in=1;
1024 display_config.pages_out=1;
1025
1026 display_config.processes=1;
1027
1028 display_config.network_io_total_tx=1;
1029 display_config.network_io_total_rx=1;
1030 display_config.network_all_stats=0;
1031
1032 display_config.disk_io_total_write=1;
1033 display_config.disk_io_total_read=1;
1034 display_config.disk_io_all_stats=0;
1035
1036 display_config.disk_total_used=0;
1037 display_config.disk_all_stats=0;
1038
1039 signal(SIGWINCH, sig_winch_handler);
1040
1041 while((cmdopt=getopt(argc, argv, "s:")) != -1){
1042 switch(cmdopt){
1043 case 's':
1044 if(!strcmp(optarg, "cpu")){
1045 sortby_ptr=cmp_cpu_used;
1046 strlcpy(display_config.sortby, CPU_USED, SORTBYMAXNAME);
1047 }
1048 if(!strcmp(optarg, "load")){
1049 sortby_ptr=cmp_load_1;
1050 strlcpy(display_config.sortby, LOAD, SORTBYMAXNAME);
1051 }
1052 if(!strcmp(optarg, "mem")){
1053 sortby_ptr=cmp_memory_used_pecent;
1054 strlcpy(display_config.sortby, MEM, SORTBYMAXNAME);
1055 }
1056 if(!strcmp(optarg, "swap")){
1057 sortby_ptr=cmp_swap_used_pecent;
1058 strlcpy(display_config.sortby, SWAP, SORTBYMAXNAME);
1059 }
1060 if(sortby_ptr==NULL){
1061 errf("Invalid sort type");
1062 exit(1);
1063 }
1064 break;
1065 }
1066 }
1067
1068 if(sortby_ptr==NULL){
1069 sortby_ptr=cmp_cpu_used;
1070 strlcpy(display_config.sortby, "CPU Used", SORTBYMAXNAME);
1071 }
1072
1073 if(argc<(optind+2)){
1074 printf("Usage is %s <-d lines> hostname port <machine list>\n", argv[0]);
1075 exit(1);
1076 }
1077
1078 servername=argv[optind];
1079 server_control_port=atoi(argv[optind+1]);
1080
1081 control=create_tcp_connection(servername, server_control_port);
1082 if(control==NULL){
1083 errf("Failed to connect (%m)");
1084 exit(1);
1085 }
1086
1087 if(argc==4){
1088 /* We've been passed a machine list */
1089 /* list currently needs to be ; seperated */
1090 machine_list=strdup(argv[3]);
1091 }
1092
1093 if((tcp_comm(control, NULL, &response, "PROTOCOL 1.1"))!=0){
1094 errf("Incorrect version number (%s)", response);
1095 exit(1);
1096 }
1097
1098 if((tcp_comm(control, "stattop", &response, "OK"))!=0){
1099 errf("Unexpected response %s", response);
1100 exit(1);
1101 }
1102
1103 if(machine_list!=NULL){
1104 if((tcp_comm(control, "SETHOSTLIST", &response, "OK"))!=0){
1105 errf("Unexpected response %s", response);
1106 exit(1);
1107 }
1108 if((tcp_comm(control, machine_list, &response, "OK"))!=0){
1109 errf("Unexpected response %s", response);
1110 exit(1);
1111 }
1112 }
1113
1114 if((tcp_comm(control, "STARTDATA", &response, NULL))!=0){
1115 errf("Unexpected response %s", response);
1116 exit(1);
1117 }
1118
1119 server_data_port=atoi(response);
1120 if(server_data_port==0){
1121 errf("Unexpected response %s", response);
1122 exit(1);
1123 }
1124
1125 data=create_tcp_connection(servername, server_data_port);
1126 if(data==NULL){
1127 errf("Failed to connect to host %s on port %d (%m)",servername, server_data_port);
1128 exit(1);
1129 }
1130
1131 initscr();
1132 nonl();
1133 cbreak();
1134 noecho();
1135 window=newwin(0, 0, 0, 0);
1136 getmaxyx(window, display_config.maxy, display_config.maxx);
1137
1138 stdin_fileno=fileno(stdin);
1139 data_fileno=fileno(data);
1140 biggest_fileno=(data_fileno>stdin_fileno) ? (data_fileno+1) : (stdin_fileno+1);
1141
1142 for(;;){
1143 FD_ZERO(&infds);
1144 FD_SET(stdin_fileno, &infds);
1145 FD_SET(data_fileno, &infds);
1146 if((select(biggest_fileno, &infds, NULL, NULL, NULL))==-1){
1147 if(errno!=EINTR){
1148 errf("select failed with (%m)");
1149 exit(1);
1150 }
1151 }
1152
1153 if(sig_winch){
1154 if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) {
1155 resizeterm(size.ws_row, size.ws_col);
1156 wrefresh(curscr);
1157 }
1158 getmaxyx(window, display_config.maxy, display_config.maxx);
1159 title=1;
1160 display(machine_data_list, &display_config, &title);
1161 refresh();
1162 sig_winch=0;
1163 continue;
1164 }
1165
1166 if(FD_ISSET(stdin_fileno, &infds)){
1167
1168 ch=getch();
1169 switch(ch){
1170 case KEY_RESIZE:
1171 sig_winch=1;
1172 break;
1173
1174 /* Quit */
1175 case 'Q':
1176 case 'q':
1177 endwin();
1178 exit(0);
1179 break;
1180 /* Units */
1181 case 'U':
1182 case 'u':
1183 if(display_config.units == 'b'){
1184 display_config.units = 'k';
1185 }else if(display_config.units == 'k'){
1186 display_config.units = 'm';
1187 }else{
1188 display_config.units = 'b';
1189 }
1190 break;
1191
1192 /* Sort by */
1193 case 'C':
1194 sortby_ptr=cmp_cpu_used;
1195 strlcpy(display_config.sortby, CPU_USED, SORTBYMAXNAME);
1196 break;
1197
1198 case 'M':
1199 sortby_ptr=cmp_memory_used_pecent;
1200 strlcpy(display_config.sortby, MEM, SORTBYMAXNAME);
1201 break;
1202
1203 case 'L':
1204 sortby_ptr=cmp_load_1;
1205 strlcpy(display_config.sortby, LOAD, SORTBYMAXNAME);
1206 break;
1207
1208 case 'S':
1209 sortby_ptr=cmp_swap_used_pecent;
1210 strlcpy(display_config.sortby, SWAP, SORTBYMAXNAME);
1211 break;
1212
1213 case 'N':
1214 if(sortby_ptr==cmp_network_io_total){
1215 strlcpy(display_config.sortby, NETIORX, SORTBYMAXNAME);
1216 sortby_ptr=cmp_network_io_total_rx;
1217 }else if(sortby_ptr==cmp_network_io_total_rx){
1218 strlcpy(display_config.sortby, NETIOTX, SORTBYMAXNAME);
1219 sortby_ptr=cmp_network_io_total_tx;
1220 }else{
1221 strlcpy(display_config.sortby, NETIO, SORTBYMAXNAME);
1222 sortby_ptr=cmp_network_io_total;
1223 }
1224 break;
1225 case 'D':
1226 if(sortby_ptr==cmp_disk_io_total){
1227 strlcpy(display_config.sortby, DISKIOR, SORTBYMAXNAME);
1228 sortby_ptr=cmp_disk_io_total_read;
1229 }else if(sortby_ptr==cmp_disk_io_total_read){
1230 strlcpy(display_config.sortby, DISKIOW, SORTBYMAXNAME);
1231 sortby_ptr=cmp_disk_io_total_write;
1232 }else{
1233 strlcpy(display_config.sortby, DISKIO, SORTBYMAXNAME);
1234 sortby_ptr=cmp_disk_io_total;
1235 }
1236 break;
1237
1238 /* Display */
1239
1240 case 'd':
1241 if(display_config.disk_io_total_read){
1242 display_config.disk_io_total_read=0;
1243 display_config.disk_io_total_write=0;
1244 }else{
1245 display_config.disk_io_total_read=1;
1246 display_config.disk_io_total_write=1;
1247 }
1248 break;
1249 case 'n':
1250 if(display_config.network_io_total_rx){
1251 display_config.network_io_total_rx=0;
1252 display_config.network_io_total_tx=0;
1253 }else{
1254 display_config.network_io_total_rx=1;
1255 display_config.network_io_total_tx=1;
1256 }
1257 break;
1258 case 'm':
1259 if(display_config.memory_used_pecent){
1260 display_config.memory_used_pecent=0;
1261 }else{
1262 display_config.memory_used_pecent=1;
1263 }
1264 break;
1265
1266 case 's':
1267 if(display_config.swap_used_pecent){
1268 display_config.swap_used_pecent=0;
1269 }else{
1270 display_config.swap_used_pecent=1;
1271 }
1272 break;
1273 case 'l':
1274 if(display_config.load_1){
1275 display_config.load_1=0;
1276 }else{
1277 display_config.load_1=1;
1278 }
1279 break;
1280 case 'p':
1281 if(display_config.pages_in){
1282 display_config.pages_in=0;
1283 display_config.pages_out=0;
1284 }else{
1285 display_config.pages_in=1;
1286 display_config.pages_out=1;
1287 }
1288 break;
1289 case 'c':
1290 if(display_config.cpu_used){
1291 display_config.cpu_used=0;
1292 }else{
1293 display_config.cpu_used=1;
1294 }
1295 break;
1296 case 'r':
1297 if(display_config.processes){
1298 display_config.processes=0;
1299 }else{
1300 display_config.processes=1;
1301 }
1302 break;
1303
1304 default:
1305 continue;
1306 }
1307
1308 /* Increment title so it becomes true (and making the screen update */
1309 title++;
1310
1311 }
1312 if(FD_ISSET(data_fileno, &infds)){
1313 response=fpgetline(data);
1314 if (response==NULL){
1315 errf("Failed to read data (%m)");
1316 exit(1);
1317 }
1318 }
1319
1320
1321 num_hosts=parse_xml(response, &machine_data_list);
1322 if(num_hosts==-1) continue;
1323 machine_data_list=sort_machine_stats(machine_data_list, num_hosts, sortby_ptr);
1324 display(machine_data_list, &display_config, &title);
1325
1326 }
1327 exit(0);
1328 }