******************************* MODULE HEADER *******************************
*                                                                           *
* FILE: Example.c                                                           *
*                                                                           *
* MACHINE: SGenNGen   LANGUAGE: METAWARE C V1.0  OS: CTOS                  *
*                                                                           *
* DESCRIPTION:                                                              *
*                                                                           *
*  This service filters File System open requests and records the filenames *
*  and access times in a recording file.  The requests are then forwarded   *
*  for normal processing.                                                   *
*                                                                           *
*  The recording file is normally closed and is only opened and written     *
*  when an internal buffer fills.                                           *
*                                                                           *
*  This is done so that another context can examine the recording file at   *
*  any time.                                                                *
*                                                                           *
*  When a StartRecord request is seen, the recording operation is started.  *
*  When a StopRecord request is seen, the recording operation is suspended. *
*  When a DeinstallExample request is seen, this service exits.             *
*                                                                           *
* HISTORY:                                                                  *
*                                                                           *
* MMDDYY VVVVMM PROGRAMMER    DESCRIPTION OF CHANGE (Most recent first) *
*                                                                           *
* 091692 12.300 S. Ahn        Added attribute information               *
* 120389 120E02 S. Emmons     Moved rgwRqs[], rqwOldExch, and nRqCodes  *
*                                 into AsyncService.c; Set protection level *
*                                 of log file to 15, to override default    *
*                                 protection level of password protected    *
*                                 systems; Gratuitous reformatting.         *
* 120289 120E01 S. Emmons     Changed c typing to CTOSbased naming and *
*                                 typing conventions; Changed references    *
*                                 from server to service.                   *
*                                                                           *
*                                                                           *
* Attributes exhibited by this software: (See SSAttributes.doc)             *
* Use attribute levels 0, E, A, S, F, I and 1...9 as decribed.              *
*                                                                           *
*  VID: 0                                                                  *
*  FIL: 0                                                                  *
*  KBD: 0                                                                  *
*  CLS: 0                                                                  *
*  KNL: 0                                                                  *
*  MEM: 0                                                                  *
*  COM: 0                                                                  *
*  TIM: 0                                                                  *
*  PFM: 0                                                                  *
*  HDW: 0                                                                  *
*  DSK: 0                                                                  *
*  DEV: 0                                                                  *
*  NLS: 0                                                                  *
*                                                                           *
* TITLE:  CTOS SYSTEM SOFTWARE                                              *
*                                                                           *
*            PROPRIETARY PROGRAM MATERIAL                                   *
*                                                                           *
* THIS MATERIAL IS PROPRIETARY TO UNISYS CORPORATION AND IS NOT TO BE       *
* REPRODUCED, USED OR DISCLOSED EXCEPT IN ACCORDANCE WITH PROGRAM LICENSE   *
* OR UPON WRITTEN AUTHORIZATION OF THE PATENT DIVISION OF UNISYS            *
* CORPORATION, DETROIT, MICHIGAN 48232, USA.                                *
*                                                                           *
* COPYRIGHT (C) 1980, 1989 CONVERGENT INCORPORATED. ALL RIGHTS RESERVED     *
* COPYRIGHT (C) 1980, 1989 UNISYS CORPORATION. ALL RIGHTS RESERVED          *
* ************************************************************************* *
*                                                                           *
* UNISYS BELIEVES THAT THE SOFTWARE FURNISHED HEREWITH IS ACCURATE AND      *
* RELIABLE, AND MUCH CARE HAS BEEN TAKEN IN ITS PREPARATION.  HOWEVER,      *
* NO RESPONSIBILITY, FINANCIAL OR OTHERWISE, CAN BE ACCEPTED FOR ANY        *
* CONSEQUENCES ARISING OUT OF THE USE OF THIS MATERIAL, INCLUDING LOSS OF   *
* PROFIT, INDIRECT, SPECIAL, OR CONSEQUENTIAL DAMAGES, THERE ARE NO         *
* WARRANTIES WHICH EXTEND BEYOND THE PROGRAM SPECIFICATION.                 *
*                                                                           *
* THE CUSTOMER SHOULD EXERCISE CARE TO ASSURE THAT USE OF THE SOFTWARE      *
* WILL BE IN FULL COMPLIANCE WITH LAWS, RULES AND REGULATIONS OF THE        *
* JURISDICTIONS WITH RESPECT TO WHICH IT IS USED.                           *
*                                                                           *
*                                                                           *
*************************** END OF MODULE HEADER ****************************
*
	External definitions.
*
define RqHeaderType
define Syslit
define sdType
define Sublit
define TRBType
include <CTOSTypes.h>

define ChangeFileLength
define CheckErc
define CloseFile
define CreateFile
define CurrentOsVersion
define ForwardRequest
define GetDateTime
define GetUserNumber
define NlsStdFormatDateTime
define OpenFile
define QueryRequestInfo
define RgParam
define SetFileStatus
include <CTOSLib.h>

define FsErc
define RqErc
include <Erc.h>

define BuildAsyncRequest
define BuildAsyncRequestDirect
define CheckContextStack
define CreateContext
define DebugTrap
define HeapAlloc
define HeapFree
define SwapContextUser
define TerminateContext
define TerminateContextUser
include Async.h

include <string.h>
include <stdio.h>
include <ctype.h>
include ExDef.h

define All
include ExRqBlk.h

*
	External functions provided by user.
*
extern void AsyncServer (void);
extern ErcType DeinstallServer (void);
extern void FatalServerError (ErcType erc);
*
	Constants
*
define NDATESIZE			19
define LF					0x0A
define rcChangeFileLength	13
define rcGetFileStatus		8
define rcWrite				36

*
	External variables.
*
extern RqHeaderType		*pRq;
extern ErcType			ercAsync;
extern Pointer			pZero;

*
	Public variables.
*
char		rgbPartitionName[] = Example;
char		rgbPad[] =         \n;
char		rgbMissedFiles[] = Could not open recording file, records discarded.\n;
Byte		bReadWritePro = 15;		* Protection = RW without password *
FlagType	fConvertToSys = TRUE;	* Set to FALSE for debugging *
FlagType	fDebug = FALSE;
FlagType	fRespond = TRUE;
Word		wOSRel,
			wOSRev;
TRBType		TimeRq;					* Timer Request Block *

*
	The following variables must be set before main () calls AsyncServer ().
	If any of these values need to be computed at runtime, do it in
	InitializeBeforeAsync ().
*
Word		cbHeap = 6000;				* Total size of heap *
Word		defaultStackSize = 1200;	* Stack space for each context *
Word		priorityServ = 0x20;		* Process priority of service *

*
	Module variables.
*
char		rgbRecordFile[255];
Word		cbRecordFile;
char		zDefaultRecordFile[] = [sys]<sys>OpenFile.log\0;
Pointer		pbBuffer[2];		* 2 buffer pointers for double buffering *
char		Buffer1[1024],
			Buffer2[1024];		* buffers for IO *
Word		iActive = 0;		* index of active buffer *
Word		iBuf = 0;			* buffer data pointer in active buffer *
char		*pWork;				* pointer to data in active buffer *
FlagType	fRecording = TRUE;	* recording boolean *
ExchType	exchOpenFile,
			exchOpenFileLL,
			exchReOpenFile;ErcType AddToBuffer (sdType *pSd)
{
	*
		This function is invoked for each open file request seen by this
		service.  The file name and the datetime it was referenced is placed
		in the current buffer.  If there is insufficient space in the buffer,
		DumpBuffer() is invoked to write the buffer to the recording file.
	*
	ErcType	erc;
	Word	len;
	DWord	dateTime;
	extern	ErcType DumpBuffer (void);

	if (fRecording)
	{
		* 
			If not enough space is left in the buffer for this entry, 
			dump the buffer to the file. 
		*
		if (iBuf + pSd>cb + NDATESIZE + 2 > sizeof (Buffer1))
		{
			erc = DumpBuffer ();
			if (erc = ercOK)
			{
				*
					Could not open file, try to record event.
				*
				strcpy (pWork, rgbMissedFiles);
				pWork += strlen (rgbMissedFiles);
				iBuf += strlen (rgbMissedFiles);
			}
		}
		*
			Get date and time of reference
		*
		erc = GetDateTime (dateTime);
		if (erc = ercOK)
			return (erc);

		*
			Expand it to humanreadable form
		*
		erc = NlsStdFormatDateTime (NULL, 16, dateTime, pWork,
									sizeof (Buffer1)  iBuf, len);
		if (erc = ercOK)
			return (erc);

		*
			Put date stamp and filename in buffer
		*
		pWork += len;
		iBuf += len;
		*pWork++ = ' ';
		iBuf += 1;
		strncpy (pWork, pSd>pb, pSd>cb);
		pWork += pSd>cb;
		iBuf += pSd>cb;
		*pWork++ = LF;	* add line feed to filenametimestamp *
		iBuf += 1;
	}

	if (CheckContextStack () = ercOK)
	{
		*
			defaultStackSize is too small
		*
		DebugTrap ();
	}
}ErcType DumpBuffer (void)
{
	*
		This function is invoked whenever 
		(1) a buffer fills,
		(2) recording is turned off,
		(3) the service is deinstalled.
	*
	Word	len;
	FhType	fh;
	ErcType	erc;
	DWord	lfa;
	Pointer	p;

	*
		Space fill between last data and end of buffer
	*
	while (iBuf < sizeof (Buffer1))
	{
		len = sizeof (rgbPad);
		if (len > (sizeof (Buffer1)  iBuf))
			len = sizeof (Buffer1)  iBuf;
		strncpy (pWork, rgbPad, len);
		pWork += len;
		iBuf += len;
	}
	pWork;
	*pWork++ = LF;

	*
		Assign a new buffer for output.
	*
	p = pbBuffer[iActive];
	iActive = (iActive + 1)  1;
	pWork = pbBuffer[iActive];
	iBuf = 0;

	*
		Open the file in mode modify
	*
	erc = BuildAsyncRequestDirect (fh, rgbRecordFile, cbRecordFile, (DWord)0,
									0, modeModify, rcOpenFileLL,
										exchOpenFileLL);
	if (erc == ercOK) 
	{
		*
			Change the file length
		*
		erc = BuildAsyncRequest (fh, 0, lfa, 4, rcGetFileStatus);
		if (erc = ercOK)
			return (erc);
		erc = BuildAsyncRequest (fh, lfa + sizeof (Buffer1),
									rcChangeFileLength);
		if (erc = ercOK)
			return (erc);

		*
			Write the data
		*
		erc = BuildAsyncRequest (fh, p, sizeof (Buffer1), lfa, len, rcWrite);
		if (erc = ercOK)
			return (erc);

		*
			Close the file
		*
		erc = BuildAsyncRequest (fh, rcCloseFile);
	}

	if (CheckContextStack () = ercOK)
	{
		*
			defaultStackSize is too small
		*
		DebugTrap ();
	}

	return (erc);
}*
	HandleTimer: The request in pRq is a Timer Request Block
	NOTE that this procedure is NOT REENTRANT.  After the call to
	CreateContext, its stack pointer has changed, so it cannot
	access any local variables on the stack.
*
void HandleTimer (void)
{
	*
		The timer is not used in this example.  This function is provided only
		to resolve the external reference made in the Asynchronous Service code.
	*
	ercAsync = CreateContext (defaultStackSize, 0);
	if (ercAsync = ercOK)
	{	*
			Context could not be started because no heap space
		*
		TimeRq.cEvents = 0;	* Reenable timer *
	}
	else
	{	*
			Context started OK.
			Insert timer processing code here.
		*

		ercAsync = TerminateContext ();
		*
			Only returns if error  normally calls WaitLoop
		*
		FatalServerError (ercAsync);
	}
}
*
	Early service initialization, service heap not yet initialized.
*
void InitializeBeforeAsync (void)
{
	ErcType	erc;
	FhType	fh;
	sdType	sd;

	*
		Process '[Recording file]' parameter
	*
	strcpy (rgbRecordFile, zDefaultRecordFile);
	cbRecordFile = strlen (zDefaultRecordFile);
	erc = RgParam (1, 0, sd) * log file name *;
	if (erc == ercOK) 
	{
		strncpy (rgbRecordFile[0], sd.pb, sd.cb);
		cbRecordFile = sd.cb;
		rgbRecordFile[sd.cb] = 0;
	}

	erc = CreateFile (rgbRecordFile, cbRecordFile, pZero, 0, 1024);
	CheckErc (OpenFile (fh, rgbRecordFile, cbRecordFile, pZero, 0,
																modeModify));
	CheckErc (ChangeFileLength (fh, 0));
	CheckErc (SetFileStatus (fh, 2, bReadWritePro, 1));
	CheckErc (CloseFile (fh));

	*
		Establish array of buffer pointers for double buffering.
	*
	pbBuffer[0] = Buffer1[0];
	pbBuffer[1] = Buffer2[0];
	pWork = pbBuffer[iActive = 0];

	*
		Get OS Version; ReOpenFile request does not exist on real mode
		Workstation OS's.
	*
	CheckErc (CurrentOsVersion (wOSRel, wOSRev));

	*
		Save exchange values for forwarding;
	*
	CheckErc (QueryRequestInfo (rcOpenFile, exchOpenFile, 2));
	CheckErc (QueryRequestInfo (rcOpenFileLL, exchOpenFileLL, 2));
	if (wOSRel >= 10)
		CheckErc (QueryRequestInfo (rcReOpenFile, exchReOpenFile, 2));

	*
		Output signon message
	*
	printf (\nFile Access Recorder installed.\n);
}*
	Servicespecific initialization, called before ConvertToSys.
	The Service Heap is initialized.
*
void InitializeServer (void)
{
	*
		No additional initialization is required by this example.
	*
}
*
	Timer initialization, called before ConvertToSys.
	The Service Heap is initialized.
*
void InitializeTimer (void)
{
	* 
		Timer unused in this example.  This function is provided to satisfy
		external reference made by the Asynchronous Service code. 
	*
}*
	Servicespecific request processing procedure.
*
ErcType ServeRequest (void)
{
	ErcType	erc,
			ercDiscard;
	sdType	sd;

	switch (pRq>rqCode)
	{
		case rcAbortExample:
		{
			AbortExampleType *prx;

			prx = (AbortExampleType *) pRq;
			erc = TerminateContextUser (prx>rqhdr.userNum, ercOK);
			break;
		}

		case rcChangeUserNumExample:
		{
			ChangeUserNumExampleType *prx;

			prx = (ChangeUserNumExampleType *) pRq;
			break;
		}

		case rcDeinstallExample:
		{
			DeinstallExampleType *prx;

			prx = (DeinstallExampleType *) pRq;
			erc = DumpBuffer ();
			fRecording = FALSE;
			DeinstallServer ();
			break;
		}

		case rcOpenFile:
		{
			OpenFileType *prx;

			prx = (OpenFileType *) pRq;
			sd.cb = prx>cbFileSpec;
			erc = HeapAlloc (sd.cb, sd.pb);
			if (erc == ercOK)
				strncpy (sd.pb, prx>pbFileSpec, sd.cb);

			ercDiscard = ForwardRequest (exchOpenFile, pRq);

			if (erc == ercOK)
			{
				ercDiscard = AddToBuffer (sd);
				ercDiscard = HeapFree (sd.pb);
			}
			fRespond = FALSE;
			break;
		}

		case rcOpenFileLL:
		{
			OpenFileLLType *prx;

			prx = (OpenFileLLType *) pRq;
			sd.cb = prx>cbFileSpec;
			erc = HeapAlloc (sd.cb, sd.pb);
			if (erc == ercOK)
				strncpy(sd.pb, prx>pbFileSpec, sd.cb);

			ercDiscard = ForwardRequest (exchOpenFileLL, pRq);

			if (erc == ercOK)
			{
				ercDiscard = AddToBuffer (sd);
				ercDiscard = HeapFree (sd.pb);
			}
			fRespond = FALSE;
			break;
		}

		case rcReOpenFile:
		{
			ReOpenFileType *prx;

			prx = (ReOpenFileType *) pRq;
			sd.cb = prx>cbFileSpec;
			erc = HeapAlloc (sd.cb, sd.pb);
			if (erc == ercOK)
				strncpy (sd.pb, prx>pbFileSpec, sd.cb);

			ercDiscard = ForwardRequest (exchReOpenFile, pRq);

			if (erc == ercOK)
			{
				ercDiscard = AddToBuffer (sd);
				ercDiscard = HeapFree (sd.pb);
			}
			fRespond = FALSE;
			break;
		}

		case rcStartRecord:
		{
			StartRecordType *prx;

			prx = (StartRecordType *) pRq;
			fRecording = TRUE;
			break;
		}

		case rcStopRecord:
		{
			StopRecordType *prx;

			prx = (StopRecordType *) pRq;
			erc = DumpBuffer ();
			fRecording = FALSE;
			break;
		}

		case rcSwapExample:
		{
			SwapExampleType *prx;

			prx = (SwapExampleType *) pRq;
			erc = SwapContextUser (prx>rqhdr.userNum);
			break;
		}

		case rcTerminateExample:
		{
			TerminateExampleType *prx;

			prx = (TerminateExampleType *) pRq;
			erc = TerminateContextUser (prx>rqhdr.userNum, ercOK);
			break;
		}

		DEFAULT:
		{
			*
				unrecognized request code
			*
			return (ercNoSuchRc);
		}
	}
	return (ercOK);
}*
	Main program.
*
void main (void)
{
	InitializeBeforeAsync ();
	AsyncServer ();
}
