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 (20 years, 9 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

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org.uk
4 * Copyright (C) 2000-2002 i-scream
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <stdarg.h>
32 #include <errno.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35
36 #include <ukcprog.h>
37 #include <statgrab.h>
38
39 #define LOG_CRIT 0
40 #define LOG_ERR 1
41 #define LOG_INFO 2
42 #define LOG_DEBUG 3
43
44 typedef struct{
45 int filtermanager_port;
46 char *filtermanager_host;
47
48 char *host_ip;
49 char *host_fqdn;
50 int preset_fqdn;
51 int preset_ip;
52
53 char *server_fqdn;
54 int server_udp_port;
55
56 /* Weird stuff iscream wants sent to it */
57 char *last_modified;
58 char *file_list;
59
60 int udp_update_time;
61 // int config_ttl;
62
63 time_t config_ttl;
64
65 }ihost_state_t;
66
67 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 extern int errno;
82
83 /* Taken from the OpenSSH code. Its licence included in function.*/
84 #ifndef HAVE_STRLCAT
85
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
113 /*
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 #endif
152 /* End strlcat function taken from OpenSSH */
153
154 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 }else{
167 fprintf(ihost_config.log, "\n");
168 }
169 fflush(ihost_config.log);
170 }
171 }
172
173 /* 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
180 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
201 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 }
205
206 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
211 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 }
226
227 if((get_host_addr(hostname, &haddr))!=0){
228 log_msg(LOG_CRIT, "Failed to lookup name for %s", hostname);
229 close(sock);
230 return NULL;
231 }
232
233 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 close(sock);
242 return NULL;
243 }
244
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 }
250
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 return -1;
277 }
278
279 *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 if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port))==NULL){
302 return -1;
303 }
304
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
318 if((tcp_comm(tcp_con, ihost_state->last_modified, &response, "OK"))==0){
319 if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){
320 goto error;
321 }
322 fclose(tcp_con);
323 return 0;
324 }else{
325 if((strcmp(response, "EXPIRED"))!=0){
326 goto error;
327 }
328 }
329 }
330
331 /* If we got to here, the config must of expired */
332
333 if((tcp_comm(tcp_con, "STARTCONFIG", &response, "OK"))!=0){
334 goto error;
335 }
336
337 if((tcp_comm_strdup(tcp_con, "LASTMODIFIED", &response, NULL))!=0){
338 goto error;
339 }
340 last_modified=response;
341
342 if((tcp_comm_strdup(tcp_con, "FILELIST", &response, NULL))!=0){
343 goto error;
344 }
345 file_list=response;
346
347 if((tcp_comm_strdup(tcp_con, "FQDN", &response, NULL))!=0){
348 goto error;
349 }
350 host_fqdn=response;
351
352 if((tcp_comm_strdup(tcp_con, "IP", &response, NULL))!=0){
353 goto error;
354 }
355 host_ip=response;
356
357 if((tcp_comm(tcp_con, "UDPUpdateTime", &response, NULL))!=0){
358 goto error;
359 }
360 udp_update_time=atoi(response);
361
362 if((tcp_comm(tcp_con, "ConfigTTL", &response, NULL))!=0){
363 goto error;
364 }
365 config_ttl=atoi(response);
366
367 if((tcp_comm(tcp_con, "ENDCONFIG", &response, NULL))!=0){
368 goto error;
369 }
370
371 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 }
398
399 if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){
400 goto error;
401 }
402
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
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
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 }
491
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 }
506
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 }
519
520
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 }
534
535
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 }
548
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 }
567
568
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
583 }
584
585
586 /* 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 "<pages><pageins>%lld</pageins><pageouts>%lld</pageouts></pages>", \
599 x, \
600 y);
601
602 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
603 }
604
605
606 /* get diskio stats */
607
608 if((diskio_stats=get_diskio_stats_diff(&diskio_entries))==NULL){
609 log_msg(LOG_CRIT, "Failed to get diskio statistics");
610 }else{
611 strlcat(xml, "<diskio>", size);
612 for(counter=0;counter<diskio_entries;counter++){
613
614 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
630 strlcat(xml, tmp, size);
631 diskio_stats++;
632 }
633
634 if(strlcat(xml, "</diskio>", size) >= size) goto too_big_error;
635
636 }
637
638
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
654 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
662 strlcat(xml, tmp, size);
663 network_stats++;
664 }
665
666 if(strlcat(xml, "</net>", size) >= size) goto too_big_error;
667
668 }
669
670
671 /* 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
692 strlcat(xml, tmp, size);
693
694 disk_stats++;
695 }
696
697 if(strlcat(xml, "</disk>", size) >= size) goto too_big_error;
698
699 }
700
701
702 if(strlcat(xml, "</packet>", size) >= size) goto too_big_error;
703
704 /*If we got to here, it should of all been filled in nicely now */
705 return 0;
706
707 too_big_error:
708 log_msg(LOG_ERR, "UDP Packet is too large. Throwing away the packet");
709 return -1;
710 }
711
712
713
714 void usage(char *progname){
715 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 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 fprintf(stderr, " -V Print version number\n");
722 fprintf(stderr, " -h Prints this help page\n");
723 exit(1);
724 }
725
726 int main(int argc, char **argv){
727
728 ihost_state_t ihost_state;
729 udp_sockinfo_t udp_sockinfo;
730
731 int cmdopt;
732 extern int optind;
733 pid_t pid;
734 FILE *f;
735 int packet_num=0;
736 int len;
737
738 char packet[MAX_UDP_PACKET_SIZE];
739
740 time_t cur_time, sleep_delay, udp_time=0, config_time=0;
741
742 /* 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 ihost_state.preset_fqdn = 0;
753 ihost_state.preset_ip = 0;
754 ihost_state.server_fqdn=NULL;
755 ihost_state.file_list=NULL;
756 ihost_state.last_modified=NULL;
757
758 while((cmdopt=getopt(argc, argv, "vfhVs:i:")) != -1){
759 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 fprintf(stderr, "%s version %s\n", argv[0], VERSION);
775 break;
776 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
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
805 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 exit(1);
811 }
812 if(ihost_state.filtermanager_port==0){
813 log_msg(LOG_ERR, "Invalid port number");
814 exit(1);
815 }
816
817 if(ihost_config.daemon){
818 pid=fork();
819 if(pid==-1){
820 log_msg(LOG_CRIT, "Failed to background exiting");
821 exit(1);
822 }else if(pid!=0){
823 /* 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 if((ihost_config.log=fopen(LOG_FILE, "a"))==NULL){
833 ihost_config.log=stderr;
834 log_msg(LOG_CRIT, "Failed to open Logfiles %s for writing", LOG_FILE);
835 exit(1);
836 }
837
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 }
871
872 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 }
877
878 config_time=time(NULL)+ihost_state.config_ttl;
879
880 /* Now have config.. collect data and send as often as required */
881 for(;;){
882 cur_time=time(NULL);
883
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 }
895 udp_time=cur_time+ihost_state.udp_update_time;
896 log_msg(LOG_DEBUG, "Next packet should be sent on %d", udp_time);
897 }
898
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
914 log_msg(LOG_DEBUG, "Config expires on %d\n", ihost_state.config_ttl);
915 }
916 }
917
918 sleep_delay=udp_time-time(NULL);
919 log_msg(LOG_DEBUG, "Sleeping for %d", sleep_delay);
920 if(sleep_delay>0) sleep(sleep_delay);
921 }
922
923 return(0);
924 }