/*
 * nqsd/nqs_autoinst.c
 * 
 * DESCRIPTION:
 *
 *	NQS automatic installation module.
 *
 *	Original Author:
 *	-------
 *	John R. Roman,  Monsanto Company
 *	July 20,  1993.
 */

#include <libnqs/license.h>
#include <libnqs/proto.h>
#include <libnqs/nqsxvars.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>

#include <libsal/license.h>
#include <libsal/proto.h>
#include <libsal/defines.h>
#include <SETUP/autoconf.h>
#include <SETUP/General.h>

/*** nqs_autoinst
 *
 *	long nqs_autoinst():
 *	Determine if an installation from the staging area is necessary, 
 *	and do it if required.
 *
 *	Check to see if the version level in the staging area is greater
 *	    than the currently running system.
 *	If so,  fork off,  daemonize,  and shutdown the system.
 *
 *	Returns:
 *		1
 */
long nqs_autoinst (void)
{
    char *cp, *acp;
    FILE *version_fd;
    char buffer[128];
    char version_file_name[128];
    char nqslib_name[128];
    char finish_autoinst_path[128];
    char c_nqs_version[64];
    struct stat stat_buff;
    int s_major, s_minor, s_pl, s_pre;
    int c_major, c_minor, c_pl, c_pre;
    int iResult;
    pid_t child_pid;
    pid_t nqsdaepid;
    char *argv [10];		/* Arguments to shell */
    char *envp [5];		/* Environment variables for process that */
				/* will be used to send NQS mail */
    char home [64];		/* HOME=........................ */
#if	!HAS_BSD_ENV
    char logname [30];		/* LOGNAME=..................... */
#else
    char user [30];		/* USER=........................ */
#endif
    
    if ((cp = getfilnam ("", LIBDIR)) == (char *) NULL){
        sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_autoinst: Could not get name of version file.\n");
        return (1);
    }
    strcpy (nqslib_name, cp);
    relfilnam (cp);
    strcpy (version_file_name, NQS_STAGE_LOC);
    strcat (version_file_name, "/VERSION");
    sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_DEBUGHIGH, "nqs_autoinst: Version file name is %s\n", version_file_name);
    if ( stat (version_file_name,  &stat_buff) == -1) {
	if (errno == ENOENT) return (1);
	sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_autoinst: stat of %s failed with errno %d.\n", version_file_name,  errno);
	return (1);   
    }
    if ((version_fd = fopen(version_file_name, "r")) == NULL){
        sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_autoinst: can't open %s\n", version_file_name);
	return (1);
    }
    if (fgets (buffer, 128, version_fd) == NULL ) {
        sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_autoinst: can't read %s\n", version_file_name);
	return (1);
    }
    cp = strchr(buffer, '\"');
    if (cp == NULL) {
        sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_autoinst: version line invalid: %s\n", buffer);
	return (1);
    }
    cp++;
    acp = strchr(cp, '\"');
    if (acp == NULL) {
        sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_autoinst: version line invalid: %s\n", buffer);
	return (1);
    }
    *acp = '\0';
    s_major = s_minor = s_pl = s_pre = 0;
    c_major = c_minor = c_pl = c_pre = 0;
    while (*cp && *cp != '.' ) {
	s_major = s_major*10 + (*cp - '0');
	cp++;
    }
    cp++;
    while (*cp && *cp != '.' ) {
	s_minor = s_minor*10 + (*cp - '0');
	cp++;
    }
    if (*cp) {
	cp++;
	while (*cp && *cp != '.') {
	    s_pl = s_pl*10 + (*cp - '0');
	    cp++;
	}
    }
    if (*cp) {
    	cp++;
        while (*cp && *cp != '.') {
	    s_pre = s_pre*10 + (*cp - '0');
	    cp++;
	}
    }
    sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_DEBUGHIGH, "nqs_autoinst: Stage version is %d.%d.%d\n", s_major, s_minor, s_pl);
    fclose (version_fd);
    strcpy(c_nqs_version, NQS_VERSION);
    cp = c_nqs_version;
    while (*cp && *cp != '.') {
	c_major = c_major*10 + (*cp - '0');
	cp++;
    }
    cp++;
    while (*cp && *cp != '.') {
	c_minor = c_minor*10 + (*cp - '0');
	cp++;
    }
    if (*cp) {
	cp++;
	while (*cp && *cp != '.') {
	    c_pl = c_pl*10 + (*cp - '0');
	    cp++;
	}
    }
    if (*cp) {
    	cp++;
        while (*cp && *cp != '.') {
	    c_pre = c_pre*10 + (*cp - '0');
	    cp++;
	}
    }
    if (c_pre)
      sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_INFO, "nqs_autoinst: Current version is %d.%d.%d pre-release %d\n", c_major, c_minor, c_pl, c_pre);
    else
      sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_INFO, "nqs_autoinst: Current version is %d.%d.%d\n", c_major, c_minor, c_pl);
  
    /*
     * Allow if the major versions are the same, and the minor version/patchlevel
     * of the new version is greater than the current.
     */
    iResult = 0;

    if (s_major == c_major)
    {
      if (s_minor > c_minor)
	iResult = 1;
      else if (s_pl > c_pl)
	iResult = 1;
      else if (c_pl > 0 && s_pl == 0)
	iResult = 1;
    }

    if (iResult) {
	sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_autoinst: Stage version greater than current\n");
	ups_shutdown( (pid_t) -1,  (uid_t) -1,  SHUTDOWN_WAIT);
#if	HAS_BSD_PIPE
        flock (Qmapfile->fd, LOCK_UN); /* Release advisory exclusive lock */
#endif
	nqsdaepid = getpid ();		    /* Save our pid for later */
	if ( (child_pid = fork()) < 0 ) {
	    return (1);
	} else if (child_pid != 0) { /* fork success, parent prepare for shutdown */
	    Shutdown = 1;
	    return (1);
	}
	/*
	 * We are now the child, get separated and wait a while.
	 */
	setsid();
	chdir ("/");
	umask (0);
	sleep (SHUTDOWN_WAIT * 2);
	/*
	 * Now kill those pids to make sure nqs is really gone!
	 */
	if (Netdaepid) kill (Netdaepid, SIGKILL);
	if (Loaddaepid) kill (Loaddaepid, SIGKILL);
	if (nqsdaepid) kill (nqsdaepid, SIGKILL);
	/*
	 * One more problem -- while we are running we cannot replace
	 * ourself.  So what we need to do is to exec a program that
	 * will do the work left to do:
	 * 
	 * 1. Invoke the script to move the files from the staging area
	 *    to the desired directories.
	 * 2. Start up NQS
	 * 3. Mail a message (optional) to the NQS manager/operator.
	 */
        strcpy (finish_autoinst_path, nqslib_name);
        strcat (finish_autoinst_path, "finish_autoinst");
	sprintf (home, "HOME=/" );
	envp [0] = home;	/* Record the home directory */
	envp [1] = "SHELL=/bin/sh";
					/* Default shell */
#if	!HAS_BSD_ENV
	envp [2] = "PATH=:/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
	sprintf (logname, "LOGNAME=root");
	envp [3] = logname;
	envp [4] = (char *) 0;	/* No more environment variables */
#else
	envp [2] = "PATH=:/usr/ucb:/bin:/usr/bin";
	sprintf (user, "USER=root");
	envp [3] = user;
	envp [4] = (char *) 0;	    /* No more environment variables */
#endif
	argv [0] = "finish_autoinst";
	argv [1] = nqslib_name;
	argv [2] = (char *) 0;
	execve (finish_autoinst_path, argv, envp);
					/* Execve() install and startup program */
	exit (1);
    }
  return 1;
}
