ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.13
Committed: Wed Apr 9 20:13:53 2003 UTC (21 years, 1 month ago) by pajs
Content type: text/plain
Branch: MAIN
Changes since 1.12: +14 -1 lines
Log Message:
Ok, im sure this prob isn't the "right" way to do resizing.. but it seems
to work.

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