ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/idar/idar.c
Revision: 1.15
Committed: Thu Apr 10 12:31:19 2003 UTC (21 years, 8 months ago) by pajs
Content type: text/plain
Branch: MAIN
CVS Tags: IDAR_1_1
Changes since 1.14: +100 -73 lines
Log Message:
Proper resize support by catching SIGWINCH. Done some tiding. Added the ability
to do process stats (r).

Changed the megabytes units to have 2d.p. so it would show more than units of
100k/sec.

File Contents

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