sysv_msg.c revision 59839
150477Speter/* $FreeBSD: head/sys/kern/sysv_msg.c 59839 2000-05-01 13:33:56Z peter $ */
22729Sdfr
32729Sdfr/*
42729Sdfr * Implementation of SVID messages
52729Sdfr *
62729Sdfr * Author:  Daniel Boulet
72729Sdfr *
82729Sdfr * Copyright 1993 Daniel Boulet and RTMX Inc.
92729Sdfr *
102729Sdfr * This system call was implemented by Daniel Boulet under contract from RTMX.
112729Sdfr *
122729Sdfr * Redistribution and use in source forms, with and without modification,
132729Sdfr * are permitted provided that this entire comment appears intact.
142729Sdfr *
152729Sdfr * Redistribution in binary form may occur without any restrictions.
162729Sdfr * Obviously, it would be nice if you gave credit where credit is due
172729Sdfr * but requiring it would be too onerous.
182729Sdfr *
192729Sdfr * This software is provided ``AS IS'' without any warranties of any kind.
202729Sdfr */
212729Sdfr
2259839Speter#include "opt_sysvipc.h"
2359839Speter
242729Sdfr#include <sys/param.h>
252729Sdfr#include <sys/systm.h>
2611626Sbde#include <sys/sysproto.h>
272729Sdfr#include <sys/kernel.h>
282729Sdfr#include <sys/proc.h>
292729Sdfr#include <sys/msg.h>
3011626Sbde#include <sys/sysent.h>
3159839Speter#include <sys/sysctl.h>
3259839Speter#include <sys/malloc.h>
332729Sdfr
3459839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
3559839Speter
3610653Sdgstatic void msginit __P((void *));
3710358Sjulian
382729Sdfr#define MSG_DEBUG
392729Sdfr#undef MSG_DEBUG_OK
402729Sdfr
4111626Sbdestatic void msg_freehdr __P((struct msg *msghdr));
422729Sdfr
4311626Sbde/* XXX casting to (sy_call_t *) is bogus, as usual. */
4412819Sphkstatic sy_call_t *msgcalls[] = {
4511626Sbde	(sy_call_t *)msgctl, (sy_call_t *)msgget,
4611626Sbde	(sy_call_t *)msgsnd, (sy_call_t *)msgrcv
4711626Sbde};
482729Sdfr
4959839Speterstruct msg {
5059839Speter	struct	msg *msg_next;	/* next msg in the chain */
5159839Speter	long	msg_type;	/* type of this message */
5259839Speter    				/* >0 -> type of this message */
5359839Speter    				/* 0 -> free header */
5459839Speter	u_short	msg_ts;		/* size of this message */
5559839Speter	short	msg_spot;	/* location of start of msg in buffer */
5659839Speter};
5759839Speter
5859839Speter
5959839Speter#ifndef MSGSSZ
6059839Speter#define MSGSSZ	8		/* Each segment must be 2^N long */
6159839Speter#endif
6259839Speter#ifndef MSGSEG
6359839Speter#define MSGSEG	2048		/* must be less than 32767 */
6459839Speter#endif
6559839Speter#define MSGMAX	(MSGSSZ*MSGSEG)
6659839Speter#ifndef MSGMNB
6759839Speter#define MSGMNB	2048		/* max # of bytes in a queue */
6859839Speter#endif
6959839Speter#ifndef MSGMNI
7059839Speter#define MSGMNI	40
7159839Speter#endif
7259839Speter#ifndef MSGTQL
7359839Speter#define MSGTQL	40
7459839Speter#endif
7559839Speter
7659839Speter/*
7759839Speter * Based on the configuration parameters described in an SVR2 (yes, two)
7859839Speter * config(1m) man page.
7959839Speter *
8059839Speter * Each message is broken up and stored in segments that are msgssz bytes
8159839Speter * long.  For efficiency reasons, this should be a power of two.  Also,
8259839Speter * it doesn't make sense if it is less than 8 or greater than about 256.
8359839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
8459839Speter * two between 8 and 1024 inclusive (and panic's if it isn't).
8559839Speter */
8659839Speterstruct msginfo msginfo = {
8759839Speter                MSGMAX,         /* max chars in a message */
8859839Speter                MSGMNI,         /* # of message queue identifiers */
8959839Speter                MSGMNB,         /* max chars in a queue */
9059839Speter                MSGTQL,         /* max messages in system */
9159839Speter                MSGSSZ,         /* size of a message segment */
9259839Speter                		/* (must be small power of 2 greater than 4) */
9359839Speter                MSGSEG          /* number of message segments */
9459839Speter};
9559839Speter
9659839Speter/*
9759839Speter * macros to convert between msqid_ds's and msqid's.
9859839Speter * (specific to this implementation)
9959839Speter */
10059839Speter#define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
10159839Speter#define MSQID_IX(id)	((id) & 0xffff)
10259839Speter#define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
10359839Speter
10459839Speter/*
10559839Speter * The rest of this file is specific to this particular implementation.
10659839Speter */
10759839Speter
10859839Speterstruct msgmap {
10959839Speter	short	next;		/* next segment in buffer */
11059839Speter    				/* -1 -> available */
11159839Speter    				/* 0..(MSGSEG-1) -> index of next segment */
11259839Speter};
11359839Speter
11459839Speter#define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
11559839Speter
11612819Sphkstatic int nfree_msgmaps;	/* # of free map entries */
11712819Sphkstatic short free_msgmaps;	/* head of linked list of free map entries */
11859839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */
11959839Speterstatic char *msgpool;		/* MSGMAX byte long msg buffer pool */
12059839Speterstatic struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
12159839Speterstatic struct msg *msghdrs;	/* MSGTQL msg headers */
12259839Speterstatic struct msqid_ds *msqids;	/* MSGMNI msqid_ds struct's */
1232729Sdfr
12459839Speterstatic void
12511626Sbdemsginit(dummy)
12611626Sbde	void *dummy;
1272729Sdfr{
1282729Sdfr	register int i;
1292729Sdfr
13059839Speter	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
13159839Speter	if (msgpool == NULL)
13259839Speter		panic("msgpool is NULL");
13359839Speter	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
13459839Speter	if (msgmaps == NULL)
13559839Speter		panic("msgmaps is NULL");
13659839Speter	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
13759839Speter	if (msghdrs == NULL)
13859839Speter		panic("msghdrs is NULL");
13959839Speter	msqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni, M_MSG, M_WAITOK);
14059839Speter	if (msqids == NULL)
14159839Speter		panic("msqids is NULL");
14259839Speter
1432729Sdfr	/*
1442729Sdfr	 * msginfo.msgssz should be a power of two for efficiency reasons.
1452729Sdfr	 * It is also pretty silly if msginfo.msgssz is less than 8
1462729Sdfr	 * or greater than about 256 so ...
1472729Sdfr	 */
1482729Sdfr
1492729Sdfr	i = 8;
1502729Sdfr	while (i < 1024 && i != msginfo.msgssz)
1512729Sdfr		i <<= 1;
1522729Sdfr    	if (i != msginfo.msgssz) {
1532729Sdfr		printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
1542729Sdfr		    msginfo.msgssz);
1552729Sdfr		panic("msginfo.msgssz not a small power of 2");
1562729Sdfr	}
1572729Sdfr
1582729Sdfr	if (msginfo.msgseg > 32767) {
1592729Sdfr		printf("msginfo.msgseg=%d\n", msginfo.msgseg);
1602729Sdfr		panic("msginfo.msgseg > 32767");
1612729Sdfr	}
1622729Sdfr
1632729Sdfr	if (msgmaps == NULL)
1642729Sdfr		panic("msgmaps is NULL");
1652729Sdfr
1662729Sdfr	for (i = 0; i < msginfo.msgseg; i++) {
1672729Sdfr		if (i > 0)
1682729Sdfr			msgmaps[i-1].next = i;
1692729Sdfr		msgmaps[i].next = -1;	/* implies entry is available */
1702729Sdfr	}
1712729Sdfr	free_msgmaps = 0;
1722729Sdfr	nfree_msgmaps = msginfo.msgseg;
1732729Sdfr
1742729Sdfr	if (msghdrs == NULL)
1752729Sdfr		panic("msghdrs is NULL");
1762729Sdfr
1772729Sdfr	for (i = 0; i < msginfo.msgtql; i++) {
1782729Sdfr		msghdrs[i].msg_type = 0;
1792729Sdfr		if (i > 0)
1802729Sdfr			msghdrs[i-1].msg_next = &msghdrs[i];
1812729Sdfr		msghdrs[i].msg_next = NULL;
1822729Sdfr    	}
1832729Sdfr	free_msghdrs = &msghdrs[0];
1842729Sdfr
1852729Sdfr	if (msqids == NULL)
1862729Sdfr		panic("msqids is NULL");
1872729Sdfr
1882729Sdfr	for (i = 0; i < msginfo.msgmni; i++) {
1892729Sdfr		msqids[i].msg_qbytes = 0;	/* implies entry is available */
1902729Sdfr		msqids[i].msg_perm.seq = 0;	/* reset to a known value */
1912729Sdfr	}
1922729Sdfr}
19359839SpeterSYSINIT(sysv_msg, SI_SUB_SYSV_MSG, SI_ORDER_FIRST, msginit, NULL)
1942729Sdfr
1952729Sdfr/*
1962729Sdfr * Entry point for all MSG calls
1972729Sdfr */
1982729Sdfrint
19930994Sphkmsgsys(p, uap)
20011626Sbde	struct proc *p;
20111626Sbde	/* XXX actually varargs. */
20211626Sbde	struct msgsys_args /* {
20311626Sbde		u_int	which;
20411626Sbde		int	a2;
20511626Sbde		int	a3;
20611626Sbde		int	a4;
20711626Sbde		int	a5;
20811626Sbde		int	a6;
20911626Sbde	} */ *uap;
2102729Sdfr{
2112729Sdfr
2122729Sdfr	if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
2132729Sdfr		return (EINVAL);
21430994Sphk	return ((*msgcalls[uap->which])(p, &uap->a2));
2152729Sdfr}
2162729Sdfr
2172729Sdfrstatic void
2182729Sdfrmsg_freehdr(msghdr)
2192729Sdfr	struct msg *msghdr;
2202729Sdfr{
2212729Sdfr	while (msghdr->msg_ts > 0) {
2222729Sdfr		short next;
2232729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
2242729Sdfr			panic("msghdr->msg_spot out of range");
2252729Sdfr		next = msgmaps[msghdr->msg_spot].next;
2262729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
2272729Sdfr		free_msgmaps = msghdr->msg_spot;
2282729Sdfr		nfree_msgmaps++;
2292729Sdfr		msghdr->msg_spot = next;
2302729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
2312729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
2322729Sdfr		else
2332729Sdfr			msghdr->msg_ts = 0;
2342729Sdfr	}
2352729Sdfr	if (msghdr->msg_spot != -1)
2362729Sdfr		panic("msghdr->msg_spot != -1");
2372729Sdfr	msghdr->msg_next = free_msghdrs;
2382729Sdfr	free_msghdrs = msghdr;
2392729Sdfr}
2402729Sdfr
24112866Speter#ifndef _SYS_SYSPROTO_H_
2422729Sdfrstruct msgctl_args {
2432729Sdfr	int	msqid;
2442729Sdfr	int	cmd;
24512866Speter	struct	msqid_ds *buf;
2462729Sdfr};
24712866Speter#endif
2482729Sdfr
24912866Speterint
25030994Sphkmsgctl(p, uap)
2512729Sdfr	struct proc *p;
2522729Sdfr	register struct msgctl_args *uap;
2532729Sdfr{
2542729Sdfr	int msqid = uap->msqid;
2552729Sdfr	int cmd = uap->cmd;
25612866Speter	struct msqid_ds *user_msqptr = uap->buf;
2573308Sphk	int rval, eval;
2582729Sdfr	struct msqid_ds msqbuf;
2592729Sdfr	register struct msqid_ds *msqptr;
2602729Sdfr
2612729Sdfr#ifdef MSG_DEBUG_OK
2622729Sdfr	printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr);
2632729Sdfr#endif
2642729Sdfr
2652729Sdfr	msqid = IPCID_TO_IX(msqid);
2662729Sdfr
2672729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
2682729Sdfr#ifdef MSG_DEBUG_OK
2692729Sdfr		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
2702729Sdfr		    msginfo.msgmni);
2712729Sdfr#endif
2722729Sdfr		return(EINVAL);
2732729Sdfr	}
2742729Sdfr
2752729Sdfr	msqptr = &msqids[msqid];
2762729Sdfr
2772729Sdfr	if (msqptr->msg_qbytes == 0) {
2782729Sdfr#ifdef MSG_DEBUG_OK
2792729Sdfr		printf("no such msqid\n");
2802729Sdfr#endif
2812729Sdfr		return(EINVAL);
2822729Sdfr	}
2832729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
2842729Sdfr#ifdef MSG_DEBUG_OK
2852729Sdfr		printf("wrong sequence number\n");
2862729Sdfr#endif
2872729Sdfr		return(EINVAL);
2882729Sdfr	}
2892729Sdfr
2902729Sdfr	eval = 0;
2912729Sdfr	rval = 0;
2922729Sdfr
2932729Sdfr	switch (cmd) {
2942729Sdfr
2952729Sdfr	case IPC_RMID:
2962729Sdfr	{
2972729Sdfr		struct msg *msghdr;
29846116Sphk		if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_M)))
2992729Sdfr			return(eval);
3002729Sdfr		/* Free the message headers */
3012729Sdfr		msghdr = msqptr->msg_first;
3022729Sdfr		while (msghdr != NULL) {
3032729Sdfr			struct msg *msghdr_tmp;
3042729Sdfr
3052729Sdfr			/* Free the segments of each message */
3062729Sdfr			msqptr->msg_cbytes -= msghdr->msg_ts;
3072729Sdfr			msqptr->msg_qnum--;
3082729Sdfr			msghdr_tmp = msghdr;
3092729Sdfr			msghdr = msghdr->msg_next;
3102729Sdfr			msg_freehdr(msghdr_tmp);
3112729Sdfr		}
3122729Sdfr
3132729Sdfr		if (msqptr->msg_cbytes != 0)
3142729Sdfr			panic("msg_cbytes is screwed up");
3152729Sdfr		if (msqptr->msg_qnum != 0)
3162729Sdfr			panic("msg_qnum is screwed up");
3172729Sdfr
3182729Sdfr		msqptr->msg_qbytes = 0;	/* Mark it as free */
3192729Sdfr
3202729Sdfr		wakeup((caddr_t)msqptr);
3212729Sdfr	}
3222729Sdfr
3232729Sdfr		break;
3242729Sdfr
3252729Sdfr	case IPC_SET:
32646116Sphk		if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_M)))
3272729Sdfr			return(eval);
3282729Sdfr		if ((eval = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
3292729Sdfr			return(eval);
33043426Sphk		if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
33146116Sphk			eval = suser(p);
33243426Sphk			if (eval)
33343426Sphk				return(eval);
33443426Sphk		}
3352729Sdfr		if (msqbuf.msg_qbytes > msginfo.msgmnb) {
3362729Sdfr#ifdef MSG_DEBUG_OK
3372729Sdfr			printf("can't increase msg_qbytes beyond %d (truncating)\n",
3382729Sdfr			    msginfo.msgmnb);
3392729Sdfr#endif
3402729Sdfr			msqbuf.msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
3412729Sdfr		}
3422729Sdfr		if (msqbuf.msg_qbytes == 0) {
3432729Sdfr#ifdef MSG_DEBUG_OK
3442729Sdfr			printf("can't reduce msg_qbytes to 0\n");
3452729Sdfr#endif
3462729Sdfr			return(EINVAL);		/* non-standard errno! */
3472729Sdfr		}
3482729Sdfr		msqptr->msg_perm.uid = msqbuf.msg_perm.uid;	/* change the owner */
3492729Sdfr		msqptr->msg_perm.gid = msqbuf.msg_perm.gid;	/* change the owner */
3502729Sdfr		msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
3512729Sdfr		    (msqbuf.msg_perm.mode & 0777);
3522729Sdfr		msqptr->msg_qbytes = msqbuf.msg_qbytes;
35334961Sphk		msqptr->msg_ctime = time_second;
3542729Sdfr		break;
3552729Sdfr
3562729Sdfr	case IPC_STAT:
35746116Sphk		if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
3582729Sdfr#ifdef MSG_DEBUG_OK
3592729Sdfr			printf("requester doesn't have read access\n");
3602729Sdfr#endif
3612729Sdfr			return(eval);
3622729Sdfr		}
3632729Sdfr		eval = copyout((caddr_t)msqptr, user_msqptr,
3642729Sdfr		    sizeof(struct msqid_ds));
3652729Sdfr		break;
3662729Sdfr
3672729Sdfr	default:
3682729Sdfr#ifdef MSG_DEBUG_OK
3692729Sdfr		printf("invalid command %d\n", cmd);
3702729Sdfr#endif
3712729Sdfr		return(EINVAL);
3722729Sdfr	}
3732729Sdfr
3742729Sdfr	if (eval == 0)
37530994Sphk		p->p_retval[0] = rval;
3762729Sdfr	return(eval);
3772729Sdfr}
3782729Sdfr
37912866Speter#ifndef _SYS_SYSPROTO_H_
3802729Sdfrstruct msgget_args {
3812729Sdfr	key_t	key;
3822729Sdfr	int	msgflg;
3832729Sdfr};
38412866Speter#endif
3852729Sdfr
38612866Speterint
38730994Sphkmsgget(p, uap)
3882729Sdfr	struct proc *p;
3892729Sdfr	register struct msgget_args *uap;
3902729Sdfr{
3912729Sdfr	int msqid, eval;
3922729Sdfr	int key = uap->key;
3932729Sdfr	int msgflg = uap->msgflg;
3942729Sdfr	struct ucred *cred = p->p_ucred;
3952836Sdg	register struct msqid_ds *msqptr = NULL;
3962729Sdfr
3972729Sdfr#ifdef MSG_DEBUG_OK
3982729Sdfr	printf("msgget(0x%x, 0%o)\n", key, msgflg);
3992729Sdfr#endif
4002729Sdfr
4012729Sdfr	if (key != IPC_PRIVATE) {
4022729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
4032729Sdfr			msqptr = &msqids[msqid];
4042729Sdfr			if (msqptr->msg_qbytes != 0 &&
4052729Sdfr			    msqptr->msg_perm.key == key)
4062729Sdfr				break;
4072729Sdfr		}
4082729Sdfr		if (msqid < msginfo.msgmni) {
4092729Sdfr#ifdef MSG_DEBUG_OK
4102729Sdfr			printf("found public key\n");
4112729Sdfr#endif
4122729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
4132729Sdfr#ifdef MSG_DEBUG_OK
4142729Sdfr				printf("not exclusive\n");
4152729Sdfr#endif
4162729Sdfr				return(EEXIST);
4172729Sdfr			}
41846116Sphk			if ((eval = ipcperm(p, &msqptr->msg_perm, msgflg & 0700 ))) {
4192729Sdfr#ifdef MSG_DEBUG_OK
4202729Sdfr				printf("requester doesn't have 0%o access\n",
4212729Sdfr				    msgflg & 0700);
4222729Sdfr#endif
4232729Sdfr				return(eval);
4242729Sdfr			}
4252729Sdfr			goto found;
4262729Sdfr		}
4272729Sdfr	}
4282729Sdfr
4292729Sdfr#ifdef MSG_DEBUG_OK
4302729Sdfr	printf("need to allocate the msqid_ds\n");
4312729Sdfr#endif
4322729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
4332729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
4342729Sdfr			/*
4352729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
4362729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
4372729Sdfr			 * they are copying the message in/out.  We can't
4382729Sdfr			 * re-use the entry until they release it.
4392729Sdfr			 */
4402729Sdfr			msqptr = &msqids[msqid];
4412729Sdfr			if (msqptr->msg_qbytes == 0 &&
4422729Sdfr			    (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
4432729Sdfr				break;
4442729Sdfr		}
4452729Sdfr		if (msqid == msginfo.msgmni) {
4462729Sdfr#ifdef MSG_DEBUG_OK
4472729Sdfr			printf("no more msqid_ds's available\n");
4482729Sdfr#endif
4498876Srgrimes			return(ENOSPC);
4502729Sdfr		}
4512729Sdfr#ifdef MSG_DEBUG_OK
4522729Sdfr		printf("msqid %d is available\n", msqid);
4532729Sdfr#endif
4542729Sdfr		msqptr->msg_perm.key = key;
4552729Sdfr		msqptr->msg_perm.cuid = cred->cr_uid;
4562729Sdfr		msqptr->msg_perm.uid = cred->cr_uid;
4572729Sdfr		msqptr->msg_perm.cgid = cred->cr_gid;
4582729Sdfr		msqptr->msg_perm.gid = cred->cr_gid;
4592729Sdfr		msqptr->msg_perm.mode = (msgflg & 0777);
4602729Sdfr		/* Make sure that the returned msqid is unique */
4612729Sdfr		msqptr->msg_perm.seq++;
4622729Sdfr		msqptr->msg_first = NULL;
4632729Sdfr		msqptr->msg_last = NULL;
4642729Sdfr		msqptr->msg_cbytes = 0;
4652729Sdfr		msqptr->msg_qnum = 0;
4662729Sdfr		msqptr->msg_qbytes = msginfo.msgmnb;
4672729Sdfr		msqptr->msg_lspid = 0;
4682729Sdfr		msqptr->msg_lrpid = 0;
4692729Sdfr		msqptr->msg_stime = 0;
4702729Sdfr		msqptr->msg_rtime = 0;
47134961Sphk		msqptr->msg_ctime = time_second;
4722729Sdfr	} else {
4732729Sdfr#ifdef MSG_DEBUG_OK
4742729Sdfr		printf("didn't find it and wasn't asked to create it\n");
4752729Sdfr#endif
4762729Sdfr		return(ENOENT);
4772729Sdfr	}
4782729Sdfr
4792729Sdfrfound:
4802729Sdfr	/* Construct the unique msqid */
48130994Sphk	p->p_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
4822729Sdfr	return(0);
4832729Sdfr}
4842729Sdfr
48512866Speter#ifndef _SYS_SYSPROTO_H_
4862729Sdfrstruct msgsnd_args {
4872729Sdfr	int	msqid;
48812866Speter	void	*msgp;
4892729Sdfr	size_t	msgsz;
4902729Sdfr	int	msgflg;
4912729Sdfr};
49212866Speter#endif
4932729Sdfr
49412866Speterint
49530994Sphkmsgsnd(p, uap)
4962729Sdfr	struct proc *p;
4972729Sdfr	register struct msgsnd_args *uap;
4982729Sdfr{
4992729Sdfr	int msqid = uap->msqid;
50012866Speter	void *user_msgp = uap->msgp;
5012729Sdfr	size_t msgsz = uap->msgsz;
5022729Sdfr	int msgflg = uap->msgflg;
5032729Sdfr	int segs_needed, eval;
5042729Sdfr	register struct msqid_ds *msqptr;
5052729Sdfr	register struct msg *msghdr;
5062729Sdfr	short next;
5072729Sdfr
5082729Sdfr#ifdef MSG_DEBUG_OK
5092729Sdfr	printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
5102729Sdfr	    msgflg);
5112729Sdfr#endif
5122729Sdfr
5132729Sdfr	msqid = IPCID_TO_IX(msqid);
5142729Sdfr
5152729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
5162729Sdfr#ifdef MSG_DEBUG_OK
5172729Sdfr		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
5182729Sdfr		    msginfo.msgmni);
5192729Sdfr#endif
5202729Sdfr		return(EINVAL);
5212729Sdfr	}
5222729Sdfr
5232729Sdfr	msqptr = &msqids[msqid];
5242729Sdfr	if (msqptr->msg_qbytes == 0) {
5252729Sdfr#ifdef MSG_DEBUG_OK
5262729Sdfr		printf("no such message queue id\n");
5272729Sdfr#endif
5282729Sdfr		return(EINVAL);
5292729Sdfr	}
5302729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
5312729Sdfr#ifdef MSG_DEBUG_OK
5322729Sdfr		printf("wrong sequence number\n");
5332729Sdfr#endif
5342729Sdfr		return(EINVAL);
5352729Sdfr	}
5362729Sdfr
53746116Sphk	if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_W))) {
5382729Sdfr#ifdef MSG_DEBUG_OK
5392729Sdfr		printf("requester doesn't have write access\n");
5402729Sdfr#endif
5412729Sdfr		return(eval);
5422729Sdfr	}
5432729Sdfr
5442729Sdfr	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
5452729Sdfr#ifdef MSG_DEBUG_OK
5462729Sdfr	printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
5472729Sdfr	    segs_needed);
5482729Sdfr#endif
5492729Sdfr	for (;;) {
5502729Sdfr		int need_more_resources = 0;
5512729Sdfr
5522729Sdfr		/*
5532729Sdfr		 * check msgsz
5542729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
5552729Sdfr		 */
5562729Sdfr
5572836Sdg		if (msgsz > msqptr->msg_qbytes) {
5582729Sdfr#ifdef MSG_DEBUG_OK
5592729Sdfr			printf("msgsz > msqptr->msg_qbytes\n");
5602729Sdfr#endif
5612729Sdfr			return(EINVAL);
5622729Sdfr		}
5632729Sdfr
5642729Sdfr		if (msqptr->msg_perm.mode & MSG_LOCKED) {
5652729Sdfr#ifdef MSG_DEBUG_OK
5662729Sdfr			printf("msqid is locked\n");
5672729Sdfr#endif
5682729Sdfr			need_more_resources = 1;
5692729Sdfr		}
5702729Sdfr		if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
5712729Sdfr#ifdef MSG_DEBUG_OK
5722729Sdfr			printf("msgsz + msg_cbytes > msg_qbytes\n");
5732729Sdfr#endif
5742729Sdfr			need_more_resources = 1;
5752729Sdfr		}
5762729Sdfr		if (segs_needed > nfree_msgmaps) {
5772729Sdfr#ifdef MSG_DEBUG_OK
5782729Sdfr			printf("segs_needed > nfree_msgmaps\n");
5792729Sdfr#endif
5802729Sdfr			need_more_resources = 1;
5812729Sdfr		}
5822729Sdfr		if (free_msghdrs == NULL) {
5832729Sdfr#ifdef MSG_DEBUG_OK
5842729Sdfr			printf("no more msghdrs\n");
5852729Sdfr#endif
5862729Sdfr			need_more_resources = 1;
5872729Sdfr		}
5882729Sdfr
5892729Sdfr		if (need_more_resources) {
5902729Sdfr			int we_own_it;
5912729Sdfr
5922729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
5932729Sdfr#ifdef MSG_DEBUG_OK
5942729Sdfr				printf("need more resources but caller doesn't want to wait\n");
5952729Sdfr#endif
5962729Sdfr				return(EAGAIN);
5972729Sdfr			}
5982729Sdfr
5992729Sdfr			if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
6002729Sdfr#ifdef MSG_DEBUG_OK
6012729Sdfr				printf("we don't own the msqid_ds\n");
6022729Sdfr#endif
6032729Sdfr				we_own_it = 0;
6042729Sdfr			} else {
6052729Sdfr				/* Force later arrivals to wait for our
6062729Sdfr				   request */
6072729Sdfr#ifdef MSG_DEBUG_OK
6082729Sdfr				printf("we own the msqid_ds\n");
6092729Sdfr#endif
6102729Sdfr				msqptr->msg_perm.mode |= MSG_LOCKED;
6112729Sdfr				we_own_it = 1;
6122729Sdfr			}
6132729Sdfr#ifdef MSG_DEBUG_OK
6142729Sdfr			printf("goodnight\n");
6152729Sdfr#endif
6162729Sdfr			eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH,
6172729Sdfr			    "msgwait", 0);
6182729Sdfr#ifdef MSG_DEBUG_OK
6192729Sdfr			printf("good morning, eval=%d\n", eval);
6202729Sdfr#endif
6212729Sdfr			if (we_own_it)
6222729Sdfr				msqptr->msg_perm.mode &= ~MSG_LOCKED;
6232729Sdfr			if (eval != 0) {
6242729Sdfr#ifdef MSG_DEBUG_OK
6252729Sdfr				printf("msgsnd:  interrupted system call\n");
6262729Sdfr#endif
6272729Sdfr				return(EINTR);
6282729Sdfr			}
6292729Sdfr
6302729Sdfr			/*
6312729Sdfr			 * Make sure that the msq queue still exists
6322729Sdfr			 */
6332729Sdfr
6342729Sdfr			if (msqptr->msg_qbytes == 0) {
6352729Sdfr#ifdef MSG_DEBUG_OK
6362729Sdfr				printf("msqid deleted\n");
6372729Sdfr#endif
6382729Sdfr				return(EIDRM);
6392729Sdfr			}
6402729Sdfr
6412729Sdfr		} else {
6422729Sdfr#ifdef MSG_DEBUG_OK
6432729Sdfr			printf("got all the resources that we need\n");
6442729Sdfr#endif
6452729Sdfr			break;
6462729Sdfr		}
6472729Sdfr	}
6482729Sdfr
6492729Sdfr	/*
6502729Sdfr	 * We have the resources that we need.
6512729Sdfr	 * Make sure!
6522729Sdfr	 */
6532729Sdfr
6542729Sdfr	if (msqptr->msg_perm.mode & MSG_LOCKED)
6552729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
6562729Sdfr	if (segs_needed > nfree_msgmaps)
6572729Sdfr		panic("segs_needed > nfree_msgmaps");
6582729Sdfr	if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
6592729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
6602729Sdfr	if (free_msghdrs == NULL)
6612729Sdfr		panic("no more msghdrs");
6622729Sdfr
6632729Sdfr	/*
6642729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
6652729Sdfr	 * message
6662729Sdfr	 */
6672729Sdfr
6682729Sdfr	if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
6692729Sdfr		panic("msqid_ds is already locked");
6702729Sdfr	msqptr->msg_perm.mode |= MSG_LOCKED;
6712729Sdfr
6722729Sdfr	/*
6732729Sdfr	 * Allocate a message header
6742729Sdfr	 */
6752729Sdfr
6762729Sdfr	msghdr = free_msghdrs;
6772729Sdfr	free_msghdrs = msghdr->msg_next;
6782729Sdfr	msghdr->msg_spot = -1;
6792729Sdfr	msghdr->msg_ts = msgsz;
6802729Sdfr
6812729Sdfr	/*
6822729Sdfr	 * Allocate space for the message
6832729Sdfr	 */
6842729Sdfr
6852729Sdfr	while (segs_needed > 0) {
6862729Sdfr		if (nfree_msgmaps <= 0)
6872729Sdfr			panic("not enough msgmaps");
6882729Sdfr		if (free_msgmaps == -1)
6892729Sdfr			panic("nil free_msgmaps");
6902729Sdfr		next = free_msgmaps;
6912729Sdfr		if (next <= -1)
6922729Sdfr			panic("next too low #1");
6932729Sdfr		if (next >= msginfo.msgseg)
6942729Sdfr			panic("next out of range #1");
6952729Sdfr#ifdef MSG_DEBUG_OK
6962729Sdfr		printf("allocating segment %d to message\n", next);
6972729Sdfr#endif
6982729Sdfr		free_msgmaps = msgmaps[next].next;
6992729Sdfr		nfree_msgmaps--;
7002729Sdfr		msgmaps[next].next = msghdr->msg_spot;
7012729Sdfr		msghdr->msg_spot = next;
7022729Sdfr		segs_needed--;
7032729Sdfr	}
7042729Sdfr
7052729Sdfr	/*
7062729Sdfr	 * Copy in the message type
7072729Sdfr	 */
7082729Sdfr
7092729Sdfr	if ((eval = copyin(user_msgp, &msghdr->msg_type,
7102729Sdfr	    sizeof(msghdr->msg_type))) != 0) {
7112729Sdfr#ifdef MSG_DEBUG_OK
7122729Sdfr		printf("error %d copying the message type\n", eval);
7132729Sdfr#endif
7142729Sdfr		msg_freehdr(msghdr);
7152729Sdfr		msqptr->msg_perm.mode &= ~MSG_LOCKED;
7162729Sdfr		wakeup((caddr_t)msqptr);
7172729Sdfr		return(eval);
7182729Sdfr	}
71917971Sbde	user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
7202729Sdfr
7212729Sdfr	/*
7222729Sdfr	 * Validate the message type
7232729Sdfr	 */
7242729Sdfr
7252729Sdfr	if (msghdr->msg_type < 1) {
7262729Sdfr		msg_freehdr(msghdr);
7272729Sdfr		msqptr->msg_perm.mode &= ~MSG_LOCKED;
7282729Sdfr		wakeup((caddr_t)msqptr);
7292729Sdfr#ifdef MSG_DEBUG_OK
7302729Sdfr		printf("mtype (%d) < 1\n", msghdr->msg_type);
7312729Sdfr#endif
7322729Sdfr		return(EINVAL);
7332729Sdfr	}
7342729Sdfr
7352729Sdfr	/*
7362729Sdfr	 * Copy in the message body
7372729Sdfr	 */
7382729Sdfr
7392729Sdfr	next = msghdr->msg_spot;
7402729Sdfr	while (msgsz > 0) {
7412729Sdfr		size_t tlen;
7422729Sdfr		if (msgsz > msginfo.msgssz)
7432729Sdfr			tlen = msginfo.msgssz;
7442729Sdfr		else
7452729Sdfr			tlen = msgsz;
7462729Sdfr		if (next <= -1)
7472729Sdfr			panic("next too low #2");
7482729Sdfr		if (next >= msginfo.msgseg)
7492729Sdfr			panic("next out of range #2");
7502729Sdfr		if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
7512729Sdfr		    tlen)) != 0) {
7522729Sdfr#ifdef MSG_DEBUG_OK
7532729Sdfr			printf("error %d copying in message segment\n", eval);
7542729Sdfr#endif
7552729Sdfr			msg_freehdr(msghdr);
7562729Sdfr			msqptr->msg_perm.mode &= ~MSG_LOCKED;
7572729Sdfr			wakeup((caddr_t)msqptr);
7582729Sdfr			return(eval);
7592729Sdfr		}
7602729Sdfr		msgsz -= tlen;
76117971Sbde		user_msgp = (char *)user_msgp + tlen;
7622729Sdfr		next = msgmaps[next].next;
7632729Sdfr	}
7642729Sdfr	if (next != -1)
7652729Sdfr		panic("didn't use all the msg segments");
7662729Sdfr
7672729Sdfr	/*
7682729Sdfr	 * We've got the message.  Unlock the msqid_ds.
7692729Sdfr	 */
7702729Sdfr
7712729Sdfr	msqptr->msg_perm.mode &= ~MSG_LOCKED;
7722729Sdfr
7732729Sdfr	/*
7742729Sdfr	 * Make sure that the msqid_ds is still allocated.
7752729Sdfr	 */
7762729Sdfr
7772729Sdfr	if (msqptr->msg_qbytes == 0) {
7782729Sdfr		msg_freehdr(msghdr);
7792729Sdfr		wakeup((caddr_t)msqptr);
7802729Sdfr		return(EIDRM);
7812729Sdfr	}
7822729Sdfr
7832729Sdfr	/*
7842729Sdfr	 * Put the message into the queue
7852729Sdfr	 */
7862729Sdfr
7872729Sdfr	if (msqptr->msg_first == NULL) {
7882729Sdfr		msqptr->msg_first = msghdr;
7892729Sdfr		msqptr->msg_last = msghdr;
7902729Sdfr	} else {
7912729Sdfr		msqptr->msg_last->msg_next = msghdr;
7922729Sdfr		msqptr->msg_last = msghdr;
7932729Sdfr	}
7942729Sdfr	msqptr->msg_last->msg_next = NULL;
7952729Sdfr
7962729Sdfr	msqptr->msg_cbytes += msghdr->msg_ts;
7972729Sdfr	msqptr->msg_qnum++;
7982729Sdfr	msqptr->msg_lspid = p->p_pid;
79934961Sphk	msqptr->msg_stime = time_second;
8002729Sdfr
8012729Sdfr	wakeup((caddr_t)msqptr);
80230994Sphk	p->p_retval[0] = 0;
8032729Sdfr	return(0);
8042729Sdfr}
8052729Sdfr
80612866Speter#ifndef _SYS_SYSPROTO_H_
8072729Sdfrstruct msgrcv_args {
8082729Sdfr	int	msqid;
8092729Sdfr	void	*msgp;
8102729Sdfr	size_t	msgsz;
8112729Sdfr	long	msgtyp;
8122729Sdfr	int	msgflg;
8132729Sdfr};
81412866Speter#endif
8152729Sdfr
81612866Speterint
81730994Sphkmsgrcv(p, uap)
8182729Sdfr	struct proc *p;
8192729Sdfr	register struct msgrcv_args *uap;
8202729Sdfr{
8212729Sdfr	int msqid = uap->msqid;
8222729Sdfr	void *user_msgp = uap->msgp;
8232729Sdfr	size_t msgsz = uap->msgsz;
8242729Sdfr	long msgtyp = uap->msgtyp;
8252729Sdfr	int msgflg = uap->msgflg;
8262729Sdfr	size_t len;
8272729Sdfr	register struct msqid_ds *msqptr;
8282729Sdfr	register struct msg *msghdr;
8292729Sdfr	int eval;
8302729Sdfr	short next;
8312729Sdfr
8322729Sdfr#ifdef MSG_DEBUG_OK
8332729Sdfr	printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
8342729Sdfr	    msgsz, msgtyp, msgflg);
8352729Sdfr#endif
8362729Sdfr
8372729Sdfr	msqid = IPCID_TO_IX(msqid);
8382729Sdfr
8392729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
8402729Sdfr#ifdef MSG_DEBUG_OK
8412729Sdfr		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
8422729Sdfr		    msginfo.msgmni);
8432729Sdfr#endif
8442729Sdfr		return(EINVAL);
8452729Sdfr	}
8462729Sdfr
8472729Sdfr	msqptr = &msqids[msqid];
8482729Sdfr	if (msqptr->msg_qbytes == 0) {
8492729Sdfr#ifdef MSG_DEBUG_OK
8502729Sdfr		printf("no such message queue id\n");
8512729Sdfr#endif
8522729Sdfr		return(EINVAL);
8532729Sdfr	}
8542729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
8552729Sdfr#ifdef MSG_DEBUG_OK
8562729Sdfr		printf("wrong sequence number\n");
8572729Sdfr#endif
8582729Sdfr		return(EINVAL);
8592729Sdfr	}
8602729Sdfr
86146116Sphk	if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
8622729Sdfr#ifdef MSG_DEBUG_OK
8632729Sdfr		printf("requester doesn't have read access\n");
8642729Sdfr#endif
8652729Sdfr		return(eval);
8662729Sdfr	}
8672729Sdfr
8682729Sdfr	msghdr = NULL;
8692729Sdfr	while (msghdr == NULL) {
8702729Sdfr		if (msgtyp == 0) {
8712729Sdfr			msghdr = msqptr->msg_first;
8722729Sdfr			if (msghdr != NULL) {
8732729Sdfr				if (msgsz < msghdr->msg_ts &&
8742729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
8752729Sdfr#ifdef MSG_DEBUG_OK
8762729Sdfr					printf("first message on the queue is too big (want %d, got %d)\n",
8772729Sdfr					    msgsz, msghdr->msg_ts);
8782729Sdfr#endif
8792729Sdfr					return(E2BIG);
8802729Sdfr				}
8812729Sdfr				if (msqptr->msg_first == msqptr->msg_last) {
8822729Sdfr					msqptr->msg_first = NULL;
8832729Sdfr					msqptr->msg_last = NULL;
8842729Sdfr				} else {
8852729Sdfr					msqptr->msg_first = msghdr->msg_next;
8862729Sdfr					if (msqptr->msg_first == NULL)
8872729Sdfr						panic("msg_first/last screwed up #1");
8882729Sdfr				}
8892729Sdfr			}
8902729Sdfr		} else {
8912729Sdfr			struct msg *previous;
8922729Sdfr			struct msg **prev;
8932729Sdfr
8942729Sdfr			previous = NULL;
8952729Sdfr			prev = &(msqptr->msg_first);
8962729Sdfr			while ((msghdr = *prev) != NULL) {
8972729Sdfr				/*
8982729Sdfr				 * Is this message's type an exact match or is
8992729Sdfr				 * this message's type less than or equal to
9002729Sdfr				 * the absolute value of a negative msgtyp?
9012729Sdfr				 * Note that the second half of this test can
9022729Sdfr				 * NEVER be true if msgtyp is positive since
9032729Sdfr				 * msg_type is always positive!
9042729Sdfr				 */
9052729Sdfr
9062729Sdfr				if (msgtyp == msghdr->msg_type ||
9072729Sdfr				    msghdr->msg_type <= -msgtyp) {
9082729Sdfr#ifdef MSG_DEBUG_OK
9092729Sdfr					printf("found message type %d, requested %d\n",
9102729Sdfr					    msghdr->msg_type, msgtyp);
9112729Sdfr#endif
9122729Sdfr					if (msgsz < msghdr->msg_ts &&
9132729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
9142729Sdfr#ifdef MSG_DEBUG_OK
9152729Sdfr						printf("requested message on the queue is too big (want %d, got %d)\n",
9162729Sdfr						    msgsz, msghdr->msg_ts);
9172729Sdfr#endif
9182729Sdfr						return(E2BIG);
9192729Sdfr					}
9202729Sdfr					*prev = msghdr->msg_next;
9212729Sdfr					if (msghdr == msqptr->msg_last) {
9222729Sdfr						if (previous == NULL) {
9232729Sdfr							if (prev !=
9242729Sdfr							    &msqptr->msg_first)
9252729Sdfr								panic("msg_first/last screwed up #2");
9262729Sdfr							msqptr->msg_first =
9272729Sdfr							    NULL;
9282729Sdfr							msqptr->msg_last =
9292729Sdfr							    NULL;
9302729Sdfr						} else {
9312729Sdfr							if (prev ==
9322729Sdfr							    &msqptr->msg_first)
9332729Sdfr								panic("msg_first/last screwed up #3");
9342729Sdfr							msqptr->msg_last =
9352729Sdfr							    previous;
9362729Sdfr						}
9372729Sdfr					}
9382729Sdfr					break;
9392729Sdfr				}
9402729Sdfr				previous = msghdr;
9412729Sdfr				prev = &(msghdr->msg_next);
9422729Sdfr			}
9432729Sdfr		}
9442729Sdfr
9452729Sdfr		/*
9462729Sdfr		 * We've either extracted the msghdr for the appropriate
9472729Sdfr		 * message or there isn't one.
9482729Sdfr		 * If there is one then bail out of this loop.
9492729Sdfr		 */
9502729Sdfr
9512729Sdfr		if (msghdr != NULL)
9522729Sdfr			break;
9532729Sdfr
9542729Sdfr		/*
9552729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
9562729Sdfr		 */
9572729Sdfr
9582729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
9592729Sdfr#ifdef MSG_DEBUG_OK
9602729Sdfr			printf("no appropriate message found (msgtyp=%d)\n",
9612729Sdfr			    msgtyp);
9622729Sdfr#endif
9632729Sdfr			/* The SVID says to return ENOMSG. */
9642729Sdfr#ifdef ENOMSG
9652729Sdfr			return(ENOMSG);
9662729Sdfr#else
9672729Sdfr			/* Unfortunately, BSD doesn't define that code yet! */
9682729Sdfr			return(EAGAIN);
9692729Sdfr#endif
9702729Sdfr		}
9712729Sdfr
9722729Sdfr		/*
9732729Sdfr		 * Wait for something to happen
9742729Sdfr		 */
9752729Sdfr
9762729Sdfr#ifdef MSG_DEBUG_OK
9772729Sdfr		printf("msgrcv:  goodnight\n");
9782729Sdfr#endif
9792729Sdfr		eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, "msgwait",
9802729Sdfr		    0);
9812729Sdfr#ifdef MSG_DEBUG_OK
9822729Sdfr		printf("msgrcv:  good morning (eval=%d)\n", eval);
9832729Sdfr#endif
9842729Sdfr
9852729Sdfr		if (eval != 0) {
9862729Sdfr#ifdef MSG_DEBUG_OK
9872729Sdfr			printf("msgsnd:  interrupted system call\n");
9882729Sdfr#endif
9892729Sdfr			return(EINTR);
9902729Sdfr		}
9912729Sdfr
9922729Sdfr		/*
9932729Sdfr		 * Make sure that the msq queue still exists
9942729Sdfr		 */
9952729Sdfr
9962729Sdfr		if (msqptr->msg_qbytes == 0 ||
9972729Sdfr		    msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
9982729Sdfr#ifdef MSG_DEBUG_OK
9992729Sdfr			printf("msqid deleted\n");
10002729Sdfr#endif
10012729Sdfr			return(EIDRM);
10022729Sdfr		}
10032729Sdfr	}
10042729Sdfr
10052729Sdfr	/*
10062729Sdfr	 * Return the message to the user.
10072729Sdfr	 *
10082729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
10092729Sdfr	 */
10102729Sdfr
10112729Sdfr	msqptr->msg_cbytes -= msghdr->msg_ts;
10122729Sdfr	msqptr->msg_qnum--;
10132729Sdfr	msqptr->msg_lrpid = p->p_pid;
101434961Sphk	msqptr->msg_rtime = time_second;
10152729Sdfr
10162729Sdfr	/*
10172729Sdfr	 * Make msgsz the actual amount that we'll be returning.
10182729Sdfr	 * Note that this effectively truncates the message if it is too long
10192729Sdfr	 * (since msgsz is never increased).
10202729Sdfr	 */
10212729Sdfr
10222729Sdfr#ifdef MSG_DEBUG_OK
10232729Sdfr	printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
10242729Sdfr	    msghdr->msg_ts);
10252729Sdfr#endif
10262729Sdfr	if (msgsz > msghdr->msg_ts)
10272729Sdfr		msgsz = msghdr->msg_ts;
10282729Sdfr
10292729Sdfr	/*
10302729Sdfr	 * Return the type to the user.
10312729Sdfr	 */
10322729Sdfr
10332729Sdfr	eval = copyout((caddr_t)&(msghdr->msg_type), user_msgp,
10342729Sdfr	    sizeof(msghdr->msg_type));
10352729Sdfr	if (eval != 0) {
10362729Sdfr#ifdef MSG_DEBUG_OK
10372729Sdfr		printf("error (%d) copying out message type\n", eval);
10382729Sdfr#endif
10392729Sdfr		msg_freehdr(msghdr);
10402729Sdfr		wakeup((caddr_t)msqptr);
10412729Sdfr		return(eval);
10422729Sdfr	}
104317971Sbde	user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
10442729Sdfr
10452729Sdfr	/*
10462729Sdfr	 * Return the segments to the user
10472729Sdfr	 */
10482729Sdfr
10492729Sdfr	next = msghdr->msg_spot;
10502729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
10512729Sdfr		size_t tlen;
10522729Sdfr
105345921Ssada		if (msgsz - len > msginfo.msgssz)
10542729Sdfr			tlen = msginfo.msgssz;
10552729Sdfr		else
105645921Ssada			tlen = msgsz - len;
10572729Sdfr		if (next <= -1)
10582729Sdfr			panic("next too low #3");
10592729Sdfr		if (next >= msginfo.msgseg)
10602729Sdfr			panic("next out of range #3");
10612729Sdfr		eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz],
10622729Sdfr		    user_msgp, tlen);
10632729Sdfr		if (eval != 0) {
10642729Sdfr#ifdef MSG_DEBUG_OK
10652729Sdfr			printf("error (%d) copying out message segment\n",
10662729Sdfr			    eval);
10672729Sdfr#endif
10682729Sdfr			msg_freehdr(msghdr);
10692729Sdfr			wakeup((caddr_t)msqptr);
10702729Sdfr			return(eval);
10712729Sdfr		}
107217971Sbde		user_msgp = (char *)user_msgp + tlen;
10732729Sdfr		next = msgmaps[next].next;
10742729Sdfr	}
10752729Sdfr
10762729Sdfr	/*
10772729Sdfr	 * Done, return the actual number of bytes copied out.
10782729Sdfr	 */
10792729Sdfr
10802729Sdfr	msg_freehdr(msghdr);
10812729Sdfr	wakeup((caddr_t)msqptr);
108230994Sphk	p->p_retval[0] = msgsz;
10832729Sdfr	return(0);
10842729Sdfr}
1085