--- projects/cms/source/ihost/ihost.c 2003/03/03 12:32:35 1.29 +++ projects/cms/source/ihost/ihost.c 2004/05/31 13:35:23 1.51 @@ -1,6 +1,6 @@ /* * i-scream central monitoring system - * http://www.i-scream.org.uk + * http://www.i-scream.org * Copyright (C) 2000-2002 i-scream * * This program is free software; you can redistribute it and/or @@ -31,13 +31,15 @@ #include #include #include +#include +#include -#include "ukcprog.h" -#include "statgrab.h" +#include +#include #define LOG_CRIT 0 #define LOG_ERR 1 -#define LOG_INFO 2 +#define LOG_INFO 2 #define LOG_DEBUG 3 typedef struct{ @@ -46,27 +48,28 @@ typedef struct{ char *host_ip; char *host_fqdn; + int preset_fqdn; + int preset_ip; char *server_fqdn; int server_udp_port; - + /* Weird stuff iscream wants sent to it */ char *last_modified; char *file_list; int udp_update_time; -// int config_ttl; time_t config_ttl; }ihost_state_t; typedef struct{ - int verbose; - int daemon; + int verbose; + int daemon; FILE *log; -}ihost_config_t; +}ihost_config_t; typedef struct{ struct sockaddr_in addr; @@ -75,8 +78,80 @@ typedef struct{ ihost_config_t ihost_config; +extern int errno; + +/* 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 +/* End strlcat function taken from OpenSSH */ + void log_msg(int level, char *format, ...){ - extern int errno; int cur_errno; va_list ap; @@ -91,27 +166,10 @@ void log_msg(int level, char *format, ...){ }else{ fprintf(ihost_config.log, "\n"); } + fflush(ihost_config.log); } } -/* 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; - - va_start(ap, num_pointers); - for(;xfiltermanager_host, ihost_state->filtermanager_port); + if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port))==NULL){ + 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){ + if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){ goto error; } fclose(tcp_con); @@ -258,7 +320,7 @@ int ihost_getconfig(ihost_state_t *ihost_state){ goto error; } last_modified=response; - + if((tcp_comm_strdup(tcp_con, "FILELIST", &response, NULL))!=0){ goto error; } @@ -303,19 +365,18 @@ int ihost_getconfig(ihost_state_t *ihost_state){ } response_ptr++; if(response_ptr==NULL){ - log_msg(LOG_ERR, "Incorrect data sent by server"); - goto error; - } + log_msg(LOG_ERR, "Incorrect data sent by server"); + goto error; + } - printf("string : %s\n", response_ptr); - server_udp_port=atoi(response_ptr); + server_udp_port=atoi(response_ptr); if (server_udp_port==0){ log_msg(LOG_ERR, "Incorrect data sent by server"); goto error; } } - + if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){ goto error; } @@ -326,16 +387,27 @@ int ihost_getconfig(ihost_state_t *ihost_state){ /* 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); + 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->server_fqdn!=NULL) free(ihost_state->server_fqdn); + if(ihost_state->preset_fqdn){ + if(host_fqdn != NULL) free(host_fqdn); + }else{ + if(ihost_state->host_fqdn!=NULL) free(ihost_state->host_fqdn); + ihost_state->host_fqdn=host_fqdn; + } + + if(ihost_state->preset_ip){ + if(host_ip != NULL) free(host_ip); + }else{ + if(ihost_state->host_ip!=NULL) free(ihost_state->host_ip); + ihost_state->host_ip=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; @@ -360,17 +432,17 @@ error: 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; + sg_cpu_percents *cpu_percent; + sg_mem_stats *mem_stats; + sg_load_stats *load_stats; + sg_user_stats *user_stats; + sg_swap_stats *swap_stats; + sg_host_info *general_stats; + sg_fs_stats *disk_stats; + sg_disk_io_stats *diskio_stats; + sg_process_count *process_stats; + sg_network_io_stats *network_stats; + sg_page_stats *page_stats; int disk_entries=0; int diskio_entries=0; int network_entries=0; @@ -381,11 +453,12 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /* Print start of the packet we want */ snprintf(xml, size, "", \ - seq_no, ihost_state->host_fqdn, time(NULL), ihost_state->host_ip); + seq_no, ihost_state->host_fqdn, (long) 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"); + if((cpu_percent=sg_get_cpu_percents())==NULL){ + log_msg(LOG_CRIT, "Failed to get cpu statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ "%3.2f%3.2f%3.2f%3.2f%3.2f", \ @@ -398,10 +471,11 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - - /*Get mem stats, and fill in xml */ - if((mem_stats=get_memory_stats())==NULL){ - log_msg(LOG_CRIT, "Failed to get memory statistics"); + + /*Get mem stats, and fill in xml */ + if((mem_stats=sg_get_mem_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get memory statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ "%lld%lld%lld%lld", \ @@ -409,14 +483,15 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ mem_stats->free, \ mem_stats->used, \ mem_stats->cache); - + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - /* Get load stats */ - if((load_stats=get_load_stats())==NULL){ - log_msg(LOG_CRIT, "Failed to get load statistics"); + /* Get load stats */ + if((load_stats=sg_get_load_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get load statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ "%.2lf%.2lf%.2lf", \ @@ -428,38 +503,41 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /* get user stats */ - - if((user_stats=get_user_stats())==NULL){ - log_msg(LOG_CRIT, "Failed to get user statistics"); + + if((user_stats=sg_get_user_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get user statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ "%s%d", \ user_stats->name_list, \ user_stats->num_entries); - + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } /* swap stats */ - if((swap_stats=get_swap_stats())==NULL){ - log_msg(LOG_CRIT, "Failed to get swap statistics"); + if((swap_stats=sg_get_swap_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get swap statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }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; } /* general stats */ - - if((general_stats=get_general_stats())==NULL){ - log_msg(LOG_CRIT, "Failed to get general statistics"); + + if((general_stats=sg_get_host_info())==NULL){ + log_msg(LOG_CRIT, "Failed to get host info statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ "%s%s%s%s%s%ld", \ @@ -469,15 +547,16 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ general_stats->hostname, \ general_stats->platform, \ (long)general_stats->uptime); - + if(strlcat(xml, tmp, size) >= size) goto too_big_error; - + } - + /* process stats */ - if((process_stats=get_process_stats())==NULL){ - log_msg(LOG_CRIT, "Failed to get general statistics"); + if((process_stats=sg_get_process_count())==NULL){ + log_msg(LOG_CRIT, "Failed to get process statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ snprintf(tmp, size, \ "%d%d%d%d%d",\ @@ -493,8 +572,9 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ /* Get paging stats */ - if((page_stats=get_page_stats_diff())==NULL){ - log_msg(LOG_CRIT, "Failed to get paging statistics"); + if((page_stats=sg_get_page_stats_diff())==NULL){ + log_msg(LOG_CRIT, "Failed to get paging statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ if(page_stats->systime!=0){ x=page_stats->pages_pagein / page_stats->systime; @@ -504,18 +584,19 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ y=page_stats->pages_pageout; } snprintf(tmp, size, \ - "%lld%lld", \ + "%lld%lld", \ x, \ y); - + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } /* get diskio stats */ - - if((diskio_stats=get_diskio_stats_diff(&diskio_entries))==NULL){ - log_msg(LOG_CRIT, "Failed to get diskio statistics"); + + if((diskio_stats=sg_get_disk_io_stats_diff(&diskio_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get disk io statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ strlcat(xml, "", size); for(counter=0;counterwrite_bytes / diskio_stats->systime; }else{ x=diskio_stats->read_bytes; - y=diskio_stats->write_bytes; + y=diskio_stats->write_bytes; } - + snprintf(tmp, size, \ "", \ counter, \ @@ -544,11 +625,12 @@ int get_system_stats(int seq_no, ihost_state_t *ihost_ } - + /* get networks stats */ - - if((network_stats=get_network_stats_diff(&network_entries))==NULL){ - log_msg(LOG_CRIT, "Failed to get network statistics"); + + if((network_stats=sg_get_network_io_stats_diff(&network_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get network io statistics: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); }else{ strlcat(xml, "", size); for(counter=0;counter", size); for(counter=0;counter", 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 */ @@ -619,22 +702,28 @@ too_big_error: } - + 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); + fprintf(stderr, "Usage %s [-v[v]] [-f] [-n name] [-i ip] [-s server] [-p port] [-V] [-h]\n\n", progname); + fprintf(stderr, " -v Verbose mode, -vv would make even more verbose\n"); + fprintf(stderr, " -f Foreground mode, print errors to stderr\n"); + fprintf(stderr, " -n Set the machine name to be reported as\n"); + fprintf(stderr, " -i Set the IP to be reported as\n"); + fprintf(stderr, " -s Specifies the i-scream server to connect to\n"); + fprintf(stderr, " default: %s\n", DEF_SERVER_NAME); + fprintf(stderr, " -p Specifies the i-scream server port\n"); + fprintf(stderr, " default: %d\n", DEF_SERVER_PORT); + fprintf(stderr, " -V Print version number\n"); + fprintf(stderr, " -h Prints this help page\n"); + fprintf(stderr, "\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT); + exit(1); } int main(int argc, char **argv){ ihost_state_t ihost_state; udp_sockinfo_t udp_sockinfo; - + int cmdopt; extern int optind; pid_t pid; @@ -646,53 +735,70 @@ int main(int argc, char **argv){ time_t cur_time, sleep_delay, udp_time=0, config_time=0; - /* Set default settings */ + /* 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.filtermanager_host=DEF_SERVER_NAME; + ihost_state.filtermanager_port=DEF_SERVER_PORT; ihost_state.host_fqdn=NULL; ihost_state.host_ip=NULL; + ihost_state.preset_fqdn = 0; + ihost_state.preset_ip = 0; 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; + while((cmdopt=getopt(argc, argv, "vfVn:i:s:p:h")) != -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 '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; + case 'n': + ihost_state.preset_fqdn = 1; + ihost_state.host_fqdn = strdup(optarg); + if(ihost_state.host_fqdn == NULL){ + fprintf(stderr, "Missing hostname\n"); + usage(argv[0]); + } + break; + case 'i': + /* Hmm.. Someone could set any string to be the IP, and it will let it */ + ihost_state.preset_ip = 1; + ihost_state.host_ip = strdup(optarg); + if(ihost_state.host_ip == NULL){ + fprintf(stderr, "Missing ip\n"); + usage(argv[0]); + } + break; - case 'V': - fprintf(stderr, "%s version %s\n", argv[0], VERSION); - break; + case 's': + ihost_state.filtermanager_host=strdup(optarg); + break; - default: - usage(argv[0]); - exit(1); - } - } + case 'p': + ihost_state.filtermanager_port=atoi(optarg); + break; - if(argc!=optind+2){ - usage(argv[0]); - exit(1); - } + case 'h': + default: + 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); @@ -706,50 +812,57 @@ int main(int argc, char **argv){ pid=fork(); if(pid==-1){ log_msg(LOG_CRIT, "Failed to background exiting"); - exit(1); + 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); - } - + /* 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); } - fclose(stdin); - fclose(stdout); - fclose(stderr); + fclose(stdin); + fclose(stdout); + fclose(stderr); - } + } - log_msg(LOG_INFO, "Starting ihost"); - - log_msg(LOG_DEBUG,"Writing PID FILE"); + log_msg(LOG_INFO, "Starting ihost..."); - pid=getpid(); + log_msg(LOG_DEBUG, "Running sg_init()"); + if(sg_init()){ + log_msg(LOG_CRIT, "sg_init failed: %s (%s)", + sg_str_error(sg_get_error()), sg_get_error_arg()); + exit(1); + } - 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"); - } - } + log_msg(LOG_DEBUG,"Writing PID FILE"); - /* Get the initial config from the filter manager. Should this fail, + 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); + sg_get_disk_io_stats_diff(&packet_num); packet_num=0; while(ihost_getconfig(&ihost_state)!=0){ @@ -757,9 +870,8 @@ int main(int argc, char **argv){ sleep(10); } - 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"); + log_msg(LOG_ERR, "Failed to create udp socket"); sleep(10); } @@ -776,14 +888,14 @@ int main(int argc, char **argv){ 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(cur_time>=config_time){ if(ihost_getconfig(&ihost_state)!=0){ /* If we can't get the config, try again 5 minutes time */ @@ -792,9 +904,9 @@ int main(int argc, char **argv){ }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); + 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; @@ -806,7 +918,7 @@ int main(int argc, char **argv){ sleep_delay=udp_time-time(NULL); log_msg(LOG_DEBUG, "Sleeping for %d", sleep_delay); if(sleep_delay>0) sleep(sleep_delay); - } - + } + return(0); }