/*
 * nqsd/nqs_complt.c
 * 
 * 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!
 *
 *
 *	Original Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	October 8, 1985.
 */

#include <libnqs/license.h>
#include <libnqs/proto.h>
#include <libnqs/nqsxvars.h>	/* NQS external vars */
#include <errno.h>
#include <signal.h>		/* Defines signals and int (*signal())(); */

#if	HAS_BSD_UTIMES
#include <sys/time.h>
#else
#include <sys/types.h>
#include <utime.h>
#endif

#include <unistd.h>

#include <libsal/license.h>
#include <libsal/proto.h>
#include <libsal/defines.h>

/*** 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[]
	= "Nqs_complt() unable to send completion code.\n";

#if	HAS_BSD_UTIMES
	struct timeval utimbuf [2];	/* Utimes() buffer */
#else
	struct utimbuf utimbuf;		/* utime() buffer */
#endif
	char path [MAX_PATHNAME+1];	/* Inter-process communication */
					/* file name */

	sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_DEBUGHIGH, "nqs_complt(): Parameters are completion_code = %ld, pid = %d\n", completion_code, pid);

	sprintf (path, "%s/%1d", Nqs_inter, pid);
#if	HAS_BSD_UTIMES
        {
	  time_t t;
	  time(&t);
	  utimbuf [0].tv_sec = t;	/* 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
	time (&utimbuf.actime);	/* Access time = current time */
	utimbuf.modtime = completion_code;
	if (utime (path, &utimbuf) == -1) {
#endif
		sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_DEBUGMEDIUM, "nqs_complt(): Interprocess communication file does not exist");

		/*
		 *  We were not successful.
		 */
		if (errno != ENOENT) {
			/*
			 *  A very serious error has occurred; either
			 *
			 *	EPERM, ENOTDIR, EACCES, EROFS, EFAULT, or
			 *	ELOOP (Berkeley).
			 */
#if	HAS_BSD_UTIMES
			sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORDATA, "Utimes() call error in nqs_complt().\n");
#else
			sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORDATA, "Utime() call error in nqs_complt().\n");
#endif
		}
		/*
		 *  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) {
			return;
		}
	}
	else if (kill (pid, SIGALRM) == -1) {
		sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_DEBUGMEDIUM, "nqs_complt(): Unable to kill process %d - error is %d\n", pid, errno);

		/*
		 *  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) {
			sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "Invalid pid given to nqs_complt().\n%s", incomplete);
		}
		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) {
			sal_dprintf (SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORRESOURCE, "NQS not running as root in nqs_complt().\n");
		}
	}
}
