ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.10
Committed: Wed Apr 2 15:41:01 2003 UTC (21 years, 2 months ago) by pajs
Content type: text/plain
Branch: MAIN
Changes since 1.9: +1 -0 lines
Log Message:
Linux now working.

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