FreeBSD-5.3/usr.sbin/i4b/isdnd/main.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1997, 2001 Hellmuth Michaelis. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
 *
 *---------------------------------------------------------------------------
 *
 *	i4b daemon - main program entry
 *	-------------------------------
 *
 * $FreeBSD: src/usr.sbin/i4b/isdnd/main.c,v 1.16 2001/12/27 08:41:10 hm Exp $
 *
 *      last edit-date: [Wed Dec 26 12:51:00 2001]
 *
 *---------------------------------------------------------------------------*/

#include <locale.h>
#include <paths.h>

#ifdef I4B_EXTERNAL_MONITOR
#include "monitor.h"
#endif

#define MAIN
#include "isdnd.h"
#undef MAIN

#ifdef I4B_EXTERNAL_MONITOR

#ifdef I4B_NOTCPIP_MONITOR
/* monitor via local socket */
static void mloop(int sockfd);
#else /* I4B_NOTCPIP_MONITOR */
/* monitor via local and tcp/ip socket */
static void mloop(int localsock, int remotesock);
#endif /* I4B_NOTCPIP_MONITOR */

#else /* I4B_EXTERNAL_MONITOR */
/* no monitoring at all */
static void mloop();
#endif /* I4B_EXTERNAL_MONITOR */

#ifdef USE_CURSES
static void kbdrdhdl(void);
#endif

static void isdnrdhdl(void);
static void usage(void);

#define MSG_BUF_SIZ	1024	/* message buffer size */

/*---------------------------------------------------------------------------*
 *	usage display and exit
 *---------------------------------------------------------------------------*/
static void
usage(void)
{
	fprintf(stderr, "\n");
	fprintf(stderr, "isdnd - i4b ISDN manager daemon, version %02d.%02d.%d, %s %s\n", VERSION, REL, STEP, __DATE__, __TIME__);
#ifdef DEBUG
	fprintf(stderr, "  usage: isdnd [-c file] [-d level] [-F] [-f [-r dev] [-t termtype]]\n");
#else
	fprintf(stderr, "  usage: isdnd [-c file] [-F] [-f [-r dev] [-t termtype]]\n");
#endif	
	fprintf(stderr, "               [-l] [-L file] [-m] [-s facility] [-u time]\n");
	fprintf(stderr, "    -c <filename> configuration file name (def: %s)\n", CONFIG_FILE_DEF);
#ifdef DEBUG
	fprintf(stderr, "    -d <level>    set debug flag bits:\n");
	fprintf(stderr, "                  general = 0x%04x, rates  = 0x%04x, timing   = 0x%04x\n", DL_MSG,   DL_RATES, DL_TIME);
	fprintf(stderr, "                  state   = 0x%04x, retry  = 0x%04x, dial     = 0x%04x\n", DL_STATE, DL_RCVRY, DL_DIAL);
	fprintf(stderr, "                  process = 0x%04x, kernio = 0x%04x, ctrlstat = 0x%04x\n", DL_PROC,  DL_DRVR,  DL_CNST);
	fprintf(stderr, "                  rc-file = 0x%04x, budget = 0x%04x, valid    = 0x%04x\n", DL_RCCF,  DL_BDGT, DL_VALID);
	fprintf(stderr, "    -dn           no debug output on fullscreen display\n");
#endif
	fprintf(stderr, "    -f            fullscreen status display\n");
	fprintf(stderr, "    -F            do not become a daemon process\n");
	fprintf(stderr, "    -l            use a logfile instead of syslog\n");
	fprintf(stderr, "    -L <file>     use file instead of %s for logging\n", LOG_FILE_DEF);
	fprintf(stderr, "    -P            pretty print real config to stdout and exit\n");
	fprintf(stderr, "    -r <device>   redirect output to other device    (for -f)\n");
	fprintf(stderr, "    -s <facility> use facility instead of %d for syslog logging\n", LOG_LOCAL0 >> 3);
	fprintf(stderr, "    -t <termtype> terminal type of redirected screen (for -f)\n");
	fprintf(stderr, "    -u <time>     length of a charging unit in seconds\n");
#ifdef I4B_EXTERNAL_MONITOR
	fprintf(stderr, "    -m            inhibit network/local monitoring (protocol %02d.%02d)\n", MPROT_VERSION, MPROT_REL);
#endif	
	fprintf(stderr, "\n");
	exit(1);
}

/*---------------------------------------------------------------------------*
 *	program entry
 *---------------------------------------------------------------------------*/
int
main(int argc, char **argv)
{
	int i;
	msg_vr_req_t mvr;
	
#ifdef I4B_EXTERNAL_MONITOR
	int sockfd = -1;		/* local monitor socket */
#ifndef I4B_NOTCPIP_MONITOR
	int remotesockfd = -1;		/* tcp/ip monitor socket */
#endif
#endif

	setlocale (LC_ALL, "");
	
	while ((i = getopt(argc, argv, "mc:d:fFlL:Pr:s:t:u:")) != -1)
	{
		switch (i)
		{
#ifdef I4B_EXTERNAL_MONITOR
			case 'm':
				inhibit_monitor = 1;
				break;
#endif
				
			case 'c':
				configfile = optarg;
				break;

#ifdef DEBUG				
			case 'd':
				if(*optarg == 'n')
					debug_noscreen = 1;
				else if((sscanf(optarg, "%i", &debug_flags)) == 1)
					do_debug = 1;
				else
					usage();				
				break;
#endif

			case 'f':
				do_fullscreen = 1;
				do_fork = 0;			
#ifndef USE_CURSES
				fprintf(stderr, "Sorry, no fullscreen mode available - daemon compiled without USE_CURSES\n");
				exit(1);
#endif
				break;

			case 'F':
				do_fork = 0;
				break;

			case 'l':
				uselogfile = 1;
				break;

			case 'L':
				strlcpy(logfile, optarg, sizeof(logfile));
				break;

			case 'P':
				do_print = 1;
				break;

			case 'r':
				rdev = optarg;
				do_rdev = 1;
				break;

			case 's':
				if(isdigit(*optarg))
				{
					int facility;
					logfacility = strtoul(optarg, NULL, 10);
					facility = logfacility << 3;

					if((facility < LOG_KERN) ||
					   (facility > LOG_FTP && facility < LOG_LOCAL0) ||
					   (facility > LOG_LOCAL7))
					{
						fprintf(stderr, "Error, option -s has invalid logging facility %d", logfacility);
						usage();
					}
					logfacility = facility;
				}
				else
				{
					fprintf(stderr, "Error: option -s requires a numeric argument!\n");
					usage();
				}
				break;

			case 't':
				ttype = optarg;
				do_ttytype = 1;
				break;

			case 'u':
				if(isdigit(*optarg))
				{
					unit_length = strtoul(optarg, NULL, 10);
					if(unit_length < ULSRC_CMDLMIN)
						unit_length = ULSRC_CMDLMIN;
					else if(unit_length > ULSRC_CMDLMAX)
						unit_length = ULSRC_CMDLMAX;
					got_unitlen = 1;
				}
				else
				{
					fprintf(stderr, "Error: option -T requires a numeric argument!\n");
					usage();
				}
				break;

			case '?':
			default:
				usage();
				break;
		}
	}
#ifdef DEBUG
	if(!do_debug)
		debug_noscreen = 0;
#endif

	if(!do_print)
	{
		umask(UMASK);	/* set our umask ... */	
	
		init_log();	/* initialize the logging subsystem */
	}
	
	check_pid();	/* check if we are already running */

	if(!do_print)
	{
		if(do_fork || (do_fullscreen && do_rdev)) /* daemon mode ? */
			daemonize();
	
		write_pid();	/* write our pid to file */
			
		/* set signal handler(s) */
	
		signal(SIGCHLD, sigchild_handler); /* process handling	*/
		signal(SIGHUP,  rereadconfig);	/* reread configuration	*/
		signal(SIGUSR1, reopenfiles);	/* reopen acct/log files*/
		signal(SIGPIPE, SIG_IGN);	/* handled manually	*/
		signal(SIGINT,  do_exit);	/* clean up on SIGINT	*/
		signal(SIGTERM, do_exit);	/* clean up on SIGTERM	*/
		signal(SIGQUIT, do_exit);	/* clean up on SIGQUIT	*/	
	}

	/* open isdn device */
	
	if((isdnfd = open(I4BDEVICE, O_RDWR)) < 0)
	{
		log(LL_ERR, "main: cannot open %s: %s", I4BDEVICE, strerror(errno));
		exit(1);
	}

	/* check kernel and userland have same version/release numbers */
	
	if((ioctl(isdnfd, I4B_VR_REQ, &mvr)) < 0)
	{
		log(LL_ERR, "main: ioctl I4B_VR_REQ failed: %s", strerror(errno));
		do_exit(1);
	}

	if(mvr.version != VERSION)
	{
		log(LL_ERR, "main: version mismatch, kernel %d, daemon %d", mvr.version, VERSION);
		do_exit(1);
	}

	if(mvr.release != REL)
	{
		log(LL_ERR, "main: release mismatch, kernel %d, daemon %d", mvr.release, REL);
		do_exit(1);
	}

	if(mvr.step != STEP)
	{
		log(LL_ERR, "main: step mismatch, kernel %d, daemon %d", mvr.step, STEP);
		do_exit(1);
	}

	/* init controller state array */

	init_controller();

	/* read runtime configuration file and configure ourselves */
	
	configure(configfile, 0);

	if(config_error_flag)
	{
		log(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
		exit(1);
	}

	/* set controller ISDN protocol */
	
	init_controller_protocol();
	
	/* init active controllers, if any */
	
	signal(SIGCHLD, SIG_IGN);		/*XXX*/

	init_active_controller();

	signal(SIGCHLD, sigchild_handler);	/*XXX*/
	
	/* handle the rates stuff */
	
	if((i = readrates(ratesfile)) == ERROR)
	{
		if(rate_error != NULL)
			log(LL_ERR, "%s", rate_error);
		exit(1);
	}

	if(i == GOOD)
	{
		got_rate = 1;	/* flag, ratesfile read and ok */
		DBGL(DL_RCCF, (log(LL_DBG, "ratesfile %s read successfully", ratesfile)));
	}
	else
	{
		if(rate_error != NULL)
			log(LL_WRN, "%s", rate_error);
	}

	/* if writing accounting info, open file, set unbuffered */
	
	if(useacctfile)
	{
		if((acctfp = fopen(acctfile, "a")) == NULL)
		{
			log(LL_ERR, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
			exit(1);
		}
		setvbuf(acctfp, (char *)NULL, _IONBF, 0);		
	}

	/* initialize alias processing */

	if(aliasing)
		init_alias(aliasfile);

	/* init holidays */
	
	init_holidays(holidayfile);		

	/* init remote monitoring */
	
#ifdef I4B_EXTERNAL_MONITOR
	if(do_monitor)
	{
		monitor_init();
		sockfd = monitor_create_local_socket();
#ifndef I4B_NOTCPIP_MONITOR
		remotesockfd = monitor_create_remote_socket(monitorport);
#endif
	}
#endif
	
	/* in case fullscreendisplay, initialize */

#ifdef USE_CURSES
	if(do_fullscreen)
	{
		init_screen();
	}
#endif

	/* init realtime priority */
  		
#ifdef USE_RTPRIO
  	if(rt_prio != RTPRIO_NOTUSED)
  	{
  		struct rtprio rtp;

  		rtp.type = RTP_PRIO_REALTIME;
  		rtp.prio = rt_prio;

  		if((rtprio(RTP_SET, getpid(), &rtp)) == -1)
  		{
			log(LL_ERR, "rtprio failed: %s", strerror(errno));
			do_exit(1);
		}
	}
#endif

	starttime = time(NULL);	/* get starttime */
	
	srandom(580403);	/* init random number gen */
	
	mloop(		/* enter loop of no return .. */
#ifdef I4B_EXTERNAL_MONITOR
		sockfd
#ifndef I4B_NOTCPIP_MONITOR
		, remotesockfd
#endif
#endif
		);
	do_exit(0);
	return(0);
}

/*---------------------------------------------------------------------------*
 *	program exit
 *---------------------------------------------------------------------------*/
void
do_exit(int exitval)
{
	close_allactive();

	unlink(PIDFILE);

	log(LL_DMN, "daemon terminating, exitval = %d", exitval);
	
#ifdef USE_CURSES
	if(do_fullscreen)
		endwin();
#endif

#ifdef I4B_EXTERNAL_MONITOR
	monitor_exit();
#endif

	exit(exitval);
}

/*---------------------------------------------------------------------------*
 *	program exit
 *---------------------------------------------------------------------------*/
void
error_exit(int exitval, const char *fmt, ...)
{
	close_allactive();

	unlink(PIDFILE);

	log(LL_DMN, "fatal error, daemon terminating, exitval = %d", exitval);
	
#ifdef USE_CURSES
	if(do_fullscreen)
		endwin();
#endif

#ifdef I4B_EXTERNAL_MONITOR
	monitor_exit();
#endif

	if(mailto[0] && mailer[0])
	{

#define EXITBL 2048

		char ebuffer[EXITBL];
		char sbuffer[EXITBL];
		va_list ap;

		va_start(ap, fmt);
		vsnprintf(ebuffer, EXITBL-1, fmt, ap);
		va_end(ap);

		signal(SIGCHLD, SIG_IGN);	/* remove handler */
		
		snprintf(sbuffer, sizeof(sbuffer), "%s%s%s%s%s%s%s%s",
			"cat << ENDOFDATA | ",
			mailer,
			" -s \"i4b isdnd: fatal error, terminating\" ",
			mailto,
			"\nThe isdnd terminated because of a fatal error:\n\n",
			ebuffer,
			"\n\nYours sincerely,\n   the isdnd\n",
			"\nENDOFDATA\n");
		system(sbuffer);
	}

	exit(exitval);
}

/*---------------------------------------------------------------------------*
 *	main loop
 *---------------------------------------------------------------------------*/
static void
mloop(
#ifdef I4B_EXTERNAL_MONITOR
	int localmonitor
#ifndef I4B_NOTCPIP_MONITOR
	, int remotemonitor
#endif
#endif
)
{
	fd_set set;
	struct timeval timeout;
	int ret;
	int high_selfd;

 	/* go into loop */
	
 	log(LL_DMN, "i4b isdn daemon started (pid = %d)", getpid());
 
	for(;;)
	{
		FD_ZERO(&set);

#ifdef USE_CURSES
		if(do_fullscreen)
			FD_SET(fileno(stdin), &set);
#endif

		FD_SET(isdnfd, &set);

		high_selfd = isdnfd;
		
#ifdef I4B_EXTERNAL_MONITOR
		if(do_monitor)
		{
			if (localmonitor != -1) {
				/* always watch for new connections */
				FD_SET(localmonitor, &set);
				if(localmonitor > high_selfd)
					high_selfd = localmonitor;
			}
#ifndef I4B_NOTCPIP_MONITOR
			if (remotemonitor != -1) {
				FD_SET(remotemonitor, &set);
				if(remotemonitor > high_selfd)
					high_selfd = remotemonitor;
			}
#endif

			/* if there are client connections, let monitor module
			 * enter them into the fdset */
			if(accepted)
			{
				monitor_prepselect(&set, &high_selfd);
			}
		}
#endif
		
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;

		ret = select(high_selfd + 1, &set, NULL, NULL, &timeout);

		if(ret > 0)
		{	
			if(FD_ISSET(isdnfd, &set))
				isdnrdhdl();

#ifdef USE_CURSES
			if(FD_ISSET(fileno(stdin), &set))
				kbdrdhdl();
#endif

#ifdef I4B_EXTERNAL_MONITOR
			if(do_monitor)
			{
				if(localmonitor != -1 && FD_ISSET(localmonitor, &set))
					monitor_handle_connect(localmonitor, 1);

#ifndef I4B_NOTCPIP_MONITOR
				if(remotemonitor != -1 && FD_ISSET(remotemonitor, &set))
					monitor_handle_connect(remotemonitor, 0);
#endif
				if(accepted)
					monitor_handle_input(&set);
			}
#endif
		}
		else if(ret == -1)
		{
			if(errno != EINTR)
			{
				log(LL_ERR, "mloop: ERROR, select error on isdn device, errno = %d!", errno);
				error_exit(1, "mloop: ERROR, select error on isdn device, errno = %d!", errno);
			}
		}			

		/* handle timeout and recovery */		

		handle_recovery();
	}
}

#ifdef USE_CURSES
/*---------------------------------------------------------------------------*
 *	data from keyboard available, read and process it 
 *---------------------------------------------------------------------------*/
static void
kbdrdhdl(void)
{
	int ch = getch();

	if(ch == ERR)
	{
		log(LL_ERR, "kbdrdhdl: ERROR, read error on controlling tty, errno = %d!", errno);
		error_exit(1, "kbdrdhdl: ERROR, read error on controlling tty, errno = %d!", errno);
	}

	switch(ch)
	{
		case 0x0c:	/* control L */
			wrefresh(curscr);
			break;
		
		case '\n':
		case '\r':
			do_menu();
			break;
	}
}
#endif

/*---------------------------------------------------------------------------*
 *	data from /dev/isdn available, read and process them
 *---------------------------------------------------------------------------*/
static void
isdnrdhdl(void)
{
	static unsigned char msg_rd_buf[MSG_BUF_SIZ];
	msg_hdr_t *hp = (msg_hdr_t *)&msg_rd_buf[0];
	
	register int len;

	if((len = read(isdnfd, msg_rd_buf, MSG_BUF_SIZ)) > 0)
	{
		switch(hp->type)
		{
			case MSG_CONNECT_IND:				
				msg_connect_ind((msg_connect_ind_t *)msg_rd_buf);
				break;
				
			case MSG_CONNECT_ACTIVE_IND:
				msg_connect_active_ind((msg_connect_active_ind_t *)msg_rd_buf);
				break;

			case MSG_DISCONNECT_IND:
				msg_disconnect_ind((msg_disconnect_ind_t *)msg_rd_buf);
				break;
				
			case MSG_DIALOUT_IND:
				msg_dialout((msg_dialout_ind_t *)msg_rd_buf);
				break;

			case MSG_ACCT_IND:
				msg_accounting((msg_accounting_ind_t *)msg_rd_buf);
				break;

			case MSG_IDLE_TIMEOUT_IND:
				msg_idle_timeout_ind((msg_idle_timeout_ind_t *)msg_rd_buf);
				break;

			case MSG_CHARGING_IND:
				msg_charging_ind((msg_charging_ind_t *)msg_rd_buf);
				break;

			case MSG_PROCEEDING_IND:
				msg_proceeding_ind((msg_proceeding_ind_t *)msg_rd_buf);
				break;

			case MSG_ALERT_IND:
				msg_alert_ind((msg_alert_ind_t *)msg_rd_buf);
				break;

			case MSG_DRVRDISC_REQ:
				msg_drvrdisc_req((msg_drvrdisc_req_t *)msg_rd_buf);
				break;

			case MSG_L12STAT_IND:
				msg_l12stat_ind((msg_l12stat_ind_t *)msg_rd_buf);
				break;

			case MSG_TEIASG_IND:
				msg_teiasg_ind((msg_teiasg_ind_t *)msg_rd_buf);
				break;

			case MSG_PDEACT_IND:
				msg_pdeact_ind((msg_pdeact_ind_t *)msg_rd_buf);
				break;

			case MSG_NEGCOMP_IND:
				msg_negcomplete_ind((msg_negcomplete_ind_t *)msg_rd_buf);
				break;

			case MSG_IFSTATE_CHANGED_IND:
				msg_ifstatechg_ind((msg_ifstatechg_ind_t *)msg_rd_buf);
				break;

			case MSG_DIALOUTNUMBER_IND:
				msg_dialoutnumber((msg_dialoutnumber_ind_t *)msg_rd_buf);
				break;

			case MSG_PACKET_IND:
				msg_packet_ind((msg_packet_ind_t *)msg_rd_buf);
				break;

			case MSG_KEYPAD_IND:
				msg_keypad((msg_keypad_ind_t *)msg_rd_buf);
				break;

			default:
				log(LL_WRN, "ERROR, unknown message received from %sisdn (0x%x)", _PATH_DEV, msg_rd_buf[0]);
				break;
		}
	}
	else
	{
		log(LL_WRN, "ERROR, read error on isdn device, errno = %d, length = %d", errno, len);
	}
}

/*---------------------------------------------------------------------------*
 *	re-read the config file on SIGHUP or menu command
 *---------------------------------------------------------------------------*/
void
rereadconfig(int dummy)
{
	extern int entrycount;

	log(LL_DMN, "re-reading configuration file");
	
	close_allactive();

#if I4B_EXTERNAL_MONITOR
	monitor_clear_rights();
#endif

	entrycount = -1;
	nentries = 0;
	
	/* read runtime configuration file and configure ourselves */
	
	configure(configfile, 1);

	if(config_error_flag)
	{
		log(LL_ERR, "rereadconfig: there were %d error(s) in the configuration file, terminating!", config_error_flag);
		error_exit(1, "rereadconfig: there were %d error(s) in the configuration file, terminating!", config_error_flag);
	}

	if(aliasing)
	{
		/* reread alias database */
		free_aliases();
		init_alias(aliasfile);
	}
}

/*---------------------------------------------------------------------------*
 *	re-open the log/acct files on SIGUSR1
 *---------------------------------------------------------------------------*/
void
reopenfiles(int dummy)
{
        if(useacctfile)
	{
		/* close file */
		
		if(acctfp)
		{
		        fflush(acctfp);
		        fclose(acctfp);
		}

	        /* if user specified a suffix, rename the old file */
	        
	        if(rotatesuffix[0] != '\0')
	        {
	        	char filename[MAXPATHLEN];

	        	snprintf(filename, sizeof(filename), "%s%s", acctfile, rotatesuffix);

			if((rename(acctfile, filename)) != 0)
			{
				log(LL_ERR, "reopenfiles: acct rename failed, cause = %s", strerror(errno));
				error_exit(1, "reopenfiles: acct rename failed, cause = %s", strerror(errno));
			}
		}

		if((acctfp = fopen(acctfile, "a")) == NULL)
		{
			log(LL_ERR, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
			error_exit(1, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
		}
		setvbuf(acctfp, (char *)NULL, _IONBF, 0);
	}

	if(uselogfile)
	{
	        finish_log();

	        /* if user specified a suffix, rename the old file */
	        
	        if(rotatesuffix[0] != '\0')
	        {
	        	char filename[MAXPATHLEN];

	        	snprintf(filename, sizeof(filename), "%s%s", logfile, rotatesuffix);

			if((rename(logfile, filename)) != 0)
			{
				log(LL_ERR, "reopenfiles: log rename failed, cause = %s", strerror(errno));
				error_exit(1, "reopenfiles: log rename failed, cause = %s", strerror(errno));
			}
		}

	        if((logfp = fopen(logfile, "a")) == NULL)
		{
			fprintf(stderr, "ERROR, cannot open logfile %s: %s\n",
				logfile, strerror(errno));
			error_exit(1, "reopenfiles: ERROR, cannot open logfile %s: %s\n",
				logfile, strerror(errno));
		}

		/* set unbuffered operation */

		setvbuf(logfp, (char *)NULL, _IONBF, 0);
	}
}

/* EOF */