sysv_msg.c revision 66085
150477Speter/* $FreeBSD: head/sys/kern/sysv_msg.c 66085 2000-09-19 22:59:22Z 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 */
19166085Speter		msqids[i].msg_perm.mode = 0;
1922729Sdfr	}
1932729Sdfr}
19459839SpeterSYSINIT(sysv_msg, SI_SUB_SYSV_MSG, SI_ORDER_FIRST, msginit, NULL)
1952729Sdfr
1962729Sdfr/*
1972729Sdfr * Entry point for all MSG calls
1982729Sdfr */
1992729Sdfrint
20030994Sphkmsgsys(p, uap)
20111626Sbde	struct proc *p;
20211626Sbde	/* XXX actually varargs. */
20311626Sbde	struct msgsys_args /* {
20411626Sbde		u_int	which;
20511626Sbde		int	a2;
20611626Sbde		int	a3;
20711626Sbde		int	a4;
20811626Sbde		int	a5;
20911626Sbde		int	a6;
21011626Sbde	} */ *uap;
2112729Sdfr{
2122729Sdfr
2132729Sdfr	if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
2142729Sdfr		return (EINVAL);
21530994Sphk	return ((*msgcalls[uap->which])(p, &uap->a2));
2162729Sdfr}
2172729Sdfr
2182729Sdfrstatic void
2192729Sdfrmsg_freehdr(msghdr)
2202729Sdfr	struct msg *msghdr;
2212729Sdfr{
2222729Sdfr	while (msghdr->msg_ts > 0) {
2232729Sdfr		short next;
2242729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
2252729Sdfr			panic("msghdr->msg_spot out of range");
2262729Sdfr		next = msgmaps[msghdr->msg_spot].next;
2272729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
2282729Sdfr		free_msgmaps = msghdr->msg_spot;
2292729Sdfr		nfree_msgmaps++;
2302729Sdfr		msghdr->msg_spot = next;
2312729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
2322729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
2332729Sdfr		else
2342729Sdfr			msghdr->msg_ts = 0;
2352729Sdfr	}
2362729Sdfr	if (msghdr->msg_spot != -1)
2372729Sdfr		panic("msghdr->msg_spot != -1");
2382729Sdfr	msghdr->msg_next = free_msghdrs;
2392729Sdfr	free_msghdrs = msghdr;
2402729Sdfr}
2412729Sdfr
24212866Speter#ifndef _SYS_SYSPROTO_H_
2432729Sdfrstruct msgctl_args {
2442729Sdfr	int	msqid;
2452729Sdfr	int	cmd;
24612866Speter	struct	msqid_ds *buf;
2472729Sdfr};
24812866Speter#endif
2492729Sdfr
25012866Speterint
25130994Sphkmsgctl(p, uap)
2522729Sdfr	struct proc *p;
2532729Sdfr	register struct msgctl_args *uap;
2542729Sdfr{
2552729Sdfr	int msqid = uap->msqid;
2562729Sdfr	int cmd = uap->cmd;
25712866Speter	struct msqid_ds *user_msqptr = uap->buf;
2583308Sphk	int rval, eval;
2592729Sdfr	struct msqid_ds msqbuf;
2602729Sdfr	register struct msqid_ds *msqptr;
2612729Sdfr
2622729Sdfr#ifdef MSG_DEBUG_OK
2632729Sdfr	printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr);
2642729Sdfr#endif
2652729Sdfr
2662729Sdfr	msqid = IPCID_TO_IX(msqid);
2672729Sdfr
2682729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
2692729Sdfr#ifdef MSG_DEBUG_OK
2702729Sdfr		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
2712729Sdfr		    msginfo.msgmni);
2722729Sdfr#endif
2732729Sdfr		return(EINVAL);
2742729Sdfr	}
2752729Sdfr
2762729Sdfr	msqptr = &msqids[msqid];
2772729Sdfr
2782729Sdfr	if (msqptr->msg_qbytes == 0) {
2792729Sdfr#ifdef MSG_DEBUG_OK
2802729Sdfr		printf("no such msqid\n");
2812729Sdfr#endif
2822729Sdfr		return(EINVAL);
2832729Sdfr	}
2842729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
2852729Sdfr#ifdef MSG_DEBUG_OK
2862729Sdfr		printf("wrong sequence number\n");
2872729Sdfr#endif
2882729Sdfr		return(EINVAL);
2892729Sdfr	}
2902729Sdfr
2912729Sdfr	eval = 0;
2922729Sdfr	rval = 0;
2932729Sdfr
2942729Sdfr	switch (cmd) {
2952729Sdfr
2962729Sdfr	case IPC_RMID:
2972729Sdfr	{
2982729Sdfr		struct msg *msghdr;
29946116Sphk		if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_M)))
3002729Sdfr			return(eval);
3012729Sdfr		/* Free the message headers */
3022729Sdfr		msghdr = msqptr->msg_first;
3032729Sdfr		while (msghdr != NULL) {
3042729Sdfr			struct msg *msghdr_tmp;
3052729Sdfr
3062729Sdfr			/* Free the segments of each message */
3072729Sdfr			msqptr->msg_cbytes -= msghdr->msg_ts;
3082729Sdfr			msqptr->msg_qnum--;
3092729Sdfr			msghdr_tmp = msghdr;
3102729Sdfr			msghdr = msghdr->msg_next;
3112729Sdfr			msg_freehdr(msghdr_tmp);
3122729Sdfr		}
3132729Sdfr
3142729Sdfr		if (msqptr->msg_cbytes != 0)
3152729Sdfr			panic("msg_cbytes is screwed up");
3162729Sdfr		if (msqptr->msg_qnum != 0)
3172729Sdfr			panic("msg_qnum is screwed up");
3182729Sdfr
3192729Sdfr		msqptr->msg_qbytes = 0;	/* Mark it as free */
3202729Sdfr
3212729Sdfr		wakeup((caddr_t)msqptr);
3222729Sdfr	}
3232729Sdfr
3242729Sdfr		break;
3252729Sdfr
3262729Sdfr	case IPC_SET:
32746116Sphk		if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_M)))
3282729Sdfr			return(eval);
3292729Sdfr		if ((eval = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
3302729Sdfr			return(eval);
33143426Sphk		if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
33246116Sphk			eval = suser(p);
33343426Sphk			if (eval)
33443426Sphk				return(eval);
33543426Sphk		}
3362729Sdfr		if (msqbuf.msg_qbytes > msginfo.msgmnb) {
3372729Sdfr#ifdef MSG_DEBUG_OK
3382729Sdfr			printf("can't increase msg_qbytes beyond %d (truncating)\n",
3392729Sdfr			    msginfo.msgmnb);
3402729Sdfr#endif
3412729Sdfr			msqbuf.msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
3422729Sdfr		}
3432729Sdfr		if (msqbuf.msg_qbytes == 0) {
3442729Sdfr#ifdef MSG_DEBUG_OK
3452729Sdfr			printf("can't reduce msg_qbytes to 0\n");
3462729Sdfr#endif
3472729Sdfr			return(EINVAL);		/* non-standard errno! */
3482729Sdfr		}
3492729Sdfr		msqptr->msg_perm.uid = msqbuf.msg_perm.uid;	/* change the owner */
3502729Sdfr		msqptr->msg_perm.gid = msqbuf.msg_perm.gid;	/* change the owner */
3512729Sdfr		msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
3522729Sdfr		    (msqbuf.msg_perm.mode & 0777);
3532729Sdfr		msqptr->msg_qbytes = msqbuf.msg_qbytes;
35434961Sphk		msqptr->msg_ctime = time_second;
3552729Sdfr		break;
3562729Sdfr
3572729Sdfr	case IPC_STAT:
35846116Sphk		if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
3592729Sdfr#ifdef MSG_DEBUG_OK
3602729Sdfr			printf("requester doesn't have read access\n");
3612729Sdfr#endif
3622729Sdfr			return(eval);
3632729Sdfr		}
3642729Sdfr		eval = copyout((caddr_t)msqptr, user_msqptr,
3652729Sdfr		    sizeof(struct msqid_ds));
3662729Sdfr		break;
3672729Sdfr
3682729Sdfr	default:
3692729Sdfr#ifdef MSG_DEBUG_OK
3702729Sdfr		printf("invalid command %d\n", cmd);
3712729Sdfr#endif
3722729Sdfr		return(EINVAL);
3732729Sdfr	}
3742729Sdfr
3752729Sdfr	if (eval == 0)
37630994Sphk		p->p_retval[0] = rval;
3772729Sdfr	return(eval);
3782729Sdfr}
3792729Sdfr
38012866Speter#ifndef _SYS_SYSPROTO_H_
3812729Sdfrstruct msgget_args {
3822729Sdfr	key_t	key;
3832729Sdfr	int	msgflg;
3842729Sdfr};
38512866Speter#endif
3862729Sdfr
38712866Speterint
38830994Sphkmsgget(p, uap)
3892729Sdfr	struct proc *p;
3902729Sdfr	register struct msgget_args *uap;
3912729Sdfr{
3922729Sdfr	int msqid, eval;
3932729Sdfr	int key = uap->key;
3942729Sdfr	int msgflg = uap->msgflg;
3952729Sdfr	struct ucred *cred = p->p_ucred;
3962836Sdg	register struct msqid_ds *msqptr = NULL;
3972729Sdfr
3982729Sdfr#ifdef MSG_DEBUG_OK
3992729Sdfr	printf("msgget(0x%x, 0%o)\n", key, msgflg);
4002729Sdfr#endif
4012729Sdfr
4022729Sdfr	if (key != IPC_PRIVATE) {
4032729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
4042729Sdfr			msqptr = &msqids[msqid];
4052729Sdfr			if (msqptr->msg_qbytes != 0 &&
4062729Sdfr			    msqptr->msg_perm.key == key)
4072729Sdfr				break;
4082729Sdfr		}
4092729Sdfr		if (msqid < msginfo.msgmni) {
4102729Sdfr#ifdef MSG_DEBUG_OK
4112729Sdfr			printf("found public key\n");
4122729Sdfr#endif
4132729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
4142729Sdfr#ifdef MSG_DEBUG_OK
4152729Sdfr				printf("not exclusive\n");
4162729Sdfr#endif
4172729Sdfr				return(EEXIST);
4182729Sdfr			}
41946116Sphk			if ((eval = ipcperm(p, &msqptr->msg_perm, msgflg & 0700 ))) {
4202729Sdfr#ifdef MSG_DEBUG_OK
4212729Sdfr				printf("requester doesn't have 0%o access\n",
4222729Sdfr				    msgflg & 0700);
4232729Sdfr#endif
4242729Sdfr				return(eval);
4252729Sdfr			}
4262729Sdfr			goto found;
4272729Sdfr		}
4282729Sdfr	}
4292729Sdfr
4302729Sdfr#ifdef MSG_DEBUG_OK
4312729Sdfr	printf("need to allocate the msqid_ds\n");
4322729Sdfr#endif
4332729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
4342729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
4352729Sdfr			/*
4362729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
4372729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
4382729Sdfr			 * they are copying the message in/out.  We can't
4392729Sdfr			 * re-use the entry until they release it.
4402729Sdfr			 */
4412729Sdfr			msqptr = &msqids[msqid];
4422729Sdfr			if (msqptr->msg_qbytes == 0 &&
4432729Sdfr			    (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
4442729Sdfr				break;
4452729Sdfr		}
4462729Sdfr		if (msqid == msginfo.msgmni) {
4472729Sdfr#ifdef MSG_DEBUG_OK
4482729Sdfr			printf("no more msqid_ds's available\n");
4492729Sdfr#endif
4508876Srgrimes			return(ENOSPC);
4512729Sdfr		}
4522729Sdfr#ifdef MSG_DEBUG_OK
4532729Sdfr		printf("msqid %d is available\n", msqid);
4542729Sdfr#endif
4552729Sdfr		msqptr->msg_perm.key = key;
4562729Sdfr		msqptr->msg_perm.cuid = cred->cr_uid;
4572729Sdfr		msqptr->msg_perm.uid = cred->cr_uid;
4582729Sdfr		msqptr->msg_perm.cgid = cred->cr_gid;
4592729Sdfr		msqptr->msg_perm.gid = cred->cr_gid;
4602729Sdfr		msqptr->msg_perm.mode = (msgflg & 0777);
4612729Sdfr		/* Make sure that the returned msqid is unique */
4622729Sdfr		msqptr->msg_perm.seq++;
4632729Sdfr		msqptr->msg_first = NULL;
4642729Sdfr		msqptr->msg_last = NULL;
4652729Sdfr		msqptr->msg_cbytes = 0;
4662729Sdfr		msqptr->msg_qnum = 0;
4672729Sdfr		msqptr->msg_qbytes = msginfo.msgmnb;
4682729Sdfr		msqptr->msg_lspid = 0;
4692729Sdfr		msqptr->msg_lrpid = 0;
4702729Sdfr		msqptr->msg_stime = 0;
4712729Sdfr		msqptr->msg_rtime = 0;
47234961Sphk		msqptr->msg_ctime = time_second;
4732729Sdfr	} else {
4742729Sdfr#ifdef MSG_DEBUG_OK
4752729Sdfr		printf("didn't find it and wasn't asked to create it\n");
4762729Sdfr#endif
4772729Sdfr		return(ENOENT);
4782729Sdfr	}
4792729Sdfr
4802729Sdfrfound:
4812729Sdfr	/* Construct the unique msqid */
48230994Sphk	p->p_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
4832729Sdfr	return(0);
4842729Sdfr}
4852729Sdfr
48612866Speter#ifndef _SYS_SYSPROTO_H_
4872729Sdfrstruct msgsnd_args {
4882729Sdfr	int	msqid;
48912866Speter	void	*msgp;
4902729Sdfr	size_t	msgsz;
4912729Sdfr	int	msgflg;
4922729Sdfr};
49312866Speter#endif
4942729Sdfr
49512866Speterint
49630994Sphkmsgsnd(p, uap)
4972729Sdfr	struct proc *p;
4982729Sdfr	register struct msgsnd_args *uap;
4992729Sdfr{
5002729Sdfr	int msqid = uap->msqid;
50112866Speter	void *user_msgp = uap->msgp;
5022729Sdfr	size_t msgsz = uap->msgsz;
5032729Sdfr	int msgflg = uap->msgflg;
5042729Sdfr	int segs_needed, eval;
5052729Sdfr	register struct msqid_ds *msqptr;
5062729Sdfr	register struct msg *msghdr;
5072729Sdfr	short next;
5082729Sdfr
5092729Sdfr#ifdef MSG_DEBUG_OK
5102729Sdfr	printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
5112729Sdfr	    msgflg);
5122729Sdfr#endif
5132729Sdfr
5142729Sdfr	msqid = IPCID_TO_IX(msqid);
5152729Sdfr
5162729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
5172729Sdfr#ifdef MSG_DEBUG_OK
5182729Sdfr		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
5192729Sdfr		    msginfo.msgmni);
5202729Sdfr#endif
5212729Sdfr		return(EINVAL);
5222729Sdfr	}
5232729Sdfr
5242729Sdfr	msqptr = &msqids[msqid];
5252729Sdfr	if (msqptr->msg_qbytes == 0) {
5262729Sdfr#ifdef MSG_DEBUG_OK
5272729Sdfr		printf("no such message queue id\n");
5282729Sdfr#endif
5292729Sdfr		return(EINVAL);
5302729Sdfr	}
5312729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
5322729Sdfr#ifdef MSG_DEBUG_OK
5332729Sdfr		printf("wrong sequence number\n");
5342729Sdfr#endif
5352729Sdfr		return(EINVAL);
5362729Sdfr	}
5372729Sdfr
53846116Sphk	if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_W))) {
5392729Sdfr#ifdef MSG_DEBUG_OK
5402729Sdfr		printf("requester doesn't have write access\n");
5412729Sdfr#endif
5422729Sdfr		return(eval);
5432729Sdfr	}
5442729Sdfr
5452729Sdfr	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
5462729Sdfr#ifdef MSG_DEBUG_OK
5472729Sdfr	printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
5482729Sdfr	    segs_needed);
5492729Sdfr#endif
5502729Sdfr	for (;;) {
5512729Sdfr		int need_more_resources = 0;
5522729Sdfr
5532729Sdfr		/*
5542729Sdfr		 * check msgsz
5552729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
5562729Sdfr		 */
5572729Sdfr
5582836Sdg		if (msgsz > msqptr->msg_qbytes) {
5592729Sdfr#ifdef MSG_DEBUG_OK
5602729Sdfr			printf("msgsz > msqptr->msg_qbytes\n");
5612729Sdfr#endif
5622729Sdfr			return(EINVAL);
5632729Sdfr		}
5642729Sdfr
5652729Sdfr		if (msqptr->msg_perm.mode & MSG_LOCKED) {
5662729Sdfr#ifdef MSG_DEBUG_OK
5672729Sdfr			printf("msqid is locked\n");
5682729Sdfr#endif
5692729Sdfr			need_more_resources = 1;
5702729Sdfr		}
5712729Sdfr		if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
5722729Sdfr#ifdef MSG_DEBUG_OK
5732729Sdfr			printf("msgsz + msg_cbytes > msg_qbytes\n");
5742729Sdfr#endif
5752729Sdfr			need_more_resources = 1;
5762729Sdfr		}
5772729Sdfr		if (segs_needed > nfree_msgmaps) {
5782729Sdfr#ifdef MSG_DEBUG_OK
5792729Sdfr			printf("segs_needed > nfree_msgmaps\n");
5802729Sdfr#endif
5812729Sdfr			need_more_resources = 1;
5822729Sdfr		}
5832729Sdfr		if (free_msghdrs == NULL) {
5842729Sdfr#ifdef MSG_DEBUG_OK
5852729Sdfr			printf("no more msghdrs\n");
5862729Sdfr#endif
5872729Sdfr			need_more_resources = 1;
5882729Sdfr		}
5892729Sdfr
5902729Sdfr		if (need_more_resources) {
5912729Sdfr			int we_own_it;
5922729Sdfr
5932729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
5942729Sdfr#ifdef MSG_DEBUG_OK
5952729Sdfr				printf("need more resources but caller doesn't want to wait\n");
5962729Sdfr#endif
5972729Sdfr				return(EAGAIN);
5982729Sdfr			}
5992729Sdfr
6002729Sdfr			if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
6012729Sdfr#ifdef MSG_DEBUG_OK
6022729Sdfr				printf("we don't own the msqid_ds\n");
6032729Sdfr#endif
6042729Sdfr				we_own_it = 0;
6052729Sdfr			} else {
6062729Sdfr				/* Force later arrivals to wait for our
6072729Sdfr				   request */
6082729Sdfr#ifdef MSG_DEBUG_OK
6092729Sdfr				printf("we own the msqid_ds\n");
6102729Sdfr#endif
6112729Sdfr				msqptr->msg_perm.mode |= MSG_LOCKED;
6122729Sdfr				we_own_it = 1;
6132729Sdfr			}
6142729Sdfr#ifdef MSG_DEBUG_OK
6152729Sdfr			printf("goodnight\n");
6162729Sdfr#endif
6172729Sdfr			eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH,
6182729Sdfr			    "msgwait", 0);
6192729Sdfr#ifdef MSG_DEBUG_OK
6202729Sdfr			printf("good morning, eval=%d\n", eval);
6212729Sdfr#endif
6222729Sdfr			if (we_own_it)
6232729Sdfr				msqptr->msg_perm.mode &= ~MSG_LOCKED;
6242729Sdfr			if (eval != 0) {
6252729Sdfr#ifdef MSG_DEBUG_OK
6262729Sdfr				printf("msgsnd:  interrupted system call\n");
6272729Sdfr#endif
6282729Sdfr				return(EINTR);
6292729Sdfr			}
6302729Sdfr
6312729Sdfr			/*
6322729Sdfr			 * Make sure that the msq queue still exists
6332729Sdfr			 */
6342729Sdfr
6352729Sdfr			if (msqptr->msg_qbytes == 0) {
6362729Sdfr#ifdef MSG_DEBUG_OK
6372729Sdfr				printf("msqid deleted\n");
6382729Sdfr#endif
6392729Sdfr				return(EIDRM);
6402729Sdfr			}
6412729Sdfr
6422729Sdfr		} else {
6432729Sdfr#ifdef MSG_DEBUG_OK
6442729Sdfr			printf("got all the resources that we need\n");
6452729Sdfr#endif
6462729Sdfr			break;
6472729Sdfr		}
6482729Sdfr	}
6492729Sdfr
6502729Sdfr	/*
6512729Sdfr	 * We have the resources that we need.
6522729Sdfr	 * Make sure!
6532729Sdfr	 */
6542729Sdfr
6552729Sdfr	if (msqptr->msg_perm.mode & MSG_LOCKED)
6562729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
6572729Sdfr	if (segs_needed > nfree_msgmaps)
6582729Sdfr		panic("segs_needed > nfree_msgmaps");
6592729Sdfr	if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
6602729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
6612729Sdfr	if (free_msghdrs == NULL)
6622729Sdfr		panic("no more msghdrs");
6632729Sdfr
6642729Sdfr	/*
6652729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
6662729Sdfr	 * message
6672729Sdfr	 */
6682729Sdfr
6692729Sdfr	if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
6702729Sdfr		panic("msqid_ds is already locked");
6712729Sdfr	msqptr->msg_perm.mode |= MSG_LOCKED;
6722729Sdfr
6732729Sdfr	/*
6742729Sdfr	 * Allocate a message header
6752729Sdfr	 */
6762729Sdfr
6772729Sdfr	msghdr = free_msghdrs;
6782729Sdfr	free_msghdrs = msghdr->msg_next;
6792729Sdfr	msghdr->msg_spot = -1;
6802729Sdfr	msghdr->msg_ts = msgsz;
6812729Sdfr
6822729Sdfr	/*
6832729Sdfr	 * Allocate space for the message
6842729Sdfr	 */
6852729Sdfr
6862729Sdfr	while (segs_needed > 0) {
6872729Sdfr		if (nfree_msgmaps <= 0)
6882729Sdfr			panic("not enough msgmaps");
6892729Sdfr		if (free_msgmaps == -1)
6902729Sdfr			panic("nil free_msgmaps");
6912729Sdfr		next = free_msgmaps;
6922729Sdfr		if (next <= -1)
6932729Sdfr			panic("next too low #1");
6942729Sdfr		if (next >= msginfo.msgseg)
6952729Sdfr			panic("next out of range #1");
6962729Sdfr#ifdef MSG_DEBUG_OK
6972729Sdfr		printf("allocating segment %d to message\n", next);
6982729Sdfr#endif
6992729Sdfr		free_msgmaps = msgmaps[next].next;
7002729Sdfr		nfree_msgmaps--;
7012729Sdfr		msgmaps[next].next = msghdr->msg_spot;
7022729Sdfr		msghdr->msg_spot = next;
7032729Sdfr		segs_needed--;
7042729Sdfr	}
7052729Sdfr
7062729Sdfr	/*
7072729Sdfr	 * Copy in the message type
7082729Sdfr	 */
7092729Sdfr
7102729Sdfr	if ((eval = copyin(user_msgp, &msghdr->msg_type,
7112729Sdfr	    sizeof(msghdr->msg_type))) != 0) {
7122729Sdfr#ifdef MSG_DEBUG_OK
7132729Sdfr		printf("error %d copying the message type\n", eval);
7142729Sdfr#endif
7152729Sdfr		msg_freehdr(msghdr);
7162729Sdfr		msqptr->msg_perm.mode &= ~MSG_LOCKED;
7172729Sdfr		wakeup((caddr_t)msqptr);
7182729Sdfr		return(eval);
7192729Sdfr	}
72017971Sbde	user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
7212729Sdfr
7222729Sdfr	/*
7232729Sdfr	 * Validate the message type
7242729Sdfr	 */
7252729Sdfr
7262729Sdfr	if (msghdr->msg_type < 1) {
7272729Sdfr		msg_freehdr(msghdr);
7282729Sdfr		msqptr->msg_perm.mode &= ~MSG_LOCKED;
7292729Sdfr		wakeup((caddr_t)msqptr);
7302729Sdfr#ifdef MSG_DEBUG_OK
7312729Sdfr		printf("mtype (%d) < 1\n", msghdr->msg_type);
7322729Sdfr#endif
7332729Sdfr		return(EINVAL);
7342729Sdfr	}
7352729Sdfr
7362729Sdfr	/*
7372729Sdfr	 * Copy in the message body
7382729Sdfr	 */
7392729Sdfr
7402729Sdfr	next = msghdr->msg_spot;
7412729Sdfr	while (msgsz > 0) {
7422729Sdfr		size_t tlen;
7432729Sdfr		if (msgsz > msginfo.msgssz)
7442729Sdfr			tlen = msginfo.msgssz;
7452729Sdfr		else
7462729Sdfr			tlen = msgsz;
7472729Sdfr		if (next <= -1)
7482729Sdfr			panic("next too low #2");
7492729Sdfr		if (next >= msginfo.msgseg)
7502729Sdfr			panic("next out of range #2");
7512729Sdfr		if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
7522729Sdfr		    tlen)) != 0) {
7532729Sdfr#ifdef MSG_DEBUG_OK
7542729Sdfr			printf("error %d copying in message segment\n", eval);
7552729Sdfr#endif
7562729Sdfr			msg_freehdr(msghdr);
7572729Sdfr			msqptr->msg_perm.mode &= ~MSG_LOCKED;
7582729Sdfr			wakeup((caddr_t)msqptr);
7592729Sdfr			return(eval);
7602729Sdfr		}
7612729Sdfr		msgsz -= tlen;
76217971Sbde		user_msgp = (char *)user_msgp + tlen;
7632729Sdfr		next = msgmaps[next].next;
7642729Sdfr	}
7652729Sdfr	if (next != -1)
7662729Sdfr		panic("didn't use all the msg segments");
7672729Sdfr
7682729Sdfr	/*
7692729Sdfr	 * We've got the message.  Unlock the msqid_ds.
7702729Sdfr	 */
7712729Sdfr
7722729Sdfr	msqptr->msg_perm.mode &= ~MSG_LOCKED;
7732729Sdfr
7742729Sdfr	/*
7752729Sdfr	 * Make sure that the msqid_ds is still allocated.
7762729Sdfr	 */
7772729Sdfr
7782729Sdfr	if (msqptr->msg_qbytes == 0) {
7792729Sdfr		msg_freehdr(msghdr);
7802729Sdfr		wakeup((caddr_t)msqptr);
7812729Sdfr		return(EIDRM);
7822729Sdfr	}
7832729Sdfr
7842729Sdfr	/*
7852729Sdfr	 * Put the message into the queue
7862729Sdfr	 */
7872729Sdfr
7882729Sdfr	if (msqptr->msg_first == NULL) {
7892729Sdfr		msqptr->msg_first = msghdr;
7902729Sdfr		msqptr->msg_last = msghdr;
7912729Sdfr	} else {
7922729Sdfr		msqptr->msg_last->msg_next = msghdr;
7932729Sdfr		msqptr->msg_last = msghdr;
7942729Sdfr	}
7952729Sdfr	msqptr->msg_last->msg_next = NULL;
7962729Sdfr
7972729Sdfr	msqptr->msg_cbytes += msghdr->msg_ts;
7982729Sdfr	msqptr->msg_qnum++;
7992729Sdfr	msqptr->msg_lspid = p->p_pid;
80034961Sphk	msqptr->msg_stime = time_second;
8012729Sdfr
8022729Sdfr	wakeup((caddr_t)msqptr);
80330994Sphk	p->p_retval[0] = 0;
8042729Sdfr	return(0);
8052729Sdfr}
8062729Sdfr
80712866Speter#ifndef _SYS_SYSPROTO_H_
8082729Sdfrstruct msgrcv_args {
8092729Sdfr	int	msqid;
8102729Sdfr	void	*msgp;
8112729Sdfr	size_t	msgsz;
8122729Sdfr	long	msgtyp;
8132729Sdfr	int	msgflg;
8142729Sdfr};
81512866Speter#endif
8162729Sdfr
81712866Speterint
81830994Sphkmsgrcv(p, uap)
8192729Sdfr	struct proc *p;
8202729Sdfr	register struct msgrcv_args *uap;
8212729Sdfr{
8222729Sdfr	int msqid = uap->msqid;
8232729Sdfr	void *user_msgp = uap->msgp;
8242729Sdfr	size_t msgsz = uap->msgsz;
8252729Sdfr	long msgtyp = uap->msgtyp;
8262729Sdfr	int msgflg = uap->msgflg;
8272729Sdfr	size_t len;
8282729Sdfr	register struct msqid_ds *msqptr;
8292729Sdfr	register struct msg *msghdr;
8302729Sdfr	int eval;
8312729Sdfr	short next;
8322729Sdfr
8332729Sdfr#ifdef MSG_DEBUG_OK
8342729Sdfr	printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
8352729Sdfr	    msgsz, msgtyp, msgflg);
8362729Sdfr#endif
8372729Sdfr
8382729Sdfr	msqid = IPCID_TO_IX(msqid);
8392729Sdfr
8402729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
8412729Sdfr#ifdef MSG_DEBUG_OK
8422729Sdfr		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
8432729Sdfr		    msginfo.msgmni);
8442729Sdfr#endif
8452729Sdfr		return(EINVAL);
8462729Sdfr	}
8472729Sdfr
8482729Sdfr	msqptr = &msqids[msqid];
8492729Sdfr	if (msqptr->msg_qbytes == 0) {
8502729Sdfr#ifdef MSG_DEBUG_OK
8512729Sdfr		printf("no such message queue id\n");
8522729Sdfr#endif
8532729Sdfr		return(EINVAL);
8542729Sdfr	}
8552729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
8562729Sdfr#ifdef MSG_DEBUG_OK
8572729Sdfr		printf("wrong sequence number\n");
8582729Sdfr#endif
8592729Sdfr		return(EINVAL);
8602729Sdfr	}
8612729Sdfr
86246116Sphk	if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
8632729Sdfr#ifdef MSG_DEBUG_OK
8642729Sdfr		printf("requester doesn't have read access\n");
8652729Sdfr#endif
8662729Sdfr		return(eval);
8672729Sdfr	}
8682729Sdfr
8692729Sdfr	msghdr = NULL;
8702729Sdfr	while (msghdr == NULL) {
8712729Sdfr		if (msgtyp == 0) {
8722729Sdfr			msghdr = msqptr->msg_first;
8732729Sdfr			if (msghdr != NULL) {
8742729Sdfr				if (msgsz < msghdr->msg_ts &&
8752729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
8762729Sdfr#ifdef MSG_DEBUG_OK
8772729Sdfr					printf("first message on the queue is too big (want %d, got %d)\n",
8782729Sdfr					    msgsz, msghdr->msg_ts);
8792729Sdfr#endif
8802729Sdfr					return(E2BIG);
8812729Sdfr				}
8822729Sdfr				if (msqptr->msg_first == msqptr->msg_last) {
8832729Sdfr					msqptr->msg_first = NULL;
8842729Sdfr					msqptr->msg_last = NULL;
8852729Sdfr				} else {
8862729Sdfr					msqptr->msg_first = msghdr->msg_next;
8872729Sdfr					if (msqptr->msg_first == NULL)
8882729Sdfr						panic("msg_first/last screwed up #1");
8892729Sdfr				}
8902729Sdfr			}
8912729Sdfr		} else {
8922729Sdfr			struct msg *previous;
8932729Sdfr			struct msg **prev;
8942729Sdfr
8952729Sdfr			previous = NULL;
8962729Sdfr			prev = &(msqptr->msg_first);
8972729Sdfr			while ((msghdr = *prev) != NULL) {
8982729Sdfr				/*
8992729Sdfr				 * Is this message's type an exact match or is
9002729Sdfr				 * this message's type less than or equal to
9012729Sdfr				 * the absolute value of a negative msgtyp?
9022729Sdfr				 * Note that the second half of this test can
9032729Sdfr				 * NEVER be true if msgtyp is positive since
9042729Sdfr				 * msg_type is always positive!
9052729Sdfr				 */
9062729Sdfr
9072729Sdfr				if (msgtyp == msghdr->msg_type ||
9082729Sdfr				    msghdr->msg_type <= -msgtyp) {
9092729Sdfr#ifdef MSG_DEBUG_OK
9102729Sdfr					printf("found message type %d, requested %d\n",
9112729Sdfr					    msghdr->msg_type, msgtyp);
9122729Sdfr#endif
9132729Sdfr					if (msgsz < msghdr->msg_ts &&
9142729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
9152729Sdfr#ifdef MSG_DEBUG_OK
9162729Sdfr						printf("requested message on the queue is too big (want %d, got %d)\n",
9172729Sdfr						    msgsz, msghdr->msg_ts);
9182729Sdfr#endif
9192729Sdfr						return(E2BIG);
9202729Sdfr					}
9212729Sdfr					*prev = msghdr->msg_next;
9222729Sdfr					if (msghdr == msqptr->msg_last) {
9232729Sdfr						if (previous == NULL) {
9242729Sdfr							if (prev !=
9252729Sdfr							    &msqptr->msg_first)
9262729Sdfr								panic("msg_first/last screwed up #2");
9272729Sdfr							msqptr->msg_first =
9282729Sdfr							    NULL;
9292729Sdfr							msqptr->msg_last =
9302729Sdfr							    NULL;
9312729Sdfr						} else {
9322729Sdfr							if (prev ==
9332729Sdfr							    &msqptr->msg_first)
9342729Sdfr								panic("msg_first/last screwed up #3");
9352729Sdfr							msqptr->msg_last =
9362729Sdfr							    previous;
9372729Sdfr						}
9382729Sdfr					}
9392729Sdfr					break;
9402729Sdfr				}
9412729Sdfr				previous = msghdr;
9422729Sdfr				prev = &(msghdr->msg_next);
9432729Sdfr			}
9442729Sdfr		}
9452729Sdfr
9462729Sdfr		/*
9472729Sdfr		 * We've either extracted the msghdr for the appropriate
9482729Sdfr		 * message or there isn't one.
9492729Sdfr		 * If there is one then bail out of this loop.
9502729Sdfr		 */
9512729Sdfr
9522729Sdfr		if (msghdr != NULL)
9532729Sdfr			break;
9542729Sdfr
9552729Sdfr		/*
9562729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
9572729Sdfr		 */
9582729Sdfr
9592729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
9602729Sdfr#ifdef MSG_DEBUG_OK
9612729Sdfr			printf("no appropriate message found (msgtyp=%d)\n",
9622729Sdfr			    msgtyp);
9632729Sdfr#endif
9642729Sdfr			/* The SVID says to return ENOMSG. */
9652729Sdfr#ifdef ENOMSG
9662729Sdfr			return(ENOMSG);
9672729Sdfr#else
9682729Sdfr			/* Unfortunately, BSD doesn't define that code yet! */
9692729Sdfr			return(EAGAIN);
9702729Sdfr#endif
9712729Sdfr		}
9722729Sdfr
9732729Sdfr		/*
9742729Sdfr		 * Wait for something to happen
9752729Sdfr		 */
9762729Sdfr
9772729Sdfr#ifdef MSG_DEBUG_OK
9782729Sdfr		printf("msgrcv:  goodnight\n");
9792729Sdfr#endif
9802729Sdfr		eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, "msgwait",
9812729Sdfr		    0);
9822729Sdfr#ifdef MSG_DEBUG_OK
9832729Sdfr		printf("msgrcv:  good morning (eval=%d)\n", eval);
9842729Sdfr#endif
9852729Sdfr
9862729Sdfr		if (eval != 0) {
9872729Sdfr#ifdef MSG_DEBUG_OK
9882729Sdfr			printf("msgsnd:  interrupted system call\n");
9892729Sdfr#endif
9902729Sdfr			return(EINTR);
9912729Sdfr		}
9922729Sdfr
9932729Sdfr		/*
9942729Sdfr		 * Make sure that the msq queue still exists
9952729Sdfr		 */
9962729Sdfr
9972729Sdfr		if (msqptr->msg_qbytes == 0 ||
9982729Sdfr		    msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
9992729Sdfr#ifdef MSG_DEBUG_OK
10002729Sdfr			printf("msqid deleted\n");
10012729Sdfr#endif
10022729Sdfr			return(EIDRM);
10032729Sdfr		}
10042729Sdfr	}
10052729Sdfr
10062729Sdfr	/*
10072729Sdfr	 * Return the message to the user.
10082729Sdfr	 *
10092729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
10102729Sdfr	 */
10112729Sdfr
10122729Sdfr	msqptr->msg_cbytes -= msghdr->msg_ts;
10132729Sdfr	msqptr->msg_qnum--;
10142729Sdfr	msqptr->msg_lrpid = p->p_pid;
101534961Sphk	msqptr->msg_rtime = time_second;
10162729Sdfr
10172729Sdfr	/*
10182729Sdfr	 * Make msgsz the actual amount that we'll be returning.
10192729Sdfr	 * Note that this effectively truncates the message if it is too long
10202729Sdfr	 * (since msgsz is never increased).
10212729Sdfr	 */
10222729Sdfr
10232729Sdfr#ifdef MSG_DEBUG_OK
10242729Sdfr	printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
10252729Sdfr	    msghdr->msg_ts);
10262729Sdfr#endif
10272729Sdfr	if (msgsz > msghdr->msg_ts)
10282729Sdfr		msgsz = msghdr->msg_ts;
10292729Sdfr
10302729Sdfr	/*
10312729Sdfr	 * Return the type to the user.
10322729Sdfr	 */
10332729Sdfr
10342729Sdfr	eval = copyout((caddr_t)&(msghdr->msg_type), user_msgp,
10352729Sdfr	    sizeof(msghdr->msg_type));
10362729Sdfr	if (eval != 0) {
10372729Sdfr#ifdef MSG_DEBUG_OK
10382729Sdfr		printf("error (%d) copying out message type\n", eval);
10392729Sdfr#endif
10402729Sdfr		msg_freehdr(msghdr);
10412729Sdfr		wakeup((caddr_t)msqptr);
10422729Sdfr		return(eval);
10432729Sdfr	}
104417971Sbde	user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
10452729Sdfr
10462729Sdfr	/*
10472729Sdfr	 * Return the segments to the user
10482729Sdfr	 */
10492729Sdfr
10502729Sdfr	next = msghdr->msg_spot;
10512729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
10522729Sdfr		size_t tlen;
10532729Sdfr
105445921Ssada		if (msgsz - len > msginfo.msgssz)
10552729Sdfr			tlen = msginfo.msgssz;
10562729Sdfr		else
105745921Ssada			tlen = msgsz - len;
10582729Sdfr		if (next <= -1)
10592729Sdfr			panic("next too low #3");
10602729Sdfr		if (next >= msginfo.msgseg)
10612729Sdfr			panic("next out of range #3");
10622729Sdfr		eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz],
10632729Sdfr		    user_msgp, tlen);
10642729Sdfr		if (eval != 0) {
10652729Sdfr#ifdef MSG_DEBUG_OK
10662729Sdfr			printf("error (%d) copying out message segment\n",
10672729Sdfr			    eval);
10682729Sdfr#endif
10692729Sdfr			msg_freehdr(msghdr);
10702729Sdfr			wakeup((caddr_t)msqptr);
10712729Sdfr			return(eval);
10722729Sdfr		}
107317971Sbde		user_msgp = (char *)user_msgp + tlen;
10742729Sdfr		next = msgmaps[next].next;
10752729Sdfr	}
10762729Sdfr
10772729Sdfr	/*
10782729Sdfr	 * Done, return the actual number of bytes copied out.
10792729Sdfr	 */
10802729Sdfr
10812729Sdfr	msg_freehdr(msghdr);
10822729Sdfr	wakeup((caddr_t)msqptr);
108330994Sphk	p->p_retval[0] = msgsz;
10842729Sdfr	return(0);
10852729Sdfr}
1086