/* Module fsys */

#define EXPORT_BOOLEAN
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/message.h>
#include <mach/mig_errors.h>

#ifndef	mig_internal
#define	mig_internal	static
#endif

#ifndef	mig_external
#define mig_external
#endif

#ifndef	TypeCheck
#define	TypeCheck 1
#endif

#ifndef	UseExternRCSId
#ifdef	hc
#define	UseExternRCSId		1
#endif
#endif

#ifndef	UseStaticMsgType
#if	!defined(hc) || defined(__STDC__)
#define	UseStaticMsgType	1
#endif
#endif

/* Due to pcc compiler bug, cannot use void */
#if	(defined(__STDC__) || defined(c_plusplus)) || defined(hc)
#define novalue void
#else
#define novalue int
#endif

#define msgh_request_port	msgh_local_port
#define MACH_MSGH_BITS_REQUEST(bits)	MACH_MSGH_BITS_LOCAL(bits)
#define msgh_reply_port		msgh_remote_port
#define MACH_MSGH_BITS_REPLY(bits)	MACH_MSGH_BITS_REMOTE(bits)

#include <mach/std_types.h>
#include <mach/mach_types.h>
#include <device/device_types.h>
#include <device/net_status.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <hurd/hurd_types.h>
#include "ufs.h"

/* Routine fsys_startup */
mig_internal novalue _Xfsys_startup
#if	(defined(__STDC__) || defined(c_plusplus))
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
#else
	(InHeadP, OutHeadP)
	mach_msg_header_t *InHeadP, *OutHeadP;
#endif
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t control_portType;
		fsys_t control_port;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_t realnodeType;
		file_t realnode;
		mach_msg_type_t dotdot_nodeType;
		file_t dotdot_node;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t fsys_startup
#if	(defined(__STDC__) || defined(c_plusplus))
		(mach_port_t bootstrap, fsys_t control_port, file_t *realnode, file_t *dotdot_node);
#else
		();
#endif

#if	UseStaticMsgType
	static mach_msg_type_t control_portCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_PORT_SEND,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	UseStaticMsgType
	static mach_msg_type_t realnodeType = {
		/* msgt_name = */		MACH_MSG_TYPE_COPY_SEND,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	UseStaticMsgType
	static mach_msg_type_t dotdot_nodeType = {
		/* msgt_name = */		MACH_MSG_TYPE_COPY_SEND,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	TypeCheck
	if ((In0P->Head.msgh_size != 32) ||
	    !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

#if	TypeCheck
#if	UseStaticMsgType
	if (* (int *) &In0P->control_portType != * (int *) &control_portCheck)
#else	UseStaticMsgType
	if ((In0P->control_portType.msgt_inline != TRUE) ||
	    (In0P->control_portType.msgt_longform != FALSE) ||
	    (In0P->control_portType.msgt_name != MACH_MSG_TYPE_PORT_SEND) ||
	    (In0P->control_portType.msgt_number != 1) ||
	    (In0P->control_portType.msgt_size != 32))
#endif	UseStaticMsgType
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

	OutP->RetCode = fsys_startup(In0P->Head.msgh_request_port, verify_fsys_port(In0P->control_port), &OutP->realnode, &OutP->dotdot_node);
	if (OutP->RetCode != KERN_SUCCESS)
		return;

	OutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
	OutP->Head.msgh_size = 48;

#if	UseStaticMsgType
	OutP->realnodeType = realnodeType;
#else	UseStaticMsgType
	OutP->realnodeType.msgt_name = MACH_MSG_TYPE_COPY_SEND;
	OutP->realnodeType.msgt_size = 32;
	OutP->realnodeType.msgt_number = 1;
	OutP->realnodeType.msgt_inline = TRUE;
	OutP->realnodeType.msgt_longform = FALSE;
	OutP->realnodeType.msgt_deallocate = FALSE;
	OutP->realnodeType.msgt_unused = 0;
#endif	UseStaticMsgType

#if	UseStaticMsgType
	OutP->dotdot_nodeType = dotdot_nodeType;
#else	UseStaticMsgType
	OutP->dotdot_nodeType.msgt_name = MACH_MSG_TYPE_COPY_SEND;
	OutP->dotdot_nodeType.msgt_size = 32;
	OutP->dotdot_nodeType.msgt_number = 1;
	OutP->dotdot_nodeType.msgt_inline = TRUE;
	OutP->dotdot_nodeType.msgt_longform = FALSE;
	OutP->dotdot_nodeType.msgt_deallocate = FALSE;
	OutP->dotdot_nodeType.msgt_unused = 0;
#endif	UseStaticMsgType
}

/* Routine fsys_goaway */
mig_internal novalue _Xfsys_goaway
#if	(defined(__STDC__) || defined(c_plusplus))
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
#else
	(InHeadP, OutHeadP)
	mach_msg_header_t *InHeadP, *OutHeadP;
#endif
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t flagsType;
		int flags;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t fsys_goaway
#if	(defined(__STDC__) || defined(c_plusplus))
		(fsys_t fsys, int flags);
#else
		();
#endif

#if	UseStaticMsgType
	static mach_msg_type_t flagsCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	TypeCheck
	if ((In0P->Head.msgh_size != 32) ||
	    (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

#if	TypeCheck
#if	UseStaticMsgType
	if (* (int *) &In0P->flagsType != * (int *) &flagsCheck)
#else	UseStaticMsgType
	if ((In0P->flagsType.msgt_inline != TRUE) ||
	    (In0P->flagsType.msgt_longform != FALSE) ||
	    (In0P->flagsType.msgt_name != MACH_MSG_TYPE_INTEGER_32) ||
	    (In0P->flagsType.msgt_number != 1) ||
	    (In0P->flagsType.msgt_size != 32))
#endif	UseStaticMsgType
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

	OutP->RetCode = fsys_goaway(verify_fsys_port(In0P->Head.msgh_request_port), In0P->flags);
}

/* Routine fsys_getroot */
mig_internal novalue _Xfsys_getroot
#if	(defined(__STDC__) || defined(c_plusplus))
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
#else
	(InHeadP, OutHeadP)
	mach_msg_header_t *InHeadP, *OutHeadP;
#endif
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t flagsType;
		int flags;
		mach_msg_type_t auth_realnodeType;
		mach_port_t auth_realnode;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_t fileType;
		mach_port_t file;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t fsys_getroot
#if	(defined(__STDC__) || defined(c_plusplus))
		(fsys_t fsys, int flags, mach_port_t auth_realnode, mach_port_t *file);
#else
		();
#endif

#if	UseStaticMsgType
	static mach_msg_type_t flagsCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	UseStaticMsgType
	static mach_msg_type_t auth_realnodeCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_PORT_SEND,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	UseStaticMsgType
	static mach_msg_type_t fileType = {
		/* msgt_name = */		MACH_MSG_TYPE_MOVE_SEND,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	TypeCheck
	if ((In0P->Head.msgh_size != 40) ||
	    !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

#if	TypeCheck
#if	UseStaticMsgType
	if (* (int *) &In0P->flagsType != * (int *) &flagsCheck)
#else	UseStaticMsgType
	if ((In0P->flagsType.msgt_inline != TRUE) ||
	    (In0P->flagsType.msgt_longform != FALSE) ||
	    (In0P->flagsType.msgt_name != MACH_MSG_TYPE_INTEGER_32) ||
	    (In0P->flagsType.msgt_number != 1) ||
	    (In0P->flagsType.msgt_size != 32))
#endif	UseStaticMsgType
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

#if	TypeCheck
#if	UseStaticMsgType
	if (* (int *) &In0P->auth_realnodeType != * (int *) &auth_realnodeCheck)
#else	UseStaticMsgType
	if ((In0P->auth_realnodeType.msgt_inline != TRUE) ||
	    (In0P->auth_realnodeType.msgt_longform != FALSE) ||
	    (In0P->auth_realnodeType.msgt_name != MACH_MSG_TYPE_PORT_SEND) ||
	    (In0P->auth_realnodeType.msgt_number != 1) ||
	    (In0P->auth_realnodeType.msgt_size != 32))
#endif	UseStaticMsgType
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

	OutP->RetCode = fsys_getroot(verify_fsys_port(In0P->Head.msgh_request_port), In0P->flags, In0P->auth_realnode, &OutP->file);
	if (OutP->RetCode != KERN_SUCCESS)
		return;

	OutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
	OutP->Head.msgh_size = 40;

#if	UseStaticMsgType
	OutP->fileType = fileType;
#else	UseStaticMsgType
	OutP->fileType.msgt_name = MACH_MSG_TYPE_MOVE_SEND;
	OutP->fileType.msgt_size = 32;
	OutP->fileType.msgt_number = 1;
	OutP->fileType.msgt_inline = TRUE;
	OutP->fileType.msgt_longform = FALSE;
	OutP->fileType.msgt_deallocate = FALSE;
	OutP->fileType.msgt_unused = 0;
#endif	UseStaticMsgType
}

/* Routine fsys_getfile */
mig_internal novalue _Xfsys_getfile
#if	(defined(__STDC__) || defined(c_plusplus))
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
#else
	(InHeadP, OutHeadP)
	mach_msg_header_t *InHeadP, *OutHeadP;
#endif
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_long_t uidsType;
		uid_t uids[512];
		mach_msg_type_long_t gidsType;
		uid_t gids[512];
		mach_msg_type_long_t filehandleType;
		char filehandle[2048];
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_t fileType;
		file_t file;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Request *In1P;
	register Request *In2P;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t fsys_getfile
#if	(defined(__STDC__) || defined(c_plusplus))
		(fsys_t fsys, idarray_t uids, mach_msg_type_number_t uidsCnt, idarray_t gids, mach_msg_type_number_t gidsCnt, data_t filehandle, mach_msg_type_number_t filehandleCnt, file_t *file);
#else
		();
#endif

#if	TypeCheck
	boolean_t msgh_simple;
#endif	TypeCheck

	unsigned int msgh_size;
	unsigned int msgh_size_delta;

#if	UseStaticMsgType
	static mach_msg_type_t fileType = {
		/* msgt_name = */		MACH_MSG_TYPE_COPY_SEND,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

#if	TypeCheck
	msgh_size = In0P->Head.msgh_size;
	msgh_simple = !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);
	if ((msgh_size < 60))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

#if	TypeCheck
	if ((In0P->uidsType.msgtl_header.msgt_longform != TRUE) ||
	    (In0P->uidsType.msgtl_name != MACH_MSG_TYPE_INTEGER_32) ||
	    (In0P->uidsType.msgtl_size != 32))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

	msgh_size_delta = (In0P->uidsType.msgtl_header.msgt_inline) ? 4 * In0P->uidsType.msgtl_number : sizeof(uid_t *);
#if	TypeCheck
	if (msgh_size < 60 + msgh_size_delta)
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
	msgh_size -= msgh_size_delta;
#endif	TypeCheck

	In1P = (Request *) ((char *) In0P + msgh_size_delta - 2048);

#if	TypeCheck
	if ((In1P->gidsType.msgtl_header.msgt_longform != TRUE) ||
	    (In1P->gidsType.msgtl_name != MACH_MSG_TYPE_INTEGER_32) ||
	    (In1P->gidsType.msgtl_size != 32))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

	msgh_size_delta = (In1P->gidsType.msgtl_header.msgt_inline) ? 4 * In1P->gidsType.msgtl_number : sizeof(uid_t *);
#if	TypeCheck
	if (msgh_size < 60 + msgh_size_delta)
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
	msgh_size -= msgh_size_delta;
#endif	TypeCheck

	In2P = (Request *) ((char *) In1P + msgh_size_delta - 2048);

#if	TypeCheck
	if ((In2P->filehandleType.msgtl_header.msgt_longform != TRUE) ||
	    (In2P->filehandleType.msgtl_name != MACH_MSG_TYPE_CHAR) ||
	    (In2P->filehandleType.msgtl_size != 8))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

#if	TypeCheck
	if (msgh_size != 60 + ((In2P->filehandleType.msgtl_header.msgt_inline) ? In2P->filehandleType.msgtl_number + 3 & ~3 : sizeof(char *)))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	TypeCheck

	OutP->RetCode = fsys_getfile(verify_fsys_port(In0P->Head.msgh_request_port), (In0P->uidsType.msgtl_header.msgt_inline) ? In0P->uids : *((uid_t **)In0P->uids), In0P->uidsType.msgtl_number, (In1P->gidsType.msgtl_header.msgt_inline) ? In1P->gids : *((uid_t **)In1P->gids), In1P->gidsType.msgtl_number, (In2P->filehandleType.msgtl_header.msgt_inline) ? In2P->filehandle : *((char **)In2P->filehandle), In2P->filehandleType.msgtl_number, &OutP->file);
	if (!In2P->filehandleType.msgtl_header.msgt_inline)
		mig_deallocate(*(char **)In2P->filehandle,  In2P->filehandleType.msgtl_number);
	if (!In1P->gidsType.msgtl_header.msgt_inline)
		mig_deallocate(*(char **)In1P->gids, 4 *  In1P->gidsType.msgtl_number);
	if (!In0P->uidsType.msgtl_header.msgt_inline)
		mig_deallocate(*(char **)In0P->uids, 4 *  In0P->uidsType.msgtl_number);
	if (OutP->RetCode != KERN_SUCCESS)
		return;

	OutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
	OutP->Head.msgh_size = 40;

#if	UseStaticMsgType
	OutP->fileType = fileType;
#else	UseStaticMsgType
	OutP->fileType.msgt_name = MACH_MSG_TYPE_COPY_SEND;
	OutP->fileType.msgt_size = 32;
	OutP->fileType.msgt_number = 1;
	OutP->fileType.msgt_inline = TRUE;
	OutP->fileType.msgt_longform = FALSE;
	OutP->fileType.msgt_deallocate = FALSE;
	OutP->fileType.msgt_unused = 0;
#endif	UseStaticMsgType
}

static mig_routine_t fsys_server_routines[] = {
		_Xfsys_startup,
		_Xfsys_goaway,
		_Xfsys_getroot,
		_Xfsys_getfile,
};

mig_external boolean_t fsys_server
#if	(defined(__STDC__) || defined(c_plusplus))
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
#else
	(InHeadP, OutHeadP)
	mach_msg_header_t *InHeadP, *OutHeadP;
#endif
{
	register mach_msg_header_t *InP =  InHeadP;
	register mig_reply_header_t *OutP = (mig_reply_header_t *) OutHeadP;

#if	UseStaticMsgType
	static mach_msg_type_t RetCodeType = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};
#endif	UseStaticMsgType

	register mig_routine_t routine;

	OutP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InP->msgh_bits), 0);
	OutP->Head.msgh_size = sizeof *OutP;
	OutP->Head.msgh_remote_port = InP->msgh_reply_port;
	OutP->Head.msgh_local_port = MACH_PORT_NULL;
	OutP->Head.msgh_seqno = 0;
	OutP->Head.msgh_id = InP->msgh_id + 100;

#if	UseStaticMsgType
	OutP->RetCodeType = RetCodeType;
#else	UseStaticMsgType
	OutP->RetCodeType.msgt_name = MACH_MSG_TYPE_INTEGER_32;
	OutP->RetCodeType.msgt_size = 32;
	OutP->RetCodeType.msgt_number = 1;
	OutP->RetCodeType.msgt_inline = TRUE;
	OutP->RetCodeType.msgt_longform = FALSE;
	OutP->RetCodeType.msgt_deallocate = FALSE;
	OutP->RetCodeType.msgt_unused = 0;
#endif	UseStaticMsgType

	if ((InP->msgh_id > 22003) || (InP->msgh_id < 22000) ||
	    ((routine = fsys_server_routines[InP->msgh_id - 22000]) == 0)) {
		OutP->RetCode = MIG_BAD_ID;
		return FALSE;
	}
	(*routine) (InP, &OutP->Head);
	return TRUE;
}

mig_external mig_routine_t fsys_server_routine
#if	(defined(__STDC__) || defined(c_plusplus))
	(mach_msg_header_t *InHeadP)
#else
	(InHeadP)
	mach_msg_header_t *InHeadP;
#endif
{
	register int msgh_id;

	msgh_id = InHeadP->msgh_id - 22000;

	if ((msgh_id > 3) || (msgh_id < 0))
		return 0;

	return fsys_server_routines[msgh_id];
}

