/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*++ nqs_upf.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/src/RCS/nqs_autoinst.c,v $
 *
 * DESCRIPTION:
 *
 *	NQS automatic installation module.
 *
 *
 *	Author:
 *	-------
 *	John R. Roman,  Monsanto Company
 *	July 20,  1993.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.2 $ $Date: 1994/03/30 20:36:28 $ $State: Exp $)
 * 
 *
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.1   JRR     20-Jul-1993     Initial version.
*	V01.2	JRR	28-Feb-1994	Added support for SOLARIS.
*					The format is mm.nn.pp!!!
*/

#include "nqs.h"
#include "nqsxvars.h"
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.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 ()
{
    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;
    int c_major, c_minor, c_pl;
    pid_t child_pid;
    pid_t nqsdaepid;
    char domainfile_name[64];	/* Name of the domain file */
    char hostname [256];          	/* Domain file line buffer */
    int i;			/* Work var */
    char *machinename;		/* Machine name */
    time_t timeofday;		/* Time of day */
    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	HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
    char logname [30];		/* LOGNAME=..................... */
#else
#if	BSD43 | ULTRIX | DECOSF
    char user [30];		/* USER=........................ */
#else
BAD SYSTEM TYPE
#endif
#endif
    
    if ((cp = getfilnam ("", LIBDIR)) == (char *) NULL){
        printf ("E$nqs_autoinst: Could not get name of version file.\n");
        fflush (stdout);
        return (1);
    }
    strcpy (nqslib_name, cp);
    relfilnam (cp);
    strcpy (version_file_name, NQS_STAGE_LOC);
    strcat (version_file_name, "/VERSION");
    if (Debug > 1) {
	printf( "D$nqs_autoinst: Version file name is %s\n", version_file_name);
	fflush (stdout);
    }
    if ( stat (version_file_name,  &stat_buff) == -1) {
	if (errno == ENOENT) return (1);
	printf ("E$nqs_autoinst: stat of %s failed with errno %d.\n", 
		    version_file_name,  errno);
	fflush (stdout);
	return (1);   
    }
    if ((version_fd = fopen(version_file_name, "r")) == NULL){
        printf ("E$nqs_autoinst: can't open %s\n", version_file_name);
	fflush (stdout);
	return (1);
    }
    if (fgets (buffer, 128, version_fd) == NULL ) {
        printf ("E$nqs_autoinst: can't read %s\n", version_file_name);
	fflush (stdout);
	return (1);
    }
    cp = strchr(buffer, '\"');
    if (cp == NULL) {
        printf ("E$nqs_autoinst: version line invalid: %s\n", buffer);
	fflush (stdout);
	return (1);
    }
    cp++;
    acp = strchr(cp, '\"');
    if (acp == NULL) {
        printf ("E$nqs_autoinst: version line invalid: %s\n", buffer);
	fflush (stdout);
	return (1);
    }
    *acp = '\0';
    s_major = s_minor = s_pl = 0;
    c_major = c_minor = c_pl = 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) {
	    s_pl = s_pl*10 + (*cp - '0');
	    cp++;
	}
    }
    if (Debug) {
	printf( "D$nqs_autoinst: Stage version is %d.%d.%d\n", s_major, s_minor, s_pl);
	fflush (stdout);
    }
    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) {
	    c_pl = c_pl*10 + (*cp - '0');
	    cp++;
	}
    }
    if (Debug) {
	printf( "D$nqs_autoinst: Current version is %d.%d.%d\n", c_major, c_minor, c_pl);
	fflush (stdout);
    }
    /*
     * Allow if the major versions are the same, and the minor version/patchlevel
     * of the new version is greater than the current.
     */
    if ( ((s_major == c_major) && (s_minor > c_minor)) ||
	   ((s_major == c_major) && (s_minor == c_minor) &&  (s_pl > c_pl) ) ) {
	       
	if (Debug) {
	    printf( "D$nqs_autoinst: Stage version greater than current\n");
	    fflush (stdout);
	}
	ups_shutdown( (pid_t) -1,  (uid_t) -1,  SHUTDOWN_WAIT);
#if	ULTRIX | DECOSF | BSD43
        flock (Qmapfile->fd, LOCK_UN); /* Release advisory exclusive lock */
#else
#if	HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
#else
BAD SYSTEM TYPE
#endif
#endif
	nqsdaepid = getpid ();		    /* Save our pid for later */
	if ( (child_pid = fork()) < 0 )  return (1);
	else if (child_pid != 0)  return (1);
	/*
	 * We are now the child, get separated and wait a while.
	 */
	setsid();
	chdir ("/");
	umask (0);
	close (STDOUT);	    /* Disconnect from log daemon */
	close (STDERR);	    /* Disconnect from log daemon */
	close (STDIN);	    /* Disconnect from log daemon */
	sleep (SHUTDOWN_WAIT * 2);
	/*
	 * Now kill those pids to make sure nqs is really gone!
	 */
	if (Logdaepid) kill (Logdaepid, SIGKILL);
	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	HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
	envp [2] = "PATH=:/bin:/usr/bin";
	sprintf (logname, "LOGNAME=root");
	envp [3] = logname;
	envp [4] = (char *) 0;	/* No more environment variables */
#else
#if	BSD43 | ULTRIX | DECOSF
	envp [2] = "PATH=:/usr/ucb:/bin:/usr/bin";
	sprintf (user, "USER=root");
	envp [3] = user;
	envp [4] = (char *) 0;	    /* No more environment variables */
#else
BAD SYSTEM TYPE
#endif
#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);
    }
}
