/*
 *	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.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR                     Initial version.
*       V01.20  JRR     16-Jan-1992	Added support for RS6000.
*	V01.3	JRR	17-Jun-1992	Added header.
*	V01.4	JRR	10-Nov-1992	Add support for HPUX.
*	V01.5	JRR	06-Apr-1993	Added support for DECOSF.
*	V01.6	JRR			Placeholder.
*	V01.7	JRR	28-Feb-1994	Added support for SOLARIS.
*/
/*++ nqs_complt.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/src/RCS/nqs_complt.c,v $
 *
 * DESCRIPTION:
 *
 *	Complete a local intra-machine NQS transaction, by sending
 *	a transaction completion code to the requesting process.
 *
 *	Let's talk for a moment, shall we?  This module could have
 *	been implemented using named-pipes, or on some systems, by a
 *	socket or socket like connection, or even by datagrams.
 *
 *	However, I'm trying very hard to keep this thing PORTABLE.
 *	Also, this implementation has one principal advantage:
 *
 *		The burden of creating and opening
 *		the file is placed on the client.
 *		If the simple inter-process communication
 *		file cannot be created and opened
 *		by the client, then the client 
 *		simply does not try to perform any
 *		transactions with the NQS daemon.
 *		We find out up front, whether or
 *		not we can talk (as a local client
 *		process), to the local NQS daemon.
 *		If the supporting system is short of
 *		open file table entries, we find this
 *		right away.
 *
 *
 *	This scheme is very sleazy, and I apologize here.  If you
 *	have a better idea that is still portable, then please
 *	step forward and tell me about it!
 *
 *
 *	Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	October 8, 1985.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.7 $ $Date: 1994/03/30 20:36:31 $ $State: Exp $)
 * $Log: nqs_complt.c,v $
 * Revision 1.7  1994/03/30  20:36:31  jrroma
 * Version 3.35.6
 *
 * Revision 1.6  93/07/13  21:33:47  jrroma
 * Version 3.34
 * 
 * Revision 1.5  92/12/22  15:39:49  jrroma
 * Version 3.30
 * 
 * Revision 1.4  92/06/18  17:30:56  jrroma
 * Added gnu header
 * 
 * Revision 1.3  92/01/17  10:48:19  jrroma
 * Unnecessary checkout.
 * 
 * Revision 1.2  92/01/17  10:44:48  jrroma
 * Added support for RS6000.
 * 
 * Revision 1.1  92/01/17  10:43:49  jrroma
 * Initial revision
 * 
 *
 */

#include "nqs.h"		/* Packet size definition */
#include "nqsxvars.h"		/* NQS external vars */
#include <errno.h>
#include <signal.h>		/* Defines signals and int (*signal())(); */
#if	BSD43 | ULTRIX | DECOSF
#include <sys/time.h>
#else
#if	SGI | SOLARIS | HPUX | SYS52 | IBMRS | LINUX
struct utimbuf {
	time_t acctime;		/* Access time */
	time_t modtime;		/* Modification time */
};
#else
BAD SYSTEM TYPE
#endif
#endif

extern time_t time();		/* Get time */

/*** nqs_complt
 *
 *
 *	void nqs_complt():
 *
 *	Complete a local intra-machine NQS transaction, by sending
 *	a transaction completion code to the requesting process.
 */
void nqs_complt (long completion_code, int pid)
{
	static char incomplete[]
	= "W$Nqs_complt() unable to send completion code.\n";

#if	BSD43 | ULTRIX | DECOSF
	struct timeval utimbuf [2];	/* Utimes() buffer */
#else
#if	SGI | SOLARIS | HPUX | SYS52 | IBMRS | LINUX
	struct utimbuf utimbuf;		/* utime() buffer */
#else
BAD SYSTEM TYPE
#endif
#endif
	char path [MAX_PATHNAME+1];	/* Inter-process communication */
					/* file name */

	sprintf (path, "%s/%1d", Nqs_inter, pid);
#if	BSD43 | ULTRIX | DECOSF
	time (&utimbuf [0].tv_sec);	/* Access time = current time */
	utimbuf [0].tv_usec = 0;
	utimbuf [1].tv_sec = completion_code;
	utimbuf [1].tv_usec = 0;
	if (utimes (path, utimbuf) == -1) {
#else
#if	SGI | SOLARIS | HPUX | SYS52 | IBMRS | LINUX
	time (&utimbuf.acctime);	/* Access time = current time */
	utimbuf.modtime = completion_code;
	if (utime (path, &utimbuf) == -1) {
#else
BAD SYSTEM TYPE
#endif
#endif
		/*
		 *  We were not successful.
		 */
		if (errno != ENOENT) {
			/*
			 *  A very serious error has occurred; either
			 *
			 *	EPERM, ENOTDIR, EACCES, EROFS, EFAULT, or
			 *	ELOOP (Berkeley).
			 */
#if	BSD43 | ULTRIX | DECOSF
			printf ("F$Utimes() call error in nqs_complt().\n");
#else
#if	SGI | SOLARIS | HPUX | SYS52 | IBMRS | LINUX
			printf ("F$Utime() call error in nqs_complt().\n");
#else
BAD SYSTEM TYPE
#endif
#endif
			nqs_abort();	/* Abort execution */
		}
		/*
		 *  The inter-process communication file did not exist.
		 *  Check to see if the client process still exists.
		 *  If the client does not exist, then we do not report
		 *  an error, and instead assume that the client has
		 *  exited prematurely, without removing their inter-
		 *  process communication file.
		 */
		if (kill (pid, 0) != -1) {
			/*
			 *  The client process still exists, but the
			 *  inter-process communication file isn't there,
			 *  or we were given the wrong process-id.
			 */
			printf ("E$Wrong pid or missing ");
			printf ("inter-process comm. file.\n");
			printf (incomplete);
			fflush (stdout);
		}
	}
	else if (kill (pid, SIGALRM) == -1) {
		/*
		 *  We successfully altered the access and modification
		 *  times of the inter-process communication file, but
		 *  were unable to signal the client process that we had
		 *  completed the transaction.
		 */
		if (errno == EINVAL) {
			printf ("E$Invalid pid given to nqs_complt().\n");
			printf (incomplete);
			fflush (stdout);
		}
		else if (errno == ESRCH) {
			/*
			 *  The client process no longer exists to
			 *  listen to our results.
			 */
			unlink (path);	/* Remove the inter-process */
					/* communication file for the */
					/* exited process. */
		}
		else if (errno == EPERM) {
			printf ("F$NQS not running as root in ");
			printf ("nqs_complt().\n");
			nqs_abort();
		}
	}
}
