ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.7
Committed: Sun Mar 30 22:16:20 2003 UTC (21 years, 8 months ago) by pajs
Content type: text/plain
Branch: MAIN
Changes since 1.6: +85 -11 lines
Log Message:
Added support for sorting on the fly. I have followed a basic convention of
a capital letter will do sorting, and a lower case letter will change the
display properties.

Currently q or Q will quit.
C will sort by CPU
S will sort by Swap
M will sort by Memory
L will sort by Load
N will sort by Network. Network sorting is toggled thru 3 options. First
time it will sort by rx+tx. 2nd time it will sort by rx, 3rd time tx. Then
it will repeat to the start again.

The display function has been updated slightly. The arguments it takes
(num_lines) now means the number of lines on the screen, rather than
the number of hosts to display. A status of what its sorting by has been
added to the bottom line. This line could be used for other "stuff" in the
future as well.

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 FILE *create_tcp_connection(char *hostname, int port){
240 int sock;
241 struct sockaddr_in addr;
242 struct in_addr haddr;
243 FILE *f;
244
245 if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){
246 return NULL;
247 }
248
249 if((get_host_addr(hostname, &haddr))!=0){
250 close(sock);
251 return NULL;
252 }
253
254 memset(&addr, 0, sizeof(addr));
255 addr.sin_family = AF_INET;
256 memcpy(&addr.sin_addr, &haddr, sizeof(haddr));
257 addr.sin_port = htons(port);
258
259 if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){
260 close(sock);
261 return NULL;
262 }
263
264 if((f=fdopen(sock, "r+"))==NULL){
265 close(sock);
266 return NULL;
267 }
268
269 return f;
270 }
271
272 int tcp_comm(FILE *f, char *send, char **response, char *expected){
273
274 if(send!=NULL){
275 fprintf(f, "%s\n", send);
276 }
277 fflush(f);
278 *response=fpgetline(f);
279 fseek(f, 0, SEEK_CUR);
280
281 if( (*response==NULL) || (strcmp(*response, "ERROR")==0) ) return -1;
282
283 if(expected==NULL) return 0;
284
285 if((strcmp(expected, *response))==0) return 0;
286
287 return -1;
288 }
289
290 /* Takes a xml char * and a machine_data_list_t. This will parse
291 * the xml and put it into the correct entry of the machine_data
292 * linked list. This will return the number of entries in the linked
293 * list, or -1 on a error.
294 */
295 int parse_xml(char *xml, machine_data_list_t **md){
296 xmlDocPtr doc;
297 xmlNodePtr cur;
298 xmlNodePtr ele;
299 xmlAttr *list;
300
301 static int num_hosts=0;
302
303 machine_data_list_t *machine_data_list=*md;
304
305 int found_host=0;
306
307 char *hostname=NULL;
308 network_data_list_t *network_data_list=NULL;
309 network_data_list_t *ndl_ptr=NULL;
310 diskio_data_list_t *diskio_data_list=NULL;
311 diskio_data_list_t *didl_ptr=NULL;
312 char *tmp;
313
314 doc=xmlParseDoc(xml);
315 if(doc==NULL) return -1;
316
317 cur = xmlDocGetRootElement(doc);
318 if(cur==NULL){
319 xmlFreeDoc(doc);
320 return -1;
321 }
322
323
324 /* Get the hostname */
325 list=cur->properties;
326 while(list!=NULL){
327 if((xmlStrcmp(list->name, (const xmlChar *) "machine_name"))==0){
328 hostname = xmlNodeGetContent(list->children);
329 if(hostname==NULL){
330 return -1;
331 }
332 }
333 list=list->next;
334 }
335 if(hostname==NULL){
336 return -1;
337 }
338
339 /* Get machine_data for host.. Or create if it doesn't have one */
340 while(machine_data_list!=NULL){
341 if((strncmp(machine_data_list->name, hostname, strlen(hostname)))==0){
342 found_host=1;
343 break;
344 }
345 machine_data_list=machine_data_list->next;
346 }
347
348 if(!found_host){
349 /* We didn't find this host, but we should be at the end of the list */
350 machine_data_list=malloc(sizeof(machine_data_list_t));
351 if(machine_data_list==NULL) return -1;
352 machine_data_list->next=(*md);
353 machine_data_list->name=hostname;
354 machine_data_list->network_data_list=NULL;
355 machine_data_list->diskio_data_list=NULL;
356 *md=machine_data_list;
357 num_hosts++;
358 }
359
360 /* Now we want to pull out the data */
361
362 cur = cur->xmlChildrenNode;
363 while(cur != NULL) {
364 ele=cur->xmlChildrenNode;
365 while(ele != NULL){
366
367 /* CPU Stats */
368 if(!xmlStrcmp(cur->name, (const xmlChar *) "cpu")){
369 tmp=xmlNodeGetContent(ele);
370 if(!xmlStrcmp(ele->name, (const xmlChar *) "user")){
371 machine_data_list->cpu_user=atof(tmp);
372 }
373 if(!xmlStrcmp(ele->name, (const xmlChar *) "kernel")){
374 machine_data_list->cpu_kernel=atof(tmp);
375 }
376 if(!xmlStrcmp(ele->name, (const xmlChar *) "idle")){
377 machine_data_list->cpu_idle=atof(tmp);
378 }
379 if(!xmlStrcmp(ele->name, (const xmlChar *) "iowait")){
380 machine_data_list->cpu_iowait=atof(tmp);
381 }
382 if(!xmlStrcmp(ele->name, (const xmlChar *) "swap")){
383 machine_data_list->cpu_iowait=atof(tmp);
384 }
385
386 if(tmp!=NULL) xmlFree(tmp);
387 }
388
389 /* Memory Stats */
390 if(!xmlStrcmp(cur->name, (const xmlChar *) "memory")){
391 tmp=xmlNodeGetContent(ele);
392 if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
393 machine_data_list->memory_total=atoll(tmp);
394 }
395 if(!xmlStrcmp(ele->name, (const xmlChar *) "free")){
396 machine_data_list->memory_free=atoll(tmp);
397 }
398 if(!xmlStrcmp(ele->name, (const xmlChar *) "used")){
399 machine_data_list->memory_used=atoll(tmp);
400 }
401
402 if(tmp!=NULL) xmlFree(tmp);
403 }
404
405 /* Load Stats */
406 if(!xmlStrcmp(cur->name, (const xmlChar *) "load")){
407 tmp=xmlNodeGetContent(ele);
408 if(!xmlStrcmp(ele->name, (const xmlChar *) "load1")){
409 machine_data_list->load_1=atof(tmp);
410 }
411 if(!xmlStrcmp(ele->name, (const xmlChar *) "load5")){
412 machine_data_list->load_5=atof(tmp);
413 }
414 if(!xmlStrcmp(ele->name, (const xmlChar *) "load15")){
415 machine_data_list->load_15=atof(tmp);
416 }
417
418 if(tmp!=NULL) xmlFree(tmp);
419 }
420
421 /* swap stats */
422 if(!xmlStrcmp(cur->name, (const xmlChar *) "swap")){
423 tmp=xmlNodeGetContent(ele);
424 if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
425 machine_data_list->swap_total=atoll(tmp);
426 }
427 if(!xmlStrcmp(ele->name, (const xmlChar *) "free")){
428 machine_data_list->swap_free=atoll(tmp);
429 }
430 if(!xmlStrcmp(ele->name, (const xmlChar *) "used")){
431 machine_data_list->swap_used=atoll(tmp);
432 }
433
434 if(tmp!=NULL) xmlFree(tmp);
435 }
436
437 /* Process stat */
438 if(!xmlStrcmp(cur->name, (const xmlChar *) "processes")){
439 tmp=xmlNodeGetContent(ele);
440 if(!xmlStrcmp(ele->name, (const xmlChar *) "sleeping")){
441 machine_data_list->processes_sleeping=atoi(tmp);
442 }
443 if(!xmlStrcmp(ele->name, (const xmlChar *) "cpu")){
444 machine_data_list->processes_cpu=atoi(tmp);
445 }
446 if(!xmlStrcmp(ele->name, (const xmlChar *) "zombie")){
447 machine_data_list->processes_zombie=atoi(tmp);
448 }
449 if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
450 machine_data_list->processes_total=atoi(tmp);
451 }
452
453 if(tmp!=NULL) xmlFree(tmp);
454 }
455
456 /* paging stats */
457 if(!xmlStrcmp(cur->name, (const xmlChar *) "pages")){
458 tmp=xmlNodeGetContent(ele);
459 if(!xmlStrcmp(ele->name, (const xmlChar *) "pageins")){
460 machine_data_list->pages_in=atoi(tmp);
461 }
462 if(!xmlStrcmp(ele->name, (const xmlChar *) "pageouts")){
463 machine_data_list->pages_out=atoi(tmp);
464 }
465
466 if(tmp!=NULL) xmlFree(tmp);
467 }
468
469 /* OS stats */
470 if(!xmlStrcmp(cur->name, (const xmlChar *) "os")){
471 tmp=xmlNodeGetContent(ele);
472 if(!xmlStrcmp(ele->name, (const xmlChar *) "sysname")){
473 strlcpy(machine_data_list->sysname, tmp, MAXHOSTNAMESIZE+1);
474 }
475 if(tmp!=NULL) xmlFree(tmp);
476 }
477
478 /* Network stats */
479 /* Needs to connect current stat to a previous one. Or create it if new */
480 /* Get name.. Walk list. If match, copy rx/tx values. Else malloc, add to list */
481 if(!xmlStrcmp(cur->name, (const xmlChar *) "net")){
482
483 list=ele->properties;
484 if(list==NULL) continue;
485 network_data_list=malloc(sizeof(network_data_list_t));
486 if(network_data_list==NULL) return -1;
487 while(list!=NULL){
488 tmp=xmlNodeGetContent(list->children);
489 if(!xmlStrcmp(list->name, (const xmlChar *) "name")){
490 network_data_list->name=strdup(tmp);
491 }
492 if(!xmlStrcmp(list->name, (const xmlChar *) "rx")){
493 network_data_list->rx=atoll(tmp);
494 }
495 if(!xmlStrcmp(list->name, (const xmlChar *) "tx")){
496 network_data_list->tx=atoll(tmp);
497 }
498
499 xmlFree(tmp);
500 list=list->next;
501 }
502 if(network_data_list->name==NULL) continue;
503 found_host=0;
504 ndl_ptr=machine_data_list->network_data_list;
505 while(ndl_ptr!=NULL){
506 if(!strcmp(ndl_ptr->name, network_data_list->name)){
507 found_host=1;
508 break;
509 }
510 ndl_ptr=ndl_ptr->next;
511 }
512 if(found_host){
513 ndl_ptr->rx=network_data_list->rx;
514 ndl_ptr->tx=network_data_list->tx;
515 free(network_data_list->name);
516 free(network_data_list);
517 }else{
518 network_data_list->next=machine_data_list->network_data_list;
519 machine_data_list->network_data_list=network_data_list;
520 }
521 }
522
523 /* Disk IO stats */
524 if(!xmlStrcmp(cur->name, (const xmlChar *) "diskio")){
525
526 list=ele->properties;
527 if(list==NULL) continue;
528 diskio_data_list=malloc(sizeof(diskio_data_list_t));
529 if(diskio_data_list==NULL) return -1;
530 while(list!=NULL){
531 tmp=xmlNodeGetContent(list->children);
532 if(!xmlStrcmp(list->name, (const xmlChar *) "name")){
533 diskio_data_list->name=strdup(tmp);
534 }
535 if(!xmlStrcmp(list->name, (const xmlChar *) "rbytes")){
536 diskio_data_list->read=atoll(tmp);
537 }
538 if(!xmlStrcmp(list->name, (const xmlChar *) "wbytes")){
539 diskio_data_list->write=atoll(tmp);
540 }
541
542 xmlFree(tmp);
543 list=list->next;
544 }
545 if(diskio_data_list->name==NULL) continue;
546 found_host=0;
547 didl_ptr=machine_data_list->diskio_data_list;
548 while(didl_ptr!=NULL){
549 if(!strcmp(didl_ptr->name, diskio_data_list->name)){
550 found_host=1;
551 break;
552 }
553 didl_ptr=didl_ptr->next;
554 }
555 if(found_host){
556 didl_ptr->read=diskio_data_list->read;
557 didl_ptr->write=diskio_data_list->write;
558 free(diskio_data_list->name);
559 free(diskio_data_list);
560 }else{
561 diskio_data_list->next=machine_data_list->diskio_data_list;
562 machine_data_list->diskio_data_list=diskio_data_list;
563 }
564 }
565
566
567
568 ele=ele->next;
569 }
570 cur=cur->next;
571 }
572
573 /* Append data we want thats not stored in the server */
574 machine_data_list->cpu_used=100.00-machine_data_list->cpu_idle;
575 machine_data_list->memory_used_pecent=((double)machine_data_list->memory_used / (double)machine_data_list->memory_total) * 100.00;
576 machine_data_list->swap_used_pecent=((double)machine_data_list->swap_used / (double)machine_data_list->swap_total) * 100.00;
577
578 ndl_ptr=machine_data_list->network_data_list;
579 machine_data_list->network_io_total_tx=0;
580 machine_data_list->network_io_total_rx=0;
581 while(ndl_ptr!=NULL){
582 machine_data_list->network_io_total_tx+=ndl_ptr->tx;
583 machine_data_list->network_io_total_rx+=ndl_ptr->rx;
584 ndl_ptr=ndl_ptr->next;
585 }
586 machine_data_list->network_io_total=machine_data_list->network_io_total_rx+machine_data_list->network_io_total_tx;
587
588 didl_ptr=machine_data_list->diskio_data_list;
589 machine_data_list->disk_io_total_read=0;
590 machine_data_list->disk_io_total_write=0;
591 while(didl_ptr!=NULL){
592 machine_data_list->disk_io_total_read+=didl_ptr->read;
593 machine_data_list->disk_io_total_write+=didl_ptr->write;
594 didl_ptr=didl_ptr->next;
595 }
596 machine_data_list->disk_io_total=machine_data_list->disk_io_total_read+machine_data_list->disk_io_total_write;
597
598 xmlFreeDoc(doc);
599
600 return num_hosts;
601
602
603 }
604
605 void display(machine_data_list_t *machine_data_list, display_config_t *display_config, int num_lines, int *title){
606 int line_num=4;
607 int counter;
608 int x=1;
609
610 if(*title){
611 move (num_lines-3, 1);
612 printw("Sorting by %-64s", display_config->sortby);
613
614 move(1,1);
615 printw("%-11s", "Hostname");
616 x=x+11+1;
617 if(display_config->cpu_used){
618 move(1,x);
619 printw("%5s", "CPU");
620 move(2,x);
621 printw("%5s", "used%");
622 x+=6;
623 }
624 if(display_config->load_1){
625 move(1,x);
626 printw("%5s", "Load");
627 move(2,x);
628 printw("%5s", "(1m)");
629 x+=6;
630 }
631 if(display_config->pages_in){
632 move(1,x);
633 printw("%5s", "Page");
634 move(2,x);
635 printw("%5s", "ins");
636 x+=6;
637 }
638 if(display_config->pages_out){
639 move(1,x);
640 printw("%5s", "Page");
641 move(2,x);
642 printw("%5s", "outs");
643 x+=6;
644 }
645 if(display_config->memory_used_pecent){
646 move(1,x);
647 printw("%5s", "Mem");
648 move(2,x);
649 printw("%5s", "used");
650 x+=6;
651 }
652 if(display_config->swap_used_pecent){
653 move(1,x);
654 printw("%5s", "Swap");
655 move(2,x);
656 printw("%5s", "used");
657 x+=6;
658 }
659 if(display_config->network_io_total_rx){
660 move(1,x);
661 printw("%8s", "Net");
662 move(2,x);
663 printw("%8s", "rx");
664 x+=9;
665 }
666 if(display_config->network_io_total_tx){
667 move(1,x);
668 printw("%8s", "Net");
669 move(2,x);
670 printw("%8s", "tx");
671 x+=9;
672 }
673 if(display_config->disk_io_total_read){
674 move(1,x);
675 printw("%9s", "Disk");
676 move(2,x);
677 printw("%9s", "read");
678 x+=10;
679 }
680 if(display_config->disk_io_total_read){
681 move(1,x);
682 printw("%9s", "Disk");
683 move(2,x);
684 printw("%9s", "write");
685 x+=10;
686 }
687
688 *title=0;
689 }
690
691 /* Counter starts at 8, for padding (eg, headers, borders etc) */
692 for(counter=8;counter<num_lines;counter++){
693 if(machine_data_list==NULL) break;
694 move(line_num++, 1);
695 printw("%-11s", machine_data_list->sysname);
696
697 if(display_config->cpu_used) printw(" %5.1f", machine_data_list->cpu_used);
698 if(display_config->load_1) printw(" %5.1f", machine_data_list->load_1);
699 if(display_config->pages_in) printw(" %5d", machine_data_list->pages_in);
700 if(display_config->pages_out) printw(" %5d", machine_data_list->pages_out);
701 if(display_config->memory_used_pecent) printw(" %5.1f", machine_data_list->memory_used_pecent);
702 if(display_config->swap_used_pecent) printw(" %5.1f", machine_data_list->swap_used_pecent);
703 if(display_config->network_io_total_rx) printw(" %8lld", machine_data_list->network_io_total_rx);
704 if(display_config->network_io_total_tx) printw(" %8lld", machine_data_list->network_io_total_tx);
705 if(display_config->disk_io_total_read) printw(" %9lld", machine_data_list->disk_io_total_read);
706 if(display_config->disk_io_total_write) printw(" %9lld", machine_data_list->disk_io_total_write);
707
708 machine_data_list=machine_data_list->next;
709 }
710
711
712 refresh();
713
714 }
715
716 int main(int argc, char **argv){
717 WINDOW *window;
718 fd_set infds;
719 int maxx, maxy;
720
721 FILE *control;
722 FILE *data;
723
724 char *machine_list=NULL;
725 char *response=NULL;
726
727 char *servername;
728 int server_control_port;
729 int server_data_port;
730
731 machine_data_list_t *machine_data_list=NULL;
732
733 int num_hosts;
734 int max_display=0;
735 int title=1;
736
737 int cmdopt;
738 extern int optind;
739 extern char *optarg;
740
741 display_config_t display_config;
742 char ch;
743
744 int data_fileno, stdin_fileno, biggest_fileno;
745
746 sortby_ptr=NULL;
747
748 /* What to display defaults */
749 display_config.cpu_user=0;
750 display_config.cpu_idle=0;
751 display_config.cpu_iowait=0;
752 display_config.cpu_kernel=0;
753 display_config.cpu_swap=0;
754 display_config.cpu_used=1;
755
756 display_config.memory_total=0;
757 display_config.memory_free=0;
758 display_config.memory_used=0;
759 display_config.memory_used_pecent=1;
760
761 display_config.swap_total=0;
762 display_config.swap_free=0;
763 display_config.swap_used=0;
764 display_config.swap_used_pecent=1;
765
766 display_config.load_1=1;
767 display_config.load_5=0;
768 display_config.load_15=0;
769
770 display_config.pages_in=1;
771 display_config.pages_out=1;
772
773 display_config.processes_total=0;
774 display_config.processes_sleeping=0;
775 display_config.processes_cpu=0;
776 display_config.processes_zombie=0;
777 display_config.processes_stopped=0;
778
779 display_config.network_io_total_tx=1;
780 display_config.network_io_total_rx=1;
781 display_config.network_all_stats=1;
782
783 display_config.disk_io_total_write=0;
784 display_config.disk_io_total_read=0;
785 display_config.disk_io_all_stats=0;
786
787 display_config.disk_total_used=0;
788 display_config.disk_all_stats=0;
789
790 while((cmdopt=getopt(argc, argv, "d:s:")) != -1){
791 switch(cmdopt){
792 case 'd':
793 max_display=atoi(optarg);
794 break;
795 case 's':
796 if(!strcmp(optarg, "cpu")){
797 sortby_ptr=cmp_cpu_used;
798 strlcpy(display_config.sortby, CPU_USED, SORTBYMAXNAME);
799 }
800 if(!strcmp(optarg, "load")){
801 sortby_ptr=cmp_load_1;
802 strlcpy(display_config.sortby, LOAD, SORTBYMAXNAME);
803 }
804 if(!strcmp(optarg, "mem")){
805 sortby_ptr=cmp_memory_used_pecent;
806 strlcpy(display_config.sortby, MEM, SORTBYMAXNAME);
807 }
808 if(!strcmp(optarg, "swap")){
809 sortby_ptr=cmp_swap_used_pecent;
810 strlcpy(display_config.sortby, SWAP, SORTBYMAXNAME);
811 }
812 if(sortby_ptr==NULL){
813 errf("Invalid sort type");
814 exit(1);
815 }
816 break;
817 }
818 }
819
820 if(sortby_ptr==NULL){
821 sortby_ptr=cmp_cpu_used;
822 strlcpy(display_config.sortby, "CPU Used", SORTBYMAXNAME);
823 }
824
825 if(argc<(optind+2)){
826 printf("Usage is %s <-d lines> hostname port <machine list>\n", argv[0]);
827 exit(1);
828 }
829
830 servername=argv[optind];
831 server_control_port=atoi(argv[optind+1]);
832
833 control=create_tcp_connection(servername, server_control_port);
834 if(control==NULL){
835 errf("Failed to connect (%m)");
836 }
837
838 if(argc==4){
839 /* We've been passed a machine list */
840 /* list currently needs to be ; seperated */
841 machine_list=strdup(argv[3]);
842 }
843
844 if((tcp_comm(control, NULL, &response, "PROTOCOL 1.1"))!=0){
845 errf("Incorrect version number (%s)", response);
846 exit(1);
847 }
848
849 if((tcp_comm(control, "stattop", &response, "OK"))!=0){
850 errf("Unexpected response %s", response);
851 exit(1);
852 }
853
854 if(machine_list!=NULL){
855 if((tcp_comm(control, "SETHOSTLIST", &response, "OK"))!=0){
856 errf("Unexpected response %s", response);
857 exit(1);
858 }
859 if((tcp_comm(control, machine_list, &response, "OK"))!=0){
860 errf("Unexpected response %s", response);
861 exit(1);
862 }
863 }
864
865 if((tcp_comm(control, "STARTDATA", &response, NULL))!=0){
866 errf("Unexpected response %s", response);
867 exit(1);
868 }
869
870 server_data_port=atoi(response);
871 if(server_data_port==0){
872 errf("Unexpected response %s", response);
873 exit(1);
874 }
875
876 data=create_tcp_connection(servername, server_data_port);
877 if(data==NULL){
878 errf("Failed to connect to host %s on port %d (%m)",servername, server_data_port);
879 }
880
881 /*
882 printf("\033[2J");
883 printf("\033[1;1HHostname CPU Load Page Page Mem Swap Net Net Disk Disk");
884 printf("\033[2;1H used%% (1m) ins outs used used rx tx read write");
885 */
886
887 initscr();
888 nonl();
889 cbreak();
890 echo();
891 window=newwin(0, 0, 0, 0);
892 getmaxyx(window, maxy, maxx);
893
894 stdin_fileno=fileno(stdin);
895 data_fileno=fileno(data);
896 biggest_fileno=(data_fileno>stdin_fileno) ? (data_fileno+1) : (stdin_fileno+1);
897
898 for(;;){
899 FD_ZERO(&infds);
900 FD_SET(stdin_fileno, &infds);
901 FD_SET(data_fileno, &infds);
902 select(biggest_fileno, &infds, NULL, NULL, NULL);
903
904 if(FD_ISSET(stdin_fileno, &infds)){
905
906 ch=getc(stdin);
907 switch(ch){
908 case 'Q':
909 case 'q':
910 endwin();
911 exit(0);
912 break;
913
914 case 'C':
915 sortby_ptr=cmp_cpu_used;
916 strlcpy(display_config.sortby, CPU_USED, SORTBYMAXNAME);
917 break;
918
919 case 'M':
920 sortby_ptr=cmp_memory_used_pecent;
921 strlcpy(display_config.sortby, MEM, SORTBYMAXNAME);
922 break;
923
924 case 'L':
925 sortby_ptr=cmp_load_1;
926 strlcpy(display_config.sortby, LOAD, SORTBYMAXNAME);
927 break;
928
929 case 'S':
930 sortby_ptr=cmp_swap_used_pecent;
931 strlcpy(display_config.sortby, SWAP, SORTBYMAXNAME);
932 break;
933
934 case 'N':
935 if(sortby_ptr==cmp_network_io_total){
936 strlcpy(display_config.sortby, NETIORX, SORTBYMAXNAME);
937 sortby_ptr=cmp_network_io_total_rx;
938 }else if(sortby_ptr==cmp_network_io_total_rx){
939 strlcpy(display_config.sortby, NETIOTX, SORTBYMAXNAME);
940 sortby_ptr=cmp_network_io_total_tx;
941 }else{
942 strlcpy(display_config.sortby, NETIO, SORTBYMAXNAME);
943 sortby_ptr=cmp_network_io_total;
944 }
945 break;
946
947 }
948
949 title=1;
950
951 }
952 if(FD_ISSET(data_fileno, &infds)){
953 response=fpgetline(data);
954 if (response==NULL){
955 errf("Failed to read data (%m)");
956 exit(1);
957 }
958 }
959
960
961 num_hosts=parse_xml(response, &machine_data_list);
962 if(num_hosts==-1) continue;
963 machine_data_list=sort_machine_stats(machine_data_list, num_hosts, sortby_ptr);
964 if(max_display==0){
965 display(machine_data_list, &display_config, maxy, &title);
966 }else{
967 display(machine_data_list, &display_config, max_display, &title);
968 }
969
970 }
971 exit(0);
972 }