ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.1
Committed: Fri Mar 28 15:37:05 2003 UTC (21 years, 9 months ago) by pajs
Content type: text/plain
Branch: MAIN
Log Message:
idar is a "top like" client which displays data collected by ihost.
It currently displays cpu, load, pageing, mem, swap, net and disk io.
There is infastructure to display much more in the future, and to be able
to sort on more than just CPU.

genmergesort is macro written by mtr to sort a linked list.

Inital version 1.0 This compiles and works. It requires libxml2 (but it
may work against libxml, but this has not been checked). It also requires
ukcprog. This will not currently compile on linux (as it lacks strlcpy).

Usage is

idar <-d number_lines_to_display> machine_name port <"fqdn1;fqdn2;fqdn3">

File Contents

# User Rev Content
1 pajs 1.1 #include <stdio.h>
2     #include <string.h>
3     #include <sys/types.h>
4     #include <sys/socket.h>
5     #include <unistd.h>
6     #include <stdlib.h>
7     #include <ukcprog.h>
8    
9     #include <libxml/xmlmemory.h>
10     #include <libxml/parser.h>
11     #include "genmergesort.h"
12    
13     struct host_line_t{
14     char *hostname;
15     int line;
16    
17     struct host_line_t *next;
18     };
19     typedef struct host_line_t host_line_list_t;
20    
21     struct diskio_data_t{
22     char *name;
23    
24     long long read;
25     long long write;
26    
27     struct diskio_data_t *next;
28     };
29     typedef struct diskio_data_t diskio_data_list_t;
30    
31     struct network_data_t{
32     char *name;
33    
34     long long rx;
35     long long tx;
36    
37     struct network_data_t *next;
38     };
39     typedef struct network_data_t network_data_list_t;
40    
41     /*
42     struct disk_data_t{
43     char *name;
44     char *mount_pnt;
45    
46     long long total_space;
47     long long total_used;
48     long long total_avail;
49     // Other data we are less intrested in are not stored
50    
51     struct disk_data_t *next;
52     };
53     typedef struct disk_data_t disk_data_list_t;
54     */
55     #define MAXHOSTNAMESIZE 10
56     struct machine_data_t{
57    
58     char *name;
59    
60     char sysname[MAXHOSTNAMESIZE+1];
61    
62     double cpu_user;
63     double cpu_idle;
64     double cpu_iowait;
65     double cpu_kernel;
66     double cpu_swap;
67     double cpu_used; /* 100 - idle */
68    
69     long long memory_total;
70     long long memory_free;
71     long long memory_used;
72     double memory_used_pecent;
73    
74     long long swap_total;
75     long long swap_free;
76     long long swap_used;
77     double swap_used_pecent;
78    
79     int pages_in;
80     int pages_out;
81    
82     double load_1;
83     double load_5;
84     double load_15;
85    
86     int processes_total;
87     int processes_sleeping;
88     int processes_cpu;
89     int processes_zombie;
90     int processes_stopped;
91    
92     network_data_list_t *network_data_list;
93     long long network_io_total_tx;
94     long long network_io_total_rx;
95    
96     diskio_data_list_t *diskio_data_list;
97     long long disk_io_total_write;
98     long long disk_io_total_read;
99    
100     /* Maybe in the future */
101     /*
102     disk_data_list_t disk_data_list;
103     double disk_total_used;
104     */
105    
106     struct machine_data_t *next;
107     };
108    
109     typedef struct machine_data_t machine_data_list_t;
110    
111     typedef struct{
112     int cpu_user;
113     int cpu_idle;
114     int cpu_iowait;
115     int cpu_kernel;
116     int cpu_swap;
117     int cpu_used;
118    
119     int memory_total;
120     int memory_free;
121     int memory_used;
122     int memory_used_pecent;
123    
124     int swap_total;
125     int swap_free;
126     int swap_used;
127     int swap_used_pecent;
128    
129     int load_1;
130     int load_5;
131     int load_15;
132    
133     int pages_in;
134     int pages_out;
135    
136     int processes_total;
137     int processes_sleeping;
138     int processes_cpu;
139     int processes_zombie;
140     int processes_stopped;
141    
142     int network_io_total_tx;
143     int network_io_total_rx;
144     int network_all_stats;
145    
146     int disk_io_total_write;
147     int disk_io_total_read;
148     int disk_io_all_stats;
149    
150     int disk_total_used;
151     int disk_all_stats;
152     }display_config_t;
153    
154     GENERIC_MERGE_SORT(static, sort_machine_stats, machine_data_list_t, next)
155    
156     int cmp_cpu(machine_data_list_t *a, machine_data_list_t *b){
157    
158     if(a->cpu_used == b->cpu_used){
159     if(a->load_1 == b->load_1) return 0;
160     if(a->load_1 > b->load_1){
161     return -1;
162     }else{
163     return 1;
164     }
165     }
166    
167     if((a->cpu_used) > (b->cpu_used)){
168     return -1;
169     }else{
170     return 1;
171     }
172     }
173    
174     FILE *create_tcp_connection(char *hostname, int port){
175     int sock;
176     struct sockaddr_in addr;
177     struct in_addr haddr;
178     FILE *f;
179    
180     if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){
181     return NULL;
182     }
183    
184     if((get_host_addr(hostname, &haddr))!=0){
185     close(sock);
186     return NULL;
187     }
188    
189     memset(&addr, 0, sizeof(addr));
190     addr.sin_family = AF_INET;
191     memcpy(&addr.sin_addr, &haddr, sizeof(haddr));
192     addr.sin_port = htons(port);
193    
194     if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){
195     close(sock);
196     return NULL;
197     }
198    
199     if((f=fdopen(sock, "r+"))==NULL){
200     close(sock);
201     return NULL;
202     }
203    
204     return f;
205     }
206    
207     int tcp_comm(FILE *f, char *send, char **response, char *expected){
208    
209     if(send!=NULL){
210     fprintf(f, "%s\n", send);
211     }
212     fflush(f);
213     *response=fpgetline(f);
214     fseek(f, 0, SEEK_CUR);
215    
216     if( (*response==NULL) || (strcmp(*response, "ERROR")==0) ) return -1;
217    
218     if(expected==NULL) return 0;
219    
220     if((strcmp(expected, *response))==0) return 0;
221    
222     return -1;
223     }
224    
225     /* Takes a xml char * and a machine_data_list_t. This will parse
226     * the xml and put it into the correct entry of the machine_data
227     * linked list. This will return the number of entries in the linked
228     * list, or -1 on a error.
229     */
230     int parse_xml(char *xml, machine_data_list_t **md){
231     xmlDocPtr doc;
232     xmlNodePtr cur;
233     xmlNodePtr ele;
234     xmlAttr *list;
235    
236     static int num_hosts=0;
237    
238     machine_data_list_t *machine_data_list=*md;
239    
240     int found_host=0;
241    
242     char *hostname=NULL;
243     network_data_list_t *network_data_list=NULL;
244     network_data_list_t *ndl_ptr=NULL;
245     diskio_data_list_t *diskio_data_list=NULL;
246     diskio_data_list_t *didl_ptr=NULL;
247     char *tmp;
248    
249     doc=xmlParseDoc(xml);
250     if(doc==NULL) return -1;
251    
252     cur = xmlDocGetRootElement(doc);
253     if(cur==NULL){
254     xmlFreeDoc(doc);
255     return -1;
256     }
257    
258    
259     /* Get the hostname */
260     list=cur->properties;
261     while(list!=NULL){
262     if((xmlStrcmp(list->name, (const xmlChar *) "machine_name"))==0){
263     hostname = xmlNodeGetContent(list->children);
264     if(hostname==NULL){
265     return -1;
266     }
267     }
268     list=list->next;
269     }
270     if(hostname==NULL){
271     return -1;
272     }
273    
274     /* Get machine_data for host.. Or create if it doesn't have one */
275     while(machine_data_list!=NULL){
276     if((strncmp(machine_data_list->name, hostname, strlen(hostname)))==0){
277     found_host=1;
278     break;
279     }
280     machine_data_list=machine_data_list->next;
281     }
282    
283     if(!found_host){
284     /* We didn't find this host, but we should be at the end of the list */
285     machine_data_list=malloc(sizeof(machine_data_list_t));
286     if(machine_data_list==NULL) return -1;
287     machine_data_list->next=(*md);
288     machine_data_list->name=hostname;
289     machine_data_list->network_data_list=NULL;
290     machine_data_list->diskio_data_list=NULL;
291     *md=machine_data_list;
292     num_hosts++;
293     }
294    
295     /* Now we want to pull out the data */
296    
297     cur = cur->xmlChildrenNode;
298     while(cur != NULL) {
299     ele=cur->xmlChildrenNode;
300     while(ele != NULL){
301    
302     /* CPU Stats */
303     if(!xmlStrcmp(cur->name, (const xmlChar *) "cpu")){
304     tmp=xmlNodeGetContent(ele);
305     if(!xmlStrcmp(ele->name, (const xmlChar *) "user")){
306     machine_data_list->cpu_user=atof(tmp);
307     }
308     if(!xmlStrcmp(ele->name, (const xmlChar *) "kernel")){
309     machine_data_list->cpu_kernel=atof(tmp);
310     }
311     if(!xmlStrcmp(ele->name, (const xmlChar *) "idle")){
312     machine_data_list->cpu_idle=atof(tmp);
313     }
314     if(!xmlStrcmp(ele->name, (const xmlChar *) "iowait")){
315     machine_data_list->cpu_iowait=atof(tmp);
316     }
317     if(!xmlStrcmp(ele->name, (const xmlChar *) "swap")){
318     machine_data_list->cpu_iowait=atof(tmp);
319     }
320    
321     if(tmp!=NULL) xmlFree(tmp);
322     }
323    
324     /* Memory Stats */
325     if(!xmlStrcmp(cur->name, (const xmlChar *) "memory")){
326     tmp=xmlNodeGetContent(ele);
327     if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
328     machine_data_list->memory_total=atoll(tmp);
329     }
330     if(!xmlStrcmp(ele->name, (const xmlChar *) "free")){
331     machine_data_list->memory_free=atoll(tmp);
332     }
333     if(!xmlStrcmp(ele->name, (const xmlChar *) "used")){
334     machine_data_list->memory_used=atoll(tmp);
335     }
336    
337     if(tmp!=NULL) xmlFree(tmp);
338     }
339    
340     /* Load Stats */
341     if(!xmlStrcmp(cur->name, (const xmlChar *) "load")){
342     tmp=xmlNodeGetContent(ele);
343     if(!xmlStrcmp(ele->name, (const xmlChar *) "load1")){
344     machine_data_list->load_1=atof(tmp);
345     }
346     if(!xmlStrcmp(ele->name, (const xmlChar *) "load5")){
347     machine_data_list->load_5=atof(tmp);
348     }
349     if(!xmlStrcmp(ele->name, (const xmlChar *) "load15")){
350     machine_data_list->load_15=atof(tmp);
351     }
352    
353     if(tmp!=NULL) xmlFree(tmp);
354     }
355    
356     /* swap stats */
357     if(!xmlStrcmp(cur->name, (const xmlChar *) "swap")){
358     tmp=xmlNodeGetContent(ele);
359     if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
360     machine_data_list->swap_total=atoll(tmp);
361     }
362     if(!xmlStrcmp(ele->name, (const xmlChar *) "free")){
363     machine_data_list->swap_free=atoll(tmp);
364     }
365     if(!xmlStrcmp(ele->name, (const xmlChar *) "used")){
366     machine_data_list->swap_used=atoll(tmp);
367     }
368    
369     if(tmp!=NULL) xmlFree(tmp);
370     }
371    
372     /* Process stat */
373     if(!xmlStrcmp(cur->name, (const xmlChar *) "processes")){
374     tmp=xmlNodeGetContent(ele);
375     if(!xmlStrcmp(ele->name, (const xmlChar *) "sleeping")){
376     machine_data_list->processes_sleeping=atoi(tmp);
377     }
378     if(!xmlStrcmp(ele->name, (const xmlChar *) "cpu")){
379     machine_data_list->processes_cpu=atoi(tmp);
380     }
381     if(!xmlStrcmp(ele->name, (const xmlChar *) "zombie")){
382     machine_data_list->processes_zombie=atoi(tmp);
383     }
384     if(!xmlStrcmp(ele->name, (const xmlChar *) "total")){
385     machine_data_list->processes_total=atoi(tmp);
386     }
387    
388     if(tmp!=NULL) xmlFree(tmp);
389     }
390    
391     /* paging stats */
392     if(!xmlStrcmp(cur->name, (const xmlChar *) "pages")){
393     tmp=xmlNodeGetContent(ele);
394     if(!xmlStrcmp(ele->name, (const xmlChar *) "pageins")){
395     machine_data_list->pages_in=atoi(tmp);
396     }
397     if(!xmlStrcmp(ele->name, (const xmlChar *) "pageouts")){
398     machine_data_list->pages_out=atoi(tmp);
399     }
400    
401     if(tmp!=NULL) xmlFree(tmp);
402     }
403    
404     /* OS stats */
405     if(!xmlStrcmp(cur->name, (const xmlChar *) "os")){
406     tmp=xmlNodeGetContent(ele);
407     if(!xmlStrcmp(ele->name, (const xmlChar *) "sysname")){
408     strlcpy(machine_data_list->sysname, tmp, MAXHOSTNAMESIZE+1);
409     }
410     if(tmp!=NULL) xmlFree(tmp);
411     }
412    
413     /* Network stats */
414     /* Needs to connect current stat to a previous one. Or create it if new */
415     /* Get name.. Walk list. If match, copy rx/tx values. Else malloc, add to list */
416     if(!xmlStrcmp(cur->name, (const xmlChar *) "net")){
417    
418     list=ele->properties;
419     if(list==NULL) continue;
420     network_data_list=malloc(sizeof(network_data_list_t));
421     if(network_data_list==NULL) return -1;
422     while(list!=NULL){
423     tmp=xmlNodeGetContent(list->children);
424     if(!xmlStrcmp(list->name, (const xmlChar *) "name")){
425     network_data_list->name=strdup(tmp);
426     }
427     if(!xmlStrcmp(list->name, (const xmlChar *) "rx")){
428     network_data_list->rx=atoll(tmp);
429     }
430     if(!xmlStrcmp(list->name, (const xmlChar *) "tx")){
431     network_data_list->tx=atoll(tmp);
432     }
433    
434     xmlFree(tmp);
435     list=list->next;
436     }
437     if(network_data_list->name==NULL) continue;
438     found_host=0;
439     ndl_ptr=machine_data_list->network_data_list;
440     while(ndl_ptr!=NULL){
441     if(!strcmp(ndl_ptr->name, network_data_list->name)){
442     found_host=1;
443     break;
444     }
445     ndl_ptr=ndl_ptr->next;
446     }
447     if(found_host){
448     ndl_ptr->rx=network_data_list->rx;
449     ndl_ptr->tx=network_data_list->tx;
450     free(network_data_list->name);
451     free(network_data_list);
452     }else{
453     network_data_list->next=machine_data_list->network_data_list;
454     machine_data_list->network_data_list=network_data_list;
455     }
456     }
457    
458     /* Disk IO stats */
459     if(!xmlStrcmp(cur->name, (const xmlChar *) "diskio")){
460    
461     list=ele->properties;
462     if(list==NULL) continue;
463     diskio_data_list=malloc(sizeof(diskio_data_list_t));
464     if(diskio_data_list==NULL) return -1;
465     while(list!=NULL){
466     tmp=xmlNodeGetContent(list->children);
467     if(!xmlStrcmp(list->name, (const xmlChar *) "name")){
468     diskio_data_list->name=strdup(tmp);
469     }
470     if(!xmlStrcmp(list->name, (const xmlChar *) "rbytes")){
471     diskio_data_list->read=atoll(tmp);
472     }
473     if(!xmlStrcmp(list->name, (const xmlChar *) "wbytes")){
474     diskio_data_list->write=atoll(tmp);
475     }
476    
477     xmlFree(tmp);
478     list=list->next;
479     }
480     if(diskio_data_list->name==NULL) continue;
481     found_host=0;
482     didl_ptr=machine_data_list->diskio_data_list;
483     while(didl_ptr!=NULL){
484     if(!strcmp(didl_ptr->name, diskio_data_list->name)){
485     found_host=1;
486     break;
487     }
488     didl_ptr=didl_ptr->next;
489     }
490     if(found_host){
491     didl_ptr->read=diskio_data_list->read;
492     didl_ptr->write=diskio_data_list->write;
493     free(diskio_data_list->name);
494     free(diskio_data_list);
495     }else{
496     diskio_data_list->next=machine_data_list->diskio_data_list;
497     machine_data_list->diskio_data_list=diskio_data_list;
498     }
499     }
500    
501    
502    
503     ele=ele->next;
504     }
505     cur=cur->next;
506     }
507    
508     /* Append data we want thats not stored in the server */
509     machine_data_list->cpu_used=100.00-machine_data_list->cpu_idle;
510     machine_data_list->memory_used_pecent=((double)machine_data_list->memory_used / (double)machine_data_list->memory_total) * 100.00;
511     machine_data_list->swap_used_pecent=((double)machine_data_list->swap_used / (double)machine_data_list->swap_total) * 100.00;
512    
513     ndl_ptr=machine_data_list->network_data_list;
514     machine_data_list->network_io_total_tx=0;
515     machine_data_list->network_io_total_rx=0;
516     while(ndl_ptr!=NULL){
517     machine_data_list->network_io_total_tx+=ndl_ptr->tx;
518     machine_data_list->network_io_total_rx+=ndl_ptr->rx;
519     ndl_ptr=ndl_ptr->next;
520     }
521    
522     didl_ptr=machine_data_list->diskio_data_list;
523     machine_data_list->disk_io_total_read=0;
524     machine_data_list->disk_io_total_write=0;
525     while(didl_ptr!=NULL){
526     machine_data_list->disk_io_total_read+=didl_ptr->read;
527     machine_data_list->disk_io_total_write+=didl_ptr->write;
528     didl_ptr=didl_ptr->next;
529     }
530    
531     xmlFreeDoc(doc);
532    
533     return num_hosts;
534    
535    
536     }
537    
538     void display(machine_data_list_t *machine_data_list, int num_lines){
539     int line_num=4;
540    
541     for(;num_lines;num_lines--){
542     if(machine_data_list==NULL) break;
543     printf("\033[%d;%dH%-11s %5.1f %5.1f %5d %5d %5.1f %5.1f %8lld %8lld %9lld %9lld", \
544     line_num++, 1, \
545     machine_data_list->sysname,
546     machine_data_list->cpu_used,
547     machine_data_list->load_1,
548     machine_data_list->pages_in,
549     machine_data_list->pages_out,
550     machine_data_list->memory_used_pecent,
551     machine_data_list->swap_used_pecent,
552     machine_data_list->network_io_total_rx,
553     machine_data_list->network_io_total_tx,
554     machine_data_list->disk_io_total_read,
555     machine_data_list->disk_io_total_write);
556     machine_data_list=machine_data_list->next;
557     }
558    
559     fflush(stdout);
560    
561     }
562    
563     int main(int argc, char **argv){
564     FILE *control;
565     FILE *data;
566    
567     char *machine_list=NULL;
568     char *response=NULL;
569    
570     char *servername;
571     int server_control_port;
572     int server_data_port;
573    
574     machine_data_list_t *machine_data_list=NULL;
575    
576     int num_hosts;
577     int max_display=0;
578    
579     int cmdopt;
580     extern int optind;
581     extern char *optarg;
582    
583     display_config_t display_config;
584    
585     /* What to display defaults */
586     display_config.cpu_user=0;
587     display_config.cpu_idle=0;
588     display_config.cpu_iowait=0;
589     display_config.cpu_kernel=0;
590     display_config.cpu_swap=0;
591     display_config.cpu_used=1;
592    
593     display_config.memory_total=0;
594     display_config.memory_free=0;
595     display_config.memory_used=0;
596     display_config.memory_used_pecent=1;
597    
598     display_config.swap_total=0;
599     display_config.swap_free=0;
600     display_config.swap_used=0;
601     display_config.swap_used_pecent=1;
602    
603     display_config.load_1=1;
604     display_config.load_5=0;
605     display_config.load_15=0;
606    
607     display_config.pages_in=1;
608     display_config.pages_out=1;
609    
610     display_config.processes_total=0;
611     display_config.processes_sleeping=0;
612     display_config.processes_cpu=0;
613     display_config.processes_zombie=0;
614     display_config.processes_stopped=0;
615    
616     display_config.network_io_total_tx=0;
617     display_config.network_io_total_rx=0;
618     display_config.network_all_stats=1;
619    
620     display_config.disk_io_total_write=0;
621     display_config.disk_io_total_read=0;
622     display_config.disk_io_all_stats=1;
623    
624     display_config.disk_total_used=0;
625     display_config.disk_all_stats=0;
626    
627     while((cmdopt=getopt(argc, argv, "d:")) != -1){
628     switch(cmdopt){
629     case 'd':
630     max_display=atoi(optarg);
631     break;
632     }
633     }
634    
635    
636     if(argc<(optind+2)){
637     printf("Usage is %s <-d lines> hostname port <machine list>\n", argv[0]);
638     exit(1);
639     }
640    
641     servername=argv[optind];
642     server_control_port=atoi(argv[optind+1]);
643    
644     control=create_tcp_connection(servername, server_control_port);
645     if(control==NULL){
646     errf("Failed to connect (%m)");
647     }
648    
649     if(argc==4){
650     /* We've been passed a machine list */
651     /* list currently needs to be ; seperated */
652     machine_list=strdup(argv[3]);
653     }
654    
655     if((tcp_comm(control, NULL, &response, "PROTOCOL 1.1"))!=0){
656     errf("Incorrect version number (%s)", response);
657     exit(1);
658     }
659    
660     if((tcp_comm(control, "stattop", &response, "OK"))!=0){
661     errf("Unexpected response %s", response);
662     exit(1);
663     }
664    
665     if(machine_list!=NULL){
666     if((tcp_comm(control, "SETHOSTLIST", &response, "OK"))!=0){
667     errf("Unexpected response %s", response);
668     exit(1);
669     }
670     if((tcp_comm(control, machine_list, &response, "OK"))!=0){
671     errf("Unexpected response %s", response);
672     exit(1);
673     }
674     }
675    
676     if((tcp_comm(control, "STARTDATA", &response, NULL))!=0){
677     errf("Unexpected response %s", response);
678     exit(1);
679     }
680    
681     server_data_port=atoi(response);
682     if(server_data_port==0){
683     errf("Unexpected response %s", response);
684     exit(1);
685     }
686    
687     data=create_tcp_connection(servername, server_data_port);
688     if(data==NULL){
689     errf("Failed to connect to host %s on port %d (%m)",servername, server_data_port);
690     }
691    
692    
693     printf("\033[2J");
694     printf("\033[1;1HHostname CPU Load Page Page Mem Swap Net Net Disk Disk");
695     printf("\033[2;1H used%% (1m) ins outs used used rx tx read write");
696     fflush(stdout);
697     for(;;){
698     response=fpgetline(data);
699     if (response==NULL){
700     errf("Failed to read data (%m)");
701     exit(1);
702     }
703    
704     num_hosts=parse_xml(response, &machine_data_list);
705     if(num_hosts==-1) continue;
706     machine_data_list=sort_machine_stats(machine_data_list, num_hosts, cmp_cpu);
707     if(max_display==0){
708     display(machine_data_list, num_hosts);
709     }else{
710     display(machine_data_list, max_display);
711     }
712    
713     }
714     exit(0);
715     }