/*********************************************/
/* blipd.c                                   */
/*                                           */
/* Brian Hatch  Sept 1, 1995                 */
/*                                           */
/* A daemon designed to watch the system log */
/* for changes in a slip connection and      */
/* re-configure the slip link using          */
/*                                           */
/* blip configure <IP_ADDRESS>               */
/*                                           */
/* Various sections borrowed blatantly from  */
/* W. Richard Stevens.                       */
/*                                           */
/* Compile with cc -o blipd blipd.c          */
/* and run as root.                          */
/*                                           */
/*                                           */
/*   Released under the GPL                  */
/*                                           */
/*********************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/param.h>
#include <errno.h>
#include <stdarg.h>


#ifdef SIGTSTP
#include <sys/file.h>
#include <sys/ioctl.h>
#endif

/* Set this to the location of the Blip program */
#define BLIP "/usr/local/bin/blip"

/* Set this to the characters _just before_ the IP address supplied.  */
#define IP_PREFIX "Your IP address is "

/* Set SYSLOG to the full path name of your system log.  */
#define SYSLOG "/var/adm/SYSLOG"

/* Set SLEEP_TIME to the number of seconds between syslog scans.  */
#define SLEEP_TIME 240



#define TRUE (1==1)
#define FALSE (0==1)
#define LINE_SIZE 200
#define IP_SIZE 20
#define MAXLINE 4096

 char	line[LINE_SIZE];
	
 void	configureSlip( char *IP );
char*	extractIP( char * );
  int 	startDaemon( int );
 void	sigChild();
 void	errSys( const char*, ... );
static  void err_doit( int, const char*, va_list);

extern  int errno;


main()
{
FILE	*log;
char	IP[IP_SIZE];
 int	RECONFIGURE=FALSE;
long	offset=1;


	startDaemon( TRUE );

	while (TRUE)
		{
		 RECONFIGURE=FALSE;

		 if ( (log = fopen( SYSLOG , "r" )) == NULL )
			break;
		 fseek( log, 0, SEEK_END );

/* check and see if log has been truncated (by cron job, etc.) */
		 if ( ftell( log ) < offset )
			{
			 offset = 1;
			}
		 fseek( log, offset, SEEK_SET ); 


		 while ( fgets( line, LINE_SIZE, log ) != NULL )
			{
			 if ( strstr( line, IP_PREFIX ) != NULL  )
				{
				 strncpy(  IP, extractIP (line), IP_SIZE );
				 RECONFIGURE = TRUE;
				}
			}
			 
		 offset=ftell( log );
		 fclose( log );
		 if ( RECONFIGURE )
			{
			 configureSlip( IP );
			}

		 sleep( SLEEP_TIME );
		}
}


		
void configureSlip( char *IP )
{
	snprintf(line, LINE_SIZE, BLIP " configure %s", IP);
	system( line );
}


char* extractIP( char *string )
{
char* orig;

	string = strstr( string, IP_PREFIX );
	string += strlen( IP_PREFIX );
	orig = string;
	while ( *string != 32 )
		string++;
	*(string-1) = 0;


	return( orig );
}


int startDaemon( int ingnoreSigChild )
{
register int	childPid, fd;

    if ( getppid() != 1 )  /* Most likely not started by init */
	{
	 

#ifdef SIGTTOU
	 signal( SIGTTOU, SIG_IGN );   /* ignore terminal stop settings */
#endif
#ifdef SIGTTIN
	 signal( SIGTTIN, SIG_IGN );   /* but only for the ones defined */
#endif
#ifdef SIGTSTP
	 signal( SIGTSTP, SIG_IGN );   /* for the system you're on.     */
#endif

/* Fork, let child live, kill parent.  This removes process leader status.  */

	 if ( (childPid = fork()) < 0 )
		errSys("Can't fork first child");

	 else if ( childPid > 0 )	/* parents must die. */
		exit(0);

#ifdef SIGTSTP	
	 if ( setpgrp(0, getpid() ) == -1 )
		errSys("Can't change process group");

	 if ( (fd = open("/dev/tty", O_RDWR)) >= 0 )
		{
		 ioctl( fd, TIOCNOTTY, (char*)NULL );	/* loose controlling */
							/* tty...            */
		 close( fd );
		}

#else

	 if (setpgrp() == -1 )
		errSys("Can't change process group");

	 signal( SIGHUP, SIG_IGN );

	 if ( (childPid = fork() ) < 0 )
		errSys("Can't fork second child");

	 else if (childPid > 0 )	/* parents must die. */
		exit(0);		
#endif

	}


    for ( fd = 0; fd < NOFILE; fd++ )	/* close any open file descriptors. */
	close(fd);

    errno = 0;				/* reset, since we probably closed  */
					/* an already closed f.d.	    */

    chdir("/");				/* get off mounted filesystems      */

    umask( 0 );				/* clear file mode creation mask    */

    if ( ingnoreSigChild )
	{

#ifdef SIGTSTP
	 signal(SIGCLD, sigChild);

#else
	 signal(SIGCLD, SIG_IGN );
#endif

	}

}


#ifdef vax
#define BSD
#endif

/* if this doesn't do it for you, compile with -DBSD yourself. */

void sigChild()
{

#ifdef BSD

int		pid;
union wait	status;	 

    while ( ( pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0 );

#endif
}



char 	*pname = NULL;

void errSys( const char* fmt, ... )
{
va_list	ap;

	va_start(ap, fmt);
	err_doit(1, fmt, ap);
	va_end(ap);
	exit(1);
}


static void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int	errno_save;
char	buf[MAXLINE];

	errno_save = errno;
	vsnprintf(buf, MAXLINE-1, fmt, ap);
	if (errnoflag)
		snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1,
				": %s", strerror(errno_save));
	strcat(buf, "\n");
	fflush(stdout);
	fputs(buf, stderr);
	fflush(NULL);
	return;
}


