sysv_msg.c revision 220399
1139804Simp/*-
22729Sdfr * Implementation of SVID messages
32729Sdfr *
42729Sdfr * Author:  Daniel Boulet
52729Sdfr *
62729Sdfr * Copyright 1993 Daniel Boulet and RTMX Inc.
72729Sdfr *
82729Sdfr * This system call was implemented by Daniel Boulet under contract from RTMX.
92729Sdfr *
102729Sdfr * Redistribution and use in source forms, with and without modification,
112729Sdfr * are permitted provided that this entire comment appears intact.
122729Sdfr *
132729Sdfr * Redistribution in binary form may occur without any restrictions.
142729Sdfr * Obviously, it would be nice if you gave credit where credit is due
152729Sdfr * but requiring it would be too onerous.
162729Sdfr *
172729Sdfr * This software is provided ``AS IS'' without any warranties of any kind.
182729Sdfr */
19140614Srwatson/*-
20140614Srwatson * Copyright (c) 2003-2005 McAfee, Inc.
21140614Srwatson * All rights reserved.
22140614Srwatson *
23140614Srwatson * This software was developed for the FreeBSD Project in part by McAfee
24140614Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
25140614Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
26140614Srwatson * program.
27140614Srwatson *
28140614Srwatson * Redistribution and use in source and binary forms, with or without
29140614Srwatson * modification, are permitted provided that the following conditions
30140614Srwatson * are met:
31140614Srwatson * 1. Redistributions of source code must retain the above copyright
32140614Srwatson *    notice, this list of conditions and the following disclaimer.
33140614Srwatson * 2. Redistributions in binary form must reproduce the above copyright
34140614Srwatson *    notice, this list of conditions and the following disclaimer in the
35140614Srwatson *    documentation and/or other materials provided with the distribution.
36140614Srwatson *
37140614Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38140614Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39140614Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40140614Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41140614Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42140614Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43140614Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44140614Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45140614Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46140614Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47140614Srwatson * SUCH DAMAGE.
48140614Srwatson */
492729Sdfr
50116182Sobrien#include <sys/cdefs.h>
51116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/sysv_msg.c 220399 2011-04-06 19:08:50Z trasz $");
52116182Sobrien
53194894Sjhb#include "opt_compat.h"
5459839Speter#include "opt_sysvipc.h"
5559839Speter
562729Sdfr#include <sys/param.h>
572729Sdfr#include <sys/systm.h>
5811626Sbde#include <sys/sysproto.h>
592729Sdfr#include <sys/kernel.h>
60164033Srwatson#include <sys/priv.h>
612729Sdfr#include <sys/proc.h>
6282607Sdillon#include <sys/lock.h>
6382607Sdillon#include <sys/mutex.h>
64129882Sphk#include <sys/module.h>
652729Sdfr#include <sys/msg.h>
66220398Strasz#include <sys/racct.h>
6769449Salfred#include <sys/syscall.h>
68140839Ssobomax#include <sys/syscallsubr.h>
6911626Sbde#include <sys/sysent.h>
7059839Speter#include <sys/sysctl.h>
7159839Speter#include <sys/malloc.h>
7268024Srwatson#include <sys/jail.h>
732729Sdfr
74163606Srwatson#include <security/mac/mac_framework.h>
75163606Srwatson
76219028SnetchildFEATURE(sysv_msg, "System V message queues support");
77219028Snetchild
7859839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
7959839Speter
80205323Skibstatic int msginit(void);
8192723Salfredstatic int msgunload(void);
8292723Salfredstatic int sysvmsg_modload(struct module *, int, void *);
8310358Sjulian
84100523Salfred#ifdef MSG_DEBUG
85100523Salfred#define DPRINTF(a)	printf a
86100523Salfred#else
87194575Srdivacky#define DPRINTF(a)	(void)0
88100523Salfred#endif
892729Sdfr
9092723Salfredstatic void msg_freehdr(struct msg *msghdr);
912729Sdfr
9259839Speter#ifndef MSGSSZ
9359839Speter#define MSGSSZ	8		/* Each segment must be 2^N long */
9459839Speter#endif
9559839Speter#ifndef MSGSEG
9659839Speter#define MSGSEG	2048		/* must be less than 32767 */
9759839Speter#endif
9859839Speter#define MSGMAX	(MSGSSZ*MSGSEG)
9959839Speter#ifndef MSGMNB
10059839Speter#define MSGMNB	2048		/* max # of bytes in a queue */
10159839Speter#endif
10259839Speter#ifndef MSGMNI
10359839Speter#define MSGMNI	40
10459839Speter#endif
10559839Speter#ifndef MSGTQL
10659839Speter#define MSGTQL	40
10759839Speter#endif
10859839Speter
10959839Speter/*
11059839Speter * Based on the configuration parameters described in an SVR2 (yes, two)
11159839Speter * config(1m) man page.
11259839Speter *
11359839Speter * Each message is broken up and stored in segments that are msgssz bytes
11459839Speter * long.  For efficiency reasons, this should be a power of two.  Also,
11559839Speter * it doesn't make sense if it is less than 8 or greater than about 256.
11659839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
11759839Speter * two between 8 and 1024 inclusive (and panic's if it isn't).
11859839Speter */
11959839Speterstruct msginfo msginfo = {
12059839Speter                MSGMAX,         /* max chars in a message */
12159839Speter                MSGMNI,         /* # of message queue identifiers */
12259839Speter                MSGMNB,         /* max chars in a queue */
12359839Speter                MSGTQL,         /* max messages in system */
12459839Speter                MSGSSZ,         /* size of a message segment */
12559839Speter                		/* (must be small power of 2 greater than 4) */
12659839Speter                MSGSEG          /* number of message segments */
12759839Speter};
12859839Speter
12959839Speter/*
13059839Speter * macros to convert between msqid_ds's and msqid's.
13159839Speter * (specific to this implementation)
13259839Speter */
13359839Speter#define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
13459839Speter#define MSQID_IX(id)	((id) & 0xffff)
13559839Speter#define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
13659839Speter
13759839Speter/*
13859839Speter * The rest of this file is specific to this particular implementation.
13959839Speter */
14059839Speter
14159839Speterstruct msgmap {
14259839Speter	short	next;		/* next segment in buffer */
14359839Speter    				/* -1 -> available */
14459839Speter    				/* 0..(MSGSEG-1) -> index of next segment */
14559839Speter};
14659839Speter
14759839Speter#define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
14859839Speter
14912819Sphkstatic int nfree_msgmaps;	/* # of free map entries */
15012819Sphkstatic short free_msgmaps;	/* head of linked list of free map entries */
15159839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */
15259839Speterstatic char *msgpool;		/* MSGMAX byte long msg buffer pool */
15359839Speterstatic struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
15459839Speterstatic struct msg *msghdrs;	/* MSGTQL msg headers */
155137613Srwatsonstatic struct msqid_kernel *msqids;	/* MSGMNI msqid_kernel struct's */
156101772Salfredstatic struct mtx msq_mtx;	/* global mutex for message queues. */
1572729Sdfr
158205323Skibstatic struct syscall_helper_data msg_syscalls[] = {
159205323Skib	SYSCALL_INIT_HELPER(msgctl),
160205323Skib	SYSCALL_INIT_HELPER(msgget),
161205323Skib	SYSCALL_INIT_HELPER(msgsnd),
162205323Skib	SYSCALL_INIT_HELPER(msgrcv),
163205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
164205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
165205323Skib	SYSCALL_INIT_HELPER(msgsys),
166205323Skib	SYSCALL_INIT_HELPER(freebsd7_msgctl),
167205323Skib#endif
168205323Skib	SYSCALL_INIT_LAST
169205323Skib};
170205323Skib
171205323Skib#ifdef COMPAT_FREEBSD32
172205323Skib#include <compat/freebsd32/freebsd32.h>
173205323Skib#include <compat/freebsd32/freebsd32_ipc.h>
174205323Skib#include <compat/freebsd32/freebsd32_proto.h>
175205323Skib#include <compat/freebsd32/freebsd32_signal.h>
176205323Skib#include <compat/freebsd32/freebsd32_syscall.h>
177205323Skib#include <compat/freebsd32/freebsd32_util.h>
178205323Skib
179205323Skibstatic struct syscall_helper_data msg32_syscalls[] = {
180205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgctl),
181205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsnd),
182205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgrcv),
183205323Skib	SYSCALL32_INIT_HELPER(msgget),
184205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsys),
185205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
186205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
187205323Skib	SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl),
188205323Skib#endif
189205323Skib	SYSCALL_INIT_LAST
190205323Skib};
191205323Skib#endif
192205323Skib
193205323Skibstatic int
19469449Salfredmsginit()
1952729Sdfr{
196205323Skib	int i, error;
1972729Sdfr
19883765Smr	TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
19983765Smr	TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
20083765Smr	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
20183765Smr	TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
202139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb);
203139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql);
20483765Smr
205111119Simp	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
206111119Simp	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
207111119Simp	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
208137613Srwatson	msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
209137613Srwatson	    M_WAITOK);
21059839Speter
2112729Sdfr	/*
2122729Sdfr	 * msginfo.msgssz should be a power of two for efficiency reasons.
2132729Sdfr	 * It is also pretty silly if msginfo.msgssz is less than 8
2142729Sdfr	 * or greater than about 256 so ...
2152729Sdfr	 */
2162729Sdfr
2172729Sdfr	i = 8;
2182729Sdfr	while (i < 1024 && i != msginfo.msgssz)
2192729Sdfr		i <<= 1;
2202729Sdfr    	if (i != msginfo.msgssz) {
221100523Salfred		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
222100523Salfred		    msginfo.msgssz));
2232729Sdfr		panic("msginfo.msgssz not a small power of 2");
2242729Sdfr	}
2252729Sdfr
2262729Sdfr	if (msginfo.msgseg > 32767) {
227100523Salfred		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
2282729Sdfr		panic("msginfo.msgseg > 32767");
2292729Sdfr	}
2302729Sdfr
2312729Sdfr	for (i = 0; i < msginfo.msgseg; i++) {
2322729Sdfr		if (i > 0)
2332729Sdfr			msgmaps[i-1].next = i;
2342729Sdfr		msgmaps[i].next = -1;	/* implies entry is available */
2352729Sdfr	}
2362729Sdfr	free_msgmaps = 0;
2372729Sdfr	nfree_msgmaps = msginfo.msgseg;
2382729Sdfr
2392729Sdfr	for (i = 0; i < msginfo.msgtql; i++) {
2402729Sdfr		msghdrs[i].msg_type = 0;
2412729Sdfr		if (i > 0)
2422729Sdfr			msghdrs[i-1].msg_next = &msghdrs[i];
2432729Sdfr		msghdrs[i].msg_next = NULL;
244140614Srwatson#ifdef MAC
245172930Srwatson		mac_sysvmsg_init(&msghdrs[i]);
246140614Srwatson#endif
2472729Sdfr    	}
2482729Sdfr	free_msghdrs = &msghdrs[0];
2492729Sdfr
2502729Sdfr	for (i = 0; i < msginfo.msgmni; i++) {
251137613Srwatson		msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
252137613Srwatson		msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
253137613Srwatson		msqids[i].u.msg_perm.mode = 0;
254140614Srwatson#ifdef MAC
255172930Srwatson		mac_sysvmsq_init(&msqids[i]);
256140614Srwatson#endif
2572729Sdfr	}
258101772Salfred	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
259205323Skib
260205323Skib	error = syscall_helper_register(msg_syscalls);
261205323Skib	if (error != 0)
262205323Skib		return (error);
263205323Skib#ifdef COMPAT_FREEBSD32
264205323Skib	error = syscall32_helper_register(msg32_syscalls);
265205323Skib	if (error != 0)
266205323Skib		return (error);
267205323Skib#endif
268205323Skib	return (0);
2692729Sdfr}
2702729Sdfr
27169449Salfredstatic int
27269449Salfredmsgunload()
27369449Salfred{
274137613Srwatson	struct msqid_kernel *msqkptr;
27569449Salfred	int msqid;
276140614Srwatson#ifdef MAC
277140614Srwatson	int i;
278140614Srwatson#endif
27969449Salfred
280205323Skib	syscall_helper_unregister(msg_syscalls);
281205323Skib#ifdef COMPAT_FREEBSD32
282205323Skib	syscall32_helper_unregister(msg32_syscalls);
283205323Skib#endif
284205323Skib
28569449Salfred	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
28669449Salfred		/*
28769449Salfred		 * Look for an unallocated and unlocked msqid_ds.
28869449Salfred		 * msqid_ds's can be locked by msgsnd or msgrcv while
28969449Salfred		 * they are copying the message in/out.  We can't
29069449Salfred		 * re-use the entry until they release it.
29169449Salfred		 */
292137613Srwatson		msqkptr = &msqids[msqid];
293137613Srwatson		if (msqkptr->u.msg_qbytes != 0 ||
294137613Srwatson		    (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
29569449Salfred			break;
29669449Salfred	}
29769449Salfred	if (msqid != msginfo.msgmni)
29869449Salfred		return (EBUSY);
29969449Salfred
300140614Srwatson#ifdef MAC
301140614Srwatson	for (i = 0; i < msginfo.msgtql; i++)
302172930Srwatson		mac_sysvmsg_destroy(&msghdrs[i]);
303140614Srwatson	for (msqid = 0; msqid < msginfo.msgmni; msqid++)
304172930Srwatson		mac_sysvmsq_destroy(&msqids[msqid]);
305140614Srwatson#endif
30669449Salfred	free(msgpool, M_MSG);
30769449Salfred	free(msgmaps, M_MSG);
30869449Salfred	free(msghdrs, M_MSG);
30969449Salfred	free(msqids, M_MSG);
310101772Salfred	mtx_destroy(&msq_mtx);
31169449Salfred	return (0);
31269449Salfred}
31369449Salfred
31469449Salfred
31569449Salfredstatic int
31669449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg)
31769449Salfred{
31869449Salfred	int error = 0;
31969449Salfred
32069449Salfred	switch (cmd) {
32169449Salfred	case MOD_LOAD:
322205323Skib		error = msginit();
323205323Skib		if (error != 0)
324205323Skib			msgunload();
32569449Salfred		break;
32669449Salfred	case MOD_UNLOAD:
32769449Salfred		error = msgunload();
32869449Salfred		break;
32969449Salfred	case MOD_SHUTDOWN:
33069449Salfred		break;
33169449Salfred	default:
33269449Salfred		error = EINVAL;
33369449Salfred		break;
33469449Salfred	}
33569449Salfred	return (error);
33669449Salfred}
33769449Salfred
33871038Sdesstatic moduledata_t sysvmsg_mod = {
33971038Sdes	"sysvmsg",
34069449Salfred	&sysvmsg_modload,
34169449Salfred	NULL
34269449Salfred};
34369449Salfred
344194832SjhbDECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
34571038SdesMODULE_VERSION(sysvmsg, 1);
34669449Salfred
3472729Sdfrstatic void
3482729Sdfrmsg_freehdr(msghdr)
3492729Sdfr	struct msg *msghdr;
3502729Sdfr{
3512729Sdfr	while (msghdr->msg_ts > 0) {
3522729Sdfr		short next;
3532729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
3542729Sdfr			panic("msghdr->msg_spot out of range");
3552729Sdfr		next = msgmaps[msghdr->msg_spot].next;
3562729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
3572729Sdfr		free_msgmaps = msghdr->msg_spot;
3582729Sdfr		nfree_msgmaps++;
3592729Sdfr		msghdr->msg_spot = next;
3602729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
3612729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
3622729Sdfr		else
3632729Sdfr			msghdr->msg_ts = 0;
3642729Sdfr	}
3652729Sdfr	if (msghdr->msg_spot != -1)
3662729Sdfr		panic("msghdr->msg_spot != -1");
3672729Sdfr	msghdr->msg_next = free_msghdrs;
3682729Sdfr	free_msghdrs = msghdr;
369140614Srwatson#ifdef MAC
370172930Srwatson	mac_sysvmsg_cleanup(msghdr);
371140614Srwatson#endif
3722729Sdfr}
3732729Sdfr
37412866Speter#ifndef _SYS_SYSPROTO_H_
3752729Sdfrstruct msgctl_args {
3762729Sdfr	int	msqid;
3772729Sdfr	int	cmd;
37812866Speter	struct	msqid_ds *buf;
3792729Sdfr};
38012866Speter#endif
38112866Speterint
38283366Sjulianmsgctl(td, uap)
38383366Sjulian	struct thread *td;
3842729Sdfr	register struct msgctl_args *uap;
3852729Sdfr{
3862729Sdfr	int msqid = uap->msqid;
3872729Sdfr	int cmd = uap->cmd;
3882729Sdfr	struct msqid_ds msqbuf;
389140839Ssobomax	int error;
390140839Ssobomax
391165403Sjkim	DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf));
392140839Ssobomax	if (cmd == IPC_SET &&
393140839Ssobomax	    (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
394140839Ssobomax		return (error);
395141471Sjhb	error = kern_msgctl(td, msqid, cmd, &msqbuf);
396140839Ssobomax	if (cmd == IPC_STAT && error == 0)
397141471Sjhb		error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
398140839Ssobomax	return (error);
399140839Ssobomax}
400140839Ssobomax
401140839Ssobomaxint
402141471Sjhbkern_msgctl(td, msqid, cmd, msqbuf)
403140839Ssobomax	struct thread *td;
404140839Ssobomax	int msqid;
405140839Ssobomax	int cmd;
406140839Ssobomax	struct msqid_ds *msqbuf;
407140839Ssobomax{
408140839Ssobomax	int rval, error, msqix;
409137613Srwatson	register struct msqid_kernel *msqkptr;
4102729Sdfr
411192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
41291703Sjhb		return (ENOSYS);
41391703Sjhb
414140839Ssobomax	msqix = IPCID_TO_IX(msqid);
4152729Sdfr
416140839Ssobomax	if (msqix < 0 || msqix >= msginfo.msgmni) {
417140839Ssobomax		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
418100523Salfred		    msginfo.msgmni));
419101772Salfred		return (EINVAL);
4202729Sdfr	}
4212729Sdfr
422140839Ssobomax	msqkptr = &msqids[msqix];
4232729Sdfr
424101772Salfred	mtx_lock(&msq_mtx);
425137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
426100523Salfred		DPRINTF(("no such msqid\n"));
42782607Sdillon		error = EINVAL;
42882607Sdillon		goto done2;
4292729Sdfr	}
430140839Ssobomax	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
431100523Salfred		DPRINTF(("wrong sequence number\n"));
43282607Sdillon		error = EINVAL;
43382607Sdillon		goto done2;
4342729Sdfr	}
435140614Srwatson#ifdef MAC
436172930Srwatson	error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd);
437162468Srwatson	if (error != 0)
438140614Srwatson		goto done2;
439140614Srwatson#endif
4402729Sdfr
44182607Sdillon	error = 0;
4422729Sdfr	rval = 0;
4432729Sdfr
4442729Sdfr	switch (cmd) {
4452729Sdfr
4462729Sdfr	case IPC_RMID:
4472729Sdfr	{
4482729Sdfr		struct msg *msghdr;
449137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
45082607Sdillon			goto done2;
451137613Srwatson
452140614Srwatson#ifdef MAC
453140614Srwatson		/*
454140614Srwatson		 * Check that the thread has MAC access permissions to
455140614Srwatson		 * individual msghdrs.  Note: We need to do this in a
456140614Srwatson		 * separate loop because the actual loop alters the
457140614Srwatson		 * msq/msghdr info as it progresses, and there is no going
458140614Srwatson		 * back if half the way through we discover that the
459140614Srwatson		 * thread cannot free a certain msghdr.  The msq will get
460140614Srwatson		 * into an inconsistent state.
461140614Srwatson		 */
462140614Srwatson		for (msghdr = msqkptr->u.msg_first; msghdr != NULL;
463140614Srwatson		    msghdr = msghdr->msg_next) {
464172930Srwatson			error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr);
465162468Srwatson			if (error != 0)
466140614Srwatson				goto done2;
467140614Srwatson		}
468140614Srwatson#endif
469140614Srwatson
470220398Strasz		racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1);
471220398Strasz		racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum);
472220398Strasz		racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes);
473220388Strasz		crfree(msqkptr->cred);
474220388Strasz		msqkptr->cred = NULL;
475220388Strasz
4762729Sdfr		/* Free the message headers */
477137613Srwatson		msghdr = msqkptr->u.msg_first;
4782729Sdfr		while (msghdr != NULL) {
4792729Sdfr			struct msg *msghdr_tmp;
4802729Sdfr
4812729Sdfr			/* Free the segments of each message */
482137613Srwatson			msqkptr->u.msg_cbytes -= msghdr->msg_ts;
483137613Srwatson			msqkptr->u.msg_qnum--;
4842729Sdfr			msghdr_tmp = msghdr;
4852729Sdfr			msghdr = msghdr->msg_next;
4862729Sdfr			msg_freehdr(msghdr_tmp);
4872729Sdfr		}
4882729Sdfr
489137613Srwatson		if (msqkptr->u.msg_cbytes != 0)
4902729Sdfr			panic("msg_cbytes is screwed up");
491137613Srwatson		if (msqkptr->u.msg_qnum != 0)
4922729Sdfr			panic("msg_qnum is screwed up");
4932729Sdfr
494137613Srwatson		msqkptr->u.msg_qbytes = 0;	/* Mark it as free */
4952729Sdfr
496140614Srwatson#ifdef MAC
497172930Srwatson		mac_sysvmsq_cleanup(msqkptr);
498140614Srwatson#endif
499140614Srwatson
500137613Srwatson		wakeup(msqkptr);
5012729Sdfr	}
5022729Sdfr
5032729Sdfr		break;
5042729Sdfr
5052729Sdfr	case IPC_SET:
506137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
50782607Sdillon			goto done2;
508140839Ssobomax		if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) {
509170587Srwatson			error = priv_check(td, PRIV_IPC_MSGSIZE);
51082607Sdillon			if (error)
51182607Sdillon				goto done2;
51243426Sphk		}
513140839Ssobomax		if (msqbuf->msg_qbytes > msginfo.msgmnb) {
514100523Salfred			DPRINTF(("can't increase msg_qbytes beyond %d"
515100523Salfred			    "(truncating)\n", msginfo.msgmnb));
516140839Ssobomax			msqbuf->msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
5172729Sdfr		}
518140839Ssobomax		if (msqbuf->msg_qbytes == 0) {
519100523Salfred			DPRINTF(("can't reduce msg_qbytes to 0\n"));
52082607Sdillon			error = EINVAL;		/* non-standard errno! */
52182607Sdillon			goto done2;
5222729Sdfr		}
523140839Ssobomax		msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid;	/* change the owner */
524140839Ssobomax		msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid;	/* change the owner */
525137613Srwatson		msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) |
526140839Ssobomax		    (msqbuf->msg_perm.mode & 0777);
527140839Ssobomax		msqkptr->u.msg_qbytes = msqbuf->msg_qbytes;
528137613Srwatson		msqkptr->u.msg_ctime = time_second;
5292729Sdfr		break;
5302729Sdfr
5312729Sdfr	case IPC_STAT:
532137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
533100523Salfred			DPRINTF(("requester doesn't have read access\n"));
53482607Sdillon			goto done2;
5352729Sdfr		}
536141471Sjhb		*msqbuf = msqkptr->u;
5372729Sdfr		break;
5382729Sdfr
5392729Sdfr	default:
540100523Salfred		DPRINTF(("invalid command %d\n", cmd));
54182607Sdillon		error = EINVAL;
54282607Sdillon		goto done2;
5432729Sdfr	}
5442729Sdfr
54582607Sdillon	if (error == 0)
54683366Sjulian		td->td_retval[0] = rval;
54782607Sdillondone2:
548101772Salfred	mtx_unlock(&msq_mtx);
549141471Sjhb	return (error);
5502729Sdfr}
5512729Sdfr
55212866Speter#ifndef _SYS_SYSPROTO_H_
5532729Sdfrstruct msgget_args {
5542729Sdfr	key_t	key;
5552729Sdfr	int	msgflg;
5562729Sdfr};
55712866Speter#endif
55812866Speterint
55983366Sjulianmsgget(td, uap)
56083366Sjulian	struct thread *td;
5612729Sdfr	register struct msgget_args *uap;
5622729Sdfr{
56382607Sdillon	int msqid, error = 0;
5642729Sdfr	int key = uap->key;
5652729Sdfr	int msgflg = uap->msgflg;
56691703Sjhb	struct ucred *cred = td->td_ucred;
567137613Srwatson	register struct msqid_kernel *msqkptr = NULL;
5682729Sdfr
569100523Salfred	DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
5702729Sdfr
571192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
57291703Sjhb		return (ENOSYS);
57391703Sjhb
574101772Salfred	mtx_lock(&msq_mtx);
5752729Sdfr	if (key != IPC_PRIVATE) {
5762729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
577137613Srwatson			msqkptr = &msqids[msqid];
578137613Srwatson			if (msqkptr->u.msg_qbytes != 0 &&
579137613Srwatson			    msqkptr->u.msg_perm.key == key)
5802729Sdfr				break;
5812729Sdfr		}
5822729Sdfr		if (msqid < msginfo.msgmni) {
583100523Salfred			DPRINTF(("found public key\n"));
5842729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
585100523Salfred				DPRINTF(("not exclusive\n"));
58682607Sdillon				error = EEXIST;
58782607Sdillon				goto done2;
5882729Sdfr			}
589137613Srwatson			if ((error = ipcperm(td, &msqkptr->u.msg_perm,
590137613Srwatson			    msgflg & 0700))) {
591100523Salfred				DPRINTF(("requester doesn't have 0%o access\n",
592100523Salfred				    msgflg & 0700));
59382607Sdillon				goto done2;
5942729Sdfr			}
595140614Srwatson#ifdef MAC
596172930Srwatson			error = mac_sysvmsq_check_msqget(cred, msqkptr);
597162468Srwatson			if (error != 0)
598140614Srwatson				goto done2;
599140614Srwatson#endif
6002729Sdfr			goto found;
6012729Sdfr		}
6022729Sdfr	}
6032729Sdfr
604100523Salfred	DPRINTF(("need to allocate the msqid_ds\n"));
6052729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
6062729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
6072729Sdfr			/*
6082729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
6092729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
6102729Sdfr			 * they are copying the message in/out.  We can't
6112729Sdfr			 * re-use the entry until they release it.
6122729Sdfr			 */
613137613Srwatson			msqkptr = &msqids[msqid];
614137613Srwatson			if (msqkptr->u.msg_qbytes == 0 &&
615137613Srwatson			    (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
6162729Sdfr				break;
6172729Sdfr		}
6182729Sdfr		if (msqid == msginfo.msgmni) {
619100523Salfred			DPRINTF(("no more msqid_ds's available\n"));
62082607Sdillon			error = ENOSPC;
62182607Sdillon			goto done2;
6222729Sdfr		}
623220398Strasz		PROC_LOCK(td->td_proc);
624220398Strasz		error = racct_add(td->td_proc, RACCT_NMSGQ, 1);
625220398Strasz		PROC_UNLOCK(td->td_proc);
626220398Strasz		if (error != 0) {
627220398Strasz			error = ENOSPC;
628220398Strasz			goto done2;
629220398Strasz		}
630100523Salfred		DPRINTF(("msqid %d is available\n", msqid));
631137613Srwatson		msqkptr->u.msg_perm.key = key;
632137613Srwatson		msqkptr->u.msg_perm.cuid = cred->cr_uid;
633137613Srwatson		msqkptr->u.msg_perm.uid = cred->cr_uid;
634137613Srwatson		msqkptr->u.msg_perm.cgid = cred->cr_gid;
635137613Srwatson		msqkptr->u.msg_perm.gid = cred->cr_gid;
636137613Srwatson		msqkptr->u.msg_perm.mode = (msgflg & 0777);
637220399Strasz		msqkptr->cred = crhold(cred);
6382729Sdfr		/* Make sure that the returned msqid is unique */
639137613Srwatson		msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff;
640137613Srwatson		msqkptr->u.msg_first = NULL;
641137613Srwatson		msqkptr->u.msg_last = NULL;
642137613Srwatson		msqkptr->u.msg_cbytes = 0;
643137613Srwatson		msqkptr->u.msg_qnum = 0;
644137613Srwatson		msqkptr->u.msg_qbytes = msginfo.msgmnb;
645137613Srwatson		msqkptr->u.msg_lspid = 0;
646137613Srwatson		msqkptr->u.msg_lrpid = 0;
647137613Srwatson		msqkptr->u.msg_stime = 0;
648137613Srwatson		msqkptr->u.msg_rtime = 0;
649137613Srwatson		msqkptr->u.msg_ctime = time_second;
650140614Srwatson#ifdef MAC
651172930Srwatson		mac_sysvmsq_create(cred, msqkptr);
652140614Srwatson#endif
6532729Sdfr	} else {
654100523Salfred		DPRINTF(("didn't find it and wasn't asked to create it\n"));
65582607Sdillon		error = ENOENT;
65682607Sdillon		goto done2;
6572729Sdfr	}
6582729Sdfr
6592729Sdfrfound:
6602729Sdfr	/* Construct the unique msqid */
661137613Srwatson	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
66282607Sdillondone2:
663101772Salfred	mtx_unlock(&msq_mtx);
66482607Sdillon	return (error);
6652729Sdfr}
6662729Sdfr
66712866Speter#ifndef _SYS_SYSPROTO_H_
6682729Sdfrstruct msgsnd_args {
6692729Sdfr	int	msqid;
670109895Salfred	const void	*msgp;
6712729Sdfr	size_t	msgsz;
6722729Sdfr	int	msgflg;
6732729Sdfr};
67412866Speter#endif
67512866Speterint
676165403Sjkimkern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype)
67783366Sjulian	struct thread *td;
678165403Sjkim	int msqid;
679165403Sjkim	const void *msgp;	/* XXX msgp is actually mtext. */
680165403Sjkim	size_t msgsz;
681165403Sjkim	int msgflg;
682165403Sjkim	long mtype;
6832729Sdfr{
684165403Sjkim	int msqix, segs_needed, error = 0;
685137613Srwatson	register struct msqid_kernel *msqkptr;
6862729Sdfr	register struct msg *msghdr;
6872729Sdfr	short next;
688220398Strasz	size_t saved_msgsz;
6892729Sdfr
690192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
69191703Sjhb		return (ENOSYS);
69291703Sjhb
693101772Salfred	mtx_lock(&msq_mtx);
694165403Sjkim	msqix = IPCID_TO_IX(msqid);
6952729Sdfr
696165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
697165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
698100523Salfred		    msginfo.msgmni));
69982607Sdillon		error = EINVAL;
70082607Sdillon		goto done2;
7012729Sdfr	}
7022729Sdfr
703165403Sjkim	msqkptr = &msqids[msqix];
704137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
705100523Salfred		DPRINTF(("no such message queue id\n"));
70682607Sdillon		error = EINVAL;
70782607Sdillon		goto done2;
7082729Sdfr	}
709165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
710100523Salfred		DPRINTF(("wrong sequence number\n"));
71182607Sdillon		error = EINVAL;
71282607Sdillon		goto done2;
7132729Sdfr	}
7142729Sdfr
715137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) {
716100523Salfred		DPRINTF(("requester doesn't have write access\n"));
71782607Sdillon		goto done2;
7182729Sdfr	}
7192729Sdfr
720140614Srwatson#ifdef MAC
721172930Srwatson	error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr);
722162468Srwatson	if (error != 0)
723140614Srwatson		goto done2;
724140614Srwatson#endif
725140614Srwatson
726220398Strasz	PROC_LOCK(td->td_proc);
727220398Strasz	if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) {
728220398Strasz		PROC_UNLOCK(td->td_proc);
729220398Strasz		error = EAGAIN;
730220398Strasz		goto done2;
731220398Strasz	}
732220398Strasz	saved_msgsz = msgsz;
733220398Strasz	if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) {
734220398Strasz		racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
735220398Strasz		PROC_UNLOCK(td->td_proc);
736220398Strasz		error = EAGAIN;
737220398Strasz		goto done2;
738220398Strasz	}
739220398Strasz	PROC_UNLOCK(td->td_proc);
740220398Strasz
7412729Sdfr	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
742165403Sjkim	DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
743165403Sjkim	    msginfo.msgssz, segs_needed));
7442729Sdfr	for (;;) {
7452729Sdfr		int need_more_resources = 0;
7462729Sdfr
7472729Sdfr		/*
7482729Sdfr		 * check msgsz
7492729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
7502729Sdfr		 */
7512729Sdfr
752137613Srwatson		if (msgsz > msqkptr->u.msg_qbytes) {
753137613Srwatson			DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n"));
75482607Sdillon			error = EINVAL;
755220398Strasz			goto done3;
7562729Sdfr		}
7572729Sdfr
758137613Srwatson		if (msqkptr->u.msg_perm.mode & MSG_LOCKED) {
759100523Salfred			DPRINTF(("msqid is locked\n"));
7602729Sdfr			need_more_resources = 1;
7612729Sdfr		}
762137613Srwatson		if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) {
763100523Salfred			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
7642729Sdfr			need_more_resources = 1;
7652729Sdfr		}
7662729Sdfr		if (segs_needed > nfree_msgmaps) {
767100523Salfred			DPRINTF(("segs_needed > nfree_msgmaps\n"));
7682729Sdfr			need_more_resources = 1;
7692729Sdfr		}
7702729Sdfr		if (free_msghdrs == NULL) {
771100523Salfred			DPRINTF(("no more msghdrs\n"));
7722729Sdfr			need_more_resources = 1;
7732729Sdfr		}
7742729Sdfr
7752729Sdfr		if (need_more_resources) {
7762729Sdfr			int we_own_it;
7772729Sdfr
7782729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
779100523Salfred				DPRINTF(("need more resources but caller "
780100523Salfred				    "doesn't want to wait\n"));
78182607Sdillon				error = EAGAIN;
782220398Strasz				goto done3;
7832729Sdfr			}
7842729Sdfr
785137613Srwatson			if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) {
786100523Salfred				DPRINTF(("we don't own the msqid_ds\n"));
7872729Sdfr				we_own_it = 0;
7882729Sdfr			} else {
7892729Sdfr				/* Force later arrivals to wait for our
7902729Sdfr				   request */
791100523Salfred				DPRINTF(("we own the msqid_ds\n"));
792137613Srwatson				msqkptr->u.msg_perm.mode |= MSG_LOCKED;
7932729Sdfr				we_own_it = 1;
7942729Sdfr			}
795164368Sjkim			DPRINTF(("msgsnd:  goodnight\n"));
796137613Srwatson			error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
797164368Sjkim			    "msgsnd", hz);
798164368Sjkim			DPRINTF(("msgsnd:  good morning, error=%d\n", error));
7992729Sdfr			if (we_own_it)
800137613Srwatson				msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
801164368Sjkim			if (error == EWOULDBLOCK) {
802164368Sjkim				DPRINTF(("msgsnd:  timed out\n"));
803164368Sjkim				continue;
804164368Sjkim			}
80582607Sdillon			if (error != 0) {
806100523Salfred				DPRINTF(("msgsnd:  interrupted system call\n"));
80782607Sdillon				error = EINTR;
808220398Strasz				goto done3;
8092729Sdfr			}
8102729Sdfr
8112729Sdfr			/*
8122729Sdfr			 * Make sure that the msq queue still exists
8132729Sdfr			 */
8142729Sdfr
815137613Srwatson			if (msqkptr->u.msg_qbytes == 0) {
816100523Salfred				DPRINTF(("msqid deleted\n"));
81782607Sdillon				error = EIDRM;
818220398Strasz				goto done3;
8192729Sdfr			}
8202729Sdfr
8212729Sdfr		} else {
822100523Salfred			DPRINTF(("got all the resources that we need\n"));
8232729Sdfr			break;
8242729Sdfr		}
8252729Sdfr	}
8262729Sdfr
8272729Sdfr	/*
8282729Sdfr	 * We have the resources that we need.
8292729Sdfr	 * Make sure!
8302729Sdfr	 */
8312729Sdfr
832137613Srwatson	if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
8332729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
8342729Sdfr	if (segs_needed > nfree_msgmaps)
8352729Sdfr		panic("segs_needed > nfree_msgmaps");
836137613Srwatson	if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
8372729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
8382729Sdfr	if (free_msghdrs == NULL)
8392729Sdfr		panic("no more msghdrs");
8402729Sdfr
8412729Sdfr	/*
8422729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
8432729Sdfr	 * message
8442729Sdfr	 */
8452729Sdfr
846137613Srwatson	if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
8472729Sdfr		panic("msqid_ds is already locked");
848137613Srwatson	msqkptr->u.msg_perm.mode |= MSG_LOCKED;
8492729Sdfr
8502729Sdfr	/*
8512729Sdfr	 * Allocate a message header
8522729Sdfr	 */
8532729Sdfr
8542729Sdfr	msghdr = free_msghdrs;
8552729Sdfr	free_msghdrs = msghdr->msg_next;
8562729Sdfr	msghdr->msg_spot = -1;
8572729Sdfr	msghdr->msg_ts = msgsz;
858165403Sjkim	msghdr->msg_type = mtype;
859140614Srwatson#ifdef MAC
860140614Srwatson	/*
861172930Srwatson	 * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here
862140614Srwatson	 * immediately?  Or, should it be checked just before the msg is
863140614Srwatson	 * enqueued in the msgq (as it is done now)?
864140614Srwatson	 */
865172930Srwatson	mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr);
866140614Srwatson#endif
8672729Sdfr
8682729Sdfr	/*
8692729Sdfr	 * Allocate space for the message
8702729Sdfr	 */
8712729Sdfr
8722729Sdfr	while (segs_needed > 0) {
8732729Sdfr		if (nfree_msgmaps <= 0)
8742729Sdfr			panic("not enough msgmaps");
8752729Sdfr		if (free_msgmaps == -1)
8762729Sdfr			panic("nil free_msgmaps");
8772729Sdfr		next = free_msgmaps;
8782729Sdfr		if (next <= -1)
8792729Sdfr			panic("next too low #1");
8802729Sdfr		if (next >= msginfo.msgseg)
8812729Sdfr			panic("next out of range #1");
882100523Salfred		DPRINTF(("allocating segment %d to message\n", next));
8832729Sdfr		free_msgmaps = msgmaps[next].next;
8842729Sdfr		nfree_msgmaps--;
8852729Sdfr		msgmaps[next].next = msghdr->msg_spot;
8862729Sdfr		msghdr->msg_spot = next;
8872729Sdfr		segs_needed--;
8882729Sdfr	}
8892729Sdfr
8902729Sdfr	/*
8912729Sdfr	 * Validate the message type
8922729Sdfr	 */
8932729Sdfr
8942729Sdfr	if (msghdr->msg_type < 1) {
8952729Sdfr		msg_freehdr(msghdr);
896137613Srwatson		msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
897137613Srwatson		wakeup(msqkptr);
898165403Sjkim		DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
89982607Sdillon		error = EINVAL;
900220398Strasz		goto done3;
9012729Sdfr	}
9022729Sdfr
9032729Sdfr	/*
9042729Sdfr	 * Copy in the message body
9052729Sdfr	 */
9062729Sdfr
9072729Sdfr	next = msghdr->msg_spot;
9082729Sdfr	while (msgsz > 0) {
9092729Sdfr		size_t tlen;
9102729Sdfr		if (msgsz > msginfo.msgssz)
9112729Sdfr			tlen = msginfo.msgssz;
9122729Sdfr		else
9132729Sdfr			tlen = msgsz;
9142729Sdfr		if (next <= -1)
9152729Sdfr			panic("next too low #2");
9162729Sdfr		if (next >= msginfo.msgseg)
9172729Sdfr			panic("next out of range #2");
918101772Salfred		mtx_unlock(&msq_mtx);
919165403Sjkim		if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
9202729Sdfr		    tlen)) != 0) {
921101772Salfred			mtx_lock(&msq_mtx);
922100523Salfred			DPRINTF(("error %d copying in message segment\n",
923100523Salfred			    error));
9242729Sdfr			msg_freehdr(msghdr);
925137613Srwatson			msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
926137613Srwatson			wakeup(msqkptr);
927220398Strasz			goto done3;
9282729Sdfr		}
929101772Salfred		mtx_lock(&msq_mtx);
9302729Sdfr		msgsz -= tlen;
931165403Sjkim		msgp = (const char *)msgp + tlen;
9322729Sdfr		next = msgmaps[next].next;
9332729Sdfr	}
9342729Sdfr	if (next != -1)
9352729Sdfr		panic("didn't use all the msg segments");
9362729Sdfr
9372729Sdfr	/*
9382729Sdfr	 * We've got the message.  Unlock the msqid_ds.
9392729Sdfr	 */
9402729Sdfr
941137613Srwatson	msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
9422729Sdfr
9432729Sdfr	/*
9442729Sdfr	 * Make sure that the msqid_ds is still allocated.
9452729Sdfr	 */
9462729Sdfr
947137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
9482729Sdfr		msg_freehdr(msghdr);
949137613Srwatson		wakeup(msqkptr);
95082607Sdillon		error = EIDRM;
951220398Strasz		goto done3;
9522729Sdfr	}
9532729Sdfr
954140614Srwatson#ifdef MAC
9552729Sdfr	/*
956140614Srwatson	 * Note: Since the task/thread allocates the msghdr and usually
957140614Srwatson	 * primes it with its own MAC label, for a majority of policies, it
958140614Srwatson	 * won't be necessary to check whether the msghdr has access
959172930Srwatson	 * permissions to the msgq.  The mac_sysvmsq_check_msqsnd check would
960140614Srwatson	 * suffice in that case.  However, this hook may be required where
961140614Srwatson	 * individual policies derive a non-identical label for the msghdr
962140614Srwatson	 * from the current thread label and may want to check the msghdr
963140614Srwatson	 * enqueue permissions, along with read/write permissions to the
964140614Srwatson	 * msgq.
965140614Srwatson	 */
966172930Srwatson	error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr);
967140614Srwatson	if (error != 0) {
968140614Srwatson		msg_freehdr(msghdr);
969140614Srwatson		wakeup(msqkptr);
970220398Strasz		goto done3;
971140614Srwatson	}
972140614Srwatson#endif
973140614Srwatson
974140614Srwatson	/*
9752729Sdfr	 * Put the message into the queue
9762729Sdfr	 */
977137613Srwatson	if (msqkptr->u.msg_first == NULL) {
978137613Srwatson		msqkptr->u.msg_first = msghdr;
979137613Srwatson		msqkptr->u.msg_last = msghdr;
9802729Sdfr	} else {
981137613Srwatson		msqkptr->u.msg_last->msg_next = msghdr;
982137613Srwatson		msqkptr->u.msg_last = msghdr;
9832729Sdfr	}
984137613Srwatson	msqkptr->u.msg_last->msg_next = NULL;
9852729Sdfr
986137613Srwatson	msqkptr->u.msg_cbytes += msghdr->msg_ts;
987137613Srwatson	msqkptr->u.msg_qnum++;
988137613Srwatson	msqkptr->u.msg_lspid = td->td_proc->p_pid;
989137613Srwatson	msqkptr->u.msg_stime = time_second;
9902729Sdfr
991137613Srwatson	wakeup(msqkptr);
99283366Sjulian	td->td_retval[0] = 0;
993220398Straszdone3:
994220398Strasz	if (error != 0) {
995220398Strasz		PROC_LOCK(td->td_proc);
996220398Strasz		racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
997220398Strasz		racct_sub(td->td_proc, RACCT_MSGQSIZE, saved_msgsz);
998220398Strasz		PROC_UNLOCK(td->td_proc);
999220398Strasz	}
100082607Sdillondone2:
1001101772Salfred	mtx_unlock(&msq_mtx);
100282607Sdillon	return (error);
10032729Sdfr}
10042729Sdfr
1005165403Sjkimint
1006165403Sjkimmsgsnd(td, uap)
1007165403Sjkim	struct thread *td;
1008165403Sjkim	register struct msgsnd_args *uap;
1009165403Sjkim{
1010165403Sjkim	int error;
1011165403Sjkim	long mtype;
1012165403Sjkim
1013165403Sjkim	DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp,
1014165403Sjkim	    uap->msgsz, uap->msgflg));
1015165403Sjkim
1016165403Sjkim	if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) {
1017165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1018165403Sjkim		return (error);
1019165403Sjkim	}
1020165403Sjkim	return (kern_msgsnd(td, uap->msqid,
1021165403Sjkim	    (const char *)uap->msgp + sizeof(mtype),
1022165403Sjkim	    uap->msgsz, uap->msgflg, mtype));
1023165403Sjkim}
1024165403Sjkim
102512866Speter#ifndef _SYS_SYSPROTO_H_
10262729Sdfrstruct msgrcv_args {
10272729Sdfr	int	msqid;
10282729Sdfr	void	*msgp;
10292729Sdfr	size_t	msgsz;
10302729Sdfr	long	msgtyp;
10312729Sdfr	int	msgflg;
10322729Sdfr};
103312866Speter#endif
103412866Speterint
1035165403Sjkimkern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype)
103683366Sjulian	struct thread *td;
1037165403Sjkim	int msqid;
1038165403Sjkim	void *msgp;	/* XXX msgp is actually mtext. */
1039165403Sjkim	size_t msgsz;
1040165403Sjkim	long msgtyp;
1041165403Sjkim	int msgflg;
1042165403Sjkim	long *mtype;
10432729Sdfr{
10442729Sdfr	size_t len;
1045137613Srwatson	register struct msqid_kernel *msqkptr;
10462729Sdfr	register struct msg *msghdr;
1047165403Sjkim	int msqix, error = 0;
10482729Sdfr	short next;
10492729Sdfr
1050192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
105191703Sjhb		return (ENOSYS);
105291703Sjhb
1053165403Sjkim	msqix = IPCID_TO_IX(msqid);
10542729Sdfr
1055165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
1056165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
1057100523Salfred		    msginfo.msgmni));
1058101772Salfred		return (EINVAL);
10592729Sdfr	}
10602729Sdfr
1061165403Sjkim	msqkptr = &msqids[msqix];
1062101772Salfred	mtx_lock(&msq_mtx);
1063137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
1064100523Salfred		DPRINTF(("no such message queue id\n"));
106582607Sdillon		error = EINVAL;
106682607Sdillon		goto done2;
10672729Sdfr	}
1068165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1069100523Salfred		DPRINTF(("wrong sequence number\n"));
107082607Sdillon		error = EINVAL;
107182607Sdillon		goto done2;
10722729Sdfr	}
10732729Sdfr
1074137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
1075100523Salfred		DPRINTF(("requester doesn't have read access\n"));
107682607Sdillon		goto done2;
10772729Sdfr	}
10782729Sdfr
1079140614Srwatson#ifdef MAC
1080172930Srwatson	error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr);
1081162468Srwatson	if (error != 0)
1082140614Srwatson		goto done2;
1083140614Srwatson#endif
1084140614Srwatson
10852729Sdfr	msghdr = NULL;
10862729Sdfr	while (msghdr == NULL) {
10872729Sdfr		if (msgtyp == 0) {
1088137613Srwatson			msghdr = msqkptr->u.msg_first;
10892729Sdfr			if (msghdr != NULL) {
10902729Sdfr				if (msgsz < msghdr->msg_ts &&
10912729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
1092100523Salfred					DPRINTF(("first message on the queue "
1093165403Sjkim					    "is too big (want %zu, got %d)\n",
1094100523Salfred					    msgsz, msghdr->msg_ts));
109582607Sdillon					error = E2BIG;
109682607Sdillon					goto done2;
10972729Sdfr				}
1098140614Srwatson#ifdef MAC
1099172930Srwatson				error = mac_sysvmsq_check_msgrcv(td->td_ucred,
1100140614Srwatson				    msghdr);
1101162468Srwatson				if (error != 0)
1102140614Srwatson					goto done2;
1103140614Srwatson#endif
1104137613Srwatson				if (msqkptr->u.msg_first == msqkptr->u.msg_last) {
1105137613Srwatson					msqkptr->u.msg_first = NULL;
1106137613Srwatson					msqkptr->u.msg_last = NULL;
11072729Sdfr				} else {
1108137613Srwatson					msqkptr->u.msg_first = msghdr->msg_next;
1109137613Srwatson					if (msqkptr->u.msg_first == NULL)
11102729Sdfr						panic("msg_first/last screwed up #1");
11112729Sdfr				}
11122729Sdfr			}
11132729Sdfr		} else {
11142729Sdfr			struct msg *previous;
11152729Sdfr			struct msg **prev;
11162729Sdfr
11172729Sdfr			previous = NULL;
1118137613Srwatson			prev = &(msqkptr->u.msg_first);
11192729Sdfr			while ((msghdr = *prev) != NULL) {
11202729Sdfr				/*
11212729Sdfr				 * Is this message's type an exact match or is
11222729Sdfr				 * this message's type less than or equal to
11232729Sdfr				 * the absolute value of a negative msgtyp?
11242729Sdfr				 * Note that the second half of this test can
11252729Sdfr				 * NEVER be true if msgtyp is positive since
11262729Sdfr				 * msg_type is always positive!
11272729Sdfr				 */
11282729Sdfr
11292729Sdfr				if (msgtyp == msghdr->msg_type ||
11302729Sdfr				    msghdr->msg_type <= -msgtyp) {
1131165403Sjkim					DPRINTF(("found message type %ld, "
1132165403Sjkim					    "requested %ld\n",
1133100523Salfred					    msghdr->msg_type, msgtyp));
11342729Sdfr					if (msgsz < msghdr->msg_ts &&
11352729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
1136100523Salfred						DPRINTF(("requested message "
1137100523Salfred						    "on the queue is too big "
1138165403Sjkim						    "(want %zu, got %hu)\n",
1139100523Salfred						    msgsz, msghdr->msg_ts));
114082607Sdillon						error = E2BIG;
114182607Sdillon						goto done2;
11422729Sdfr					}
1143140614Srwatson#ifdef MAC
1144172930Srwatson					error = mac_sysvmsq_check_msgrcv(
1145140614Srwatson					    td->td_ucred, msghdr);
1146162468Srwatson					if (error != 0)
1147140614Srwatson						goto done2;
1148140614Srwatson#endif
11492729Sdfr					*prev = msghdr->msg_next;
1150137613Srwatson					if (msghdr == msqkptr->u.msg_last) {
11512729Sdfr						if (previous == NULL) {
11522729Sdfr							if (prev !=
1153137613Srwatson							    &msqkptr->u.msg_first)
11542729Sdfr								panic("msg_first/last screwed up #2");
1155137613Srwatson							msqkptr->u.msg_first =
11562729Sdfr							    NULL;
1157137613Srwatson							msqkptr->u.msg_last =
11582729Sdfr							    NULL;
11592729Sdfr						} else {
11602729Sdfr							if (prev ==
1161137613Srwatson							    &msqkptr->u.msg_first)
11622729Sdfr								panic("msg_first/last screwed up #3");
1163137613Srwatson							msqkptr->u.msg_last =
11642729Sdfr							    previous;
11652729Sdfr						}
11662729Sdfr					}
11672729Sdfr					break;
11682729Sdfr				}
11692729Sdfr				previous = msghdr;
11702729Sdfr				prev = &(msghdr->msg_next);
11712729Sdfr			}
11722729Sdfr		}
11732729Sdfr
11742729Sdfr		/*
11752729Sdfr		 * We've either extracted the msghdr for the appropriate
11762729Sdfr		 * message or there isn't one.
11772729Sdfr		 * If there is one then bail out of this loop.
11782729Sdfr		 */
11792729Sdfr
11802729Sdfr		if (msghdr != NULL)
11812729Sdfr			break;
11822729Sdfr
11832729Sdfr		/*
11842729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
11852729Sdfr		 */
11862729Sdfr
11872729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
1188165403Sjkim			DPRINTF(("no appropriate message found (msgtyp=%ld)\n",
1189100523Salfred			    msgtyp));
11902729Sdfr			/* The SVID says to return ENOMSG. */
119182607Sdillon			error = ENOMSG;
119282607Sdillon			goto done2;
11932729Sdfr		}
11942729Sdfr
11952729Sdfr		/*
11962729Sdfr		 * Wait for something to happen
11972729Sdfr		 */
11982729Sdfr
1199100523Salfred		DPRINTF(("msgrcv:  goodnight\n"));
1200137613Srwatson		error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
1201164368Sjkim		    "msgrcv", 0);
1202100523Salfred		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
12032729Sdfr
120482607Sdillon		if (error != 0) {
1205164368Sjkim			DPRINTF(("msgrcv:  interrupted system call\n"));
120682607Sdillon			error = EINTR;
120782607Sdillon			goto done2;
12082729Sdfr		}
12092729Sdfr
12102729Sdfr		/*
12112729Sdfr		 * Make sure that the msq queue still exists
12122729Sdfr		 */
12132729Sdfr
1214137613Srwatson		if (msqkptr->u.msg_qbytes == 0 ||
1215165403Sjkim		    msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1216100523Salfred			DPRINTF(("msqid deleted\n"));
121782607Sdillon			error = EIDRM;
121882607Sdillon			goto done2;
12192729Sdfr		}
12202729Sdfr	}
12212729Sdfr
12222729Sdfr	/*
12232729Sdfr	 * Return the message to the user.
12242729Sdfr	 *
12252729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
12262729Sdfr	 */
12272729Sdfr
1228137613Srwatson	msqkptr->u.msg_cbytes -= msghdr->msg_ts;
1229137613Srwatson	msqkptr->u.msg_qnum--;
1230137613Srwatson	msqkptr->u.msg_lrpid = td->td_proc->p_pid;
1231137613Srwatson	msqkptr->u.msg_rtime = time_second;
12322729Sdfr
1233220398Strasz	racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, 1);
1234220398Strasz	racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msghdr->msg_ts);
1235220398Strasz
12362729Sdfr	/*
12372729Sdfr	 * Make msgsz the actual amount that we'll be returning.
12382729Sdfr	 * Note that this effectively truncates the message if it is too long
12392729Sdfr	 * (since msgsz is never increased).
12402729Sdfr	 */
12412729Sdfr
1242165403Sjkim	DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz,
1243100523Salfred	    msghdr->msg_ts));
12442729Sdfr	if (msgsz > msghdr->msg_ts)
12452729Sdfr		msgsz = msghdr->msg_ts;
1246165403Sjkim	*mtype = msghdr->msg_type;
12472729Sdfr
12482729Sdfr	/*
12492729Sdfr	 * Return the segments to the user
12502729Sdfr	 */
12512729Sdfr
12522729Sdfr	next = msghdr->msg_spot;
12532729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
12542729Sdfr		size_t tlen;
12552729Sdfr
125645921Ssada		if (msgsz - len > msginfo.msgssz)
12572729Sdfr			tlen = msginfo.msgssz;
12582729Sdfr		else
125945921Ssada			tlen = msgsz - len;
12602729Sdfr		if (next <= -1)
12612729Sdfr			panic("next too low #3");
12622729Sdfr		if (next >= msginfo.msgseg)
12632729Sdfr			panic("next out of range #3");
1264101772Salfred		mtx_unlock(&msq_mtx);
1265165403Sjkim		error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
1266101772Salfred		mtx_lock(&msq_mtx);
126782607Sdillon		if (error != 0) {
1268100523Salfred			DPRINTF(("error (%d) copying out message segment\n",
1269100523Salfred			    error));
12702729Sdfr			msg_freehdr(msghdr);
1271137613Srwatson			wakeup(msqkptr);
127282607Sdillon			goto done2;
12732729Sdfr		}
1274165403Sjkim		msgp = (char *)msgp + tlen;
12752729Sdfr		next = msgmaps[next].next;
12762729Sdfr	}
12772729Sdfr
12782729Sdfr	/*
12792729Sdfr	 * Done, return the actual number of bytes copied out.
12802729Sdfr	 */
12812729Sdfr
12822729Sdfr	msg_freehdr(msghdr);
1283137613Srwatson	wakeup(msqkptr);
128483366Sjulian	td->td_retval[0] = msgsz;
128582607Sdillondone2:
1286101772Salfred	mtx_unlock(&msq_mtx);
128782607Sdillon	return (error);
12882729Sdfr}
128977461Sdd
1290165403Sjkimint
1291165403Sjkimmsgrcv(td, uap)
1292165403Sjkim	struct thread *td;
1293165403Sjkim	register struct msgrcv_args *uap;
1294165403Sjkim{
1295165403Sjkim	int error;
1296165403Sjkim	long mtype;
1297165403Sjkim
1298165403Sjkim	DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid,
1299165403Sjkim	    uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg));
1300165403Sjkim
1301165403Sjkim	if ((error = kern_msgrcv(td, uap->msqid,
1302165403Sjkim	    (char *)uap->msgp + sizeof(mtype), uap->msgsz,
1303165403Sjkim	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1304165403Sjkim		return (error);
1305165403Sjkim	if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0)
1306165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1307165403Sjkim	return (error);
1308165403Sjkim}
1309165403Sjkim
131077461Sddstatic int
131177461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS)
131277461Sdd{
131377461Sdd
131477461Sdd	return (SYSCTL_OUT(req, msqids,
1315137613Srwatson	    sizeof(struct msqid_kernel) * msginfo.msgmni));
131677461Sdd}
131777461Sdd
1318141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
1319141710Scsjp    "Maximum message size");
1320141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
1321141710Scsjp    "Number of message queue identifiers");
1322141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
1323141710Scsjp    "Maximum number of bytes in a queue");
1324141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
1325141710Scsjp    "Maximum number of messages in the system");
1326141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
1327141710Scsjp    "Size of a message segment");
1328141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
1329141710Scsjp    "Number of message segments");
1330217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLTYPE_OPAQUE | CTLFLAG_RD,
133177461Sdd    NULL, 0, sysctl_msqids, "", "Message queue IDs");
1332194894Sjhb
1333205323Skib#ifdef COMPAT_FREEBSD32
1334205323Skibint
1335205323Skibfreebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1336205323Skib{
1337205323Skib
1338194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1339194894Sjhb    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1340205323Skib	switch (uap->which) {
1341205323Skib	case 0:
1342205323Skib		return (freebsd7_freebsd32_msgctl(td,
1343205323Skib		    (struct freebsd7_freebsd32_msgctl_args *)&uap->a2));
1344205323Skib	case 2:
1345205323Skib		return (freebsd32_msgsnd(td,
1346205323Skib		    (struct freebsd32_msgsnd_args *)&uap->a2));
1347205323Skib	case 3:
1348205323Skib		return (freebsd32_msgrcv(td,
1349205323Skib		    (struct freebsd32_msgrcv_args *)&uap->a2));
1350205323Skib	default:
1351205323Skib		return (msgsys(td, (struct msgsys_args *)uap));
1352205323Skib	}
1353205323Skib#else
1354205323Skib	return (nosys(td, NULL));
1355205323Skib#endif
1356205323Skib}
1357194894Sjhb
1358205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1359205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1360205323Skibint
1361205323Skibfreebsd7_freebsd32_msgctl(struct thread *td,
1362205323Skib    struct freebsd7_freebsd32_msgctl_args *uap)
1363205323Skib{
1364205323Skib	struct msqid_ds msqbuf;
1365205323Skib	struct msqid_ds32_old msqbuf32;
1366205323Skib	int error;
1367205323Skib
1368205323Skib	if (uap->cmd == IPC_SET) {
1369205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1370205323Skib		if (error)
1371205323Skib			return (error);
1372205323Skib		freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1373205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1374205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1375205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1376205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1377205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1378205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1379205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1380205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1381205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1382205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1383205323Skib	}
1384205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1385205323Skib	if (error)
1386205323Skib		return (error);
1387205323Skib	if (uap->cmd == IPC_STAT) {
1388205323Skib		bzero(&msqbuf32, sizeof(msqbuf32));
1389205323Skib		freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1390205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1391205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1392205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1393205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1394205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1395205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1396205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1397205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1398205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1399205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1400205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1401205323Skib	}
1402205323Skib	return (error);
1403205323Skib}
1404205323Skib#endif
1405205323Skib
1406205323Skibint
1407205323Skibfreebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap)
1408205323Skib{
1409205323Skib	struct msqid_ds msqbuf;
1410205323Skib	struct msqid_ds32 msqbuf32;
1411205323Skib	int error;
1412205323Skib
1413205323Skib	if (uap->cmd == IPC_SET) {
1414205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1415205323Skib		if (error)
1416205323Skib			return (error);
1417205323Skib		freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1418205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1419205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1420205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1421205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1422205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1423205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1424205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1425205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1426205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1427205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1428205323Skib	}
1429205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1430205323Skib	if (error)
1431205323Skib		return (error);
1432205323Skib	if (uap->cmd == IPC_STAT) {
1433205323Skib		freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1434205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1435205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1436205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1437205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1438205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1439205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1440205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1441205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1442205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1443205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1444205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1445205323Skib	}
1446205323Skib	return (error);
1447205323Skib}
1448205323Skib
1449205323Skibint
1450205323Skibfreebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap)
1451205323Skib{
1452205323Skib	const void *msgp;
1453205323Skib	long mtype;
1454205323Skib	int32_t mtype32;
1455205323Skib	int error;
1456205323Skib
1457205323Skib	msgp = PTRIN(uap->msgp);
1458205323Skib	if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0)
1459205323Skib		return (error);
1460205323Skib	mtype = mtype32;
1461205323Skib	return (kern_msgsnd(td, uap->msqid,
1462205323Skib	    (const char *)msgp + sizeof(mtype32),
1463205323Skib	    uap->msgsz, uap->msgflg, mtype));
1464205323Skib}
1465205323Skib
1466205323Skibint
1467205323Skibfreebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap)
1468205323Skib{
1469205323Skib	void *msgp;
1470205323Skib	long mtype;
1471205323Skib	int32_t mtype32;
1472205323Skib	int error;
1473205323Skib
1474205323Skib	msgp = PTRIN(uap->msgp);
1475205323Skib	if ((error = kern_msgrcv(td, uap->msqid,
1476205323Skib	    (char *)msgp + sizeof(mtype32), uap->msgsz,
1477205323Skib	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1478205323Skib		return (error);
1479205323Skib	mtype32 = (int32_t)mtype;
1480205323Skib	return (copyout(&mtype32, msgp, sizeof(mtype32)));
1481205323Skib}
1482205323Skib#endif
1483205323Skib
1484205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1485205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1486205323Skib
1487194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */
1488194894Sjhbstatic sy_call_t *msgcalls[] = {
1489194910Sjhb	(sy_call_t *)freebsd7_msgctl, (sy_call_t *)msgget,
1490194894Sjhb	(sy_call_t *)msgsnd, (sy_call_t *)msgrcv
1491194894Sjhb};
1492194894Sjhb
1493194894Sjhb/*
1494194894Sjhb * Entry point for all MSG calls.
1495194894Sjhb */
1496194894Sjhbint
1497194894Sjhbmsgsys(td, uap)
1498194894Sjhb	struct thread *td;
1499194894Sjhb	/* XXX actually varargs. */
1500194894Sjhb	struct msgsys_args /* {
1501194894Sjhb		int	which;
1502194894Sjhb		int	a2;
1503194894Sjhb		int	a3;
1504194894Sjhb		int	a4;
1505194894Sjhb		int	a5;
1506194894Sjhb		int	a6;
1507194894Sjhb	} */ *uap;
1508194894Sjhb{
1509194894Sjhb	int error;
1510194894Sjhb
1511194894Sjhb	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1512194894Sjhb		return (ENOSYS);
1513194894Sjhb	if (uap->which < 0 ||
1514194894Sjhb	    uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
1515194894Sjhb		return (EINVAL);
1516194894Sjhb	error = (*msgcalls[uap->which])(td, &uap->a2);
1517194894Sjhb	return (error);
1518194894Sjhb}
1519194910Sjhb
1520205323Skib#ifndef CP
1521194910Sjhb#define CP(src, dst, fld)	do { (dst).fld = (src).fld; } while (0)
1522205323Skib#endif
1523194910Sjhb
1524194910Sjhb#ifndef _SYS_SYSPROTO_H_
1525194910Sjhbstruct freebsd7_msgctl_args {
1526194910Sjhb	int	msqid;
1527194910Sjhb	int	cmd;
1528194910Sjhb	struct	msqid_ds_old *buf;
1529194910Sjhb};
1530194910Sjhb#endif
1531194910Sjhbint
1532194910Sjhbfreebsd7_msgctl(td, uap)
1533194910Sjhb	struct thread *td;
1534194910Sjhb	struct freebsd7_msgctl_args *uap;
1535194910Sjhb{
1536194910Sjhb	struct msqid_ds_old msqold;
1537194910Sjhb	struct msqid_ds msqbuf;
1538194910Sjhb	int error;
1539194910Sjhb
1540194910Sjhb	DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd,
1541194910Sjhb	    uap->buf));
1542194910Sjhb	if (uap->cmd == IPC_SET) {
1543194910Sjhb		error = copyin(uap->buf, &msqold, sizeof(msqold));
1544194910Sjhb		if (error)
1545194910Sjhb			return (error);
1546194910Sjhb		ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm);
1547194910Sjhb		CP(msqold, msqbuf, msg_first);
1548194910Sjhb		CP(msqold, msqbuf, msg_last);
1549194910Sjhb		CP(msqold, msqbuf, msg_cbytes);
1550194910Sjhb		CP(msqold, msqbuf, msg_qnum);
1551194910Sjhb		CP(msqold, msqbuf, msg_qbytes);
1552194910Sjhb		CP(msqold, msqbuf, msg_lspid);
1553194910Sjhb		CP(msqold, msqbuf, msg_lrpid);
1554194910Sjhb		CP(msqold, msqbuf, msg_stime);
1555194910Sjhb		CP(msqold, msqbuf, msg_rtime);
1556194910Sjhb		CP(msqold, msqbuf, msg_ctime);
1557194910Sjhb	}
1558194910Sjhb	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1559194910Sjhb	if (error)
1560194910Sjhb		return (error);
1561194910Sjhb	if (uap->cmd == IPC_STAT) {
1562194910Sjhb		bzero(&msqold, sizeof(msqold));
1563194910Sjhb		ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm);
1564194910Sjhb		CP(msqbuf, msqold, msg_first);
1565194910Sjhb		CP(msqbuf, msqold, msg_last);
1566194910Sjhb		CP(msqbuf, msqold, msg_cbytes);
1567194910Sjhb		CP(msqbuf, msqold, msg_qnum);
1568194910Sjhb		CP(msqbuf, msqold, msg_qbytes);
1569194910Sjhb		CP(msqbuf, msqold, msg_lspid);
1570194910Sjhb		CP(msqbuf, msqold, msg_lrpid);
1571194910Sjhb		CP(msqbuf, msqold, msg_stime);
1572194910Sjhb		CP(msqbuf, msqold, msg_rtime);
1573194910Sjhb		CP(msqbuf, msqold, msg_ctime);
1574194910Sjhb		error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old));
1575194910Sjhb	}
1576194910Sjhb	return (error);
1577194910Sjhb}
1578194910Sjhb
1579194910Sjhb#undef CP
1580194910Sjhb
1581194894Sjhb#endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1582194894Sjhb	   COMPAT_FREEBSD7 */
1583