ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.9
Committed: Wed Apr 2 15:23:26 2003 UTC (21 years, 7 months ago) by pajs
Content type: text/plain
Branch: MAIN
Changes since 1.8: +71 -0 lines
Log Message:
(unchecked) This update should mean it will compile on linux and freebsd.
I think we've got to the point where it should be called 1.1 :)
(If this actually works that is :) )

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