/*
 * The V UNIX server: a V kernel and V server simulator for VAX/UNIX
 * that provides a subset of UNIX system services to SUN workstations
 * running the V distributed kernel.
 * Copyright (c) 1982 David R. Cheriton, all rights reserved.
 *
 * Instance request processing routines
 */

#include "config.h"
#include <signal.h>
#include <sgtty.h>
#include <Venviron.h>
#include <Vio.h>
#include <Vioprotocol.h>
#include <errno.h>
#include <server.h>
#include <debug.h>
#include <sys/types.h>
#include <sys/dir.h>

/* EXPORTS: */
SystemCode CreateInstance();
SystemCode QueryInstance();
SystemCode ReadInstance();
SystemCode ReadAndForward();
SystemCode WriteInstance();
SystemCode ReleaseInstance();
SystemCode SetInstanceOwner();

/* IMPORTS: */
extern FileInstance *AllocInstance();
extern		    FreeInstance();
extern FileInstance *FindInstance();
extern FileInstance *GetInstance();
extern SystemCode QueueIORequest();
extern SystemCode GetName();
extern ReclaimInstances();
extern SystemCode SetupInstance(), SetupDirectoryInstance();
extern Reply();
extern SetStringName();
extern SystemCode ExecuteProgram();
extern char *FindContext(), *malloc();

/* Imported variables */
extern ProcessId MyPid;
extern int errno;
extern char BlockBuffer[];


SystemCode CreateInstance( req, pid, segsize )
    register CreateInstanceRequest *req;
    ProcessId pid;
    unsigned segsize;
   /* 
    * Create an instance of the specified file or call
    * ExecuteProgram if the mode is FEXECUTE.
    */
  {
    register FileInstance *desc;
    register CreateInstanceReply *reply = (CreateInstanceReply *) req;
    register SystemCode r;
    char *nameptr;
    char c;
    int	file;
    char *fileName;
    unsigned fileNameLen;
    InstanceType InstType;
    ContextPair ctx;
  
    if ( req->requestcode == CREATE_INSTANCE_RETRY &&
	 IgnoreRetry(req, pid, BlockBuffer, &segsize, MyPid) )
       return DISCARD_REPLY;

    /* Special creation request? */
    /* done this way to speed up most common mode: file instances */
    switch ( req->filemode & (FEXECUTE|FDIRECTORY) )
      {    
	case 0: /* normal files */
		InstType = FILE_INSTANCE;
		break;

	case FDIRECTORY:	/* open file as a directory */
		/* Don't let main server read directories */
		if ( Session == NULL )
		     return( ILLEGAL_REQUEST );

		if ( req->filemode != (FDIRECTORY|FREAD) )
		     return( INVALID_MODE );

		req->filemode = FREAD;		/* clear FDIRECTORY bit */
		InstType = DIRECTORY_INSTANCE;
		break;
	case FEXECUTE:
	        return ( ExecuteProgram( req, pid, segsize ) );
		break;
	default:
		return( INVALID_MODE );
		break;
      }

    /* Get the fully qualified pathname */
    r = GetName( req, pid, &segsize, &nameptr, &ctx );

    if (r == MULTI_MANAGER && InstType == DIRECTORY_INSTANCE)
	InstType = MMCONTEXT_INSTANCE;
    else if (r != OK)
        return( r );

    if( IDebug ) printf( "CreateInstance in 0x%x: \"%s\"\n", MyPid, nameptr );

    if( Session != NULL ) /* Only load files thru main server process */
      {
	Session->inactivity = 0;
      }
    else if( req->filemode != FREAD ) return( NO_PERMISSION );

    /* Use MyPid here instead of pid, because the "pid" really doesn't
       own the instance yet and we may have to ReclaimInstances which
       cause an unnecessary ValidPid to be done on "pid"
     */
    if( (desc = AllocInstance( MyPid, InstType )) == NULL ) 
	return( NO_SERVER_RESOURCES );

retry:
    switch( req->filemode )
      {
	case FREAD:
	  {
	    if  (InstType == DIRECTORY_INSTANCE )
	      {
		file = (int) opendir( nameptr);
	        desc->filetype = READABLE+FIXED_LENGTH;
		if (file==NULL) file = -1;
	      }
	    else if (InstType == MMCONTEXT_INSTANCE)
	      {
		file = -2;
	        desc->filetype = READABLE+FIXED_LENGTH;
	      }
	    else
	      {
		file = open( nameptr, 0 );
	        desc->filetype = READABLE+FIXED_LENGTH+MULTI_BLOCK;
	      }
	    break;
	  }
	case FCREATE:
	  {
	    if ( (file = creat( nameptr, DEFAULT_CREAT_MODE )) != -1) 
	      {
		close( file );
		file = open( nameptr, 2 );
		desc->filetype = READABLE+WRITEABLE+MULTI_BLOCK;
	      }
	    break;
	  }
	case FMODIFY:
	  {
	    if( (file = open( nameptr, 2)) != -1 )
		desc->filetype = READABLE+WRITEABLE+MULTI_BLOCK;
	    break;
	  }
	case FAPPEND:
	  {
	    if ( (file = open( nameptr, 2 )) == -1 )
	      {
		if ( (file = creat( nameptr, DEFAULT_CREAT_MODE )) != -1 )
		  {
		    close( file );
		    file = open( nameptr, 2 );
		  }
	      }
	    desc->filetype = READABLE+WRITEABLE+APPEND_ONLY+MULTI_BLOCK;
	    break;
	  }
	default: 
	    FreeInstance( desc );
	    return( INVALID_MODE );
	    break;
      }

    if( file == -1 ) /* Failed to open the file */
      {
	switch( errno )
	  {
	    case ENOENT: r = NOT_FOUND;
			 break;
	    case EPERM:
	    case EACCES:
	    case EISDIR: 
	      {
		r = NO_PERMISSION;
		break;
	      }
	    case ENFILE: /* System open file table full try to make room. */
	    case EMFILE: /* Too many open files, try to reclaim open files. */
	      {
		if (ReclaimInstances(RI_FREE_DESCRIPTOR)) goto retry;
 		r = NO_SERVER_RESOURCES;
		break;
	      }
	    default: 
	      {
		if ( GDebug ) perror( "CreateInstance: ");
		r = INTERNAL_ERROR; 
		break;
	      }
	  }
	FreeInstance( desc );
	return( r );
      }

    if ( InstType == DIRECTORY_INSTANCE ) 
      {
    	if ( (r = SetupDirectoryInstance( file, desc, nameptr, pid ))
		 != OK )
          {
	    closedir(file);
	    FreeInstance( desc );
	    return( r );
	  }
        ioctl( ((DIR *)desc->unixfile)->dd_fd, FIOCLEX, NULL);
	 		/* Close file on successful "exec"*/
      }
    else if ( InstType == MMCONTEXT_INSTANCE )
      {
	if ( (r = SetupMMContextInstance( ctx, desc, pid )) != OK )
	  {
	    FreeInstance( desc );
	    return( r );
	  }
      }
    else
      {
	if ( (r = SetupInstance( file, desc, nameptr, pid )) != OK )
	  {
	    close( file );
	    FreeInstance( desc );
	    return( r );
	  }
        ioctl( desc->unixfile, FIOCLEX, NULL);
	 		/* Close file on successful "exec"*/
      }

    reply->fileid = desc->id;

    r = QueryInstance( (QueryInstanceRequest *)reply );
    if (InstType == MMCONTEXT_INSTANCE && r == OK)
	return MORE_REPLIES;
    else
	return r;

  } /* CreateInstance */

SystemCode QueryInstance( req )
   register QueryInstanceRequest *req;

  /* 
   * Satisfy a query instance request from a process.
   */
  {
    register CreateInstanceReply *reply = (CreateInstanceReply *) req;
    register FileInstance *desc;

    if( (desc = GetInstance(req->fileid)) == NULL ) return( INVALID_FILE_ID );

    if( IDebug ) printf( "QueryInstance: fileid 0x%x\n", req->fileid );

    if( Session != NULL ) Session->inactivity = 0;

    reply->fileserver = MyPid;
    reply->filetype = desc->filetype;
    reply->filelastblock = desc->lastblock;
    reply->filenextblock = desc->nextblock;
    reply->blocksize = desc->blocksize;
    reply->filelastbytes = desc->lastbytes;

    return( OK );
  } /* QueryInstance */



SystemCode ReadInstance( req, pid )
   register IoRequest *req; 
   ProcessId pid;
  /* 
   * Handle a read instance request.
   */
  {
    register SystemCode	r;
#define reply	((IoReply*)req)
    int bytes, fid;
    char *ptr;
    unsigned count, totalbytes;
    register FileInstance *filedesc;
#define procdesc	((ProcessInstance*)filedesc)
    register char *buffer;

    count = req->bytecount;
    if ( count == 0 ) return( OK );
    req->bytecount = 0;

    if( (filedesc = GetInstance(req->fileid)) == NULL ) 
        return( INVALID_FILE_ID);

    if( filedesc->filetype & READABLE == 0 ) return( NOT_READABLE );

    if( Session != NULL ) Session->inactivity = 0;

    bytes = req->blocknumber;
    if( IDebug ) printf("ReadInstance fileid 0x%4x, block %d, bytes %d\n",
			    req->fileid, bytes, count );

    switch( filedesc->type ) 
      {
	case FILE_INSTANCE:
	  {
	    bytes *=  (filedesc->blocksize); 

	    if( lseek(filedesc->unixfile, bytes, 0) == -1 ) 
	        return( BAD_BLOCK_NO );

	    fid = filedesc->unixfile;
	    buffer = BlockBuffer;
	    break;
	  }
	case PROCESS_INSTANCE:
	  {
	    buffer = procdesc->lastdata;
	    if ( bytes == filedesc->nextblock - 1 )
	      {
		if ( PDebug ) printf( "ReRead of Block #%d\n", bytes );
	        reply->bytecount = procdesc->lastdatasize;
	        if( procdesc->lastdatasize <= IO_MSG_BUFFER )
	          { /* send inside of message */
		    if (DifferentByteOrder(pid))
			ByteSwapLongCopy(buffer, req->shortbuffer,
					 procdesc->lastdatasize+1);
		    else
			bcopy(buffer, req->shortbuffer,
			      procdesc->lastdatasize+1);
		    r = procdesc->lastreply;
	          }
		/*
		 * NOTE: we are using the fact that procdesc->blocksize
		 * is not greater than MAX_APPENDED_SEGMENT.  It would be
 		 * ridiculous to have it different anyway
		 */
	        else if( req->requestcode != READ_AND_FORWARD )
	          {
		    ptr = req->bufferptr;
	            reply->replycode = procdesc->lastreply;
	            ReplyWithSegment( reply, pid
		    	, buffer, ptr, procdesc->lastdatasize );
	            r = NOT_AWAITINGREPLY;
		  }
		else
		  {
		    ptr = req->bufferptr;
	            r = MoveTo( pid, ptr, buffer, procdesc->lastdatasize );
		  }
  		return( r );
	      } 	    
	    else if ( bytes != procdesc->nextblock ) 
	      {
		if (PDebug) 
		    printf( "Bad block number, got %d, expected %d\n"
		            , bytes, procdesc->nextblock);
		return( BAD_BLOCK_NO );
	      }

	    /* We are reading the correct block */
	    fid = procdesc->pipedesc;
	    ioctl( fid, FIONREAD, &bytes ); /* how much available */

	    if ( bytes <= 0 ) 
		switch ( ((ProcessInstance *)procdesc)->state )
		  {
		    case PD_DEAD:
		    case PD_KILLED:
		        return ( END_OF_FILE );
			break;
		    case PD_STOPPED:
		    case PD_RUNNING:
			/* No bytes now, so hang request until data avail*/
			req->bytecount = count;  /* restore req */
			return( QueueIORequest( req, pid ) );
			break;
		    default:
			if ( GDebug ) 
			    printf( "ReadInstance, unknown state = %d\n"
				    , ((ProcessInstance *)procdesc)->state );
			return( INTERNAL_ERROR );
			break;
		  } /* switch */
	    
	    /* Don't attempt read more than what is in the pipe. */
	    count = bytes < count ? bytes : count;
	    break;
	  }
	case DIRECTORY_INSTANCE:
	    /* NOTE: bytes is really block number */
	    return( ReadDirectory( req, pid, filedesc, bytes, count ) );
	    break;
	case MMCONTEXT_INSTANCE:
	    /* NOTE: bytes is really block number */
	    return( ReadMMContext( req, pid, filedesc, bytes, count ) );
	    break;
	default:
	    return( INTERNAL_ERROR );
	    break;
      } /* switch ( instance type ) */

    /* From this point on, all instances are alike */
    ptr = req->bufferptr;
    totalbytes = 0;

    while( totalbytes < count )
      {
	bytes = count - totalbytes;
	bytes = (bytes < BUFFER_SIZE ) ? bytes :  BUFFER_SIZE;
	bytes = read( fid, buffer, bytes );

	if ( bytes < 0 ) 
	  {
	    if ( GDebug ) perror("ReadInstance:");
	    r = DEVICE_ERROR;
	    break;
	  } 
	if( bytes == 0 )
	  {
	     r = END_OF_FILE;
	     break;
	  }
	if( bytes <= IO_MSG_BUFFER && totalbytes == 0 )
	  { /* Concatenate onto message */
	    r = OK;
	    if (DifferentByteOrder(pid))
		ByteSwapLongCopy(buffer, req->shortbuffer, bytes+1);
	    else
		bcopy(buffer, req->shortbuffer, bytes+1);
	  }
	else if( (bytes <= MAX_APPENDED_SEGMENT) && (Session != NULL)
		&& req->requestcode != READ_AND_FORWARD )
	  { /* Session check prevents the boot service from using this */
	    totalbytes += bytes;
	    reply->bytecount = totalbytes;
	    reply->replycode = ((totalbytes < count) ? END_OF_FILE : OK);
	    ReplyWithSegment( reply, pid, buffer, ptr, bytes );
	    r = NOT_AWAITINGREPLY;
	  } 
	else
	  {
	    r = MoveTo( pid, ptr, buffer, bytes );
	    ptr += bytes;
	  }
	if( r != OK ) break;
	totalbytes += bytes;
      }

    /* this should be a generalized stream check, not just for PROCESS's */
    if ( filedesc->type == PROCESS_INSTANCE )
      {
	/* Set the reply code, check for ReplyWithSegment */
        procdesc->lastreply = r == NOT_AWAITINGREPLY ? reply->replycode : r;
	if ( procdesc->lastreply == OK || procdesc->lastreply == END_OF_FILE )
	  {
	    procdesc->nextblock++;
            procdesc->lastdatasize = totalbytes;
	    /* data should be in the right place already */
	  }
	else
	    procdesc->lastdatasize = 0;
      }

    if ( r == OK || r == END_OF_FILE )
        reply->bytecount = totalbytes;

    return( r );

#undef procdesc
#undef reply
  } /* ReadInstance */

SystemCode ReadAndForward( req, pid )
    IoRequest *req;
    ProcessId pid;

  /* Read the specified amount and then forward back requestor back
   * to original sender. Used initially for efficient program loading.
   */
  {
    SystemCode r;
    ProcessId forwarder;

    if( (forwarder = Forwarder( pid )) == 0) return( BAD_STATE );

    if( IDebug ) printf("ReadAndForward: forwarder 0x%8x fileid 0x%4x\n",
				forwarder, req->fileid );

    if( (r = ReadInstance( req, pid )) == NO_REPLY ) return( NO_REPLY );

    /* If r == NOT_AWAIT... then a ReplyWithSegment was done in ReadInst */
    /* Stuff in the replycode ??? */
    req->blocknumber = (unsigned) r == NOT_AWAITINGREPLY ? OK : r; 

    Forward( req, pid, forwarder );
    return( NOT_AWAITINGREPLY );
  } /* ReadAndForward */



SystemCode WriteInstance( req, pid, segsize )
    register IoRequest *req; 
    ProcessId pid; 
    unsigned segsize;

  /* Handle a write instance request to a file
   */
  {
#define reply ((IoReply*)req)
    SystemCode r;
    unsigned requestCount, bytes, bytesWrittenSoFar;
    int bytesWritten;
    register char *ptr;
    int fid;
    register FileInstance *desc;
    char *buffer;

    requestCount = req->bytecount;
    req->bytecount = 0;		/* Return zero if an error */
    buffer = BlockBuffer; /* by default */

    if ((desc = GetInstance(req->fileid)) == NULL) return INVALID_FILE_ID;

    if (desc->filetype & WRITEABLE == 0) 
	return NOT_WRITEABLE;

    if (Session != NULL) 
	Session->inactivity = 0;

    bytesWrittenSoFar = 0;
    ptr = req->bufferptr;
    bytes = req->blocknumber;

    if (IDebug)
	printf("WriteInstance fileid 0x%4x, block %d, bytes %d\n",
	       req->fileid, bytes, requestCount);
    switch (desc->type) 
      {
	case FILE_INSTANCE:
	  {
	    bytes *= desc->blocksize;
	    if (lseek(desc->unixfile, bytes, 0) == -1) return BAD_BLOCK_NO;
	    fid = desc->unixfile;
	    break;
	  }
	case PROCESS_INSTANCE:
	  {
	    register ProcessInstance *pdesc = (ProcessInstance *)desc;

	    if (bytes == pdesc->lastblock)
	      {
		if (PDebug)
		    printf("Repeat WriteInstance block %d\n", bytes);
		reply->bytecount = pdesc->lastdatasize;
	        return pdesc->lastreply;
 	      }
	    if (bytes != pdesc->lastblock + 1) 
	      {
		if (PDebug) 
		    printf("Bad block number, got %d, expected %d\n",
		           bytes, pdesc->lastblock + 1);
		return BAD_BLOCK_NO;
	      }
	    switch (pdesc->state)
	      {
		case PD_DEAD:
		case PD_KILLED:
		    return END_OF_FILE;
		    break;
		case PD_STOPPED:
		case PD_RUNNING:
		    break;
		default:
		    if (GDebug) 
			printf("WriteInstance, unknown state = %d\n",
			       pdesc->state);
		    return INTERNAL_ERROR;
		    break;
	      } /* switch */

	    if (pdesc->lastdata != NULL)
	      {
		buffer = pdesc->lastdata;
		segsize = pdesc->lastdatasize; /* unwritten data in the buffer*/
	      }
	    fid = pdesc->pipedesc;
	    break;
	  }
	default:
	    if (GDebug)
	        printf("WriteInstance unknown instance type, 0x%x\n",
		       desc->type);
	    return INTERNAL_ERROR;
	    break;
      } /* switch */

    while (bytesWrittenSoFar < requestCount)
      {
	bytes = requestCount - bytesWrittenSoFar;
	bytes = (bytes < BUFFER_SIZE) ? bytes : BUFFER_SIZE;

	r = OK;
	if (requestCount <= IO_MSG_BUFFER) /* Get data from message */
	  {
	    if (DifferentByteOrder(pid))
		ByteSwapLongCopy(req->shortbuffer, buffer, bytes+1);
	    else
		bcopy(req->shortbuffer, buffer, bytes+1);
	  }
	else if (bytes > segsize)
	  {
	    r = MoveFrom(pid, ptr+segsize, &buffer[segsize], bytes-segsize);
	    if (r != OK)
		break;
	    segsize = 0; /* in case we're here again */
	  }

	bytesWritten = write(fid, buffer, bytes);
        if (bytesWritten <= 0)
	  {
	    if (desc->type == PROCESS_INSTANCE)
	      {
		/* The write() probably failed because the pipe was full
		 * (Recall that we made writes to this pipe non-blocking.)
		 * We adjust the request message to reflect any data that we
		 * \were/ able to write, and then queue the request until we
		 * are able to satisfy it.  
		 */
		register ProcessInstance *pdesc = (ProcessInstance *)desc;

		req->bytecount = requestCount - bytesWrittenSoFar;
		req->bufferptr += bytesWrittenSoFar;
		pdesc->lastdatasize = bytes; /* Data already in the buffer */
		if (pdesc->lastdata == NULL)
		  {
		    /* Create a new buffer, & copy the unwritten bytes to it. */
		    pdesc->lastdata = malloc(bytes);
		    bcopy(buffer, pdesc->lastdata, bytes);
		  }

		return QueueIORequest(req, pid);
	      }
	    else
	      {
		r = DEVICE_ERROR;
		break;
	      }
	  }
	if (bytesWritten < bytes)
	  {
	    /* (Unlikely situation:)  We didn't write all that we wanted to, 
	     * so we move the unwritten bytes to the front of the buffer, for 
	     * the next time round the loop.
	     */
	    segsize = bytes - bytesWritten;
	    bcopy(&buffer[bytesWritten], &buffer, segsize);
	  }
	ptr += bytesWritten;
	bytesWrittenSoFar += bytesWritten;
      }
    req->bytecount = bytesWrittenSoFar;

    if (desc->type == PROCESS_INSTANCE &&
	((ProcessInstance *)desc)->lastdata != NULL)
      {
	/* A deferred write to a pipe has finally succeeded, so we can free the
	 * buffer that we used.
	 */
	free(((ProcessInstance *)desc)->lastdata);
	((ProcessInstance *)desc)->lastdata = NULL;
      }

    /* Update the descriptor's notion of the end of file, if necessary: */
    switch (desc->type)
      {
	case FILE_INSTANCE:
	      {
		unsigned newblock, newbytes;
		
		newblock = req->blocknumber + bytesWrittenSoFar/desc->blocksize;
		newbytes = bytesWrittenSoFar%desc->blocksize;
		if (newblock > desc->lastblock)
		  {
		    desc->lastblock = newblock;
		    desc->lastbytes = newbytes;
		  }
		else if (newblock == desc->lastblock &&
			 newbytes > desc->lastbytes)
		    desc->lastbytes = newbytes;
	      }
	    break;
	case PROCESS_INSTANCE:
	  {
	    register ProcessInstance *pdesc = (ProcessInstance *)desc;

	    pdesc->lastreply = r;
	    if (r == OK)
	      {
		pdesc->lastdatasize = bytesWrittenSoFar;
		pdesc->lastblock++;
	      }
	    else
		pdesc->lastdatasize = 0;
	    break;
	  }
      }
    return r;
#undef reply
 } /* WriteInstance */



SystemCode ReleaseInstance( req, pid )
   IoRequest *req; ProcessId;

  /*
   * Release the instance but first perform the necessary clean up
   * actions as follows (only if requestor has permission):
   *		FILE_INSTANCE:  Close the file 
   *		DIRECTORY_INSTANCE: Close the file
   *		PROCESS_INSTANCE: Send hup signal to process free descriptor
   *				  only if there is another one for this
   *				  process.  Otherwise must keep desc around
   *				  to make sure the process gets killed eg,
   *				  it is ignoring SIGHUP.
   *		MMCONTEXT_INSTANCE: None.
   */
  {
    register FileInstance *desc;


    if( (desc = GetInstance(req->fileid)) == NULL ) return( INVALID_FILE_ID );


    if( IDebug ) printf( "ReleaseInstance on fileid 0x%x\n", req->fileid );

    if( Session != NULL ) Session->inactivity = 0;

    switch ( desc->type ) 
      {
	case DIRECTORY_INSTANCE:
	  {
/*    	    if (desc->owner != pid) return (NO_PERMISSION);*/
    	    if (IDebug && desc->owner != pid)
	        printf("Warning: ReleaseInstance(): owner (0x%08x) != invoking pid (0x%08x)\n", desc->owner, pid);
	    closedir( (DIR *)desc->unixfile );
            FreeInstance( desc );
	    break;
	  }
	case FILE_INSTANCE:
	  {
/*    	    if (desc->owner != pid) return (NO_PERMISSION);*/
    	    if (IDebug && desc->owner != pid)
	        printf("Warning: ReleaseInstance(): owner (0x%08x) != invoking pid (0x%08x)\n", desc->owner, pid);
	    close( desc->unixfile );
            FreeInstance( desc );
	    break;
	  }
	case PROCESS_INSTANCE:
	  {
	    register ProcessInstance *pdesc;
	    register long upid;

/*    	    if (desc->owner != pid) return (NO_PERMISSION);*/
    	    if (IDebug && desc->owner != pid)
	        printf("Warning: ReleaseInstance(): owner (0x%08x) != invoking pid (0x%08x)\n", desc->owner, pid);
	    pdesc = (ProcessInstance *) desc;
	    close( pdesc->pipedesc );
	    pdesc->pipedesc = -1;	/* invalidate */

	    upid = pdesc->pid;
	    pdesc->pid = 0;	/* Mark this desc so that it won't be found */
	    if( (desc = FindInstance( upid, PROCESS_INSTANCE )) == NULL )
	      {
		if ( PDebug ) printf( "pid %d no sibling,", upid );
		if ( pdesc->state == PD_DEAD || pdesc->state == PD_KILLED )
		  {
		    if ( PDebug ) printf( "freeing \n" );
	            FreeInstance( pdesc );
		  }
		else
		  {
		    if ( PDebug ) printf( "awaiting death\n" );
	            pdesc->state = PD_AWAITING_DEATH;
		    killpg( getpgrp( upid ), SIGHUP );
		    pdesc->pid = upid;		/* save pid for SIGCHLD */
		    pdesc->id = 0;		/* instance no longer valid */
		  }
	      }
	    else
	      {
		if (PDebug) printf( "pid %d freeing not killing\n", upid );
		pdesc->name = NULL;	/* don't free the name */
	        FreeInstance( pdesc );	/* other guy will kill the process,
					   and free the name */
	      }
	    break;
          }
      } /* switch */

    return( OK );
  } /* ReleaseInstance */

SystemCode SetInstanceOwner(req, pid)
   IoRequest *req;

  /*
   * Set the owner of the instance to pid in request iff the requestor
   * is the current owner.
   */
  {
    register FileInstance *desc;

    if ((desc = GetInstance(req->fileid)) == NULL) return (INVALID_FILE_ID);

/*    if (desc->owner != pid) return (NO_PERMISSION);*/
    if (IDebug && desc->owner != pid)
	printf("Warning: SetInstanceOwner(): current owner (0x%08x) != invoking pid (0x%08x)\n", desc->owner, pid);

    if (Session != NULL) Session->inactivity = 0;

    desc->owner = req->instanceowner;
    
    if (IDebug)
        printf("SetInstanceOwner: set owner pid 0x%x for instance id 0x%x\n",
	       desc->owner, desc->id);

    return (OK);
  } /* SetInstanceOwner */


/*
 * IgnoreRetry
 *
 * Determine whether we are one of the servers that should ignore this
 *  request (probably a CREATE_INSTANCE_RETRY).  Return 1 if so, 0 if not.
 * Assumes there is a 0-terminated list of pids beginning at req->segPtr
 *  in the client's address space, and returns true if the given
 *  serverpid is on the list.
 * If an appended segment was received, segbuf and *segsize should
 *  indicate its location and size.  This routine may read in more
 *  of the segment; if so, it alters the "segsize" parameter to
 *  reflect what it read.  Assumes segbuf points to an area of at
 *  least MAX_APPENDED_SEGMENT bytes.
 * Copied from V library 1-13-86.
 */

int IgnoreRetry(req, pid, segbuf, segsize, serverpid)
  register MsgStruct *req;
  ProcessId pid, serverpid;
  register char *segbuf;
  register unsigned *segsize;
  {
    register char *rsegp, *lsegp;
    register SystemCode r;
    register unsigned lsegsize, segleft;
    ProcessId checkpid;

    rsegp = req->segmentPtr;	/* remote addr of next pid to look at */
    segleft = req->segmentSize;	/* bytes not yet examined */
    lsegp = segbuf;
    lsegsize = *segsize;

    while (segleft >= sizeof(ProcessId))
      {
	if (lsegsize < sizeof(ProcessId))
	  {
	    lsegsize = (segleft < MAX_APPENDED_SEGMENT) ? 
		        segleft : MAX_APPENDED_SEGMENT;
	    r = MoveFrom(pid, segbuf, rsegp, lsegsize);
	    if (r != OK) return 1;
	    if (rsegp == req->segmentPtr)
	        *segsize = lsegsize;
	    else
	        *segsize = 0;
	  }

	if (DifferentByteOrder(pid))
	    ByteSwapLongCopy(lsegp, &checkpid, sizeof(ProcessId));
	else
	    checkpid = *(ProcessId *) lsegp;

	if (checkpid == serverpid) return 1;
	if (checkpid == 0) return 0;

	rsegp += sizeof(ProcessId);
	segleft -= sizeof(ProcessId);
        lsegp += sizeof(ProcessId);
	lsegsize -= sizeof(ProcessId);
      }

    return 0;
  }
