/* -*- mode: C -*-  Time-stamp: "2005-01-07 22:39:14 jemarch"
 *
 *      File:        hush_trivfs.c
 *      Author:      Jose E. Marchesi <jemarch@gnu.org>
 *      Date:        9/2003
 *
 *      libtrivfs callbacks for hush
 *
 */


#include "hush.h"


extern hushtrans_t curtrans;

/*** TrivFS configuration variables ***/


int trivfs_fstype = FSTYPE_MISC;
int trivfs_fsid = 0;


int trivfs_allow_open = 0;     /* Defined dinamically by the script */
 

int trivfs_support_read = 0;   /* Defined dinamically by the script */
int trivfs_support_write = 0;
int trivfs_support_exec = 0;



/*** TrivFS callback functions ***/


/*
 *      Routine:      trivfs_S_io_read
 *      Purpose:
 *              Read callback.
 *      Conditions:
 *              Global variable curtrans must be initialized.
 *      Returns:
 *              0
 *
 */

kern_return_t
trivfs_S_io_read (struct trivfs_protid *cred,
		  mach_port_t reply, mach_msg_type_name_t replytype,
		  char **data,
		  mach_msg_type_number_t *datalen,
		  loff_t offs,
		  mach_msg_type_number_t amt)
{
  SHELL_VAR *iovar;
  int retval;

  /* Deny access if they have bad credentials. */
  if (! cred)
    return EOPNOTSUPP;
  else if (! (cred->po->openmodes & O_READ))
    return EBADF;


  if (curtrans.operation.read != NULL)
    {

      /* Make the IO variable available */
      iovar = (VAR_SHELL *) bind_iovar (curtrans.operation.read->iovar->word, "");
      
      /* Executes the stored read code */
      retval = execute_command(curtrans.operation.read->action);

      if (retval == EXECUTION_FAILURE)
	{
	  jump_to_top_level(EXITPROG);
	}

      /* Copy into data the requested information */
      *data = memcpy ((char *) *data, get_iovar_value(iovar) + offs, *datalen); 


      /* Destroy the iovar */
      unbind_iovar(iovar);

    }
  else
    {
      /* Default: operation not permitted */
      return EOPNOTSUPP;
    }

  /* success */
  return 0;

} /* End of routine trivfs_S_io_read */

/*
 *      Routine:      trivfs_S_io_write
 *      Purpose:
 *              Write callback.
 *      Conditions:
 *              Global variable curtrans must be initialized.
 *      Returns:
 *              0
 *
 */

kern_return_t
trivfs_S_io_write (struct trivfs_protid *cred,
		   mach_port_t reply, mach_msg_type_name_t replytype,
		   char *data, mach_msg_type_number_t datalen,
		   loff_t offs, mach_msg_type_number_t *amt)
		   
{
  int retval;
  SHELL_VAR *iovar;


  /* Deny access if they have bad credentials. */
  if (! cred)
    return EOPNOTSUPP;
  else if (! (cred->po->openmodes & O_WRITE))
    return EBADF;



  if (curtrans.operation.write != NULL)
    {

      /* Make the IO variable available */
      iovar = bind_iovar (VAR_SHELL *)(curtrans.operation.write->iovar->word,
			  *data);
      /* XXX: take care about datalength! */

      /* Executes the stored read code */
      retval = execute_command(curtrans.operation.write->action);

      if (retval == EXECUTION_FAILURE)
	{
	  jump_to_top_level(EXITPROG);
	}

      /* Destroy the iovar */
      unbind_iovar (iovar);

    }
  else
    {
      /* Default: operation not permitted */
      return EOPNOTSUPP;
    }

  /* success */
  return 0;

} /* End of routine trivfs_S_io_write */


/*
 *      Routine:      trivfs_S_io_exec
 *      Purpose:
 *              Exec callback.
 *      Conditions:
 *              Global variable curtrans must be initialized.
 *      Returns:
 *              0
 *
 */

kern_return_t
trivfs_S_io_exec (void)
{
  int retval;

  /* Deny access if they have bad credentials. */
/*   if (! cred) */
/*     return EOPNOTSUPP; */
/*   else if (! (cred->po->openmodes & O_EXEC)) */
/*     return EBADF; */



  if (curtrans.operation.exec != NULL)
    {

      /* Executes the stored read code */
      retval = execute_command(curtrans.operation.exec->action);

      if (retval == EXECUTION_FAILURE)
	{
	  /* Abort the translator */
	  jump_to_top_level(EXITPROG);
	}

    }
  else
    {
      /* Default: operation not permitted */
      return EOPNOTSUPP;
    }

  /* success */
  return 0;

} /* End of routine trivfs_S_io_exec */


/*
 *      Routine:      trivfs_goaway
 *      Purpose:
 *              The translator goes away.
 *      Conditions:
 *              curtrans.operation.goaway must point to a COMMAND
 *              data structure representing the operation code.
 *      Returns:
 *              None
 *
 */

error_t
trivfs_goaway (struct trivfs_control *cntl,
	       int flags)
{
  int retval;

  if (curtrans.operation.goaway != NULL)
    {

      /* Executes the stored go away code */
      retval = execute_command(curtrans.operation.goaway->action);

      if (retval == EXECUTION_FAILURE)
	{
	  jump_to_top_level(EXITPROG);
	}
    }
  else
    {
      /* Default: do nothing */

    }

} /* End of routine trivfs_goaway */





/*** Dummy callbacks ***/

void
trivfs_modify_stat (struct trivfs_protid *protid,
		    struct stat *stat)
{
  /* Currently does nothing */

  
} /* End of routine trivfs_modify_stat */



kern_return_t
trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
			   mach_port_t reply, mach_msg_type_name_t replytype,
			   int *bits)
{
  if (!cred)
    return EOPNOTSUPP;
  else
    {
      *bits = cred->po->openmodes;
      return 0;
    }
}

error_t
trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
			      mach_port_t reply,
			      mach_msg_type_name_t replytype,
			      int mode)
{
  if (!cred)
    return EOPNOTSUPP;
  else
    return 0;
}

kern_return_t
trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
				mach_port_t reply,
				mach_msg_type_name_t replytype,
				int bits)
{
  if (!cred)
    return EOPNOTSUPP;
  else
    return 0;
}

kern_return_t
trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
				  mach_port_t reply,
				  mach_msg_type_name_t replytype,
				  int bits)
{
  if (!cred)
    return EOPNOTSUPP;
  else
    return 0;
}

kern_return_t
trivfs_S_io_get_owner (struct trivfs_protid *cred,
		       mach_port_t reply,
		       mach_msg_type_name_t replytype,
		       pid_t *owner)
{
  if (!cred)
    return EOPNOTSUPP;
  *owner = 0;
  return 0;
}

kern_return_t
trivfs_S_io_mod_owner (struct trivfs_protid *cred,
		       mach_port_t reply, mach_msg_type_name_t replytype,
		       pid_t owner)
{
  if (!cred)
    return EOPNOTSUPP;
  else
    return EINVAL;
}

kern_return_t
trivfs_S_io_map (struct trivfs_protid *cred,
		 mach_port_t reply, mach_msg_type_name_t replytype,
		 memory_object_t *rdobj,
		 mach_msg_type_name_t *rdtype,
		 memory_object_t *wrobj,
		 mach_msg_type_name_t *wrtype)
{
  return EINVAL;
}
