/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1990-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped

/*
 * syscall message server side send
 */

#include "msglib.h"

#include <cs.h>

/*
 * send a response to a msgrecv() message
 * message size is returned
 */

ssize_t
msgsend(int fd, register Msg_call_t* msg, unsigned long call, long ret, int err, void* data)
{
	register struct stat*		sp;
	register struct dirent*		dp;
	register struct dirent*		de;
	register struct statvfs*	vp;
	int				i;
	char*				b;
	char*				e;

	if (call & MSG_ACK)
	{
		if ((fd = csbind(&cs, "udp", msg->ack.addr, msg->ack.port, 0L)) < 0)
			return -1;
		ret = ret == -1 ? ~msg->stamp : msg->stamp;
		err = 0;
		data = 0;
	}
	b = msg->data + MSG_SIZE_SIZE;
	e = msg->data + sizeof(msg->data);
	msgputu(&b, e, call);
	msgputu(&b, e, ret);
	if (ret == -1) msgputu(&b, e, err);
	else if (data) switch (MSG_CALL(call))
	{
	case MSG_getdents:
		dp = (struct dirent*)data;
		de = (struct dirent*)((char*)dp + ret);
		while (dp < de)
		{
			i = D_NAMLEN(dp);
			msgputz(&b, e, dp->d_name, i + 1);
			msgputu(&b, e, D_FILENO(dp));
#if _mem_d_reclen_dirent
			i = dp->d_reclen;
#else
			i = D_RECSIZ(dp, i);
#endif
			dp = (struct dirent*)((char*)dp + i);
		}
		msgputu(&b, e, 0);
		break;
	case MSG_stat:
		sp = (struct stat*)data;
		msgputu(&b, e, sp->st_dev);
		msgputu(&b, e, sp->st_ino);
		msgputu(&b, e, sp->st_mode);
		msgputu(&b, e, sp->st_nlink);
		msgputu(&b, e, sp->st_uid);
		msgputu(&b, e, sp->st_gid);
		msgputu(&b, e, sp->st_size);
		msgputu(&b, e, sp->st_atime);
		msgputu(&b, e, sp->st_mtime);
		msgputu(&b, e, sp->st_ctime);
#if _mem_st_blksize_stat
		msgputu(&b, e, sp->st_blksize);
#else
		msgputu(&b, e, 1024);
#endif
#if _mem_st_blocks_stat
		msgputu(&b, e, sp->st_blocks);
#else
		msgputu(&b, e, sp->st_size ? ((sp->st_size - 1) / 1024 + 1) : 0);
#endif
		break;
	case MSG_statfs:
		vp = (struct statvfs*)data;
		msgputu(&b, e, vp->f_bsize);
		msgputu(&b, e, vp->f_frsize);
		msgputu(&b, e, vp->f_blocks);
		msgputu(&b, e, vp->f_bfree);
		msgputu(&b, e, vp->f_bavail);
		msgputu(&b, e, vp->f_files);
		msgputu(&b, e, vp->f_ffree);
		msgputu(&b, e, vp->f_favail);
#if _mem_f_fsid_statvfs
		msgputu(&b, e, vp->f_fsid);
#else
		msgputu(&b, e, 0);
#endif
#if _mem_f_basetype_statvfs
		msgputz(&b, e, vp->f_basetype, strlen(vp->f_basetype) + 1);
#else
		msgputz(&b, e, "ufs", 4);
#endif
		msgputu(&b, e, vp->f_flag);
		msgputu(&b, e, vp->f_namemax);
#if _mem_f_fstr_statvfs
		msgputz(&b, e, vp->f_fstr, strlen(vp->f_fstr) + 1);
#endif
		break;
	default:
		msgputz(&b, e, data, ret);
		break;
	}
	ret = b - msg->data;
	msgsetsize(msg->data, ret);
	if (cswrite(&cs, fd, msg->data, ret) != ret)
		ret = -1;
	if (call & MSG_ACK)
		close(fd);
	return ret;
}
