--- projects/cms/source/ihost/ihost.c 2002/05/13 09:22:02 1.7 +++ projects/cms/source/ihost/ihost.c 2003/03/08 20:41:46 1.33 @@ -1,335 +1,885 @@ +/* + * i-scream central monitoring system + * http://www.i-scream.org.uk + * Copyright (C) 2000-2002 i-scream + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include -#include #include #include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#define RECONFIGURE_RETURN_CODE 2 +#include "ukcprog.h" +#include "statgrab.h" +#define LOG_CRIT 0 +#define LOG_ERR 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + typedef struct{ - int fm_port; - char *fm_host; - - char *my_fqdn; + int filtermanager_port; + char *filtermanager_host; + + char *host_ip; + char *host_fqdn; + char *server_fqdn; int server_udp_port; - int server_tcp_port; + + /* Weird stuff iscream wants sent to it */ char *last_modified; - char *files_list; - char *key; + char *file_list; + int udp_update_time; - int tcp_update_time; +// int config_ttl; + time_t config_ttl; + }ihost_state_t; -char* sock_comm(FILE *f_r, FILE *f_w, char *sendString){ - char *reply; - fprintf(f_w, "%s\n", sendString); - fflush(f_w); - reply=fpgetline(f_r); - /* Returns pointer to static buffer */ - return reply; -} +typedef struct{ + int verbose; + int daemon; -int ihost_configure(ihost_state_t *ihost_state){ + FILE *log; +}ihost_config_t; + +typedef struct{ struct sockaddr_in addr; - struct in_addr haddr; - int sd; - FILE *fm_fd_r, *fm_fd_w; - char *reply; - char *reply_ptr; + int sock; +}udp_sockinfo_t; - /* Check to see if anything needs to be free'd */ - if (ihost_state->my_fqdn!=NULL) free(ihost_state->my_fqdn); - if (ihost_state->server_fqdn!=NULL) free(ihost_state->server_fqdn); - if (ihost_state->last_modified!=NULL) free(ihost_state->last_modified); - if (ihost_state->files_list!=NULL) free(ihost_state->files_list); +ihost_config_t ihost_config; - if ((sd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { - errf("Can't create AF_INET socket (%m)"); - return -1; - } +extern int errno; - if (get_host_addr(ihost_state->fm_host, &haddr) != 0){ - errf("Failed to resolve address %s (%m)", ihost_state->fm_host); - return -1; +/* Taken from the openssh code. Its licence included in function.*/ +//#ifndef HAVE_STRLCAT + +/* + * Copyright (c) 1998 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +//#endif + + +void log_msg(int level, char *format, ...){ + int cur_errno; + va_list ap; + + cur_errno=errno; + + if(level<=ihost_config.verbose){ + va_start(ap, format); + vfprintf(ihost_config.log, format, ap); + va_end(ap); + if(level==LOG_CRIT){ + fprintf(ihost_config.log, " (%s)\n", strerror(cur_errno)); + }else{ + fprintf(ihost_config.log, "\n"); + } } +} - memset((char *)&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - memcpy((char *)&addr.sin_addr, &haddr, sizeof haddr); - addr.sin_port = htons(ihost_state->fm_port); +/* Takes many pointers, checks if they are NULL or not, and then free's them */ +/* Deprciated - and i only wrote it today! :) +void m_free(int num_pointers, ...){ + int x=0; + va_list ap; + void *p; - if (connect(sd, (struct sockaddr *)&addr, sizeof addr) != 0) { - errf("Failed to connect to %s on port %d (%m)", ihost_state->fm_host, ihost_state->fm_port); - return -1; + va_start(ap, num_pointers); + for(;xsock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){ + log_msg(LOG_CRIT, "Failed to create UDP socket"); + return 1; } - reply=sock_comm(fm_fd_r, fm_fd_w, "STARTCONFIG"); - if ((reply==NULL) || (strncasecmp(reply, "OK", 2) != 0) ) { - errf("Server error"); - return -1; + memset(&(udp_sockinfo->addr), 0, sizeof(struct sockaddr_in)); + udp_sockinfo->addr.sin_family=AF_INET; + memcpy((char *)&(udp_sockinfo->addr.sin_addr), &haddr, sizeof(haddr)); + udp_sockinfo->addr.sin_port = htons(port); + + log_msg(LOG_DEBUG, "Socket created"); + return 0; +} + +FILE *create_tcp_connection(char *hostname, int port){ + int sock; + struct sockaddr_in addr; + struct in_addr haddr; + FILE *f; + + log_msg(LOG_DEBUG, "Creating tcp socket"); + if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){ + log_msg(LOG_CRIT, "Failed to make TCP Socket"); + return NULL; } - reply=sock_comm(fm_fd_r, fm_fd_w, "LASTMODIFIED"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0)){ - errf("Server error (%m)"); - return -1; + if((get_host_addr(hostname, &haddr))!=0){ + log_msg(LOG_CRIT, "Failed to lookup name for %s", hostname); + return NULL; } - if((ihost_state->last_modified=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; - } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + memcpy(&addr.sin_addr, &haddr, sizeof(haddr)); + addr.sin_port = htons(port); + + log_msg(LOG_DEBUG, "Creating a tcp connection"); + if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){ + log_msg(LOG_CRIT, "Failed to connect to hostname %s on port %d", hostname, port); + return NULL; + } + + if((f=fdopen(sock, "r+"))==NULL){ + log_msg(LOG_CRIT, "Failed to connect to open filedescriptor on tcp connection"); + close(sock); + return NULL; + } + + return f; +} + +int tcp_comm(FILE *f, char *send, char **response, char *expected){ + + log_msg(LOG_DEBUG, "Sending %s", send); + fprintf(f, "%s\n", send); + fflush(f); + *response=fpgetline(f); + fseek(f, 0, SEEK_CUR); + + if(*response!=NULL) log_msg(LOG_DEBUG, "Recieved %s", *response); + + if( (*response==NULL) || (strcmp(*response, "ERROR")==0) ) return -1; - reply=sock_comm(fm_fd_r, fm_fd_w, "FILELIST"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0)){ - errf("Server error (%m)"); + if(expected==NULL) return 0; + + if((strcmp(expected, *response))==0) return 0; + + log_msg(LOG_DEBUG, "Did not get expected response"); + return -1; +} + +int tcp_comm_strdup(FILE *f, char *send, char **response, char *expected){ + if((tcp_comm(f, send, response, expected))!=0){ return -1; } - if((ihost_state->files_list=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, "FQDN"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5)==0)){ - errf("Server error (%m)"); - return -1; + *response=strdup(*response); + if (response==NULL) return -1; + + return 0; +} + +int ihost_getconfig(ihost_state_t *ihost_state){ + + FILE *tcp_con; + char *response; + char *response_ptr; + + /* Keep these in case of a failure and so it can keep running on the old config */ + char *file_list=NULL; + char *last_modified=NULL; + char *host_fqdn=NULL; + char *host_ip=NULL; + int udp_update_time=0; + char *server_fqdn=NULL; + int server_udp_port=0; + time_t config_ttl=0; + + if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port))==NULL){ + goto error; } - if((ihost_state->my_fqdn=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; + + if(ihost_state->file_list!=NULL || ihost_state->last_modified!=NULL){ + if(tcp_con==NULL){ + goto error; + } + + if((tcp_comm(tcp_con, "CHECKCONFIG", &response, "OK"))!=0){ + goto error; + } + + if((tcp_comm(tcp_con, ihost_state->file_list, &response, "OK"))!=0){ + goto error; + } + + if((tcp_comm(tcp_con, ihost_state->last_modified, &response, "OK"))==0){ + if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){ + goto error; + } + fclose(tcp_con); + return 0; + }else{ + if((strcmp(response, "EXPIRED"))!=0){ + goto error; + } + } } - reply=sock_comm(fm_fd_r, fm_fd_w, "UDPUpdateTime"); - if(reply== NULL){ - errf("Server error (%m)"); - return -1; + /* If we got to here, the config must of expired */ + + if((tcp_comm(tcp_con, "STARTCONFIG", &response, "OK"))!=0){ + goto error; } - if (strncasecmp(reply, "ERROR", 5) != 0){ - ihost_state->udp_update_time=atoi(reply); + + if((tcp_comm_strdup(tcp_con, "LASTMODIFIED", &response, NULL))!=0){ + goto error; } + last_modified=response; + + if((tcp_comm_strdup(tcp_con, "FILELIST", &response, NULL))!=0){ + goto error; + } + file_list=response; - reply=sock_comm(fm_fd_r, fm_fd_w, "TCPUpdateTime"); - if(reply== NULL){ - errf("Server error (%m)"); - return -1; + if((tcp_comm_strdup(tcp_con, "FQDN", &response, NULL))!=0){ + goto error; } - if (strncasecmp(reply, "ERROR", 5) != 0){ - ihost_state->tcp_update_time=atoi(reply); + host_fqdn=response; + + if((tcp_comm_strdup(tcp_con, "IP", &response, NULL))!=0){ + goto error; } + host_ip=response; - reply=sock_comm(fm_fd_r, fm_fd_w, "ENDCONFIG"); - if(reply== NULL){ - errf("Server error (%m)"); - return -1; + if((tcp_comm(tcp_con, "UDPUpdateTime", &response, NULL))!=0){ + goto error; } + udp_update_time=atoi(response); - reply=sock_comm(fm_fd_r, fm_fd_w, "FILTER"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5)==0)){ - errf("Server error (%m)"); - return -1; + if((tcp_comm(tcp_con, "ConfigTTL", &response, NULL))!=0){ + goto error; } - reply_ptr=strchr(reply,';'); - if (reply_ptr==NULL){ - errf("Incorrect data returned"); - return -1; + config_ttl=atoi(response); + + if((tcp_comm(tcp_con, "ENDCONFIG", &response, NULL))!=0){ + goto error; } - *reply_ptr='\0'; - if((ihost_state->server_fqdn=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; + + if((tcp_comm(tcp_con, "FILTER", &response, NULL))!=0){ + goto error; + }else{ + response_ptr=strchr(response,';'); + if(response_ptr==NULL){ + log_msg(LOG_ERR, "Incorrect data sent by server"); + goto error; + } + *response_ptr='\0'; + server_fqdn=strdup(response); + if(server_fqdn==NULL){ + goto error; + } + response_ptr++; + if(response_ptr==NULL){ + log_msg(LOG_ERR, "Incorrect data sent by server"); + goto error; + } + + printf("string : %s\n", response_ptr); + server_udp_port=atoi(response_ptr); + + if (server_udp_port==0){ + log_msg(LOG_ERR, "Incorrect data sent by server"); + goto error; + } } - reply=++reply_ptr; - reply_ptr=strchr(reply,';'); - if (reply_ptr==NULL){ - errf("Incorrect data returned 2"); - return -1; + + if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){ + goto error; } - *reply_ptr='\0'; - ihost_state->server_udp_port=atoi(reply); - reply=++reply_ptr; - ihost_state->server_tcp_port=atoi(reply); - if ((ihost_state->server_tcp_port==0) || (ihost_state->server_udp_port==0)){ - errf("Incorrect data returned 3 "); - return -1; + + fclose(tcp_con); + + /* We have the data we need, and its all been read correctly */ + + /* Free the old data before pointing them to the new data. m_free copes should + * this already be NULL */ + if(ihost_state->file_list!=NULL) free(ihost_state->file_list); + if(ihost_state->last_modified!=NULL) free(ihost_state->last_modified); + if(ihost_state->host_fqdn!=NULL) free(ihost_state->host_fqdn); + if(ihost_state->server_fqdn!=NULL) free(ihost_state->server_fqdn); + if(ihost_state->host_ip!=NULL) free(ihost_state->host_ip); + + ihost_state->file_list=file_list; + ihost_state->last_modified=last_modified; + ihost_state->host_fqdn=host_fqdn; + ihost_state->host_ip=host_ip; + ihost_state->server_fqdn=server_fqdn; + ihost_state->server_udp_port=server_udp_port; + ihost_state->udp_update_time=udp_update_time; + ihost_state->config_ttl=config_ttl; + + log_msg(LOG_DEBUG, "UDP Update time %d", udp_update_time); + log_msg(LOG_DEBUG, "Configure ttl %d", config_ttl); + + return 0; + +error: + + if(file_list!=NULL) free(file_list); + if(last_modified!=NULL) free(last_modified); + if(host_fqdn!=NULL) free(host_fqdn); + if(server_fqdn!=NULL) free(server_fqdn); + if(host_ip!=NULL) free(host_ip); + fclose(tcp_con); + + return -1; +} + +int get_system_stats(int seq_no, ihost_state_t *ihost_state, char *xml, int size){ + char tmp[size]; + cpu_percent_t *cpu_percent; + mem_stat_t *mem_stats; + load_stat_t *load_stats; + user_stat_t *user_stats; + swap_stat_t *swap_stats; + general_stat_t *general_stats; + disk_stat_t *disk_stats; + diskio_stat_t *diskio_stats; + process_stat_t *process_stats; + network_stat_t *network_stats; + page_stat_t *page_stats; + int disk_entries=0; + int diskio_entries=0; + int network_entries=0; + + int counter; + long long x; + long long y; + + /* Print start of the packet we want */ + snprintf(xml, size, "", \ + seq_no, ihost_state->host_fqdn, time(NULL), ihost_state->host_ip); + + /* Get cpu stats, check it is correct, then fill in its entry for the xml */ + if((cpu_percent=cpu_percent_usage())==NULL){ + log_msg(LOG_CRIT, "Failed to get cpu statistics"); + }else{ + snprintf(tmp, size, \ + "%3.2f%3.2f%3.2f%3.2f%3.2f", \ + cpu_percent->user, \ + cpu_percent->kernel, \ + cpu_percent->idle, \ + cpu_percent->iowait, \ + cpu_percent->swap); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - reply=sock_comm(fm_fd_r, fm_fd_w, "END"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0 )){ - errf("Server error (%m)"); - return -1; + + /*Get mem stats, and fill in xml */ + if((mem_stats=get_memory_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get memory statistics"); + }else{ + snprintf(tmp, size, \ + "%lld%lld%lld%lld", \ + mem_stats->total, \ + mem_stats->free, \ + mem_stats->used, \ + mem_stats->cache); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - if(fclose(fm_fd_r) !=0){ - errf("Failed to close FD (%m)"); - return -1; + + /* Get load stats */ + if((load_stats=get_load_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get load statistics"); + }else{ + snprintf(tmp, size, \ + "%.2lf%.2lf%.2lf", \ + load_stats->min1, \ + load_stats->min5, \ + load_stats->min15); + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - if(fclose(fm_fd_w) !=0){ - errf("Failed to close FD (%m)"); - return -1; + + + /* get user stats */ + + if((user_stats=get_user_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get user statistics"); + }else{ + + snprintf(tmp, size, \ + "%s%d", \ + user_stats->name_list, \ + user_stats->num_entries); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - return 0; -} -int heartbeat(ihost_state_t *ihost_state){ - struct sockaddr_in addr; - struct in_addr haddr; - int sd; - FILE *fm_fd_r, *fm_fd_w; - char *reply; - int exitcode=0; + /* swap stats */ + if((swap_stats=get_swap_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get swap statistics"); + }else{ + snprintf(tmp, size, \ + "%lld%lld%lld",\ + swap_stats->total, \ + swap_stats->used, \ + swap_stats->free); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + } - if ((sd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { - errf("Can't create AF_INET socket (%m)"); - return -1; - } - if (get_host_addr(ihost_state->server_fqdn, &haddr) != 0){ - errf("Failed to resolve address %s (%m)", ihost_state->fm_host); - return -1; - } + /* general stats */ + + if((general_stats=get_general_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get general statistics"); + }else{ + snprintf(tmp, size, \ + "%s%s%s%s%s%ld", \ + general_stats->os_name, \ + general_stats->os_release, \ + general_stats->os_version, \ + general_stats->hostname, \ + general_stats->platform, \ + (long)general_stats->uptime); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + + } - memset((char *)&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - memcpy((char *)&addr.sin_addr, &haddr, sizeof haddr); - addr.sin_port = htons(ihost_state->server_tcp_port); + + /* process stats */ + if((process_stats=get_process_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get general statistics"); + }else{ + snprintf(tmp, size, \ + "%d%d%d%d%d",\ + process_stats->sleeping, \ + process_stats->running, \ + process_stats->zombie, \ + process_stats->stopped, \ + process_stats->total); - if (connect(sd, (struct sockaddr *)&addr, sizeof addr) != 0) { - errf("Failed to connect to %s on port %d (%m)", ihost_state->fm_host, ihost_state->fm_port); - return -1; - } + if(strlcat(xml, tmp, size) >= size) goto too_big_error; - /* Need to open 2 files, one for reading one for writing, as it gets confused if we only use 1 :) */ - if ((fm_fd_r=fdopen(sd,"r")) == NULL){ - errf("Failed to open stream (%m)"); - return -1; - } + } - if ((fm_fd_w=fdopen(dup(sd),"w")) == NULL){ - errf("Failed to open stream (%m)"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, "HEARTBEAT"); - if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) { - errf("Server error"); - return -1; - } - if (ihost_state->fm_host!=NULL) free(ihost_state->fm_host); - reply=sock_comm(fm_fd_r, fm_fd_w, "CONFIG"); - if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) { - errf("Server error"); - return -1; - } + /* Get paging stats */ + if((page_stats=get_page_stats_diff())==NULL){ + log_msg(LOG_CRIT, "Failed to get paging statistics"); + }else{ + if(page_stats->systime!=0){ + x=page_stats->pages_pagein / page_stats->systime; + y=page_stats->pages_pageout / page_stats->systime; + }else{ + x=page_stats->pages_pagein; + y=page_stats->pages_pageout; + } + snprintf(tmp, size, \ + "%lld%lld", \ + x, \ + y); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + } - reply=sock_comm(fm_fd_r, fm_fd_w, ihost_state->files_list); - if ((reply==NULL) || (strncasecmp(reply, "OK", 2) != 0) ) { - errf("Server error"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, ihost_state->last_modified); - if (reply==NULL) { - errf("Server error"); - return -1; - } - if (strncasecmp(reply, "ERROR", 5) == 0){ - /* Means the config has changed */ - exitcode=RECONFIGURE_RETURN_CODE; + /* get diskio stats */ + + if((diskio_stats=get_diskio_stats_diff(&diskio_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get diskio statistics"); + }else{ + strlcat(xml, "", size); + for(counter=0;countersystime!=0){ + x=diskio_stats->read_bytes / diskio_stats->systime; + y=diskio_stats->write_bytes / diskio_stats->systime; + }else{ + x=diskio_stats->read_bytes; + y=diskio_stats->write_bytes; + } + + snprintf(tmp, size, \ + "", \ + counter, \ + diskio_stats->disk_name, \ + x, \ + y, \ + counter); + + strlcat(xml, tmp, size); + diskio_stats++; + } + + if(strlcat(xml, "", size) >= size) goto too_big_error; + } - reply=sock_comm(fm_fd_r, fm_fd_w, "KEY"); - if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) { - errf("Server error"); - return -1; - } - if (ihost_state->key!=NULL) free(ihost_state->key); - - if((ihost_state->key=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, "ENDHEARTBEAT"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0 )){ - errf("Server error (%m)"); - return -1; - } + + /* get networks stats */ + + if((network_stats=get_network_stats_diff(&network_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get network statistics"); + }else{ + strlcat(xml, "", size); + for(counter=0;countersystime!=0){ + x=network_stats->rx / network_stats->systime; + y=network_stats->tx / network_stats->systime; + }else{ + x=network_stats->rx; + y=network_stats->tx; + } - if(fclose(fm_fd_r) !=0){ - errf("Failed to close FD (%m)"); - return -1; - } - if(fclose(fm_fd_w) !=0){ - errf("Failed to close FD (%m)"); - return -1; - } + snprintf(tmp, size, \ + "", \ + counter, \ + network_stats->interface_name, \ + x, \ + y, \ + counter); - return exitcode; + strlcat(xml, tmp, size); + network_stats++; + } + + if(strlcat(xml, "", size) >= size) goto too_big_error; + + } + + + /* get disk stats */ + + if((disk_stats=get_disk_stats(&disk_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get disk statistics"); + }else{ + strlcat(xml, "", size); + for(counter=0;counter", \ + counter, \ + disk_stats->device_name, \ + disk_stats->mnt_point, \ + disk_stats->fs_type, \ + disk_stats->size, \ + disk_stats->used, \ + disk_stats->avail, \ + disk_stats->total_inodes, \ + disk_stats->used_inodes, \ + disk_stats->free_inodes, \ + counter); + + strlcat(xml, tmp, size); + + disk_stats++; + } + + if(strlcat(xml, "", size) >= size) goto too_big_error; + + } + + + if(strlcat(xml, "", size) >= size) goto too_big_error; + + /*If we got to here, it should of all been filled in nicely now */ + return 0; + +too_big_error: + log_msg(LOG_ERR, "UDP Packet is too large. Throwing away the packet"); + return -1; } + +void usage(char *progname){ + fprintf(stderr, "Usage %s [options] server port\n", progname); + fprintf(stderr, "Options\n"); + fprintf(stderr, " -v Verbose mode,-vv would make even more verbose\n"); + fprintf(stderr, " -f Foreground mode, print errors to stderr\n"); + fprintf(stderr, " -V Print version number\n"); + fprintf(stderr, " -h Prints this help page\n"); + exit(1); +} + int main(int argc, char **argv){ + ihost_state_t ihost_state; - int heartbeat_exit; - int counter=0; + udp_sockinfo_t udp_sockinfo; + + int cmdopt; + extern int optind; + pid_t pid; + FILE *f; + int packet_num=0; + int len; + char packet[MAX_UDP_PACKET_SIZE]; - /* NULL'ify so i can tell if i need to free it or not */ - ihost_state.fm_host=NULL; - ihost_state.my_fqdn=NULL; - ihost_state.server_fqdn=NULL; - ihost_state.last_modified=NULL; - ihost_state.files_list=NULL; - ihost_state.key=NULL; + time_t cur_time, sleep_delay, udp_time=0, config_time=0; - errf_set_progname(argv[0]); - if(argc!=3){ - errf_usage(" "); + /* Set default settings */ + ihost_config.verbose=1; + ihost_config.daemon=1; + /* Set all errors to go down stderr until told otherwise */ + ihost_config.log=stderr; + + /* Blank ihost_state to default settings */ + ihost_state.filtermanager_host=NULL; + ihost_state.host_fqdn=NULL; + ihost_state.host_ip=NULL; + ihost_state.server_fqdn=NULL; + ihost_state.file_list=NULL; + ihost_state.last_modified=NULL; + + while((cmdopt=getopt(argc, argv, "vfhV")) != -1){ + switch(cmdopt){ + case 'v': + ihost_config.verbose++; + break; + + case 'f': + /* Force syslog logging since stderr will be closed in this case */ + ihost_config.daemon=0; + break; + + case 'h': + usage(argv[0]); + break; + + case 'V': + fprintf(stderr, "%s version %s\n", argv[0], VERSION); + break; + + default: + usage(argv[0]); + exit(1); + } + } + + if(argc!=optind+2){ + usage(argv[0]); + exit(1); + } + + ihost_state.filtermanager_host=strdup(argv[optind]); + ihost_state.filtermanager_port=atoi(argv[optind+1]); + + if(gethostbyname(ihost_state.filtermanager_host)==NULL){ + log_msg(LOG_CRIT, "Failed to lookup hostname. Please check settings"); exit(1); } + if(ihost_state.filtermanager_port==0){ + log_msg(LOG_ERR, "Invalid port number"); + exit(1); + } - ihost_state.fm_host=argv[1]; - ihost_state.fm_port=atoi(argv[2]); + if(ihost_config.daemon){ + pid=fork(); + if(pid==-1){ + log_msg(LOG_CRIT, "Failed to background exiting"); + exit(1); + }else if(pid!=0){ + /* Parent process */ + return 0; + } + /* We should now be in the background*/ + if(setsid()==-1){ + log_msg(LOG_CRIT, "setsid failed"); + exit(1); + } + + if((ihost_config.log=fopen(LOG_FILE, "a"))==NULL){ + ihost_config.log=stderr; + log_msg(LOG_CRIT, "Failed to open Logfiles %s for writing", LOG_FILE); + exit(1); + } - if(ihost_configure(&ihost_state)!=0){ - errf("configure failed"); - /* Ok, ideally we prob should have 2 copies of the structure and carry on if this - happens.. But we dont :) (at the moment) */ - exit(1); + fclose(stdin); + fclose(stdout); + fclose(stderr); + + } + + log_msg(LOG_INFO, "Starting ihost"); + + log_msg(LOG_DEBUG,"Writing PID FILE"); + + pid=getpid(); + + if((f=fopen(PID_FILE,"w")) == NULL){ + log_msg(LOG_CRIT, "Failed to write PID file"); + }else{ + if((fprintf(f,"%d",(int)pid)) <= 0 ){ + log_msg(LOG_CRIT, "Failed to write PID file"); + } + if((fclose(f))!=0){ + log_msg(LOG_CRIT, "failed to close PID file"); + } + } + + /* Get the initial config from the filter manager. Should this fail, + * wait, and then try again. */ + + get_diskio_stats_diff(&packet_num); + packet_num=0; + + while(ihost_getconfig(&ihost_state)!=0){ + log_msg(LOG_ERR, "Failed to get ihost config"); + sleep(10); } - while(TRUE){ + printf("%s\n%d\n", ihost_state.server_fqdn, ihost_state.server_udp_port); + while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){ + log_msg(LOG_ERR, "Failed to create udp socket"); + sleep(10); + } - heartbeat_exit=heartbeat(&ihost_state); - if(heartbeat_exit==RECONFIGURE_RETURN_CODE){ - errf("heartbeat needs to be reconfigured"); - ihost_configure(&ihost_state); + config_time=time(NULL)+ihost_state.config_ttl; + + /* Now have config.. collect data and send as often as required */ + for(;;){ + cur_time=time(NULL); + + if(cur_time>=udp_time){ + if((get_system_stats(packet_num++, &ihost_state, packet, MAX_UDP_PACKET_SIZE))!=0){ + log_msg(LOG_ERR, "Failed to get system stats"); + } + + len=strlen(packet); + log_msg(LOG_DEBUG, "Packet size: %d\nPacket: %s\n", len, packet); + + if((sendto(udp_sockinfo.sock, packet, len, 0, (struct sockaddr *) &udp_sockinfo.addr, sizeof(udp_sockinfo.addr)))!=len){ + log_msg(LOG_CRIT, "Failed to send packet"); + } + udp_time=cur_time+ihost_state.udp_update_time; + log_msg(LOG_DEBUG, "Next packet should be sent on %d", udp_time); } - if(heartbeat_exit==-1){ - errf("ah crap"); - exit(1); - } - printf("Count : %d\n",counter++); - printf("waiting %d\n",ihost_state.tcp_update_time); - sleep(ihost_state.tcp_update_time); - } - return 0; -} + + if(cur_time>=config_time){ + if(ihost_getconfig(&ihost_state)!=0){ + /* If we can't get the config, try again 5 minutes time */ + log_msg(LOG_ERR, "Failed to get config, try again 5 minutes time"); + config_time=time(NULL)+300; + }else{ + close(udp_sockinfo.sock); + while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){ + log_msg(LOG_CRIT, "Failed to create udp socket"); + sleep(10); + } + + config_time=time(NULL)+ihost_state.config_ttl; + + log_msg(LOG_DEBUG, "Config expires on %d\n", ihost_state.config_ttl); + } + } + + sleep_delay=udp_time-time(NULL); + log_msg(LOG_DEBUG, "Sleeping for %d", sleep_delay); + if(sleep_delay>0) sleep(sleep_delay); + } + + return(0); +}