/*
 * Copyright 2000, International Business Machines Corporation and others.
 * All Rights Reserved.
 * 
 * This software has been released under the terms of the IBM Public
 * License.  For details, see the LICENSE file in the top-level source
 * directory or online at http://www.openafs.org/dl/license10.html
 */

/*
 * In which the structures needed to facilitate interception of file system
 * related system calls by a user process ("agent", or "venus").
 */

#define RT_VERSION	3	/* Version number, should be incremented
				   before incompatible changes are released */
/*
 *      Version 1 - April 4/84.
 * 	Version 2 - May 4/84.
 *      Version 3 - May 30/85.
 *      Version 4 - June 19/85.
 */

/* Maximum number of arguments to a system call */
#define RT_MAX_ARGS		( (sizeof u.u_arg) / (sizeof (int)) )

#ifndef	KERNEL
extern struct user u;
#endif /* KERNEL */
/* Maximum size of combined string or structure arguments passed between
   the kernel and a venus */
#define RT_MAXDATASIZE		(MAXPATHLEN*2)

/* The format of the message passed between Venus and the kernel */
struct	intercept_message {
    u_short	im_type;	/* Message type */
    u_short     im_dsize;	/* Number of bytes in im_data */
    int		im_client;	/* The process id of the client side of the
    				   transaction */
    short	im_uid;		/* The effective user id of the client */
    short	im_gid;		/* The effective group id of the client */
    int		im_seq;		/* The sequence number of this transaction.
				   Never 0 */
    afs_int32	im_wdfid[3];	/* Current directory on the remote file system
    				   Vice II only. */
    int		im_error;	/* u.u_error copied from this */
    char	im_follow1;	/* 1=>follow last component of first pathname
				   if symbolic link; 0=>don't */
    char	im_follow2;	/* ditto for second pathname */
    afs_int32	im_pag;		/* process authentication group */
    /* im_arg contains a representation of the arguments to the intercepted
       system call, when transmitted from the kernel to Venus.
       Returned values are passed back from Venus to the kernel the same way */
    struct im_arg {
	int	im_aval; 	/* Value of the argument
				   OR index of argument in im_data */
	int	im_asize;	/* If im_aval is the index of an argument in
				   im_data, then this is its size in bytes.
				   Otherwise this is 0. */
    } im_arg[RT_MAX_ARGS];
    char	im_data[RT_MAXDATASIZE];
				/* Variable length field containing string
				   or structure arguments */
    /* No fields should be added here, the record may be truncated on
       transmission in either direction to an appropriate size */
};



#define RT_HEADERSIZE	((sizeof (struct intercept_message)) - RT_MAXDATASIZE)

#ifdef KERNEL
/* The following shouldn't be done in this manner, but there doesn't
   seem to be an easy mechanism to discover the device id.  The auto-
   config stuff is only for real devices, I think.
 */
#ifdef sun
#define RMT_MAJ		30
#endif
#ifdef vax
#define RMT_MAJ		33
#endif

/* Sleep priorities */
#define RMT_NOINT_PRI	(PINOD+1)/* Sleep with signal handling enabled */
#define RMT_INTOK_PRI	(PSLEP-1)/* Disallow aborts due to signal handling */

/* Private data used by the remote intercept routines in the kernel */
/* Note:  this was originally designed for only a single remote device.
   To make it work for multiple devices, I simply unfolded the code
   by turning this into an array (1 entry per device) and using a macro
   in the code to reference the appropriate entry. */
struct remote {
    int		rt_flags;	/* for flag values, see below */
    int		rt_seq;		/* sequence number generator */
    char	rt_open;	/* 1 if the device is open */  /* XXX UNALIGNED */
    struct proc	*rt_selproc;	/* process waiting for select */
    char	rt_attach;	/* wait channel for process waiting to attach
    				   this structure */
    char	rt_read;	/* wait channel for a venus waiting for an
    				   intercept */
    char	rt_reply;	/* wait channel for a client process waiting
    				   for a reply */
    struct	intercept_message rt_imr;	/* buffer for agent reads */
    struct	intercept_message rt_imw;	/* buffer for agent writes */
#include "rfs.h"
} remote[NRFS];
#undef NRFS

/* Hack to unfold code for multiple devices */
#define rmt     (*rmtp)
#define devhack(dev) register struct remote *rmtp = &remote[minor(dev)]

/* Flags for rmt.rt_flags */
#define RT_RBUF		1	/* processing venus read request */
#define RT_WBUF		2	/* processing venus write request */
#define RT_SENDING	4	/* sending the structure to the venus */
#define RT_REPLY	8	/* reply from venus to client */
#define RT_SIGNAL	16	/* signal occured, want to send message to
				   venus at next opportunity */

/* This bogus stuff is used for rename/link */
struct Name {
    int func;        /* This used to be a function in BSD 4.2... */
    int follow;
    struct buf *buf;
    char *name;
    dev_t dev;
    enum {havePath, isLocal, haveDev, isRemote} state;
};

extern struct inode *RemoteNamei();
extern int RemoteMaybe();
#endif /* KERNEL */

/*
 * Message type codes for messages sent from the kernel.
 * NB:  the kernel ignores the type field on reply (it merely matches
 * sequence numbers).  Unexpected messages from an venus are ignored (they
 * may have been destined for a process which has died in the meantime).
 * At all times, the kernel tries to maintain its own integrity, so that
 * in the worst case an venus restart should work fine.
 */

/*
 * In the capsule descriptions below, "(?)" means that the flagged item
 * is probably a good candidate for negotiation.
 */

#define RT_BOGUS	0
/* For debugging purposes in kernel */

#define RT_access	1
/* From kernel: 0: uninterpreted part of pathname
 *		1: mode
 * NB: uid/gid for this call are the real (not effective) uid/gid's.
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 * NB: return value is implicit in im_error.
 */

#define RT_chdir	2
/* From kernel: 0: uninterpreted part of pathname
 * Vice I response:
 *		0: new pathname (with ..'s removed, symbolic
 *		   links NOT expanded).
 *		   length<MAXPATHLEN.  Null terminated.
 *		im_error
 * Vice II response:
 * 		im_wdfid:  the file identifier (volume, vnode, unique)
 * 		   of the new working directory.
 *		im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_chmod	3
/* From kernel: 0: uninterpreted part of pathname
 *		1: mode
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_chown	4
/* From kernel: 0: uninterpreted part of pathname
 *		1: new uid
 *		2: new gid
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_close	5
/* From kernel: 0: file identifier.
 *		im_error: either 0 or one of the error codes
 *			  listed below (RTE_*, see RT_open).
 * Response:	im_error (for programs that want to know)
 * N.B.: close MUST always cleanup state; it will never be issued
 * twice for the same identifier.  If RT_signal is received during
 * a close, venus can use this as a hint to return early from the
 * close.  Venus should not return EINTR for this system call, however.
 */

#define RT_fchmod	6
/* From kernel: 0: file identifier
 * 		1: mode
 * Response:	im_error
 */

#define RT_fchown	7
/* From kernel:	0: file identifier
 *		1: new uid
 *		2: new gid
 * Response:	im_error
 */

#define RT_fcntl	8
/* Not implemented */

#define RT_flock	9
/* From kernel: 0: file identifier
 *  		1: operation
 * Response:	im_error
 */

#define RT_fstat	10
/* From kernel: 0: file identifier.
 * Response:	0: struct stat
 *		im_error
 */

#define RT_fsync	11
/* From kernel: 0: file identifier.
 * Response:	im_error
 */

#define RT_ftruncate	12
/* From kernel: 0: file identifier.
 *		1: truncated length. (? right now, kernel truncates
 *		   open cached inode)
 * Response:	im_error
 */

#define RT_link		13
/* From kernel: 0: the uninterpreted part of the original path
 *		1: the uninterpreted part of the pathname which
 *		   will be the new link
 * Response:	im_error
 * if im_error == EABSPATH1 or EABSPATH2 then:
 *		0: Resolved absolute path name.
 */

#define RT_lstat	14
/* Obsolete--not generated by the kernel.  The im_follow1
   field is used in conjunction with RT_stat to implement
   lstat.  VICE I will continue to work since it does not
   distinguish between stat and lstat */

#define RT_mkdir	15
/* From kernel: 0: uninterpreted part of pathname
 *		1: mode
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_open		16
/* From kernel: 0: uninterpreted part of pathname
 *	        1: flags
 *		2: mode
 * Vice 1 Response:
 *		0: file identifier assigned (for subsequent
 * 	  	   messages dealing with open files).
 *		1: pathname of the local, cached file.	
 *		im_error
 * Note:	the returned filename is not created, truncated(?),
 *  		or otherwise fiddled with by the kernel.  It must
 *		exist and must be a plain file.  N.B: Protection modes
 *		are ignored when it is finally opened.  The exec bit,
 *		however, should never be set unless the file is
 *		really executable.  (It should never be set for
 *		directories).  If there are problems opening the
 *		file, the user gets an error, the kernel gets a close
 *		message (possibly with one of the RTE_* errors, below,
 *		set in im_error).
 * Vice 2 Response:
 *		0: file identifier assigned (for subsequent
 * 	  	   messages dealing with open files).
 *		1: device where the file resides.
 *	 	2: inode number of the file.
 * 		im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 * (?) Non-blocking open.
 */

#define RT_readlink	17
/* From kernel: 0: uninterpreted part of link pathname
 * Response:	0: number of characters read from link
 *		1: contents of link (not null terminated).  Size must not be
 *		   greater than MAXPATHLEN (because this is checked by the
 *		   kernel intercept code).
 *		im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_rename	18
/* From kernel: 0: uninterpreted part of original pathname
 *  		1: ditto for new pathname
 * Response:	im_error
 * if im_error == EABSPATH1 or EABSPATH2 then:
 *		0: Resolved absolute path name.
 */

#define RT_rmdir	19
/* From kernel: 0: uninterpreted part of pathname
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_stat		20
/* From kernel: 0: uninterpreted part of pathname
 * Response:	0: struct stat
 * 		im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 * Note:  this now implements the lstat call, as well,
 * by means of the im_follow1 field in the header.
 */

#define RT_symlink	21
/* From kernel: 0: the string value of the new symbolic link.
 *		1: the uninterpreted part of the pathname to
 *		   contain the link.
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_truncate	22
/* From kernel: 0: uninterpreted part of pathname
 *		1: truncated length
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_unlink	23
/* From kernel: 0: uninterpreted part of pathname
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_utimes	24
/* From kernel: 0: uninterpreted part of pathname
 *		1: struct timeval tvp[2]
 * Response:	im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */

#define RT_signal	25
/* Request to abort the previous operation requested WITH THE
 * SAME im_seq FIELD.  No action is expected on the part of
 * the venus--this is merely advice that the operation may
 * be completed early.  VENUS SHOULD NOT REPLY TO THIS MESSAGE.
 * The error returned on final completion by the venus need not
 * acknowledge that the system call was interrupted.  The interrupt
 * will occur at the end of the system call regardless.  EINTR
 * should be returned if the system call actually is aborted.
 * VENUS MAY RETURN EARLY FROM A   C L O S E  SYSTEM CALL, BUT MUST STILL
 * CLEANUP STATE FOR THE CLOSE--ANOTHER CLOSE CALL FOR THE SAME
 * DESCRIPTOR WILL NEVER BE ISSUED.
 * RT_signal messages for which a reply has already been issued
 * sholuld be ignored by venus.
 */

#define RT_ioctl	26
/*
 * From kernel: 0: file identifier
 *              1: command (see below)
 *              2: uninterpreted data (up to RT_MAXDATASIZE).
 * Response:    0: data to be returned to user
 *              im_error
 * NOTE:  the information passed to/from venus is not in the
 * same format as that coming to/from the user.  See the file
 * vice.h.
 */


#define RT_pioctl	27
/*
 * From kernel: 0: uninterpreted part of pathname
 * 		1: command (as in RT_ioctl)
 *		2: uninterpreted data
 * Note: argument 3, do not follow symbolic links, is
 *   obsolete; this is compatible with VICE I, since the
 *   field was ignored anyway.
 * Response:    0: data to be returned to user
 *		im_error
 * if im_error == EABSPATH1 then:
 *		0: Resolved absolute path name.
 */


/* Error codes -- each is set by the kernel for the explicit error indicated.
 * These are set in im_error (which should normally be 0 in every message from
 * the kernel).  Errors of this form indicate that the venus process has
 * almost certainly done something wrong.  The associated user process gets an
 * ERFS (remote file system error) for each of these error types.
 */

/* The following error codes all occur at open (exec?) and are sent by the
 * kernel with the associated close message for the file identifier returned
 * from the open.
 */

#define	RTE_BADARG 1    /* The size of a structure or string argument returned
			   by the venus to the kernel is bogus.
			   (the im_size field is not zero, or part of the
			   argument is outside the message buffer, or the
			   argument is too large) */

#define RTE_NOFILE 2	/* The file name (or inode, in VICE II) returned to
			   the kernel, to open or exec in lieu of the original
			   name supplied by the process cannot be opened or
			   exec'd */

#define RTE_NOTREG 3    /* The file (or inode, in VICE II) returned to the
			   kernel, to open or exec in lieu of the original
			   name supplied by the process, is not a IF_REG
			   type file, i.e. it is a device, socket, or
			   directory */


/* The following error codes are set by Venus when a pathname argument supplied
 * by the kernel resolves to an absolute pathname outside of the name space 
 * of this venus.  The resolved absolute pathname is returned in argument 0.
 * The kernel is expected to retry the system call with this new information.
 * The kernel never passes this error on to the original issuer of the system
 * call.
 */
#define EABSPATH1 126	/* The first pathname, or only pathname, of a system
			   call resolved to an absolute pathname */
#define EABSPATH2 127	/* The second pathname of the rename or link system
			   call resolved to an absolute pathname */
