ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/ihost/ihost.c
Revision: 1.41
Committed: Fri Aug 22 14:40:11 2003 UTC (21 years, 4 months ago) by pajs
Content type: text/plain
Branch: MAIN
CVS Tags: IHOST_1_5_6
Changes since 1.40: +39 -5 lines
Log Message:
Added support to be able to specify the hostname or IP address of the host.
This is mainly useful for machines with multiple NIC's and you want it to be
called something specific (which may not be the IP you use to connect to the
server with)

File Contents

# User Rev Content
1 tdb 1.11 /*
2     * i-scream central monitoring system
3 tdb 1.23 * http://www.i-scream.org.uk
4 tdb 1.11 * 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 tdb 1.26 #ifdef HAVE_CONFIG_H
22     #include "config.h"
23     #endif
24    
25 pajs 1.1 #include <stdio.h>
26     #include <stdlib.h>
27 pajs 1.28 #include <unistd.h>
28     #include <string.h>
29 pajs 1.18 #include <sys/types.h>
30 pajs 1.28 #include <sys/socket.h>
31     #include <stdarg.h>
32     #include <errno.h>
33 pajs 1.1 #include <netdb.h>
34 pajs 1.40 #include <netinet/in.h>
35 pajs 1.28
36 tdb 1.39 #include <ukcprog.h>
37     #include <statgrab.h>
38 pajs 1.1
39 pajs 1.28 #define LOG_CRIT 0
40     #define LOG_ERR 1
41     #define LOG_INFO 2
42     #define LOG_DEBUG 3
43    
44 pajs 1.1 typedef struct{
45 pajs 1.28 int filtermanager_port;
46     char *filtermanager_host;
47    
48     char *host_ip;
49     char *host_fqdn;
50 pajs 1.41 int preset_fqdn;
51     int preset_ip;
52 pajs 1.16
53 pajs 1.1 char *server_fqdn;
54     int server_udp_port;
55 pajs 1.28
56     /* Weird stuff iscream wants sent to it */
57 pajs 1.4 char *last_modified;
58 pajs 1.28 char *file_list;
59    
60 pajs 1.1 int udp_update_time;
61 pajs 1.28 // int config_ttl;
62    
63     time_t config_ttl;
64 pajs 1.1
65     }ihost_state_t;
66    
67 pajs 1.28 typedef struct{
68     int verbose;
69     int daemon;
70    
71     FILE *log;
72     }ihost_config_t;
73    
74     typedef struct{
75     struct sockaddr_in addr;
76     int sock;
77     }udp_sockinfo_t;
78    
79     ihost_config_t ihost_config;
80    
81 pajs 1.33 extern int errno;
82    
83 tdb 1.34 /* Taken from the OpenSSH code. Its licence included in function.*/
84     #ifndef HAVE_STRLCAT
85 pajs 1.33
86     /*
87     * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
88     * All rights reserved.
89     *
90     * Redistribution and use in source and binary forms, with or without
91     * modification, are permitted provided that the following conditions
92     * are met:
93     * 1. Redistributions of source code must retain the above copyright
94     * notice, this list of conditions and the following disclaimer.
95     * 2. Redistributions in binary form must reproduce the above copyright
96     * notice, this list of conditions and the following disclaimer in the
97     * documentation and/or other materials provided with the distribution.
98     * 3. The name of the author may not be used to endorse or promote products
99     * derived from this software without specific prior written permission.
100     *
101     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
102     * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
103     * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
104     * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
105     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
106     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
107     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
108     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
109     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
110     * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
111     */
112 tdb 1.34
113 pajs 1.33 /*
114     * Appends src to string dst of size siz (unlike strncat, siz is the
115     * full size of dst, not space left). At most siz-1 characters
116     * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
117     * Returns strlen(src) + MIN(siz, strlen(initial dst)).
118     * If retval >= siz, truncation occurred.
119     */
120     size_t
121     strlcat(dst, src, siz)
122     char *dst;
123     const char *src;
124     size_t siz;
125     {
126     register char *d = dst;
127     register const char *s = src;
128     register size_t n = siz;
129     size_t dlen;
130    
131     /* Find the end of dst and adjust bytes left but don't go past end */
132     while (n-- != 0 && *d != '\0')
133     d++;
134     dlen = d - dst;
135     n = siz - dlen;
136    
137     if (n == 0)
138     return(dlen + strlen(s));
139     while (*s != '\0') {
140     if (n != 1) {
141     *d++ = *s;
142     n--;
143     }
144     s++;
145     }
146     *d = '\0';
147    
148     return(dlen + (s - src)); /* count does not include NUL */
149     }
150    
151 tdb 1.34 #endif
152     /* End strlcat function taken from OpenSSH */
153 pajs 1.33
154 pajs 1.28 void log_msg(int level, char *format, ...){
155     int cur_errno;
156     va_list ap;
157    
158     cur_errno=errno;
159    
160     if(level<=ihost_config.verbose){
161     va_start(ap, format);
162     vfprintf(ihost_config.log, format, ap);
163     va_end(ap);
164     if(level==LOG_CRIT){
165     fprintf(ihost_config.log, " (%s)\n", strerror(cur_errno));
166 pajs 1.18 }else{
167 pajs 1.28 fprintf(ihost_config.log, "\n");
168 pajs 1.18 }
169 pajs 1.37 fflush(ihost_config.log);
170 pajs 1.28 }
171 pajs 1.18 }
172    
173 pajs 1.28 /* Takes many pointers, checks if they are NULL or not, and then free's them */
174     /* Deprciated - and i only wrote it today! :)
175     void m_free(int num_pointers, ...){
176     int x=0;
177     va_list ap;
178     void *p;
179 pajs 1.1
180 pajs 1.28 va_start(ap, num_pointers);
181     for(;x<num_pointers;x++){
182     p=va_arg(ap, void*);
183     if(p!=NULL){
184     free(p);
185     }
186     }
187     va_end(ap);
188     }
189     */
190    
191     int create_udp_sockinfo(udp_sockinfo_t *udp_sockinfo, char *hostname, int port){
192    
193     struct in_addr haddr;
194    
195     log_msg(LOG_DEBUG, "Resolving name for udp connection");
196     if(get_host_addr(hostname, &haddr) != 0){
197     log_msg(LOG_CRIT, "Failed to lookup name");
198     return 1;
199     }
200 pajs 1.1
201 pajs 1.28 if((udp_sockinfo->sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
202     log_msg(LOG_CRIT, "Failed to create UDP socket");
203     return 1;
204 pajs 1.1 }
205    
206 pajs 1.28 memset(&(udp_sockinfo->addr), 0, sizeof(struct sockaddr_in));
207     udp_sockinfo->addr.sin_family=AF_INET;
208     memcpy((char *)&(udp_sockinfo->addr.sin_addr), &haddr, sizeof(haddr));
209     udp_sockinfo->addr.sin_port = htons(port);
210 pajs 1.1
211 pajs 1.28 log_msg(LOG_DEBUG, "Socket created");
212     return 0;
213     }
214    
215     FILE *create_tcp_connection(char *hostname, int port){
216     int sock;
217     struct sockaddr_in addr;
218     struct in_addr haddr;
219     FILE *f;
220    
221     log_msg(LOG_DEBUG, "Creating tcp socket");
222     if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){
223     log_msg(LOG_CRIT, "Failed to make TCP Socket");
224     return NULL;
225 pajs 1.1 }
226    
227 pajs 1.28 if((get_host_addr(hostname, &haddr))!=0){
228     log_msg(LOG_CRIT, "Failed to lookup name for %s", hostname);
229 pajs 1.38 close(sock);
230 pajs 1.28 return NULL;
231 pajs 1.2 }
232    
233 pajs 1.28 memset(&addr, 0, sizeof(addr));
234     addr.sin_family = AF_INET;
235     memcpy(&addr.sin_addr, &haddr, sizeof(haddr));
236     addr.sin_port = htons(port);
237    
238     log_msg(LOG_DEBUG, "Creating a tcp connection");
239     if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){
240     log_msg(LOG_CRIT, "Failed to connect to hostname %s on port %d", hostname, port);
241 pajs 1.38 close(sock);
242 pajs 1.28 return NULL;
243 pajs 1.1 }
244 pajs 1.28
245     if((f=fdopen(sock, "r+"))==NULL){
246     log_msg(LOG_CRIT, "Failed to connect to open filedescriptor on tcp connection");
247     close(sock);
248     return NULL;
249 pajs 1.16 }
250 pajs 1.28
251     return f;
252     }
253    
254     int tcp_comm(FILE *f, char *send, char **response, char *expected){
255    
256     log_msg(LOG_DEBUG, "Sending %s", send);
257     fprintf(f, "%s\n", send);
258     fflush(f);
259     *response=fpgetline(f);
260     fseek(f, 0, SEEK_CUR);
261    
262     if(*response!=NULL) log_msg(LOG_DEBUG, "Recieved %s", *response);
263    
264     if( (*response==NULL) || (strcmp(*response, "ERROR")==0) ) return -1;
265    
266     if(expected==NULL) return 0;
267    
268     if((strcmp(expected, *response))==0) return 0;
269    
270     log_msg(LOG_DEBUG, "Did not get expected response");
271     return -1;
272     }
273    
274     int tcp_comm_strdup(FILE *f, char *send, char **response, char *expected){
275     if((tcp_comm(f, send, response, expected))!=0){
276 pajs 1.16 return -1;
277     }
278 pajs 1.25
279 pajs 1.28 *response=strdup(*response);
280     if (response==NULL) return -1;
281    
282     return 0;
283     }
284    
285     int ihost_getconfig(ihost_state_t *ihost_state){
286    
287     FILE *tcp_con;
288     char *response;
289     char *response_ptr;
290    
291     /* Keep these in case of a failure and so it can keep running on the old config */
292     char *file_list=NULL;
293     char *last_modified=NULL;
294     char *host_fqdn=NULL;
295     char *host_ip=NULL;
296     int udp_update_time=0;
297     char *server_fqdn=NULL;
298     int server_udp_port=0;
299     time_t config_ttl=0;
300    
301 pajs 1.30 if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port))==NULL){
302 pajs 1.35 return -1;
303 pajs 1.30 }
304 pajs 1.28
305     if(ihost_state->file_list!=NULL || ihost_state->last_modified!=NULL){
306     if(tcp_con==NULL){
307     goto error;
308     }
309    
310     if((tcp_comm(tcp_con, "CHECKCONFIG", &response, "OK"))!=0){
311     goto error;
312     }
313    
314     if((tcp_comm(tcp_con, ihost_state->file_list, &response, "OK"))!=0){
315     goto error;
316     }
317 pajs 1.18
318 pajs 1.28 if((tcp_comm(tcp_con, ihost_state->last_modified, &response, "OK"))==0){
319 pajs 1.32 if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){
320 pajs 1.28 goto error;
321     }
322     fclose(tcp_con);
323     return 0;
324     }else{
325     if((strcmp(response, "EXPIRED"))!=0){
326     goto error;
327     }
328     }
329 pajs 1.1 }
330    
331 pajs 1.28 /* If we got to here, the config must of expired */
332 pajs 1.18
333 pajs 1.28 if((tcp_comm(tcp_con, "STARTCONFIG", &response, "OK"))!=0){
334     goto error;
335 pajs 1.1 }
336    
337 pajs 1.28 if((tcp_comm_strdup(tcp_con, "LASTMODIFIED", &response, NULL))!=0){
338     goto error;
339 pajs 1.1 }
340 pajs 1.28 last_modified=response;
341    
342     if((tcp_comm_strdup(tcp_con, "FILELIST", &response, NULL))!=0){
343     goto error;
344 pajs 1.1 }
345 pajs 1.28 file_list=response;
346 pajs 1.1
347 pajs 1.28 if((tcp_comm_strdup(tcp_con, "FQDN", &response, NULL))!=0){
348     goto error;
349 pajs 1.1 }
350 pajs 1.28 host_fqdn=response;
351    
352     if((tcp_comm_strdup(tcp_con, "IP", &response, NULL))!=0){
353     goto error;
354 pajs 1.1 }
355 pajs 1.28 host_ip=response;
356    
357     if((tcp_comm(tcp_con, "UDPUpdateTime", &response, NULL))!=0){
358     goto error;
359 pajs 1.1 }
360 pajs 1.28 udp_update_time=atoi(response);
361    
362     if((tcp_comm(tcp_con, "ConfigTTL", &response, NULL))!=0){
363     goto error;
364 pajs 1.1 }
365 pajs 1.28 config_ttl=atoi(response);
366 pajs 1.1
367 pajs 1.28 if((tcp_comm(tcp_con, "ENDCONFIG", &response, NULL))!=0){
368     goto error;
369 pajs 1.1 }
370    
371 pajs 1.28 if((tcp_comm(tcp_con, "FILTER", &response, NULL))!=0){
372     goto error;
373     }else{
374     response_ptr=strchr(response,';');
375     if(response_ptr==NULL){
376     log_msg(LOG_ERR, "Incorrect data sent by server");
377     goto error;
378     }
379     *response_ptr='\0';
380     server_fqdn=strdup(response);
381     if(server_fqdn==NULL){
382     goto error;
383     }
384     response_ptr++;
385     if(response_ptr==NULL){
386     log_msg(LOG_ERR, "Incorrect data sent by server");
387     goto error;
388     }
389    
390     printf("string : %s\n", response_ptr);
391     server_udp_port=atoi(response_ptr);
392    
393     if (server_udp_port==0){
394     log_msg(LOG_ERR, "Incorrect data sent by server");
395     goto error;
396     }
397 pajs 1.2 }
398 pajs 1.28
399     if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){
400     goto error;
401 pajs 1.2 }
402 pajs 1.28
403     fclose(tcp_con);
404    
405     /* We have the data we need, and its all been read correctly */
406    
407     /* Free the old data before pointing them to the new data. m_free copes should
408     * this already be NULL */
409     if(ihost_state->file_list!=NULL) free(ihost_state->file_list);
410     if(ihost_state->last_modified!=NULL) free(ihost_state->last_modified);
411     if(ihost_state->server_fqdn!=NULL) free(ihost_state->server_fqdn);
412 pajs 1.41
413     if(ihost_state->preset_fqdn){
414     if(host_fqdn != NULL) free(host_fqdn);
415     }else{
416     if(ihost_state->host_fqdn!=NULL) free(ihost_state->host_fqdn);
417     ihost_state->host_fqdn=host_fqdn;
418     }
419    
420     if(ihost_state->preset_ip){
421     if(host_ip != NULL) free(host_ip);
422     }else{
423     if(ihost_state->host_ip!=NULL) free(ihost_state->host_ip);
424     ihost_state->host_ip=host_ip;
425     }
426    
427 pajs 1.28
428     ihost_state->file_list=file_list;
429     ihost_state->last_modified=last_modified;
430     ihost_state->server_fqdn=server_fqdn;
431     ihost_state->server_udp_port=server_udp_port;
432     ihost_state->udp_update_time=udp_update_time;
433     ihost_state->config_ttl=config_ttl;
434    
435     log_msg(LOG_DEBUG, "UDP Update time %d", udp_update_time);
436     log_msg(LOG_DEBUG, "Configure ttl %d", config_ttl);
437    
438     return 0;
439    
440     error:
441    
442     if(file_list!=NULL) free(file_list);
443     if(last_modified!=NULL) free(last_modified);
444     if(host_fqdn!=NULL) free(host_fqdn);
445     if(server_fqdn!=NULL) free(server_fqdn);
446     if(host_ip!=NULL) free(host_ip);
447     fclose(tcp_con);
448    
449     return -1;
450     }
451    
452     int get_system_stats(int seq_no, ihost_state_t *ihost_state, char *xml, int size){
453     char tmp[size];
454     cpu_percent_t *cpu_percent;
455     mem_stat_t *mem_stats;
456     load_stat_t *load_stats;
457     user_stat_t *user_stats;
458     swap_stat_t *swap_stats;
459     general_stat_t *general_stats;
460     disk_stat_t *disk_stats;
461     diskio_stat_t *diskio_stats;
462     process_stat_t *process_stats;
463     network_stat_t *network_stats;
464     page_stat_t *page_stats;
465     int disk_entries=0;
466     int diskio_entries=0;
467     int network_entries=0;
468    
469     int counter;
470     long long x;
471     long long y;
472    
473     /* Print start of the packet we want */
474     snprintf(xml, size, "<packet seq_no=\"%d\" machine_name=\"%s\" date=\"%ld\" type=\"data\" ip=\"%s\">", \
475     seq_no, ihost_state->host_fqdn, time(NULL), ihost_state->host_ip);
476    
477     /* Get cpu stats, check it is correct, then fill in its entry for the xml */
478     if((cpu_percent=cpu_percent_usage())==NULL){
479     log_msg(LOG_CRIT, "Failed to get cpu statistics");
480     }else{
481     snprintf(tmp, size, \
482     "<cpu><user>%3.2f</user><kernel>%3.2f</kernel><idle>%3.2f</idle><iowait>%3.2f</iowait><swap>%3.2f</swap></cpu>", \
483     cpu_percent->user, \
484     cpu_percent->kernel, \
485     cpu_percent->idle, \
486     cpu_percent->iowait, \
487     cpu_percent->swap);
488    
489     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
490 pajs 1.2 }
491 pajs 1.28
492    
493     /*Get mem stats, and fill in xml */
494     if((mem_stats=get_memory_stats())==NULL){
495     log_msg(LOG_CRIT, "Failed to get memory statistics");
496     }else{
497     snprintf(tmp, size, \
498     "<memory><total>%lld</total><free>%lld</free><used>%lld</used><cache>%lld</cache></memory>", \
499     mem_stats->total, \
500     mem_stats->free, \
501     mem_stats->used, \
502     mem_stats->cache);
503    
504     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
505 pajs 1.2 }
506 pajs 1.28
507    
508     /* Get load stats */
509     if((load_stats=get_load_stats())==NULL){
510     log_msg(LOG_CRIT, "Failed to get load statistics");
511     }else{
512     snprintf(tmp, size, \
513     "<load><load1>%.2lf</load1><load5>%.2lf</load5><load15>%.2lf</load15></load>", \
514     load_stats->min1, \
515     load_stats->min5, \
516     load_stats->min15);
517     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
518 pajs 1.2 }
519    
520 pajs 1.28
521     /* get user stats */
522    
523     if((user_stats=get_user_stats())==NULL){
524     log_msg(LOG_CRIT, "Failed to get user statistics");
525     }else{
526    
527     snprintf(tmp, size, \
528     "<users><list>%s</list><count>%d</count></users>", \
529     user_stats->name_list, \
530     user_stats->num_entries);
531    
532     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
533 pajs 1.2 }
534 pajs 1.1
535 pajs 1.28
536     /* swap stats */
537     if((swap_stats=get_swap_stats())==NULL){
538     log_msg(LOG_CRIT, "Failed to get swap statistics");
539     }else{
540     snprintf(tmp, size, \
541     "<swap><total>%lld</total><used>%lld</used><free>%lld</free></swap>",\
542     swap_stats->total, \
543     swap_stats->used, \
544     swap_stats->free);
545    
546     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
547 pajs 1.2 }
548 pajs 1.28
549    
550     /* general stats */
551    
552     if((general_stats=get_general_stats())==NULL){
553     log_msg(LOG_CRIT, "Failed to get general statistics");
554     }else{
555     snprintf(tmp, size, \
556     "<os><name>%s</name><release>%s</release><version>%s</version><sysname>%s</sysname><platform>%s</platform><uptime>%ld</uptime></os>", \
557     general_stats->os_name, \
558     general_stats->os_release, \
559     general_stats->os_version, \
560     general_stats->hostname, \
561     general_stats->platform, \
562     (long)general_stats->uptime);
563    
564     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
565    
566 pajs 1.2 }
567 pajs 1.1
568 pajs 1.28
569     /* process stats */
570     if((process_stats=get_process_stats())==NULL){
571     log_msg(LOG_CRIT, "Failed to get general statistics");
572     }else{
573     snprintf(tmp, size, \
574     "<processes><sleeping>%d</sleeping><cpu>%d</cpu><zombie>%d</zombie><stopped>%d</stopped><total>%d</total></processes>",\
575     process_stats->sleeping, \
576     process_stats->running, \
577     process_stats->zombie, \
578     process_stats->stopped, \
579     process_stats->total);
580    
581     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
582 pajs 1.4
583 pajs 1.28 }
584 pajs 1.4
585    
586 pajs 1.28 /* Get paging stats */
587     if((page_stats=get_page_stats_diff())==NULL){
588     log_msg(LOG_CRIT, "Failed to get paging statistics");
589     }else{
590     if(page_stats->systime!=0){
591     x=page_stats->pages_pagein / page_stats->systime;
592     y=page_stats->pages_pageout / page_stats->systime;
593     }else{
594     x=page_stats->pages_pagein;
595     y=page_stats->pages_pageout;
596     }
597     snprintf(tmp, size, \
598 tdb 1.36 "<pages><pageins>%lld</pageins><pageouts>%lld</pageouts></pages>", \
599 pajs 1.28 x, \
600     y);
601    
602     if(strlcat(xml, tmp, size) >= size) goto too_big_error;
603     }
604 pajs 1.4
605    
606 pajs 1.28 /* get diskio stats */
607    
608     if((diskio_stats=get_diskio_stats_diff(&diskio_entries))==NULL){
609 pajs 1.31 log_msg(LOG_CRIT, "Failed to get diskio statistics");
610 pajs 1.28 }else{
611     strlcat(xml, "<diskio>", size);
612     for(counter=0;counter<diskio_entries;counter++){
613 pajs 1.4
614 pajs 1.28 if(diskio_stats->systime!=0){
615     x=diskio_stats->read_bytes / diskio_stats->systime;
616     y=diskio_stats->write_bytes / diskio_stats->systime;
617     }else{
618     x=diskio_stats->read_bytes;
619     y=diskio_stats->write_bytes;
620     }
621    
622     snprintf(tmp, size, \
623     "<p%d name=\"%s\" rbytes=\"%lld\" wbytes=\"%lld\"></p%d>", \
624     counter, \
625     diskio_stats->disk_name, \
626     x, \
627     y, \
628     counter);
629 pajs 1.9
630 pajs 1.28 strlcat(xml, tmp, size);
631     diskio_stats++;
632     }
633 pajs 1.4
634 pajs 1.28 if(strlcat(xml, "</diskio>", size) >= size) goto too_big_error;
635 pajs 1.4
636     }
637 pajs 1.18
638 pajs 1.28
639     /* get networks stats */
640    
641     if((network_stats=get_network_stats_diff(&network_entries))==NULL){
642     log_msg(LOG_CRIT, "Failed to get network statistics");
643     }else{
644     strlcat(xml, "<net>", size);
645     for(counter=0;counter<network_entries;counter++){
646     if(network_stats->systime!=0){
647     x=network_stats->rx / network_stats->systime;
648     y=network_stats->tx / network_stats->systime;
649     }else{
650     x=network_stats->rx;
651     y=network_stats->tx;
652     }
653 pajs 1.4
654 pajs 1.28 snprintf(tmp, size, \
655     "<p%d name=\"%s\" rx=\"%lld\" tx=\"%lld\"></p%d>", \
656     counter, \
657     network_stats->interface_name, \
658     x, \
659     y, \
660     counter);
661 pajs 1.4
662 pajs 1.28 strlcat(xml, tmp, size);
663     network_stats++;
664     }
665 pajs 1.10
666 pajs 1.28 if(strlcat(xml, "</net>", size) >= size) goto too_big_error;
667 pajs 1.6
668 pajs 1.28 }
669 pajs 1.4
670 pajs 1.18
671 pajs 1.28 /* get disk stats */
672    
673     if((disk_stats=get_disk_stats(&disk_entries))==NULL){
674     log_msg(LOG_CRIT, "Failed to get disk statistics");
675     }else{
676     strlcat(xml, "<disk>", size);
677     for(counter=0;counter<disk_entries;counter++){
678     snprintf(tmp, size, \
679     "<p%d name=\"%s\" mount=\"%s\" fstype=\"%s\" total=\"%lld\" used=\"%lld\" avail=\"%lld\" totalinodes=\"%lld\" usedinodes=\"%lld\" freeinodes=\"%lld\"></p%d>", \
680     counter, \
681     disk_stats->device_name, \
682     disk_stats->mnt_point, \
683     disk_stats->fs_type, \
684     disk_stats->size, \
685     disk_stats->used, \
686     disk_stats->avail, \
687     disk_stats->total_inodes, \
688     disk_stats->used_inodes, \
689     disk_stats->free_inodes, \
690     counter);
691 pajs 1.18
692 pajs 1.28 strlcat(xml, tmp, size);
693 pajs 1.9
694 pajs 1.28 disk_stats++;
695     }
696 pajs 1.9
697 pajs 1.28 if(strlcat(xml, "</disk>", size) >= size) goto too_big_error;
698 pajs 1.9
699     }
700 pajs 1.28
701 pajs 1.9
702 pajs 1.28 if(strlcat(xml, "</packet>", size) >= size) goto too_big_error;
703 pajs 1.9
704 pajs 1.28 /*If we got to here, it should of all been filled in nicely now */
705     return 0;
706 pajs 1.10
707 pajs 1.28 too_big_error:
708     log_msg(LOG_ERR, "UDP Packet is too large. Throwing away the packet");
709     return -1;
710 pajs 1.9 }
711 pajs 1.1
712 pajs 1.28
713    
714 pajs 1.17 void usage(char *progname){
715 pajs 1.28 fprintf(stderr, "Usage %s [options] server port\n", progname);
716     fprintf(stderr, "Options\n");
717     fprintf(stderr, " -v Verbose mode,-vv would make even more verbose\n");
718     fprintf(stderr, " -f Foreground mode, print errors to stderr\n");
719 pajs 1.41 fprintf(stderr, " -s Set the machine name to be reported as\n");
720     fprintf(stderr, " -i Set the IP to be reported as\n");
721 pajs 1.28 fprintf(stderr, " -V Print version number\n");
722     fprintf(stderr, " -h Prints this help page\n");
723     exit(1);
724 pajs 1.17 }
725    
726 pajs 1.3 int main(int argc, char **argv){
727 pajs 1.28
728 pajs 1.2 ihost_state_t ihost_state;
729 pajs 1.28 udp_sockinfo_t udp_sockinfo;
730    
731 pajs 1.17 int cmdopt;
732     extern int optind;
733 pajs 1.28 pid_t pid;
734 pajs 1.19 FILE *f;
735 pajs 1.28 int packet_num=0;
736     int len;
737 pajs 1.18
738 pajs 1.28 char packet[MAX_UDP_PACKET_SIZE];
739 pajs 1.18
740 pajs 1.28 time_t cur_time, sleep_delay, udp_time=0, config_time=0;
741 pajs 1.18
742 pajs 1.28 /* Set default settings */
743     ihost_config.verbose=1;
744     ihost_config.daemon=1;
745     /* Set all errors to go down stderr until told otherwise */
746     ihost_config.log=stderr;
747    
748     /* Blank ihost_state to default settings */
749     ihost_state.filtermanager_host=NULL;
750     ihost_state.host_fqdn=NULL;
751     ihost_state.host_ip=NULL;
752 pajs 1.41 ihost_state.preset_fqdn = 0;
753     ihost_state.preset_ip = 0;
754 pajs 1.28 ihost_state.server_fqdn=NULL;
755     ihost_state.file_list=NULL;
756     ihost_state.last_modified=NULL;
757    
758 pajs 1.41 while((cmdopt=getopt(argc, argv, "vfhVs:i:")) != -1){
759 pajs 1.28 switch(cmdopt){
760     case 'v':
761     ihost_config.verbose++;
762     break;
763    
764     case 'f':
765     /* Force syslog logging since stderr will be closed in this case */
766     ihost_config.daemon=0;
767     break;
768    
769     case 'h':
770     usage(argv[0]);
771     break;
772    
773     case 'V':
774 tdb 1.29 fprintf(stderr, "%s version %s\n", argv[0], VERSION);
775 pajs 1.28 break;
776 pajs 1.41 case 's':
777     ihost_state.preset_fqdn = 1;
778     ihost_state.host_fqdn = strdup(optarg);
779     if(ihost_state.host_fqdn == NULL){
780     fprintf(stderr, "Missing hostname\n");
781     usage(argv[0]);
782     }
783     break;
784     case 'i':
785     /* Hmm.. Someone could set any string to be the IP, and it will let it */
786     ihost_state.preset_ip = 1;
787     ihost_state.host_ip = strdup(optarg);
788     if(ihost_state.host_ip == NULL){
789     fprintf(stderr, "Missing ip\n");
790     usage(argv[0]);
791     }
792     break;
793 pajs 1.28
794     default:
795     usage(argv[0]);
796     exit(1);
797     }
798     }
799    
800     if(argc!=optind+2){
801     usage(argv[0]);
802     exit(1);
803     }
804 pajs 1.17
805 pajs 1.28 ihost_state.filtermanager_host=strdup(argv[optind]);
806     ihost_state.filtermanager_port=atoi(argv[optind+1]);
807    
808     if(gethostbyname(ihost_state.filtermanager_host)==NULL){
809     log_msg(LOG_CRIT, "Failed to lookup hostname. Please check settings");
810 pajs 1.3 exit(1);
811     }
812 pajs 1.28 if(ihost_state.filtermanager_port==0){
813     log_msg(LOG_ERR, "Invalid port number");
814     exit(1);
815 pajs 1.17 }
816 pajs 1.18
817 pajs 1.28 if(ihost_config.daemon){
818 pajs 1.18 pid=fork();
819     if(pid==-1){
820 pajs 1.28 log_msg(LOG_CRIT, "Failed to background exiting");
821     exit(1);
822 pajs 1.18 }else if(pid!=0){
823 pajs 1.28 /* Parent process */
824     return 0;
825     }
826     /* We should now be in the background*/
827     if(setsid()==-1){
828     log_msg(LOG_CRIT, "setsid failed");
829     exit(1);
830     }
831    
832 tdb 1.29 if((ihost_config.log=fopen(LOG_FILE, "a"))==NULL){
833 pajs 1.28 ihost_config.log=stderr;
834 tdb 1.29 log_msg(LOG_CRIT, "Failed to open Logfiles %s for writing", LOG_FILE);
835 pajs 1.18 exit(1);
836     }
837 pajs 1.28
838     fclose(stdin);
839     fclose(stdout);
840     fclose(stderr);
841    
842     }
843    
844     log_msg(LOG_INFO, "Starting ihost");
845    
846     log_msg(LOG_DEBUG,"Writing PID FILE");
847    
848     pid=getpid();
849    
850     if((f=fopen(PID_FILE,"w")) == NULL){
851     log_msg(LOG_CRIT, "Failed to write PID file");
852     }else{
853     if((fprintf(f,"%d",(int)pid)) <= 0 ){
854     log_msg(LOG_CRIT, "Failed to write PID file");
855     }
856     if((fclose(f))!=0){
857     log_msg(LOG_CRIT, "failed to close PID file");
858     }
859     }
860    
861     /* Get the initial config from the filter manager. Should this fail,
862     * wait, and then try again. */
863    
864     get_diskio_stats_diff(&packet_num);
865     packet_num=0;
866    
867     while(ihost_getconfig(&ihost_state)!=0){
868     log_msg(LOG_ERR, "Failed to get ihost config");
869     sleep(10);
870 pajs 1.18 }
871    
872 pajs 1.28 printf("%s\n%d\n", ihost_state.server_fqdn, ihost_state.server_udp_port);
873     while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){
874     log_msg(LOG_ERR, "Failed to create udp socket");
875     sleep(10);
876 pajs 1.18 }
877 pajs 1.2
878 pajs 1.28 config_time=time(NULL)+ihost_state.config_ttl;
879 pajs 1.5
880 pajs 1.28 /* Now have config.. collect data and send as often as required */
881 pajs 1.9 for(;;){
882     cur_time=time(NULL);
883 pajs 1.28
884     if(cur_time>=udp_time){
885     if((get_system_stats(packet_num++, &ihost_state, packet, MAX_UDP_PACKET_SIZE))!=0){
886     log_msg(LOG_ERR, "Failed to get system stats");
887     }
888    
889     len=strlen(packet);
890     log_msg(LOG_DEBUG, "Packet size: %d\nPacket: %s\n", len, packet);
891    
892     if((sendto(udp_sockinfo.sock, packet, len, 0, (struct sockaddr *) &udp_sockinfo.addr, sizeof(udp_sockinfo.addr)))!=len){
893     log_msg(LOG_CRIT, "Failed to send packet");
894 pajs 1.9 }
895 pajs 1.28 udp_time=cur_time+ihost_state.udp_update_time;
896     log_msg(LOG_DEBUG, "Next packet should be sent on %d", udp_time);
897 pajs 1.9 }
898 pajs 1.28
899     if(cur_time>=config_time){
900     if(ihost_getconfig(&ihost_state)!=0){
901     /* If we can't get the config, try again 5 minutes time */
902     log_msg(LOG_ERR, "Failed to get config, try again 5 minutes time");
903     config_time=time(NULL)+300;
904     }else{
905     close(udp_sockinfo.sock);
906    
907     while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){
908     log_msg(LOG_CRIT, "Failed to create udp socket");
909     sleep(10);
910     }
911    
912     config_time=time(NULL)+ihost_state.config_ttl;
913 pajs 1.10
914 pajs 1.28 log_msg(LOG_DEBUG, "Config expires on %d\n", ihost_state.config_ttl);
915 pajs 1.9 }
916     }
917 pajs 1.10
918 pajs 1.28 sleep_delay=udp_time-time(NULL);
919     log_msg(LOG_DEBUG, "Sleeping for %d", sleep_delay);
920 pajs 1.10 if(sleep_delay>0) sleep(sleep_delay);
921 pajs 1.28 }
922    
923     return(0);
924 pajs 1.1 }