/*
 * main.c	Execute local prologue/epilogue scripts.
 *
 *		Part of nqsexejob, for Generic NQS v3.51.0
 *
 * Version	1.0
 * 
 * Author	Stuart Herbert
 *		(S.Herbert@sheffield.ac.uk)
 *
 * Copyright	(c) 1998 Stuart Herbert
 *		Released under v2 of the GNU GPL
 *
 * HOW IT WORKS:
 *
 *	The GNQS shepherd process has just kicked off the system
 *	prologue/epilogue script.  That script has done what it
 *	has to do, and now wants to run the actual job.
 *
 *	This is where we come in.
 *
 *	We start off with real uid = effective uid = 0.
 *	stdin is a pipe back to the shepherd process
 *	stdout and stderr are pipes to the staged output files
 *	Our environment is the same the actual job would have had
 *	under previous versions of GNQS.
 *
 *	We do the following:
 *
 *	a) setup real and effective uid to be the owner of the job
 *	   setup the gid to be the owner of the job too
 *	   we get this information from the UID and GID environment
 *	   vars, which are set by the GNQS daemon, and can only be
 *	   changed by the system prologue/epilogue script
 *	b) run the script $NQS_LIBEXE/user_job
 *	c) game over
 */

#include <SETUP/General.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int  nqs_RunScript (char *);
void nqs_SetUid    (void);

/* =-=-=-=-=
 *	nqs_RunScript()
 *
 *	At this point, we want to execute the job the user actually
 *	submitted to GNQS.
 *
 *	fd 0 (stdin) is connected to either the script we want to execute,
 *	or a user-visible file which contains the name of the script we want
 *	to execute.  This was done by the NQS daemon.
 *
 *	fd 1 (stdout) and fd 2 (stderr) are open to the staged stdout and
 *	stderr files.  This was done by the NQS daemon.
 */

#define MAX_COMMAND 1024

int nqs_RunScript (char * szScript)
{
	char szCommand [MAX_COMMAND];
	int  iResult    = 0;

	sprintf(szCommand, "%s/%s", NQS_LIBEXE, szScript);

	iResult = system (szCommand);
	if (iResult != 0)
	    fprintf(stderr, "User's command returned %d\n", iResult);

	return iResult;
}

void nqs_SetUid (void)
{
	char * szGid   = NULL;
	char * szUid   = NULL;
	int    iGroups = 0;

	gid_t  iGidset[NGROUPS_MAX];

	szGid = getenv("QSUB_GID");
	if (szGid == NULL)
	{
		fprintf(stderr, "nqsexejob: Missing environment variable QSUB_GID - aborting\n");
		exit(127);
	}

	/*
	 * Fix for correct gid handling by Jack Perdue
	 *
	 * Thanks to Michale Andrews for making sure it didn't
	 * get left out!
	 */

	initgroups (getenv("QSUB_USER"), atoi(szGid));
	iGroups = getgroups (NGROUPS_MAX, iGidset);
	setgroups (iGroups, iGidset);

	setgid(atoi(szGid));

	szUid = getenv("QSUB_UID");
	if (szUid == NULL)
	{
		fprintf(stderr, "nqsexejob: Missing environment variable QSUB_UID - aborting\n");
		exit(127);
	}

	setuid(atoi(szUid));
}

int main (int argc, char * argv[])
{
	/* change uid, euid, and gid 
	 *
	 * The uid and gid are specified in the UID and GID environment
	 * variables respectively.  euid == uid
	 */

	nqs_SetUid();

	/* run local prologue script 
	 *
	 * remember - if the script fails to run, this is not a fatal
	 * error (perhaps it should be?)
	 */

	return nqs_RunScript("user_job");
}
