/*
 * :set tabstop=4
 * vme_acfail.c
 * spd@daphne.cps.unizar.es
 * Mon Apr 28 12:48:47 MET DST 1997
 * Solaris 2.5 sparc; FORCE VME
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>

#include <errno.h>
#include <values.h>
#include <signal.h>

#include <sys/wait.h>


/*#include <sys/vme_types.h>*/
/*#include <sys/vui.h>*/
/*
 * gcc 2.7.2.1 doesn't likes
 * typedef unsigned long long     vmeaddr_t
 * in vme_types.h
 */
int vui_acfail_wait(int dev);
int vui_acfail_signal( int dev, int signal );

#define PATH_SEP        '/'

static char __ident[] = "@(#)SPDsoft, Mon Apr 28, 1997";

#define VERS_STR		((char*)&__ident[4])

char			*app;
void			(*sigint)(int);
int				vmedev;
int				daemon=0;

void usage(void);
int main (int argc, char **argv);
void die(int s);
void merror(char *msg);
int launch( char *cmd[], int *status );

void usage(void)
{
	fprintf(stderr,"Use: %s [-hd]\n-d:\tdaemon mode\n", app);
	exit(0);
}

void merror(char *msg)
{
	int error;

	if ( daemon )
	{
		error=errno;
		openlog( app, LOG_PID | LOG_NDELAY | LOG_NOWAIT , LOG_USER);
		syslog( LOG_ERR, "%s (%s)", msg, strerror(error) );
		closelog();
	}
	else
	{
		perror(msg);
	}
	return;
}

void die(int s)
{
	char *cmd[] = {
/*		"/bin/sleep","30",*/
/*		NULL*/
		"/usr/sbin/shutdown","-y","-g300","-i5",
		"Power fail", NULL
		};
	int		status;
	int		error;

	sigset(SIGINT, sigint);

	openlog( app, LOG_PID | LOG_NDELAY | LOG_NOWAIT , LOG_USER);
	syslog( LOG_EMERG, "Power Fail, I'm going down" );
	closelog();

	if(0==(error=launch( cmd, &status)))
	{
		if ( status == 0 )
		exit(0);
	}
	else
	{
		openlog( app, LOG_PID | LOG_NDELAY | LOG_NOWAIT , LOG_USER);
		syslog( LOG_ERR, "execvp failed (%s)", strerror(errno) );
		closelog();
	}

	return;
}

int main (int argc, char **argv)
{
	extern char	*optarg;
	extern int	optind,opterr;
	int			opt;

	int			st=0;


	if ((app = strrchr(argv[0], PATH_SEP))  != NULL)
		app = app+1;
	else
		app = argv[0];

	while ( (opt=getopt(argc,argv,"hdV")) != EOF )
	{
		switch(opt)
		{
			case 'd':
				daemon=1;
				break;

			case 'V':
				fprintf(stdout,"%s\n", VERS_STR);
				exit(0);
				break;

			case 'h':
			default:
				usage();
				break;
		}
	}
    
	if ((vmedev = open ("/dev/vmectl", O_RDWR)) == -1)
	{
	    perror ("open /dev/vmectl");
		st = -1;
	}
	else
	{
		if (!daemon)
		{
			char name[32];
			short id;
			if ( 0 == vui_board( vmedev, name, &id ))
				fprintf(stderr, "%s: Board: %s (%d)\n", app, name, id);
			if ( 0 == vui_interface( vmedev, name, &id ))
				fprintf(stderr, "%s: Interface: %s (%d)\n", app, name, id);
		}
		else
		{
			freopen("/dev/null", "r", stdin);
			freopen("/dev/null", "w", stdout);
			freopen("/dev/null", "w", stderr);
			if (fork())
				exit (0);
		}

		if ( 0 != vui_acfail_signal(vmedev, SIGINT))
		{
			close (vmedev);
			merror("acfail_signal");
			st=-1;
		}
		else
		{
			close (vmedev);
			while(st==0)
			{
				if ( SIG_ERR == (sigint=sigset(SIGINT, die)))
				{
					merror("sigset");
					st=-1;
				}
				else
				{
					sigpause(SIGINT);
				}
			}
		}
	}

    exit(st);
}

/*************************************************************************/

int launch( char *cmd[], int *status )
{
	int		res=0;
	int		st;
	int		pid;
	char	s[256];

	switch ( pid = fork() )
	{
	case -1:	/* error */
			merror ( "fork" );
			res = -1;
			break;

	case 0:	
			execvp ( cmd[0], &cmd[0] );
			merror("execvp");
			exit(-2);
			break;

	default:	
			*status = 0;

			while ( pid != wait ( &st ))
			{
				if (( st == -1 ) && ( errno != EINTR ))
					merror("wait");
			}

			if (WIFSTOPPED(st))
			{
				sprintf(s,"%s: %s stoped %d\n", app, cmd[0], WSTOPSIG(st));
				merror(s);
				res = -6;
			}
			else if(WIFEXITED(st))
			{
				*status = WEXITSTATUS(st);
			}
			else if(WIFSIGNALED(st))
			{
				sprintf(s,"%s: %s signaled %d\n",
				app, cmd[0],WTERMSIG(st));
				merror(s);
				res = -6;
			}

			if(st&0200)
			{
				sprintf(s,"%s: %s core dumped\n", app, cmd[0]);
				res=-7;
			}

			break;

	}

	return res;
}