ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.12
Committed: Thu Apr 3 10:59:28 2003 UTC (21 years, 7 months ago) by pajs
Content type: text/plain
Branch: MAIN
Changes since 1.11: +1 -0 lines
Log Message:
Fixed bug which caused it to seg fault if given a invalid host. (I
carefully did the check, then forgot to call exit(1).. Ooops :) )

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