sysv_msg.c revision 109895
150477Speter/* $FreeBSD: head/sys/kern/sysv_msg.c 109895 2003-01-26 20:09:34Z alfred $ */
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>
2982607Sdillon#include <sys/lock.h>
3082607Sdillon#include <sys/mutex.h>
312729Sdfr#include <sys/msg.h>
3269449Salfred#include <sys/syscall.h>
3311626Sbde#include <sys/sysent.h>
3459839Speter#include <sys/sysctl.h>
3559839Speter#include <sys/malloc.h>
3668024Srwatson#include <sys/jail.h>
372729Sdfr
3859839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
3959839Speter
4092723Salfredstatic void msginit(void);
4192723Salfredstatic int msgunload(void);
4292723Salfredstatic int sysvmsg_modload(struct module *, int, void *);
4310358Sjulian
44100523Salfred#ifdef MSG_DEBUG
45100523Salfred#define DPRINTF(a)	printf a
46100523Salfred#else
47100523Salfred#define DPRINTF(a)
48100523Salfred#endif
492729Sdfr
5092723Salfredstatic void msg_freehdr(struct msg *msghdr);
512729Sdfr
5211626Sbde/* XXX casting to (sy_call_t *) is bogus, as usual. */
5312819Sphkstatic sy_call_t *msgcalls[] = {
5411626Sbde	(sy_call_t *)msgctl, (sy_call_t *)msgget,
5511626Sbde	(sy_call_t *)msgsnd, (sy_call_t *)msgrcv
5611626Sbde};
572729Sdfr
5859839Speterstruct msg {
5959839Speter	struct	msg *msg_next;	/* next msg in the chain */
6059839Speter	long	msg_type;	/* type of this message */
6159839Speter    				/* >0 -> type of this message */
6259839Speter    				/* 0 -> free header */
6359839Speter	u_short	msg_ts;		/* size of this message */
6459839Speter	short	msg_spot;	/* location of start of msg in buffer */
6559839Speter};
6659839Speter
6759839Speter
6859839Speter#ifndef MSGSSZ
6959839Speter#define MSGSSZ	8		/* Each segment must be 2^N long */
7059839Speter#endif
7159839Speter#ifndef MSGSEG
7259839Speter#define MSGSEG	2048		/* must be less than 32767 */
7359839Speter#endif
7459839Speter#define MSGMAX	(MSGSSZ*MSGSEG)
7559839Speter#ifndef MSGMNB
7659839Speter#define MSGMNB	2048		/* max # of bytes in a queue */
7759839Speter#endif
7859839Speter#ifndef MSGMNI
7959839Speter#define MSGMNI	40
8059839Speter#endif
8159839Speter#ifndef MSGTQL
8259839Speter#define MSGTQL	40
8359839Speter#endif
8459839Speter
8559839Speter/*
8659839Speter * Based on the configuration parameters described in an SVR2 (yes, two)
8759839Speter * config(1m) man page.
8859839Speter *
8959839Speter * Each message is broken up and stored in segments that are msgssz bytes
9059839Speter * long.  For efficiency reasons, this should be a power of two.  Also,
9159839Speter * it doesn't make sense if it is less than 8 or greater than about 256.
9259839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
9359839Speter * two between 8 and 1024 inclusive (and panic's if it isn't).
9459839Speter */
9559839Speterstruct msginfo msginfo = {
9659839Speter                MSGMAX,         /* max chars in a message */
9759839Speter                MSGMNI,         /* # of message queue identifiers */
9859839Speter                MSGMNB,         /* max chars in a queue */
9959839Speter                MSGTQL,         /* max messages in system */
10059839Speter                MSGSSZ,         /* size of a message segment */
10159839Speter                		/* (must be small power of 2 greater than 4) */
10259839Speter                MSGSEG          /* number of message segments */
10359839Speter};
10459839Speter
10559839Speter/*
10659839Speter * macros to convert between msqid_ds's and msqid's.
10759839Speter * (specific to this implementation)
10859839Speter */
10959839Speter#define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
11059839Speter#define MSQID_IX(id)	((id) & 0xffff)
11159839Speter#define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
11259839Speter
11359839Speter/*
11459839Speter * The rest of this file is specific to this particular implementation.
11559839Speter */
11659839Speter
11759839Speterstruct msgmap {
11859839Speter	short	next;		/* next segment in buffer */
11959839Speter    				/* -1 -> available */
12059839Speter    				/* 0..(MSGSEG-1) -> index of next segment */
12159839Speter};
12259839Speter
12359839Speter#define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
12459839Speter
12512819Sphkstatic int nfree_msgmaps;	/* # of free map entries */
12612819Sphkstatic short free_msgmaps;	/* head of linked list of free map entries */
12759839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */
12859839Speterstatic char *msgpool;		/* MSGMAX byte long msg buffer pool */
12959839Speterstatic struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
13059839Speterstatic struct msg *msghdrs;	/* MSGTQL msg headers */
13159839Speterstatic struct msqid_ds *msqids;	/* MSGMNI msqid_ds struct's */
132101772Salfredstatic struct mtx msq_mtx;	/* global mutex for message queues. */
1332729Sdfr
13459839Speterstatic void
13569449Salfredmsginit()
1362729Sdfr{
1372729Sdfr	register int i;
1382729Sdfr
13983765Smr	TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
14083765Smr	TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
14183765Smr	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
14283765Smr	TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
14383765Smr
144109623Salfred	msgpool = malloc(msginfo.msgmax, M_MSG, 0);
14559839Speter	if (msgpool == NULL)
14659839Speter		panic("msgpool is NULL");
147109623Salfred	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, 0);
14859839Speter	if (msgmaps == NULL)
14959839Speter		panic("msgmaps is NULL");
150109623Salfred	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, 0);
15159839Speter	if (msghdrs == NULL)
15259839Speter		panic("msghdrs is NULL");
153109623Salfred	msqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni, M_MSG, 0);
15459839Speter	if (msqids == NULL)
15559839Speter		panic("msqids is NULL");
15659839Speter
1572729Sdfr	/*
1582729Sdfr	 * msginfo.msgssz should be a power of two for efficiency reasons.
1592729Sdfr	 * It is also pretty silly if msginfo.msgssz is less than 8
1602729Sdfr	 * or greater than about 256 so ...
1612729Sdfr	 */
1622729Sdfr
1632729Sdfr	i = 8;
1642729Sdfr	while (i < 1024 && i != msginfo.msgssz)
1652729Sdfr		i <<= 1;
1662729Sdfr    	if (i != msginfo.msgssz) {
167100523Salfred		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
168100523Salfred		    msginfo.msgssz));
1692729Sdfr		panic("msginfo.msgssz not a small power of 2");
1702729Sdfr	}
1712729Sdfr
1722729Sdfr	if (msginfo.msgseg > 32767) {
173100523Salfred		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
1742729Sdfr		panic("msginfo.msgseg > 32767");
1752729Sdfr	}
1762729Sdfr
1772729Sdfr	if (msgmaps == NULL)
1782729Sdfr		panic("msgmaps is NULL");
1792729Sdfr
1802729Sdfr	for (i = 0; i < msginfo.msgseg; i++) {
1812729Sdfr		if (i > 0)
1822729Sdfr			msgmaps[i-1].next = i;
1832729Sdfr		msgmaps[i].next = -1;	/* implies entry is available */
1842729Sdfr	}
1852729Sdfr	free_msgmaps = 0;
1862729Sdfr	nfree_msgmaps = msginfo.msgseg;
1872729Sdfr
1882729Sdfr	if (msghdrs == NULL)
1892729Sdfr		panic("msghdrs is NULL");
1902729Sdfr
1912729Sdfr	for (i = 0; i < msginfo.msgtql; i++) {
1922729Sdfr		msghdrs[i].msg_type = 0;
1932729Sdfr		if (i > 0)
1942729Sdfr			msghdrs[i-1].msg_next = &msghdrs[i];
1952729Sdfr		msghdrs[i].msg_next = NULL;
1962729Sdfr    	}
1972729Sdfr	free_msghdrs = &msghdrs[0];
1982729Sdfr
1992729Sdfr	if (msqids == NULL)
2002729Sdfr		panic("msqids is NULL");
2012729Sdfr
2022729Sdfr	for (i = 0; i < msginfo.msgmni; i++) {
2032729Sdfr		msqids[i].msg_qbytes = 0;	/* implies entry is available */
2042729Sdfr		msqids[i].msg_perm.seq = 0;	/* reset to a known value */
20566085Speter		msqids[i].msg_perm.mode = 0;
2062729Sdfr	}
207101772Salfred	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
2082729Sdfr}
2092729Sdfr
21069449Salfredstatic int
21169449Salfredmsgunload()
21269449Salfred{
21369449Salfred	struct msqid_ds *msqptr;
21469449Salfred	int msqid;
21569449Salfred
21669449Salfred	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
21769449Salfred		/*
21869449Salfred		 * Look for an unallocated and unlocked msqid_ds.
21969449Salfred		 * msqid_ds's can be locked by msgsnd or msgrcv while
22069449Salfred		 * they are copying the message in/out.  We can't
22169449Salfred		 * re-use the entry until they release it.
22269449Salfred		 */
22369449Salfred		msqptr = &msqids[msqid];
22469449Salfred		if (msqptr->msg_qbytes != 0 ||
22569449Salfred		    (msqptr->msg_perm.mode & MSG_LOCKED) != 0)
22669449Salfred			break;
22769449Salfred	}
22869449Salfred	if (msqid != msginfo.msgmni)
22969449Salfred		return (EBUSY);
23069449Salfred
23169449Salfred	free(msgpool, M_MSG);
23269449Salfred	free(msgmaps, M_MSG);
23369449Salfred	free(msghdrs, M_MSG);
23469449Salfred	free(msqids, M_MSG);
235101772Salfred	mtx_destroy(&msq_mtx);
23669449Salfred	return (0);
23769449Salfred}
23869449Salfred
23969449Salfred
24069449Salfredstatic int
24169449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg)
24269449Salfred{
24369449Salfred	int error = 0;
24469449Salfred
24569449Salfred	switch (cmd) {
24669449Salfred	case MOD_LOAD:
24769449Salfred		msginit();
24869449Salfred		break;
24969449Salfred	case MOD_UNLOAD:
25069449Salfred		error = msgunload();
25169449Salfred		break;
25269449Salfred	case MOD_SHUTDOWN:
25369449Salfred		break;
25469449Salfred	default:
25569449Salfred		error = EINVAL;
25669449Salfred		break;
25769449Salfred	}
25869449Salfred	return (error);
25969449Salfred}
26069449Salfred
26171038Sdesstatic moduledata_t sysvmsg_mod = {
26271038Sdes	"sysvmsg",
26369449Salfred	&sysvmsg_modload,
26469449Salfred	NULL
26569449Salfred};
26669449Salfred
26788633SalfredSYSCALL_MODULE_HELPER(msgsys);
26888633SalfredSYSCALL_MODULE_HELPER(msgctl);
26988633SalfredSYSCALL_MODULE_HELPER(msgget);
27088633SalfredSYSCALL_MODULE_HELPER(msgsnd);
27188633SalfredSYSCALL_MODULE_HELPER(msgrcv);
27269449Salfred
27371038SdesDECLARE_MODULE(sysvmsg, sysvmsg_mod,
27469449Salfred	SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
27571038SdesMODULE_VERSION(sysvmsg, 1);
27669449Salfred
2772729Sdfr/*
2782729Sdfr * Entry point for all MSG calls
27982607Sdillon *
28082607Sdillon * MPSAFE
2812729Sdfr */
2822729Sdfrint
28383366Sjulianmsgsys(td, uap)
28483366Sjulian	struct thread *td;
28511626Sbde	/* XXX actually varargs. */
28611626Sbde	struct msgsys_args /* {
28711626Sbde		u_int	which;
28811626Sbde		int	a2;
28911626Sbde		int	a3;
29011626Sbde		int	a4;
29111626Sbde		int	a5;
29211626Sbde		int	a6;
29311626Sbde	} */ *uap;
2942729Sdfr{
29582607Sdillon	int error;
2962729Sdfr
29791703Sjhb	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
29891703Sjhb		return (ENOSYS);
29991703Sjhb	if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
30091703Sjhb		return (EINVAL);
30183366Sjulian	error = (*msgcalls[uap->which])(td, &uap->a2);
30282607Sdillon	return (error);
3032729Sdfr}
3042729Sdfr
3052729Sdfrstatic void
3062729Sdfrmsg_freehdr(msghdr)
3072729Sdfr	struct msg *msghdr;
3082729Sdfr{
3092729Sdfr	while (msghdr->msg_ts > 0) {
3102729Sdfr		short next;
3112729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
3122729Sdfr			panic("msghdr->msg_spot out of range");
3132729Sdfr		next = msgmaps[msghdr->msg_spot].next;
3142729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
3152729Sdfr		free_msgmaps = msghdr->msg_spot;
3162729Sdfr		nfree_msgmaps++;
3172729Sdfr		msghdr->msg_spot = next;
3182729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
3192729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
3202729Sdfr		else
3212729Sdfr			msghdr->msg_ts = 0;
3222729Sdfr	}
3232729Sdfr	if (msghdr->msg_spot != -1)
3242729Sdfr		panic("msghdr->msg_spot != -1");
3252729Sdfr	msghdr->msg_next = free_msghdrs;
3262729Sdfr	free_msghdrs = msghdr;
3272729Sdfr}
3282729Sdfr
32912866Speter#ifndef _SYS_SYSPROTO_H_
3302729Sdfrstruct msgctl_args {
3312729Sdfr	int	msqid;
3322729Sdfr	int	cmd;
33312866Speter	struct	msqid_ds *buf;
3342729Sdfr};
33512866Speter#endif
3362729Sdfr
33782607Sdillon/*
33882607Sdillon * MPSAFE
33982607Sdillon */
34012866Speterint
34183366Sjulianmsgctl(td, uap)
34283366Sjulian	struct thread *td;
3432729Sdfr	register struct msgctl_args *uap;
3442729Sdfr{
3452729Sdfr	int msqid = uap->msqid;
3462729Sdfr	int cmd = uap->cmd;
34712866Speter	struct msqid_ds *user_msqptr = uap->buf;
34882607Sdillon	int rval, error;
3492729Sdfr	struct msqid_ds msqbuf;
3502729Sdfr	register struct msqid_ds *msqptr;
3512729Sdfr
352100523Salfred	DPRINTF(("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr));
35391703Sjhb	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
35491703Sjhb		return (ENOSYS);
35591703Sjhb
3562729Sdfr	msqid = IPCID_TO_IX(msqid);
3572729Sdfr
3582729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
359100523Salfred		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
360100523Salfred		    msginfo.msgmni));
361101772Salfred		return (EINVAL);
3622729Sdfr	}
363101772Salfred	if (cmd == IPC_SET &&
364101772Salfred	    (error = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
365101772Salfred		return (error);
3662729Sdfr
3672729Sdfr	msqptr = &msqids[msqid];
3682729Sdfr
369101772Salfred	mtx_lock(&msq_mtx);
3702729Sdfr	if (msqptr->msg_qbytes == 0) {
371100523Salfred		DPRINTF(("no such msqid\n"));
37282607Sdillon		error = EINVAL;
37382607Sdillon		goto done2;
3742729Sdfr	}
3752729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
376100523Salfred		DPRINTF(("wrong sequence number\n"));
37782607Sdillon		error = EINVAL;
37882607Sdillon		goto done2;
3792729Sdfr	}
3802729Sdfr
38182607Sdillon	error = 0;
3822729Sdfr	rval = 0;
3832729Sdfr
3842729Sdfr	switch (cmd) {
3852729Sdfr
3862729Sdfr	case IPC_RMID:
3872729Sdfr	{
3882729Sdfr		struct msg *msghdr;
38983366Sjulian		if ((error = ipcperm(td, &msqptr->msg_perm, IPC_M)))
39082607Sdillon			goto done2;
3912729Sdfr		/* Free the message headers */
3922729Sdfr		msghdr = msqptr->msg_first;
3932729Sdfr		while (msghdr != NULL) {
3942729Sdfr			struct msg *msghdr_tmp;
3952729Sdfr
3962729Sdfr			/* Free the segments of each message */
3972729Sdfr			msqptr->msg_cbytes -= msghdr->msg_ts;
3982729Sdfr			msqptr->msg_qnum--;
3992729Sdfr			msghdr_tmp = msghdr;
4002729Sdfr			msghdr = msghdr->msg_next;
4012729Sdfr			msg_freehdr(msghdr_tmp);
4022729Sdfr		}
4032729Sdfr
4042729Sdfr		if (msqptr->msg_cbytes != 0)
4052729Sdfr			panic("msg_cbytes is screwed up");
4062729Sdfr		if (msqptr->msg_qnum != 0)
4072729Sdfr			panic("msg_qnum is screwed up");
4082729Sdfr
4092729Sdfr		msqptr->msg_qbytes = 0;	/* Mark it as free */
4102729Sdfr
411100511Salfred		wakeup(msqptr);
4122729Sdfr	}
4132729Sdfr
4142729Sdfr		break;
4152729Sdfr
4162729Sdfr	case IPC_SET:
41783366Sjulian		if ((error = ipcperm(td, &msqptr->msg_perm, IPC_M)))
41882607Sdillon			goto done2;
41943426Sphk		if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
42093593Sjhb			error = suser(td);
42182607Sdillon			if (error)
42282607Sdillon				goto done2;
42343426Sphk		}
4242729Sdfr		if (msqbuf.msg_qbytes > msginfo.msgmnb) {
425100523Salfred			DPRINTF(("can't increase msg_qbytes beyond %d"
426100523Salfred			    "(truncating)\n", msginfo.msgmnb));
4272729Sdfr			msqbuf.msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
4282729Sdfr		}
4292729Sdfr		if (msqbuf.msg_qbytes == 0) {
430100523Salfred			DPRINTF(("can't reduce msg_qbytes to 0\n"));
43182607Sdillon			error = EINVAL;		/* non-standard errno! */
43282607Sdillon			goto done2;
4332729Sdfr		}
4342729Sdfr		msqptr->msg_perm.uid = msqbuf.msg_perm.uid;	/* change the owner */
4352729Sdfr		msqptr->msg_perm.gid = msqbuf.msg_perm.gid;	/* change the owner */
4362729Sdfr		msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
4372729Sdfr		    (msqbuf.msg_perm.mode & 0777);
4382729Sdfr		msqptr->msg_qbytes = msqbuf.msg_qbytes;
43934961Sphk		msqptr->msg_ctime = time_second;
4402729Sdfr		break;
4412729Sdfr
4422729Sdfr	case IPC_STAT:
44383366Sjulian		if ((error = ipcperm(td, &msqptr->msg_perm, IPC_R))) {
444100523Salfred			DPRINTF(("requester doesn't have read access\n"));
44582607Sdillon			goto done2;
4462729Sdfr		}
4472729Sdfr		break;
4482729Sdfr
4492729Sdfr	default:
450100523Salfred		DPRINTF(("invalid command %d\n", cmd));
45182607Sdillon		error = EINVAL;
45282607Sdillon		goto done2;
4532729Sdfr	}
4542729Sdfr
45582607Sdillon	if (error == 0)
45683366Sjulian		td->td_retval[0] = rval;
45782607Sdillondone2:
458101772Salfred	mtx_unlock(&msq_mtx);
459101772Salfred	if (cmd == IPC_STAT && error == 0)
460101772Salfred		error = copyout(msqptr, user_msqptr, sizeof(struct msqid_ds));
46182607Sdillon	return(error);
4622729Sdfr}
4632729Sdfr
46412866Speter#ifndef _SYS_SYSPROTO_H_
4652729Sdfrstruct msgget_args {
4662729Sdfr	key_t	key;
4672729Sdfr	int	msgflg;
4682729Sdfr};
46912866Speter#endif
4702729Sdfr
47182607Sdillon/*
47282607Sdillon * MPSAFE
47382607Sdillon */
47412866Speterint
47583366Sjulianmsgget(td, uap)
47683366Sjulian	struct thread *td;
4772729Sdfr	register struct msgget_args *uap;
4782729Sdfr{
47982607Sdillon	int msqid, error = 0;
4802729Sdfr	int key = uap->key;
4812729Sdfr	int msgflg = uap->msgflg;
48291703Sjhb	struct ucred *cred = td->td_ucred;
4832836Sdg	register struct msqid_ds *msqptr = NULL;
4842729Sdfr
485100523Salfred	DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
4862729Sdfr
48791703Sjhb	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
48891703Sjhb		return (ENOSYS);
48991703Sjhb
490101772Salfred	mtx_lock(&msq_mtx);
4912729Sdfr	if (key != IPC_PRIVATE) {
4922729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
4932729Sdfr			msqptr = &msqids[msqid];
4942729Sdfr			if (msqptr->msg_qbytes != 0 &&
4952729Sdfr			    msqptr->msg_perm.key == key)
4962729Sdfr				break;
4972729Sdfr		}
4982729Sdfr		if (msqid < msginfo.msgmni) {
499100523Salfred			DPRINTF(("found public key\n"));
5002729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
501100523Salfred				DPRINTF(("not exclusive\n"));
50282607Sdillon				error = EEXIST;
50382607Sdillon				goto done2;
5042729Sdfr			}
50583366Sjulian			if ((error = ipcperm(td, &msqptr->msg_perm, msgflg & 0700 ))) {
506100523Salfred				DPRINTF(("requester doesn't have 0%o access\n",
507100523Salfred				    msgflg & 0700));
50882607Sdillon				goto done2;
5092729Sdfr			}
5102729Sdfr			goto found;
5112729Sdfr		}
5122729Sdfr	}
5132729Sdfr
514100523Salfred	DPRINTF(("need to allocate the msqid_ds\n"));
5152729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
5162729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
5172729Sdfr			/*
5182729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
5192729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
5202729Sdfr			 * they are copying the message in/out.  We can't
5212729Sdfr			 * re-use the entry until they release it.
5222729Sdfr			 */
5232729Sdfr			msqptr = &msqids[msqid];
5242729Sdfr			if (msqptr->msg_qbytes == 0 &&
5252729Sdfr			    (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
5262729Sdfr				break;
5272729Sdfr		}
5282729Sdfr		if (msqid == msginfo.msgmni) {
529100523Salfred			DPRINTF(("no more msqid_ds's available\n"));
53082607Sdillon			error = ENOSPC;
53182607Sdillon			goto done2;
5322729Sdfr		}
533100523Salfred		DPRINTF(("msqid %d is available\n", msqid));
5342729Sdfr		msqptr->msg_perm.key = key;
5352729Sdfr		msqptr->msg_perm.cuid = cred->cr_uid;
5362729Sdfr		msqptr->msg_perm.uid = cred->cr_uid;
5372729Sdfr		msqptr->msg_perm.cgid = cred->cr_gid;
5382729Sdfr		msqptr->msg_perm.gid = cred->cr_gid;
5392729Sdfr		msqptr->msg_perm.mode = (msgflg & 0777);
5402729Sdfr		/* Make sure that the returned msqid is unique */
541107896Smaxim		msqptr->msg_perm.seq = (msqptr->msg_perm.seq + 1) & 0x7fff;
5422729Sdfr		msqptr->msg_first = NULL;
5432729Sdfr		msqptr->msg_last = NULL;
5442729Sdfr		msqptr->msg_cbytes = 0;
5452729Sdfr		msqptr->msg_qnum = 0;
5462729Sdfr		msqptr->msg_qbytes = msginfo.msgmnb;
5472729Sdfr		msqptr->msg_lspid = 0;
5482729Sdfr		msqptr->msg_lrpid = 0;
5492729Sdfr		msqptr->msg_stime = 0;
5502729Sdfr		msqptr->msg_rtime = 0;
55134961Sphk		msqptr->msg_ctime = time_second;
5522729Sdfr	} else {
553100523Salfred		DPRINTF(("didn't find it and wasn't asked to create it\n"));
55482607Sdillon		error = ENOENT;
55582607Sdillon		goto done2;
5562729Sdfr	}
5572729Sdfr
5582729Sdfrfound:
5592729Sdfr	/* Construct the unique msqid */
56083366Sjulian	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
56182607Sdillondone2:
562101772Salfred	mtx_unlock(&msq_mtx);
56382607Sdillon	return (error);
5642729Sdfr}
5652729Sdfr
56612866Speter#ifndef _SYS_SYSPROTO_H_
5672729Sdfrstruct msgsnd_args {
5682729Sdfr	int	msqid;
569109895Salfred	const void	*msgp;
5702729Sdfr	size_t	msgsz;
5712729Sdfr	int	msgflg;
5722729Sdfr};
57312866Speter#endif
5742729Sdfr
57582607Sdillon/*
57682607Sdillon * MPSAFE
57782607Sdillon */
57812866Speterint
57983366Sjulianmsgsnd(td, uap)
58083366Sjulian	struct thread *td;
5812729Sdfr	register struct msgsnd_args *uap;
5822729Sdfr{
5832729Sdfr	int msqid = uap->msqid;
584109895Salfred	const void *user_msgp = uap->msgp;
5852729Sdfr	size_t msgsz = uap->msgsz;
5862729Sdfr	int msgflg = uap->msgflg;
58782607Sdillon	int segs_needed, error = 0;
5882729Sdfr	register struct msqid_ds *msqptr;
5892729Sdfr	register struct msg *msghdr;
5902729Sdfr	short next;
5912729Sdfr
592100523Salfred	DPRINTF(("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
593100523Salfred	    msgflg));
59491703Sjhb	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
59591703Sjhb		return (ENOSYS);
59691703Sjhb
597101772Salfred	mtx_lock(&msq_mtx);
5982729Sdfr	msqid = IPCID_TO_IX(msqid);
5992729Sdfr
6002729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
601100523Salfred		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
602100523Salfred		    msginfo.msgmni));
60382607Sdillon		error = EINVAL;
60482607Sdillon		goto done2;
6052729Sdfr	}
6062729Sdfr
6072729Sdfr	msqptr = &msqids[msqid];
6082729Sdfr	if (msqptr->msg_qbytes == 0) {
609100523Salfred		DPRINTF(("no such message queue id\n"));
61082607Sdillon		error = EINVAL;
61182607Sdillon		goto done2;
6122729Sdfr	}
6132729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
614100523Salfred		DPRINTF(("wrong sequence number\n"));
61582607Sdillon		error = EINVAL;
61682607Sdillon		goto done2;
6172729Sdfr	}
6182729Sdfr
61983366Sjulian	if ((error = ipcperm(td, &msqptr->msg_perm, IPC_W))) {
620100523Salfred		DPRINTF(("requester doesn't have write access\n"));
62182607Sdillon		goto done2;
6222729Sdfr	}
6232729Sdfr
6242729Sdfr	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
625100523Salfred	DPRINTF(("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
626100523Salfred	    segs_needed));
6272729Sdfr	for (;;) {
6282729Sdfr		int need_more_resources = 0;
6292729Sdfr
6302729Sdfr		/*
6312729Sdfr		 * check msgsz
6322729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
6332729Sdfr		 */
6342729Sdfr
6352836Sdg		if (msgsz > msqptr->msg_qbytes) {
636100523Salfred			DPRINTF(("msgsz > msqptr->msg_qbytes\n"));
63782607Sdillon			error = EINVAL;
63882607Sdillon			goto done2;
6392729Sdfr		}
6402729Sdfr
6412729Sdfr		if (msqptr->msg_perm.mode & MSG_LOCKED) {
642100523Salfred			DPRINTF(("msqid is locked\n"));
6432729Sdfr			need_more_resources = 1;
6442729Sdfr		}
6452729Sdfr		if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
646100523Salfred			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
6472729Sdfr			need_more_resources = 1;
6482729Sdfr		}
6492729Sdfr		if (segs_needed > nfree_msgmaps) {
650100523Salfred			DPRINTF(("segs_needed > nfree_msgmaps\n"));
6512729Sdfr			need_more_resources = 1;
6522729Sdfr		}
6532729Sdfr		if (free_msghdrs == NULL) {
654100523Salfred			DPRINTF(("no more msghdrs\n"));
6552729Sdfr			need_more_resources = 1;
6562729Sdfr		}
6572729Sdfr
6582729Sdfr		if (need_more_resources) {
6592729Sdfr			int we_own_it;
6602729Sdfr
6612729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
662100523Salfred				DPRINTF(("need more resources but caller "
663100523Salfred				    "doesn't want to wait\n"));
66482607Sdillon				error = EAGAIN;
66582607Sdillon				goto done2;
6662729Sdfr			}
6672729Sdfr
6682729Sdfr			if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
669100523Salfred				DPRINTF(("we don't own the msqid_ds\n"));
6702729Sdfr				we_own_it = 0;
6712729Sdfr			} else {
6722729Sdfr				/* Force later arrivals to wait for our
6732729Sdfr				   request */
674100523Salfred				DPRINTF(("we own the msqid_ds\n"));
6752729Sdfr				msqptr->msg_perm.mode |= MSG_LOCKED;
6762729Sdfr				we_own_it = 1;
6772729Sdfr			}
678100523Salfred			DPRINTF(("goodnight\n"));
679101772Salfred			error = msleep(msqptr, &msq_mtx, (PZERO - 4) | PCATCH,
6802729Sdfr			    "msgwait", 0);
681100523Salfred			DPRINTF(("good morning, error=%d\n", error));
6822729Sdfr			if (we_own_it)
6832729Sdfr				msqptr->msg_perm.mode &= ~MSG_LOCKED;
68482607Sdillon			if (error != 0) {
685100523Salfred				DPRINTF(("msgsnd:  interrupted system call\n"));
68682607Sdillon				error = EINTR;
68782607Sdillon				goto done2;
6882729Sdfr			}
6892729Sdfr
6902729Sdfr			/*
6912729Sdfr			 * Make sure that the msq queue still exists
6922729Sdfr			 */
6932729Sdfr
6942729Sdfr			if (msqptr->msg_qbytes == 0) {
695100523Salfred				DPRINTF(("msqid deleted\n"));
69682607Sdillon				error = EIDRM;
69782607Sdillon				goto done2;
6982729Sdfr			}
6992729Sdfr
7002729Sdfr		} else {
701100523Salfred			DPRINTF(("got all the resources that we need\n"));
7022729Sdfr			break;
7032729Sdfr		}
7042729Sdfr	}
7052729Sdfr
7062729Sdfr	/*
7072729Sdfr	 * We have the resources that we need.
7082729Sdfr	 * Make sure!
7092729Sdfr	 */
7102729Sdfr
7112729Sdfr	if (msqptr->msg_perm.mode & MSG_LOCKED)
7122729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
7132729Sdfr	if (segs_needed > nfree_msgmaps)
7142729Sdfr		panic("segs_needed > nfree_msgmaps");
7152729Sdfr	if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
7162729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
7172729Sdfr	if (free_msghdrs == NULL)
7182729Sdfr		panic("no more msghdrs");
7192729Sdfr
7202729Sdfr	/*
7212729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
7222729Sdfr	 * message
7232729Sdfr	 */
7242729Sdfr
7252729Sdfr	if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
7262729Sdfr		panic("msqid_ds is already locked");
7272729Sdfr	msqptr->msg_perm.mode |= MSG_LOCKED;
7282729Sdfr
7292729Sdfr	/*
7302729Sdfr	 * Allocate a message header
7312729Sdfr	 */
7322729Sdfr
7332729Sdfr	msghdr = free_msghdrs;
7342729Sdfr	free_msghdrs = msghdr->msg_next;
7352729Sdfr	msghdr->msg_spot = -1;
7362729Sdfr	msghdr->msg_ts = msgsz;
7372729Sdfr
7382729Sdfr	/*
7392729Sdfr	 * Allocate space for the message
7402729Sdfr	 */
7412729Sdfr
7422729Sdfr	while (segs_needed > 0) {
7432729Sdfr		if (nfree_msgmaps <= 0)
7442729Sdfr			panic("not enough msgmaps");
7452729Sdfr		if (free_msgmaps == -1)
7462729Sdfr			panic("nil free_msgmaps");
7472729Sdfr		next = free_msgmaps;
7482729Sdfr		if (next <= -1)
7492729Sdfr			panic("next too low #1");
7502729Sdfr		if (next >= msginfo.msgseg)
7512729Sdfr			panic("next out of range #1");
752100523Salfred		DPRINTF(("allocating segment %d to message\n", next));
7532729Sdfr		free_msgmaps = msgmaps[next].next;
7542729Sdfr		nfree_msgmaps--;
7552729Sdfr		msgmaps[next].next = msghdr->msg_spot;
7562729Sdfr		msghdr->msg_spot = next;
7572729Sdfr		segs_needed--;
7582729Sdfr	}
7592729Sdfr
7602729Sdfr	/*
7612729Sdfr	 * Copy in the message type
7622729Sdfr	 */
7632729Sdfr
764101772Salfred	mtx_unlock(&msq_mtx);
76582607Sdillon	if ((error = copyin(user_msgp, &msghdr->msg_type,
7662729Sdfr	    sizeof(msghdr->msg_type))) != 0) {
767101772Salfred		mtx_lock(&msq_mtx);
768100523Salfred		DPRINTF(("error %d copying the message type\n", error));
7692729Sdfr		msg_freehdr(msghdr);
7702729Sdfr		msqptr->msg_perm.mode &= ~MSG_LOCKED;
771100511Salfred		wakeup(msqptr);
77282607Sdillon		goto done2;
7732729Sdfr	}
774101772Salfred	mtx_lock(&msq_mtx);
77517971Sbde	user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
7762729Sdfr
7772729Sdfr	/*
7782729Sdfr	 * Validate the message type
7792729Sdfr	 */
7802729Sdfr
7812729Sdfr	if (msghdr->msg_type < 1) {
7822729Sdfr		msg_freehdr(msghdr);
7832729Sdfr		msqptr->msg_perm.mode &= ~MSG_LOCKED;
784100511Salfred		wakeup(msqptr);
785100523Salfred		DPRINTF(("mtype (%d) < 1\n", msghdr->msg_type));
78682607Sdillon		error = EINVAL;
78782607Sdillon		goto done2;
7882729Sdfr	}
7892729Sdfr
7902729Sdfr	/*
7912729Sdfr	 * Copy in the message body
7922729Sdfr	 */
7932729Sdfr
7942729Sdfr	next = msghdr->msg_spot;
7952729Sdfr	while (msgsz > 0) {
7962729Sdfr		size_t tlen;
7972729Sdfr		if (msgsz > msginfo.msgssz)
7982729Sdfr			tlen = msginfo.msgssz;
7992729Sdfr		else
8002729Sdfr			tlen = msgsz;
8012729Sdfr		if (next <= -1)
8022729Sdfr			panic("next too low #2");
8032729Sdfr		if (next >= msginfo.msgseg)
8042729Sdfr			panic("next out of range #2");
805101772Salfred		mtx_unlock(&msq_mtx);
80682607Sdillon		if ((error = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
8072729Sdfr		    tlen)) != 0) {
808101772Salfred			mtx_lock(&msq_mtx);
809100523Salfred			DPRINTF(("error %d copying in message segment\n",
810100523Salfred			    error));
8112729Sdfr			msg_freehdr(msghdr);
8122729Sdfr			msqptr->msg_perm.mode &= ~MSG_LOCKED;
813100511Salfred			wakeup(msqptr);
81482607Sdillon			goto done2;
8152729Sdfr		}
816101772Salfred		mtx_lock(&msq_mtx);
8172729Sdfr		msgsz -= tlen;
81817971Sbde		user_msgp = (char *)user_msgp + tlen;
8192729Sdfr		next = msgmaps[next].next;
8202729Sdfr	}
8212729Sdfr	if (next != -1)
8222729Sdfr		panic("didn't use all the msg segments");
8232729Sdfr
8242729Sdfr	/*
8252729Sdfr	 * We've got the message.  Unlock the msqid_ds.
8262729Sdfr	 */
8272729Sdfr
8282729Sdfr	msqptr->msg_perm.mode &= ~MSG_LOCKED;
8292729Sdfr
8302729Sdfr	/*
8312729Sdfr	 * Make sure that the msqid_ds is still allocated.
8322729Sdfr	 */
8332729Sdfr
8342729Sdfr	if (msqptr->msg_qbytes == 0) {
8352729Sdfr		msg_freehdr(msghdr);
836100511Salfred		wakeup(msqptr);
83782607Sdillon		error = EIDRM;
83882607Sdillon		goto done2;
8392729Sdfr	}
8402729Sdfr
8412729Sdfr	/*
8422729Sdfr	 * Put the message into the queue
8432729Sdfr	 */
8442729Sdfr
8452729Sdfr	if (msqptr->msg_first == NULL) {
8462729Sdfr		msqptr->msg_first = msghdr;
8472729Sdfr		msqptr->msg_last = msghdr;
8482729Sdfr	} else {
8492729Sdfr		msqptr->msg_last->msg_next = msghdr;
8502729Sdfr		msqptr->msg_last = msghdr;
8512729Sdfr	}
8522729Sdfr	msqptr->msg_last->msg_next = NULL;
8532729Sdfr
8542729Sdfr	msqptr->msg_cbytes += msghdr->msg_ts;
8552729Sdfr	msqptr->msg_qnum++;
85683366Sjulian	msqptr->msg_lspid = td->td_proc->p_pid;
85734961Sphk	msqptr->msg_stime = time_second;
8582729Sdfr
859100511Salfred	wakeup(msqptr);
86083366Sjulian	td->td_retval[0] = 0;
86182607Sdillondone2:
862101772Salfred	mtx_unlock(&msq_mtx);
86382607Sdillon	return (error);
8642729Sdfr}
8652729Sdfr
86612866Speter#ifndef _SYS_SYSPROTO_H_
8672729Sdfrstruct msgrcv_args {
8682729Sdfr	int	msqid;
8692729Sdfr	void	*msgp;
8702729Sdfr	size_t	msgsz;
8712729Sdfr	long	msgtyp;
8722729Sdfr	int	msgflg;
8732729Sdfr};
87412866Speter#endif
8752729Sdfr
87682607Sdillon/*
87782607Sdillon * MPSAFE
87882607Sdillon */
87912866Speterint
88083366Sjulianmsgrcv(td, uap)
88183366Sjulian	struct thread *td;
8822729Sdfr	register struct msgrcv_args *uap;
8832729Sdfr{
8842729Sdfr	int msqid = uap->msqid;
8852729Sdfr	void *user_msgp = uap->msgp;
8862729Sdfr	size_t msgsz = uap->msgsz;
8872729Sdfr	long msgtyp = uap->msgtyp;
8882729Sdfr	int msgflg = uap->msgflg;
8892729Sdfr	size_t len;
8902729Sdfr	register struct msqid_ds *msqptr;
8912729Sdfr	register struct msg *msghdr;
89282607Sdillon	int error = 0;
8932729Sdfr	short next;
8942729Sdfr
895100523Salfred	DPRINTF(("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
896100523Salfred	    msgsz, msgtyp, msgflg));
8972729Sdfr
89891703Sjhb	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
89991703Sjhb		return (ENOSYS);
90091703Sjhb
9012729Sdfr	msqid = IPCID_TO_IX(msqid);
9022729Sdfr
9032729Sdfr	if (msqid < 0 || msqid >= msginfo.msgmni) {
904100523Salfred		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
905100523Salfred		    msginfo.msgmni));
906101772Salfred		return (EINVAL);
9072729Sdfr	}
9082729Sdfr
9092729Sdfr	msqptr = &msqids[msqid];
910101772Salfred	mtx_lock(&msq_mtx);
9112729Sdfr	if (msqptr->msg_qbytes == 0) {
912100523Salfred		DPRINTF(("no such message queue id\n"));
91382607Sdillon		error = EINVAL;
91482607Sdillon		goto done2;
9152729Sdfr	}
9162729Sdfr	if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
917100523Salfred		DPRINTF(("wrong sequence number\n"));
91882607Sdillon		error = EINVAL;
91982607Sdillon		goto done2;
9202729Sdfr	}
9212729Sdfr
92283366Sjulian	if ((error = ipcperm(td, &msqptr->msg_perm, IPC_R))) {
923100523Salfred		DPRINTF(("requester doesn't have read access\n"));
92482607Sdillon		goto done2;
9252729Sdfr	}
9262729Sdfr
9272729Sdfr	msghdr = NULL;
9282729Sdfr	while (msghdr == NULL) {
9292729Sdfr		if (msgtyp == 0) {
9302729Sdfr			msghdr = msqptr->msg_first;
9312729Sdfr			if (msghdr != NULL) {
9322729Sdfr				if (msgsz < msghdr->msg_ts &&
9332729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
934100523Salfred					DPRINTF(("first message on the queue "
935100523Salfred					    "is too big (want %d, got %d)\n",
936100523Salfred					    msgsz, msghdr->msg_ts));
93782607Sdillon					error = E2BIG;
93882607Sdillon					goto done2;
9392729Sdfr				}
9402729Sdfr				if (msqptr->msg_first == msqptr->msg_last) {
9412729Sdfr					msqptr->msg_first = NULL;
9422729Sdfr					msqptr->msg_last = NULL;
9432729Sdfr				} else {
9442729Sdfr					msqptr->msg_first = msghdr->msg_next;
9452729Sdfr					if (msqptr->msg_first == NULL)
9462729Sdfr						panic("msg_first/last screwed up #1");
9472729Sdfr				}
9482729Sdfr			}
9492729Sdfr		} else {
9502729Sdfr			struct msg *previous;
9512729Sdfr			struct msg **prev;
9522729Sdfr
9532729Sdfr			previous = NULL;
9542729Sdfr			prev = &(msqptr->msg_first);
9552729Sdfr			while ((msghdr = *prev) != NULL) {
9562729Sdfr				/*
9572729Sdfr				 * Is this message's type an exact match or is
9582729Sdfr				 * this message's type less than or equal to
9592729Sdfr				 * the absolute value of a negative msgtyp?
9602729Sdfr				 * Note that the second half of this test can
9612729Sdfr				 * NEVER be true if msgtyp is positive since
9622729Sdfr				 * msg_type is always positive!
9632729Sdfr				 */
9642729Sdfr
9652729Sdfr				if (msgtyp == msghdr->msg_type ||
9662729Sdfr				    msghdr->msg_type <= -msgtyp) {
967100523Salfred					DPRINTF(("found message type %d, "
968100523Salfred					    "requested %d\n",
969100523Salfred					    msghdr->msg_type, msgtyp));
9702729Sdfr					if (msgsz < msghdr->msg_ts &&
9712729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
972100523Salfred						DPRINTF(("requested message "
973100523Salfred						    "on the queue is too big "
974100523Salfred						    "(want %d, got %d)\n",
975100523Salfred						    msgsz, msghdr->msg_ts));
97682607Sdillon						error = E2BIG;
97782607Sdillon						goto done2;
9782729Sdfr					}
9792729Sdfr					*prev = msghdr->msg_next;
9802729Sdfr					if (msghdr == msqptr->msg_last) {
9812729Sdfr						if (previous == NULL) {
9822729Sdfr							if (prev !=
9832729Sdfr							    &msqptr->msg_first)
9842729Sdfr								panic("msg_first/last screwed up #2");
9852729Sdfr							msqptr->msg_first =
9862729Sdfr							    NULL;
9872729Sdfr							msqptr->msg_last =
9882729Sdfr							    NULL;
9892729Sdfr						} else {
9902729Sdfr							if (prev ==
9912729Sdfr							    &msqptr->msg_first)
9922729Sdfr								panic("msg_first/last screwed up #3");
9932729Sdfr							msqptr->msg_last =
9942729Sdfr							    previous;
9952729Sdfr						}
9962729Sdfr					}
9972729Sdfr					break;
9982729Sdfr				}
9992729Sdfr				previous = msghdr;
10002729Sdfr				prev = &(msghdr->msg_next);
10012729Sdfr			}
10022729Sdfr		}
10032729Sdfr
10042729Sdfr		/*
10052729Sdfr		 * We've either extracted the msghdr for the appropriate
10062729Sdfr		 * message or there isn't one.
10072729Sdfr		 * If there is one then bail out of this loop.
10082729Sdfr		 */
10092729Sdfr
10102729Sdfr		if (msghdr != NULL)
10112729Sdfr			break;
10122729Sdfr
10132729Sdfr		/*
10142729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
10152729Sdfr		 */
10162729Sdfr
10172729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
1018100523Salfred			DPRINTF(("no appropriate message found (msgtyp=%d)\n",
1019100523Salfred			    msgtyp));
10202729Sdfr			/* The SVID says to return ENOMSG. */
102182607Sdillon			error = ENOMSG;
102282607Sdillon			goto done2;
10232729Sdfr		}
10242729Sdfr
10252729Sdfr		/*
10262729Sdfr		 * Wait for something to happen
10272729Sdfr		 */
10282729Sdfr
1029100523Salfred		DPRINTF(("msgrcv:  goodnight\n"));
1030101772Salfred		error = msleep(msqptr, &msq_mtx, (PZERO - 4) | PCATCH,
1031101772Salfred		    "msgwait", 0);
1032100523Salfred		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
10332729Sdfr
103482607Sdillon		if (error != 0) {
1035100523Salfred			DPRINTF(("msgsnd:  interrupted system call\n"));
103682607Sdillon			error = EINTR;
103782607Sdillon			goto done2;
10382729Sdfr		}
10392729Sdfr
10402729Sdfr		/*
10412729Sdfr		 * Make sure that the msq queue still exists
10422729Sdfr		 */
10432729Sdfr
10442729Sdfr		if (msqptr->msg_qbytes == 0 ||
10452729Sdfr		    msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
1046100523Salfred			DPRINTF(("msqid deleted\n"));
104782607Sdillon			error = EIDRM;
104882607Sdillon			goto done2;
10492729Sdfr		}
10502729Sdfr	}
10512729Sdfr
10522729Sdfr	/*
10532729Sdfr	 * Return the message to the user.
10542729Sdfr	 *
10552729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
10562729Sdfr	 */
10572729Sdfr
10582729Sdfr	msqptr->msg_cbytes -= msghdr->msg_ts;
10592729Sdfr	msqptr->msg_qnum--;
106083366Sjulian	msqptr->msg_lrpid = td->td_proc->p_pid;
106134961Sphk	msqptr->msg_rtime = time_second;
10622729Sdfr
10632729Sdfr	/*
10642729Sdfr	 * Make msgsz the actual amount that we'll be returning.
10652729Sdfr	 * Note that this effectively truncates the message if it is too long
10662729Sdfr	 * (since msgsz is never increased).
10672729Sdfr	 */
10682729Sdfr
1069100523Salfred	DPRINTF(("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
1070100523Salfred	    msghdr->msg_ts));
10712729Sdfr	if (msgsz > msghdr->msg_ts)
10722729Sdfr		msgsz = msghdr->msg_ts;
10732729Sdfr
10742729Sdfr	/*
10752729Sdfr	 * Return the type to the user.
10762729Sdfr	 */
10772729Sdfr
1078101772Salfred	mtx_unlock(&msq_mtx);
1079100511Salfred	error = copyout(&(msghdr->msg_type), user_msgp,
10802729Sdfr	    sizeof(msghdr->msg_type));
1081101772Salfred	mtx_lock(&msq_mtx);
108282607Sdillon	if (error != 0) {
1083100523Salfred		DPRINTF(("error (%d) copying out message type\n", error));
10842729Sdfr		msg_freehdr(msghdr);
1085100511Salfred		wakeup(msqptr);
108682607Sdillon		goto done2;
10872729Sdfr	}
108817971Sbde	user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
10892729Sdfr
10902729Sdfr	/*
10912729Sdfr	 * Return the segments to the user
10922729Sdfr	 */
10932729Sdfr
10942729Sdfr	next = msghdr->msg_spot;
10952729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
10962729Sdfr		size_t tlen;
10972729Sdfr
109845921Ssada		if (msgsz - len > msginfo.msgssz)
10992729Sdfr			tlen = msginfo.msgssz;
11002729Sdfr		else
110145921Ssada			tlen = msgsz - len;
11022729Sdfr		if (next <= -1)
11032729Sdfr			panic("next too low #3");
11042729Sdfr		if (next >= msginfo.msgseg)
11052729Sdfr			panic("next out of range #3");
1106101772Salfred		mtx_unlock(&msq_mtx);
1107100511Salfred		error = copyout(&msgpool[next * msginfo.msgssz],
11082729Sdfr		    user_msgp, tlen);
1109101772Salfred		mtx_lock(&msq_mtx);
111082607Sdillon		if (error != 0) {
1111100523Salfred			DPRINTF(("error (%d) copying out message segment\n",
1112100523Salfred			    error));
11132729Sdfr			msg_freehdr(msghdr);
1114100511Salfred			wakeup(msqptr);
111582607Sdillon			goto done2;
11162729Sdfr		}
111717971Sbde		user_msgp = (char *)user_msgp + tlen;
11182729Sdfr		next = msgmaps[next].next;
11192729Sdfr	}
11202729Sdfr
11212729Sdfr	/*
11222729Sdfr	 * Done, return the actual number of bytes copied out.
11232729Sdfr	 */
11242729Sdfr
11252729Sdfr	msg_freehdr(msghdr);
1126100511Salfred	wakeup(msqptr);
112783366Sjulian	td->td_retval[0] = msgsz;
112882607Sdillondone2:
1129101772Salfred	mtx_unlock(&msq_mtx);
113082607Sdillon	return (error);
11312729Sdfr}
113277461Sdd
113377461Sddstatic int
113477461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS)
113577461Sdd{
113677461Sdd
113777461Sdd	return (SYSCTL_OUT(req, msqids,
113877461Sdd	    sizeof(struct msqid_ds) * msginfo.msgmni));
113977461Sdd}
114077461Sdd
114177461SddSYSCTL_DECL(_kern_ipc);
114277461SddSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, "");
114377461SddSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RD, &msginfo.msgmni, 0, "");
114477461SddSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RD, &msginfo.msgmnb, 0, "");
114577461SddSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RD, &msginfo.msgtql, 0, "");
114677461SddSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RD, &msginfo.msgssz, 0, "");
1147100076SmarkmSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RD, &msginfo.msgseg, 0, "");
114877461SddSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_RD,
114977461Sdd    NULL, 0, sysctl_msqids, "", "Message queue IDs");
1150