ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/ihost/ihost.c
Revision: 1.46
Committed: Mon Jan 5 16:48:55 2004 UTC (20 years, 4 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.45: +0 -2 lines
Log Message:
A few more minor tidies.

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org
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 int create_udp_sockinfo(udp_sockinfo_t *udp_sockinfo, char *hostname, int port){
174
175 struct in_addr haddr;
176
177 log_msg(LOG_DEBUG, "Resolving name for udp connection");
178 if(get_host_addr(hostname, &haddr) != 0){
179 log_msg(LOG_CRIT, "Failed to lookup name");
180 return 1;
181 }
182
183 if((udp_sockinfo->sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
184 log_msg(LOG_CRIT, "Failed to create UDP socket");
185 return 1;
186 }
187
188 memset(&(udp_sockinfo->addr), 0, sizeof(struct sockaddr_in));
189 udp_sockinfo->addr.sin_family=AF_INET;
190 memcpy((char *)&(udp_sockinfo->addr.sin_addr), &haddr, sizeof(haddr));
191 udp_sockinfo->addr.sin_port = htons(port);
192
193 log_msg(LOG_DEBUG, "Socket created");
194 return 0;
195 }
196
197 FILE *create_tcp_connection(char *hostname, int port){
198 int sock;
199 struct sockaddr_in addr;
200 struct in_addr haddr;
201 FILE *f;
202
203 log_msg(LOG_DEBUG, "Creating tcp socket");
204 if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){
205 log_msg(LOG_CRIT, "Failed to make TCP Socket");
206 return NULL;
207 }
208
209 if((get_host_addr(hostname, &haddr))!=0){
210 log_msg(LOG_CRIT, "Failed to lookup name for %s", hostname);
211 close(sock);
212 return NULL;
213 }
214
215 memset(&addr, 0, sizeof(addr));
216 addr.sin_family = AF_INET;
217 memcpy(&addr.sin_addr, &haddr, sizeof(haddr));
218 addr.sin_port = htons(port);
219
220 log_msg(LOG_DEBUG, "Creating a tcp connection");
221 if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){
222 log_msg(LOG_CRIT, "Failed to connect to hostname %s on port %d", hostname, port);
223 close(sock);
224 return NULL;
225 }
226
227 if((f=fdopen(sock, "r+"))==NULL){
228 log_msg(LOG_CRIT, "Failed to connect to open filedescriptor on tcp connection");
229 close(sock);
230 return NULL;
231 }
232
233 return f;
234 }
235
236 int tcp_comm(FILE *f, char *send, char **response, char *expected){
237
238 log_msg(LOG_DEBUG, "Sending %s", send);
239 fprintf(f, "%s\n", send);
240 fflush(f);
241 *response=fpgetline(f);
242 fseek(f, 0, SEEK_CUR);
243
244 if(*response!=NULL) log_msg(LOG_DEBUG, "Recieved %s", *response);
245
246 if( (*response==NULL) || (strcmp(*response, "ERROR")==0) ) return -1;
247
248 if(expected==NULL) return 0;
249
250 if((strcmp(expected, *response))==0) return 0;
251
252 log_msg(LOG_DEBUG, "Did not get expected response");
253 return -1;
254 }
255
256 int tcp_comm_strdup(FILE *f, char *send, char **response, char *expected){
257 if((tcp_comm(f, send, response, expected))!=0){
258 return -1;
259 }
260
261 *response=strdup(*response);
262 if (response==NULL) return -1;
263
264 return 0;
265 }
266
267 int ihost_getconfig(ihost_state_t *ihost_state){
268
269 FILE *tcp_con;
270 char *response;
271 char *response_ptr;
272
273 /* Keep these in case of a failure and so it can keep running on the old config */
274 char *file_list=NULL;
275 char *last_modified=NULL;
276 char *host_fqdn=NULL;
277 char *host_ip=NULL;
278 int udp_update_time=0;
279 char *server_fqdn=NULL;
280 int server_udp_port=0;
281 time_t config_ttl=0;
282
283 if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port))==NULL){
284 return -1;
285 }
286
287 if(ihost_state->file_list!=NULL || ihost_state->last_modified!=NULL){
288 if(tcp_con==NULL){
289 goto error;
290 }
291
292 if((tcp_comm(tcp_con, "CHECKCONFIG", &response, "OK"))!=0){
293 goto error;
294 }
295
296 if((tcp_comm(tcp_con, ihost_state->file_list, &response, "OK"))!=0){
297 goto error;
298 }
299
300 if((tcp_comm(tcp_con, ihost_state->last_modified, &response, "OK"))==0){
301 if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){
302 goto error;
303 }
304 fclose(tcp_con);
305 return 0;
306 }else{
307 if((strcmp(response, "EXPIRED"))!=0){
308 goto error;
309 }
310 }
311 }
312
313 /* If we got to here, the config must of expired */
314
315 if((tcp_comm(tcp_con, "STARTCONFIG", &response, "OK"))!=0){
316 goto error;
317 }
318
319 if((tcp_comm_strdup(tcp_con, "LASTMODIFIED", &response, NULL))!=0){
320 goto error;
321 }
322 last_modified=response;
323
324 if((tcp_comm_strdup(tcp_con, "FILELIST", &response, NULL))!=0){
325 goto error;
326 }
327 file_list=response;
328
329 if((tcp_comm_strdup(tcp_con, "FQDN", &response, NULL))!=0){
330 goto error;
331 }
332 host_fqdn=response;
333
334 if((tcp_comm_strdup(tcp_con, "IP", &response, NULL))!=0){
335 goto error;
336 }
337 host_ip=response;
338
339 if((tcp_comm(tcp_con, "UDPUpdateTime", &response, NULL))!=0){
340 goto error;
341 }
342 udp_update_time=atoi(response);
343
344 if((tcp_comm(tcp_con, "ConfigTTL", &response, NULL))!=0){
345 goto error;
346 }
347 config_ttl=atoi(response);
348
349 if((tcp_comm(tcp_con, "ENDCONFIG", &response, NULL))!=0){
350 goto error;
351 }
352
353 if((tcp_comm(tcp_con, "FILTER", &response, NULL))!=0){
354 goto error;
355 }else{
356 response_ptr=strchr(response,';');
357 if(response_ptr==NULL){
358 log_msg(LOG_ERR, "Incorrect data sent by server");
359 goto error;
360 }
361 *response_ptr='\0';
362 server_fqdn=strdup(response);
363 if(server_fqdn==NULL){
364 goto error;
365 }
366 response_ptr++;
367 if(response_ptr==NULL){
368 log_msg(LOG_ERR, "Incorrect data sent by server");
369 goto error;
370 }
371
372 server_udp_port=atoi(response_ptr);
373
374 if (server_udp_port==0){
375 log_msg(LOG_ERR, "Incorrect data sent by server");
376 goto error;
377 }
378 }
379
380 if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){
381 goto error;
382 }
383
384 fclose(tcp_con);
385
386 /* We have the data we need, and its all been read correctly */
387
388 /* Free the old data before pointing them to the new data. m_free copes should
389 * this already be NULL */
390 if(ihost_state->file_list!=NULL) free(ihost_state->file_list);
391 if(ihost_state->last_modified!=NULL) free(ihost_state->last_modified);
392 if(ihost_state->server_fqdn!=NULL) free(ihost_state->server_fqdn);
393
394 if(ihost_state->preset_fqdn){
395 if(host_fqdn != NULL) free(host_fqdn);
396 }else{
397 if(ihost_state->host_fqdn!=NULL) free(ihost_state->host_fqdn);
398 ihost_state->host_fqdn=host_fqdn;
399 }
400
401 if(ihost_state->preset_ip){
402 if(host_ip != NULL) free(host_ip);
403 }else{
404 if(ihost_state->host_ip!=NULL) free(ihost_state->host_ip);
405 ihost_state->host_ip=host_ip;
406 }
407
408
409 ihost_state->file_list=file_list;
410 ihost_state->last_modified=last_modified;
411 ihost_state->server_fqdn=server_fqdn;
412 ihost_state->server_udp_port=server_udp_port;
413 ihost_state->udp_update_time=udp_update_time;
414 ihost_state->config_ttl=config_ttl;
415
416 log_msg(LOG_DEBUG, "UDP Update time %d", udp_update_time);
417 log_msg(LOG_DEBUG, "Configure ttl %d", config_ttl);
418
419 return 0;
420
421 error:
422
423 if(file_list!=NULL) free(file_list);
424 if(last_modified!=NULL) free(last_modified);
425 if(host_fqdn!=NULL) free(host_fqdn);
426 if(server_fqdn!=NULL) free(server_fqdn);
427 if(host_ip!=NULL) free(host_ip);
428 fclose(tcp_con);
429
430 return -1;
431 }
432
433 int get_system_stats(int seq_no, ihost_state_t *ihost_state, char *xml, int size){
434 char tmp[size];
435 cpu_percent_t *cpu_percent;
436 mem_stat_t *mem_stats;
437 load_stat_t *load_stats;
438 user_stat_t *user_stats;
439 swap_stat_t *swap_stats;
440 general_stat_t *general_stats;
441 disk_stat_t *disk_stats;
442 diskio_stat_t *diskio_stats;
443 process_stat_t *process_stats;
444 network_stat_t *network_stats;
445 page_stat_t *page_stats;
446 int disk_entries=0;
447 int diskio_entries=0;
448 int network_entries=0;
449
450 int counter;
451 long long x;
452 long long y;
453
454 /* Print start of the packet we want */
455 snprintf(xml, size, "<packet seq_no=\"%d\" machine_name=\"%s\" date=\"%ld\" type=\"data\" ip=\"%s\">", \
456 seq_no, ihost_state->host_fqdn, time(NULL), ihost_state->host_ip);
457
458 /* Get cpu stats, check it is correct, then fill in its entry for the xml */
459 if((cpu_percent=cpu_percent_usage())==NULL){
460 log_msg(LOG_CRIT, "Failed to get cpu statistics");
461 }else{
462 snprintf(tmp, size, \
463 "<cpu><user>%3.2f</user><kernel>%3.2f</kernel><idle>%3.2f</idle><iowait>%3.2f</iowait><swap>%3.2f</swap></cpu>", \
464 cpu_percent->user, \
465 cpu_percent->kernel, \
466 cpu_percent->idle, \
467 cpu_percent->iowait, \
468 cpu_percent->swap);
469
470 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
471 }
472
473
474 /*Get mem stats, and fill in xml */
475 if((mem_stats=get_memory_stats())==NULL){
476 log_msg(LOG_CRIT, "Failed to get memory statistics");
477 }else{
478 snprintf(tmp, size, \
479 "<memory><total>%lld</total><free>%lld</free><used>%lld</used><cache>%lld</cache></memory>", \
480 mem_stats->total, \
481 mem_stats->free, \
482 mem_stats->used, \
483 mem_stats->cache);
484
485 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
486 }
487
488
489 /* Get load stats */
490 if((load_stats=get_load_stats())==NULL){
491 log_msg(LOG_CRIT, "Failed to get load statistics");
492 }else{
493 snprintf(tmp, size, \
494 "<load><load1>%.2lf</load1><load5>%.2lf</load5><load15>%.2lf</load15></load>", \
495 load_stats->min1, \
496 load_stats->min5, \
497 load_stats->min15);
498 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
499 }
500
501
502 /* get user stats */
503
504 if((user_stats=get_user_stats())==NULL){
505 log_msg(LOG_CRIT, "Failed to get user statistics");
506 }else{
507
508 snprintf(tmp, size, \
509 "<users><list>%s</list><count>%d</count></users>", \
510 user_stats->name_list, \
511 user_stats->num_entries);
512
513 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
514 }
515
516
517 /* swap stats */
518 if((swap_stats=get_swap_stats())==NULL){
519 log_msg(LOG_CRIT, "Failed to get swap statistics");
520 }else{
521 snprintf(tmp, size, \
522 "<swap><total>%lld</total><used>%lld</used><free>%lld</free></swap>",\
523 swap_stats->total, \
524 swap_stats->used, \
525 swap_stats->free);
526
527 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
528 }
529
530
531 /* general stats */
532
533 if((general_stats=get_general_stats())==NULL){
534 log_msg(LOG_CRIT, "Failed to get general statistics");
535 }else{
536 snprintf(tmp, size, \
537 "<os><name>%s</name><release>%s</release><version>%s</version><sysname>%s</sysname><platform>%s</platform><uptime>%ld</uptime></os>", \
538 general_stats->os_name, \
539 general_stats->os_release, \
540 general_stats->os_version, \
541 general_stats->hostname, \
542 general_stats->platform, \
543 (long)general_stats->uptime);
544
545 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
546
547 }
548
549
550 /* process stats */
551 if((process_stats=get_process_stats())==NULL){
552 log_msg(LOG_CRIT, "Failed to get general statistics");
553 }else{
554 snprintf(tmp, size, \
555 "<processes><sleeping>%d</sleeping><cpu>%d</cpu><zombie>%d</zombie><stopped>%d</stopped><total>%d</total></processes>",\
556 process_stats->sleeping, \
557 process_stats->running, \
558 process_stats->zombie, \
559 process_stats->stopped, \
560 process_stats->total);
561
562 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
563
564 }
565
566
567 /* Get paging stats */
568 if((page_stats=get_page_stats_diff())==NULL){
569 log_msg(LOG_CRIT, "Failed to get paging statistics");
570 }else{
571 if(page_stats->systime!=0){
572 x=page_stats->pages_pagein / page_stats->systime;
573 y=page_stats->pages_pageout / page_stats->systime;
574 }else{
575 x=page_stats->pages_pagein;
576 y=page_stats->pages_pageout;
577 }
578 snprintf(tmp, size, \
579 "<pages><pageins>%lld</pageins><pageouts>%lld</pageouts></pages>", \
580 x, \
581 y);
582
583 if(strlcat(xml, tmp, size) >= size) goto too_big_error;
584 }
585
586
587 /* get diskio stats */
588
589 if((diskio_stats=get_diskio_stats_diff(&diskio_entries))==NULL){
590 log_msg(LOG_CRIT, "Failed to get diskio statistics");
591 }else{
592 strlcat(xml, "<diskio>", size);
593 for(counter=0;counter<diskio_entries;counter++){
594
595 if(diskio_stats->systime!=0){
596 x=diskio_stats->read_bytes / diskio_stats->systime;
597 y=diskio_stats->write_bytes / diskio_stats->systime;
598 }else{
599 x=diskio_stats->read_bytes;
600 y=diskio_stats->write_bytes;
601 }
602
603 snprintf(tmp, size, \
604 "<p%d name=\"%s\" rbytes=\"%lld\" wbytes=\"%lld\"></p%d>", \
605 counter, \
606 diskio_stats->disk_name, \
607 x, \
608 y, \
609 counter);
610
611 strlcat(xml, tmp, size);
612 diskio_stats++;
613 }
614
615 if(strlcat(xml, "</diskio>", size) >= size) goto too_big_error;
616
617 }
618
619
620 /* get networks stats */
621
622 if((network_stats=get_network_stats_diff(&network_entries))==NULL){
623 log_msg(LOG_CRIT, "Failed to get network statistics");
624 }else{
625 strlcat(xml, "<net>", size);
626 for(counter=0;counter<network_entries;counter++){
627 if(network_stats->systime!=0){
628 x=network_stats->rx / network_stats->systime;
629 y=network_stats->tx / network_stats->systime;
630 }else{
631 x=network_stats->rx;
632 y=network_stats->tx;
633 }
634
635 snprintf(tmp, size, \
636 "<p%d name=\"%s\" rx=\"%lld\" tx=\"%lld\"></p%d>", \
637 counter, \
638 network_stats->interface_name, \
639 x, \
640 y, \
641 counter);
642
643 strlcat(xml, tmp, size);
644 network_stats++;
645 }
646
647 if(strlcat(xml, "</net>", size) >= size) goto too_big_error;
648
649 }
650
651
652 /* get disk stats */
653
654 if((disk_stats=get_disk_stats(&disk_entries))==NULL){
655 log_msg(LOG_CRIT, "Failed to get disk statistics");
656 }else{
657 strlcat(xml, "<disk>", size);
658 for(counter=0;counter<disk_entries;counter++){
659 snprintf(tmp, size, \
660 "<p%d name=\"%s\" mount=\"%s\" fstype=\"%s\" total=\"%lld\" used=\"%lld\" avail=\"%lld\" totalinodes=\"%lld\" usedinodes=\"%lld\" freeinodes=\"%lld\"></p%d>", \
661 counter, \
662 disk_stats->device_name, \
663 disk_stats->mnt_point, \
664 disk_stats->fs_type, \
665 disk_stats->size, \
666 disk_stats->used, \
667 disk_stats->avail, \
668 disk_stats->total_inodes, \
669 disk_stats->used_inodes, \
670 disk_stats->free_inodes, \
671 counter);
672
673 strlcat(xml, tmp, size);
674
675 disk_stats++;
676 }
677
678 if(strlcat(xml, "</disk>", size) >= size) goto too_big_error;
679
680 }
681
682
683 if(strlcat(xml, "</packet>", size) >= size) goto too_big_error;
684
685 /*If we got to here, it should of all been filled in nicely now */
686 return 0;
687
688 too_big_error:
689 log_msg(LOG_ERR, "UDP Packet is too large. Throwing away the packet");
690 return -1;
691 }
692
693
694
695 void usage(char *progname){
696 fprintf(stderr, "Usage %s [-v[v]] [-f] [-n name] [-i ip] [-s server] [-p port] [-V] [-h]\n\n", progname);
697 fprintf(stderr, " -v Verbose mode, -vv would make even more verbose\n");
698 fprintf(stderr, " -f Foreground mode, print errors to stderr\n");
699 fprintf(stderr, " -n Set the machine name to be reported as\n");
700 fprintf(stderr, " -i Set the IP to be reported as\n");
701 fprintf(stderr, " -s Specifies the i-scream server to connect to\n");
702 fprintf(stderr, " default: %s\n", DEF_SERVER_NAME);
703 fprintf(stderr, " -p Specifies the i-scream server port\n");
704 fprintf(stderr, " default: %d\n", DEF_SERVER_PORT);
705 fprintf(stderr, " -V Print version number\n");
706 fprintf(stderr, " -h Prints this help page\n");
707 fprintf(stderr, "\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
708 exit(1);
709 }
710
711 int main(int argc, char **argv){
712
713 ihost_state_t ihost_state;
714 udp_sockinfo_t udp_sockinfo;
715
716 int cmdopt;
717 extern int optind;
718 pid_t pid;
719 FILE *f;
720 int packet_num=0;
721 int len;
722
723 char packet[MAX_UDP_PACKET_SIZE];
724
725 time_t cur_time, sleep_delay, udp_time=0, config_time=0;
726
727 /* Set default settings */
728 ihost_config.verbose=1;
729 ihost_config.daemon=1;
730 /* Set all errors to go down stderr until told otherwise */
731 ihost_config.log=stderr;
732
733 /* Blank ihost_state to default settings */
734 ihost_state.filtermanager_host=DEF_SERVER_NAME;
735 ihost_state.filtermanager_port=DEF_SERVER_PORT;
736 ihost_state.host_fqdn=NULL;
737 ihost_state.host_ip=NULL;
738 ihost_state.preset_fqdn = 0;
739 ihost_state.preset_ip = 0;
740 ihost_state.server_fqdn=NULL;
741 ihost_state.file_list=NULL;
742 ihost_state.last_modified=NULL;
743
744 while((cmdopt=getopt(argc, argv, "vfhVs:i:")) != -1){
745 switch(cmdopt){
746 case 'v':
747 ihost_config.verbose++;
748 break;
749
750 case 'f':
751 /* Force syslog logging since stderr will be closed in this case */
752 ihost_config.daemon=0;
753 break;
754
755 case 'V':
756 fprintf(stderr, "%s version %s\n", argv[0], VERSION);
757 break;
758 case 'n':
759 ihost_state.preset_fqdn = 1;
760 ihost_state.host_fqdn = strdup(optarg);
761 if(ihost_state.host_fqdn == NULL){
762 fprintf(stderr, "Missing hostname\n");
763 usage(argv[0]);
764 }
765 break;
766 case 'i':
767 /* Hmm.. Someone could set any string to be the IP, and it will let it */
768 ihost_state.preset_ip = 1;
769 ihost_state.host_ip = strdup(optarg);
770 if(ihost_state.host_ip == NULL){
771 fprintf(stderr, "Missing ip\n");
772 usage(argv[0]);
773 }
774 break;
775
776 case 's':
777 ihost_state.filtermanager_host=strdup(optarg);
778 break;
779
780 case 'p':
781 ihost_state.filtermanager_port=atoi(optarg);
782 break;
783
784 case 'h':
785 default:
786 usage(argv[0]);
787 exit(1);
788 }
789 }
790
791 if(gethostbyname(ihost_state.filtermanager_host)==NULL){
792 log_msg(LOG_CRIT, "Failed to lookup hostname. Please check settings");
793 exit(1);
794 }
795 if(ihost_state.filtermanager_port==0){
796 log_msg(LOG_ERR, "Invalid port number");
797 exit(1);
798 }
799
800 if(ihost_config.daemon){
801 pid=fork();
802 if(pid==-1){
803 log_msg(LOG_CRIT, "Failed to background exiting");
804 exit(1);
805 }else if(pid!=0){
806 /* Parent process */
807 return 0;
808 }
809 /* We should now be in the background*/
810 if(setsid()==-1){
811 log_msg(LOG_CRIT, "setsid failed");
812 exit(1);
813 }
814
815 if((ihost_config.log=fopen(LOG_FILE, "a"))==NULL){
816 ihost_config.log=stderr;
817 log_msg(LOG_CRIT, "Failed to open Logfiles %s for writing", LOG_FILE);
818 exit(1);
819 }
820
821 fclose(stdin);
822 fclose(stdout);
823 fclose(stderr);
824
825 }
826
827 log_msg(LOG_INFO, "Starting ihost...");
828
829 log_msg(LOG_DEBUG, "Running statgrab_init()");
830 if(!statgrab_init()){
831 log_msg(LOG_CRIT, "statgrab_init failed (%m)");
832 exit(1);
833 }
834
835 log_msg(LOG_DEBUG,"Writing PID FILE");
836
837 pid=getpid();
838
839 if((f=fopen(PID_FILE,"w")) == NULL){
840 log_msg(LOG_CRIT, "Failed to write PID file");
841 }else{
842 if((fprintf(f,"%d",(int)pid)) <= 0 ){
843 log_msg(LOG_CRIT, "Failed to write PID file");
844 }
845 if((fclose(f))!=0){
846 log_msg(LOG_CRIT, "failed to close PID file");
847 }
848 }
849
850 /* Get the initial config from the filter manager. Should this fail,
851 * wait, and then try again. */
852
853 get_diskio_stats_diff(&packet_num);
854 packet_num=0;
855
856 while(ihost_getconfig(&ihost_state)!=0){
857 log_msg(LOG_ERR, "Failed to get ihost config");
858 sleep(10);
859 }
860
861 while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){
862 log_msg(LOG_ERR, "Failed to create udp socket");
863 sleep(10);
864 }
865
866 config_time=time(NULL)+ihost_state.config_ttl;
867
868 /* Now have config.. collect data and send as often as required */
869 for(;;){
870 cur_time=time(NULL);
871
872 if(cur_time>=udp_time){
873 if((get_system_stats(packet_num++, &ihost_state, packet, MAX_UDP_PACKET_SIZE))!=0){
874 log_msg(LOG_ERR, "Failed to get system stats");
875 }
876
877 len=strlen(packet);
878 log_msg(LOG_DEBUG, "Packet size: %d\nPacket: %s\n", len, packet);
879
880 if((sendto(udp_sockinfo.sock, packet, len, 0, (struct sockaddr *) &udp_sockinfo.addr, sizeof(udp_sockinfo.addr)))!=len){
881 log_msg(LOG_CRIT, "Failed to send packet");
882 }
883 udp_time=cur_time+ihost_state.udp_update_time;
884 log_msg(LOG_DEBUG, "Next packet should be sent on %d", udp_time);
885 }
886
887 if(cur_time>=config_time){
888 if(ihost_getconfig(&ihost_state)!=0){
889 /* If we can't get the config, try again 5 minutes time */
890 log_msg(LOG_ERR, "Failed to get config, try again 5 minutes time");
891 config_time=time(NULL)+300;
892 }else{
893 close(udp_sockinfo.sock);
894
895 while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){
896 log_msg(LOG_CRIT, "Failed to create udp socket");
897 sleep(10);
898 }
899
900 config_time=time(NULL)+ihost_state.config_ttl;
901
902 log_msg(LOG_DEBUG, "Config expires on %d\n", ihost_state.config_ttl);
903 }
904 }
905
906 sleep_delay=udp_time-time(NULL);
907 log_msg(LOG_DEBUG, "Sleeping for %d", sleep_delay);
908 if(sleep_delay>0) sleep(sleep_delay);
909 }
910
911 return(0);
912 }