2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Implementation of SVID messages
31 * Author: Daniel Boulet
33 * Copyright 1993 Daniel Boulet and RTMX Inc.
35 * This system call was implemented by Daniel Boulet under contract from RTMX.
37 * Redistribution and use in source forms, with and without modification,
38 * are permitted provided that this entire comment appears intact.
40 * Redistribution in binary form may occur without any restrictions.
41 * Obviously, it would be nice if you gave credit where credit is due
42 * but requiring it would be too onerous.
44 * This software is provided ``AS IS'' without any warranties of any kind.
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/proc_internal.h>
51 #include <sys/kauth.h>
53 #include <sys/malloc.h>
54 #include <mach/mach_types.h>
56 #include <bsm/audit_kernel.h>
58 #include <sys/filedesc.h>
59 #include <sys/file_internal.h>
60 #include <sys/sysctl.h>
61 #include <sys/sysproto.h>
64 static void msginit(void *);
69 static void msg_freehdr(struct msg
*msghdr
);
71 typedef int sy_call_t(struct proc
*, void *, int *);
73 /* XXX casting to (sy_call_t *) is bogus, as usual. */
74 static sy_call_t
*msgcalls
[] = {
75 (sy_call_t
*)msgctl
, (sy_call_t
*)msgget
,
76 (sy_call_t
*)msgsnd
, (sy_call_t
*)msgrcv
79 static int nfree_msgmaps
; /* # of free map entries */
80 static short free_msgmaps
; /* free map entries list head */
81 static struct msg
*free_msghdrs
; /* list of free msg headers */
82 char *msgpool
; /* MSGMAX byte long msg buffer pool */
83 struct msgmap
*msgmaps
; /* MSGSEG msgmap structures */
84 struct msg
*msghdrs
; /* MSGTQL msg headers */
85 struct user_msqid_ds
*msqids
; /* MSGMNI user_msqid_ds struct's */
87 static lck_grp_t
*sysv_msg_subsys_lck_grp
;
88 static lck_grp_attr_t
*sysv_msg_subsys_lck_grp_attr
;
89 static lck_attr_t
*sysv_msg_subsys_lck_attr
;
90 static lck_mtx_t sysv_msg_subsys_mutex
;
92 #define SYSV_MSG_SUBSYS_LOCK() lck_mtx_lock(&sysv_msg_subsys_mutex)
93 #define SYSV_MSG_SUBSYS_UNLOCK() lck_mtx_unlock(&sysv_msg_subsys_mutex)
95 void sysv_msg_lock_init(void);
98 #ifdef __APPLE_API_PRIVATE
99 struct msginfo msginfo
= {
100 MSGMAX
, /* = (MSGSSZ*MSGSEG) : max chars in a message */
101 MSGMNI
, /* = 40 : max message queue identifiers */
102 MSGMNB
, /* = 2048 : max chars in a queue */
103 MSGTQL
, /* = 40 : max messages in system */
104 MSGSSZ
, /* = 8 : size of a message segment (2^N long) */
105 MSGSEG
/* = 2048 : number of message segments */
107 #endif /* __APPLE_API_PRIVATE */
109 /* Initialize the mutex governing access to the SysV msg subsystem */
110 __private_extern__
void
111 sysv_msg_lock_init( void )
113 sysv_msg_subsys_lck_grp_attr
= lck_grp_attr_alloc_init();
114 lck_grp_attr_setstat(sysv_msg_subsys_lck_grp_attr
);
116 sysv_msg_subsys_lck_grp
= lck_grp_alloc_init("sysv_msg_subsys_lock", sysv_msg_subsys_lck_grp_attr
);
118 sysv_msg_subsys_lck_attr
= lck_attr_alloc_init();
119 /* lck_attr_setdebug(sysv_msg_subsys_lck_attr); */
120 lck_mtx_init(&sysv_msg_subsys_mutex
, sysv_msg_subsys_lck_grp
, sysv_msg_subsys_lck_attr
);
123 static __inline__ user_time_t
132 * NOTE: Source and target may *NOT* overlap! (target is smaller)
135 msqid_ds_64to32(struct user_msqid_ds
*in
, struct msqid_ds
*out
)
137 out
->msg_perm
= in
->msg_perm
;
138 out
->msg_qnum
= in
->msg_qnum
;
139 out
->msg_cbytes
= in
->msg_cbytes
; /* for ipcs */
140 out
->msg_qbytes
= in
->msg_qbytes
;
141 out
->msg_lspid
= in
->msg_lspid
;
142 out
->msg_lrpid
= in
->msg_lrpid
;
143 out
->msg_stime
= in
->msg_stime
; /* XXX loss of range */
144 out
->msg_rtime
= in
->msg_rtime
; /* XXX loss of range */
145 out
->msg_ctime
= in
->msg_ctime
; /* XXX loss of range */
149 * NOTE: Source and target may are permitted to overlap! (source is smaller);
150 * this works because we copy fields in order from the end of the struct to
154 msqid_ds_32to64(struct msqid_ds
*in
, struct user_msqid_ds
*out
)
156 out
->msg_ctime
= in
->msg_ctime
;
157 out
->msg_rtime
= in
->msg_rtime
;
158 out
->msg_stime
= in
->msg_stime
;
159 out
->msg_lrpid
= in
->msg_lrpid
;
160 out
->msg_lspid
= in
->msg_lspid
;
161 out
->msg_qbytes
= in
->msg_qbytes
;
162 out
->msg_cbytes
= in
->msg_cbytes
; /* for ipcs */
163 out
->msg_qnum
= in
->msg_qnum
;
164 out
->msg_perm
= in
->msg_perm
;
167 /* This routine assumes the system is locked prior to calling this routine */
169 msginit(__unused
void *dummy
)
171 static int initted
= 0;
174 /* Lazy initialization on first system call; we don't have SYSINIT(). */
179 msgpool
= (char *)_MALLOC(msginfo
.msgmax
, M_SHM
, M_WAITOK
);
180 MALLOC(msgmaps
, struct msgmap
*,
181 sizeof(struct msgmap
) * msginfo
.msgseg
,
183 MALLOC(msghdrs
, struct msg
*,
184 sizeof(struct msg
) * msginfo
.msgtql
,
186 MALLOC(msqids
, struct user_msqid_ds
*,
187 sizeof(struct user_msqid_ds
) * msginfo
.msgmni
,
191 * msginfo.msgssz should be a power of two for efficiency reasons.
192 * It is also pretty silly if msginfo.msgssz is less than 8
193 * or greater than about 256 so ...
197 while (i
< 1024 && i
!= msginfo
.msgssz
)
199 if (i
!= msginfo
.msgssz
) {
200 printf("msginfo.msgssz=%d (0x%x)\n", msginfo
.msgssz
,
202 panic("msginfo.msgssz not a small power of 2");
205 if (msginfo
.msgseg
> 32767) {
206 printf("msginfo.msgseg=%d\n", msginfo
.msgseg
);
207 panic("msginfo.msgseg > 32767");
211 panic("msgmaps is NULL");
213 for (i
= 0; i
< msginfo
.msgseg
; i
++) {
215 msgmaps
[i
-1].next
= i
;
216 msgmaps
[i
].next
= -1; /* implies entry is available */
219 nfree_msgmaps
= msginfo
.msgseg
;
222 panic("msghdrs is NULL");
224 for (i
= 0; i
< msginfo
.msgtql
; i
++) {
225 msghdrs
[i
].msg_type
= 0;
227 msghdrs
[i
-1].msg_next
= &msghdrs
[i
];
228 msghdrs
[i
].msg_next
= NULL
;
230 free_msghdrs
= &msghdrs
[0];
233 panic("msqids is NULL");
235 for (i
= 0; i
< msginfo
.msgmni
; i
++) {
236 msqids
[i
].msg_qbytes
= 0; /* implies entry is available */
237 msqids
[i
].msg_perm
.seq
= 0; /* reset to a known value */
242 * Entry point for all MSG calls
244 /* XXX actually varargs. */
246 msgsys(struct proc
*p
, struct msgsys_args
*uap
, register_t
*retval
)
248 if (uap
->which
>= sizeof(msgcalls
)/sizeof(msgcalls
[0]))
250 return ((*msgcalls
[uap
->which
])(p
, &uap
->a2
, retval
));
254 msg_freehdr(struct msg
*msghdr
)
256 while (msghdr
->msg_ts
> 0) {
258 if (msghdr
->msg_spot
< 0 || msghdr
->msg_spot
>= msginfo
.msgseg
)
259 panic("msghdr->msg_spot out of range");
260 next
= msgmaps
[msghdr
->msg_spot
].next
;
261 msgmaps
[msghdr
->msg_spot
].next
= free_msgmaps
;
262 free_msgmaps
= msghdr
->msg_spot
;
264 msghdr
->msg_spot
= next
;
265 if (msghdr
->msg_ts
>= msginfo
.msgssz
)
266 msghdr
->msg_ts
-= msginfo
.msgssz
;
270 if (msghdr
->msg_spot
!= -1)
271 panic("msghdr->msg_spot != -1");
272 msghdr
->msg_next
= free_msghdrs
;
273 free_msghdrs
= msghdr
;
277 msgctl(struct proc
*p
, struct msgctl_args
*uap
, register_t
*retval
)
279 int msqid
= uap
->msqid
;
281 kauth_cred_t cred
= kauth_cred_get();
283 struct user_msqid_ds msqbuf
;
284 struct user_msqid_ds
*msqptr
;
285 struct user_msqid_ds umsds
;
287 SYSV_MSG_SUBSYS_LOCK();
292 printf("call to msgctl(%d, %d, 0x%qx)\n", msqid
, cmd
, uap
->buf
);
295 AUDIT_ARG(svipc_cmd
, cmd
);
296 AUDIT_ARG(svipc_id
, msqid
);
297 msqid
= IPCID_TO_IX(msqid
);
299 if (msqid
< 0 || msqid
>= msginfo
.msgmni
) {
301 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid
,
308 msqptr
= &msqids
[msqid
];
310 if (msqptr
->msg_qbytes
== 0) {
312 printf("no such msqid\n");
317 if (msqptr
->msg_perm
.seq
!= IPCID_TO_SEQ(uap
->msqid
)) {
319 printf("wrong sequence number\n");
333 if ((eval
= ipcperm(cred
, &msqptr
->msg_perm
, IPC_M
)))
336 /* Free the message headers */
337 msghdr
= msqptr
->msg_first
;
338 while (msghdr
!= NULL
) {
339 struct msg
*msghdr_tmp
;
341 /* Free the segments of each message */
342 msqptr
->msg_cbytes
-= msghdr
->msg_ts
;
345 msghdr
= msghdr
->msg_next
;
346 msg_freehdr(msghdr_tmp
);
349 if (msqptr
->msg_cbytes
!= 0)
350 panic("msg_cbytes is messed up");
351 if (msqptr
->msg_qnum
!= 0)
352 panic("msg_qnum is messed up");
354 msqptr
->msg_qbytes
= 0; /* Mark it as free */
356 wakeup((caddr_t
)msqptr
);
362 if ((eval
= ipcperm(cred
, &msqptr
->msg_perm
, IPC_M
)))
365 SYSV_MSG_SUBSYS_UNLOCK();
367 if (IS_64BIT_PROCESS(p
)) {
368 eval
= copyin(uap
->buf
, &msqbuf
, sizeof(struct user_msqid_ds
));
370 eval
= copyin(uap
->buf
, &msqbuf
, sizeof(struct msqid_ds
));
371 /* convert in place; ugly, but safe */
372 msqid_ds_32to64((struct msqid_ds
*)&msqbuf
, &msqbuf
);
377 SYSV_MSG_SUBSYS_LOCK();
379 if (msqbuf
.msg_qbytes
> msqptr
->msg_qbytes
) {
380 eval
= suser(cred
, &p
->p_acflag
);
386 /* compare (msglen_t) value against restrict (int) value */
387 if (msqbuf
.msg_qbytes
> (msglen_t
)msginfo
.msgmnb
) {
389 printf("can't increase msg_qbytes beyond %d (truncating)\n",
392 msqbuf
.msg_qbytes
= msginfo
.msgmnb
; /* silently restrict qbytes to system limit */
394 if (msqbuf
.msg_qbytes
== 0) {
396 printf("can't reduce msg_qbytes to 0\n");
401 msqptr
->msg_perm
.uid
= msqbuf
.msg_perm
.uid
; /* change the owner */
402 msqptr
->msg_perm
.gid
= msqbuf
.msg_perm
.gid
; /* change the owner */
403 msqptr
->msg_perm
.mode
= (msqptr
->msg_perm
.mode
& ~0777) |
404 (msqbuf
.msg_perm
.mode
& 0777);
405 msqptr
->msg_qbytes
= msqbuf
.msg_qbytes
;
406 msqptr
->msg_ctime
= sysv_msgtime();
410 if ((eval
= ipcperm(cred
, &msqptr
->msg_perm
, IPC_R
))) {
412 printf("requester doesn't have read access\n");
417 bcopy(msqptr
, &umsds
, sizeof(struct user_msqid_ds
));
419 SYSV_MSG_SUBSYS_UNLOCK();
420 if (IS_64BIT_PROCESS(p
)) {
421 eval
= copyout(&umsds
, uap
->buf
, sizeof(struct user_msqid_ds
));
423 struct msqid_ds msqid_ds32
;
424 msqid_ds_64to32(&umsds
, &msqid_ds32
);
425 eval
= copyout(&msqid_ds32
, uap
->buf
, sizeof(struct msqid_ds
));
427 SYSV_MSG_SUBSYS_LOCK();
432 printf("invalid command %d\n", cmd
);
441 SYSV_MSG_SUBSYS_UNLOCK();
446 msgget(__unused
struct proc
*p
, struct msgget_args
*uap
, register_t
*retval
)
450 int msgflg
= uap
->msgflg
;
451 kauth_cred_t cred
= kauth_cred_get();
452 struct user_msqid_ds
*msqptr
= NULL
;
454 SYSV_MSG_SUBSYS_LOCK();
458 printf("msgget(0x%x, 0%o)\n", key
, msgflg
);
461 if (key
!= IPC_PRIVATE
) {
462 for (msqid
= 0; msqid
< msginfo
.msgmni
; msqid
++) {
463 msqptr
= &msqids
[msqid
];
464 if (msqptr
->msg_qbytes
!= 0 &&
465 msqptr
->msg_perm
.key
== key
)
468 if (msqid
< msginfo
.msgmni
) {
470 printf("found public key\n");
472 if ((msgflg
& IPC_CREAT
) && (msgflg
& IPC_EXCL
)) {
474 printf("not exclusive\n");
479 if ((eval
= ipcperm(cred
, &msqptr
->msg_perm
, msgflg
& 0700 ))) {
481 printf("requester doesn't have 0%o access\n",
491 printf("need to allocate the user_msqid_ds\n");
493 if (key
== IPC_PRIVATE
|| (msgflg
& IPC_CREAT
)) {
494 for (msqid
= 0; msqid
< msginfo
.msgmni
; msqid
++) {
496 * Look for an unallocated and unlocked user_msqid_ds.
497 * user_msqid_ds's can be locked by msgsnd or msgrcv
498 * while they are copying the message in/out. We
499 * can't re-use the entry until they release it.
501 msqptr
= &msqids
[msqid
];
502 if (msqptr
->msg_qbytes
== 0 &&
503 (msqptr
->msg_perm
.mode
& MSG_LOCKED
) == 0)
506 if (msqid
== msginfo
.msgmni
) {
508 printf("no more user_msqid_ds's available\n");
514 printf("msqid %d is available\n", msqid
);
516 msqptr
->msg_perm
.key
= key
;
517 msqptr
->msg_perm
.cuid
= kauth_cred_getuid(cred
);
518 msqptr
->msg_perm
.uid
= kauth_cred_getuid(cred
);
519 msqptr
->msg_perm
.cgid
= cred
->cr_gid
;
520 msqptr
->msg_perm
.gid
= cred
->cr_gid
;
521 msqptr
->msg_perm
.mode
= (msgflg
& 0777);
522 /* Make sure that the returned msqid is unique */
523 msqptr
->msg_perm
.seq
++;
524 msqptr
->msg_first
= NULL
;
525 msqptr
->msg_last
= NULL
;
526 msqptr
->msg_cbytes
= 0;
527 msqptr
->msg_qnum
= 0;
528 msqptr
->msg_qbytes
= msginfo
.msgmnb
;
529 msqptr
->msg_lspid
= 0;
530 msqptr
->msg_lrpid
= 0;
531 msqptr
->msg_stime
= 0;
532 msqptr
->msg_rtime
= 0;
533 msqptr
->msg_ctime
= sysv_msgtime();
536 printf("didn't find it and wasn't asked to create it\n");
543 /* Construct the unique msqid */
544 *retval
= IXSEQ_TO_IPCID(msqid
, msqptr
->msg_perm
);
545 AUDIT_ARG(svipc_id
, *retval
);
548 SYSV_MSG_SUBSYS_UNLOCK();
554 msgsnd(struct proc
*p
, struct msgsnd_args
*uap
, register_t
*retval
)
556 int msqid
= uap
->msqid
;
557 user_addr_t user_msgp
= uap
->msgp
;
558 size_t msgsz
= (size_t)uap
->msgsz
; /* limit to 4G */
559 int msgflg
= uap
->msgflg
;
560 int segs_needed
, eval
;
561 struct user_msqid_ds
*msqptr
;
567 SYSV_MSG_SUBSYS_LOCK();
571 printf("call to msgsnd(%d, 0x%qx, %d, %d)\n", msqid
, user_msgp
, msgsz
,
575 AUDIT_ARG(svipc_id
, msqid
);
576 msqid
= IPCID_TO_IX(msqid
);
578 if (msqid
< 0 || msqid
>= msginfo
.msgmni
) {
580 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid
,
587 msqptr
= &msqids
[msqid
];
588 if (msqptr
->msg_qbytes
== 0) {
590 printf("no such message queue id\n");
595 if (msqptr
->msg_perm
.seq
!= IPCID_TO_SEQ(uap
->msqid
)) {
597 printf("wrong sequence number\n");
603 if ((eval
= ipcperm(kauth_cred_get(), &msqptr
->msg_perm
, IPC_W
))) {
605 printf("requester doesn't have write access\n");
610 segs_needed
= (msgsz
+ msginfo
.msgssz
- 1) / msginfo
.msgssz
;
612 printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz
, msginfo
.msgssz
,
616 int need_more_resources
= 0;
620 * (inside this loop in case msg_qbytes changes while we sleep)
623 if (msgsz
> msqptr
->msg_qbytes
) {
625 printf("msgsz > msqptr->msg_qbytes\n");
631 if (msqptr
->msg_perm
.mode
& MSG_LOCKED
) {
633 printf("msqid is locked\n");
635 need_more_resources
= 1;
637 if (msgsz
+ msqptr
->msg_cbytes
> msqptr
->msg_qbytes
) {
639 printf("msgsz + msg_cbytes > msg_qbytes\n");
641 need_more_resources
= 1;
643 if (segs_needed
> nfree_msgmaps
) {
645 printf("segs_needed > nfree_msgmaps\n");
647 need_more_resources
= 1;
649 if (free_msghdrs
== NULL
) {
651 printf("no more msghdrs\n");
653 need_more_resources
= 1;
656 if (need_more_resources
) {
659 if ((msgflg
& IPC_NOWAIT
) != 0) {
661 printf("need more resources but caller doesn't want to wait\n");
667 if ((msqptr
->msg_perm
.mode
& MSG_LOCKED
) != 0) {
669 printf("we don't own the user_msqid_ds\n");
673 /* Force later arrivals to wait for our
676 printf("we own the user_msqid_ds\n");
678 msqptr
->msg_perm
.mode
|= MSG_LOCKED
;
682 printf("goodnight\n");
684 eval
= msleep((caddr_t
)msqptr
, &sysv_msg_subsys_mutex
, (PZERO
- 4) | PCATCH
,
687 printf("good morning, eval=%d\n", eval
);
690 msqptr
->msg_perm
.mode
&= ~MSG_LOCKED
;
693 printf("msgsnd: interrupted system call\n");
700 * Make sure that the msq queue still exists
703 if (msqptr
->msg_qbytes
== 0) {
705 printf("msqid deleted\n");
707 /* The SVID says to return EIDRM. */
711 /* Unfortunately, BSD doesn't define that code
721 printf("got all the resources that we need\n");
728 * We have the resources that we need.
732 if (msqptr
->msg_perm
.mode
& MSG_LOCKED
)
733 panic("msg_perm.mode & MSG_LOCKED");
734 if (segs_needed
> nfree_msgmaps
)
735 panic("segs_needed > nfree_msgmaps");
736 if (msgsz
+ msqptr
->msg_cbytes
> msqptr
->msg_qbytes
)
737 panic("msgsz + msg_cbytes > msg_qbytes");
738 if (free_msghdrs
== NULL
)
739 panic("no more msghdrs");
742 * Re-lock the user_msqid_ds in case we page-fault when copying in
746 if ((msqptr
->msg_perm
.mode
& MSG_LOCKED
) != 0)
747 panic("user_msqid_ds is already locked");
748 msqptr
->msg_perm
.mode
|= MSG_LOCKED
;
751 * Allocate a message header
754 msghdr
= free_msghdrs
;
755 free_msghdrs
= msghdr
->msg_next
;
756 msghdr
->msg_spot
= -1;
757 msghdr
->msg_ts
= msgsz
;
760 * Allocate space for the message
763 while (segs_needed
> 0) {
764 if (nfree_msgmaps
<= 0)
765 panic("not enough msgmaps");
766 if (free_msgmaps
== -1)
767 panic("nil free_msgmaps");
770 panic("next too low #1");
771 if (next
>= msginfo
.msgseg
)
772 panic("next out of range #1");
774 printf("allocating segment %d to message\n", next
);
776 free_msgmaps
= msgmaps
[next
].next
;
778 msgmaps
[next
].next
= msghdr
->msg_spot
;
779 msghdr
->msg_spot
= next
;
784 * Copy in the message type. For a 64 bit process, this is 64 bits,
785 * but we only ever use the low 32 bits, so the cast is OK.
787 if (IS_64BIT_PROCESS(p
)) {
788 SYSV_MSG_SUBSYS_UNLOCK();
789 eval
= copyin(user_msgp
, &msgtype
, sizeof(msgtype
));
790 SYSV_MSG_SUBSYS_LOCK();
791 msghdr
->msg_type
= CAST_DOWN(long,msgtype
);
792 user_msgp
= user_msgp
+ sizeof(msgtype
); /* ptr math */
794 SYSV_MSG_SUBSYS_UNLOCK();
795 eval
= copyin(user_msgp
, &msghdr
->msg_type
, sizeof(long));
796 SYSV_MSG_SUBSYS_LOCK();
797 user_msgp
= user_msgp
+ sizeof(long); /* ptr math */
802 printf("error %d copying the message type\n", eval
);
805 msqptr
->msg_perm
.mode
&= ~MSG_LOCKED
;
806 wakeup((caddr_t
)msqptr
);
812 * Validate the message type
814 if (msghdr
->msg_type
< 1) {
816 msqptr
->msg_perm
.mode
&= ~MSG_LOCKED
;
817 wakeup((caddr_t
)msqptr
);
819 printf("mtype (%d) < 1\n", msghdr
->msg_type
);
826 * Copy in the message body
828 next
= msghdr
->msg_spot
;
831 /* compare input (size_t) value against restrict (int) value */
832 if (msgsz
> (size_t)msginfo
.msgssz
)
833 tlen
= msginfo
.msgssz
;
837 panic("next too low #2");
838 if (next
>= msginfo
.msgseg
)
839 panic("next out of range #2");
841 SYSV_MSG_SUBSYS_UNLOCK();
842 eval
= copyin(user_msgp
, &msgpool
[next
* msginfo
.msgssz
], tlen
);
843 SYSV_MSG_SUBSYS_LOCK();
847 printf("error %d copying in message segment\n", eval
);
850 msqptr
->msg_perm
.mode
&= ~MSG_LOCKED
;
851 wakeup((caddr_t
)msqptr
);
856 user_msgp
= user_msgp
+ tlen
; /* ptr math */
857 next
= msgmaps
[next
].next
;
860 panic("didn't use all the msg segments");
863 * We've got the message. Unlock the user_msqid_ds.
866 msqptr
->msg_perm
.mode
&= ~MSG_LOCKED
;
869 * Make sure that the user_msqid_ds is still allocated.
872 if (msqptr
->msg_qbytes
== 0) {
874 wakeup((caddr_t
)msqptr
);
875 /* The SVID says to return EIDRM. */
879 /* Unfortunately, BSD doesn't define that code yet! */
886 * Put the message into the queue
889 if (msqptr
->msg_first
== NULL
) {
890 msqptr
->msg_first
= msghdr
;
891 msqptr
->msg_last
= msghdr
;
893 msqptr
->msg_last
->msg_next
= msghdr
;
894 msqptr
->msg_last
= msghdr
;
896 msqptr
->msg_last
->msg_next
= NULL
;
898 msqptr
->msg_cbytes
+= msghdr
->msg_ts
;
900 msqptr
->msg_lspid
= p
->p_pid
;
901 msqptr
->msg_stime
= sysv_msgtime();
903 wakeup((caddr_t
)msqptr
);
908 SYSV_MSG_SUBSYS_UNLOCK();
914 msgrcv(struct proc
*p
, struct msgrcv_args
*uap
, user_ssize_t
*retval
)
916 int msqid
= uap
->msqid
;
917 user_addr_t user_msgp
= uap
->msgp
;
918 size_t msgsz
= (size_t)uap
->msgsz
; /* limit to 4G */
919 long msgtyp
= (long)uap
->msgtyp
; /* limit to 32 bits */
920 int msgflg
= uap
->msgflg
;
922 struct user_msqid_ds
*msqptr
;
929 SYSV_MSG_SUBSYS_LOCK();
933 printf("call to msgrcv(%d, 0x%qx, %d, %ld, %d)\n", msqid
, user_msgp
,
934 msgsz
, msgtyp
, msgflg
);
937 AUDIT_ARG(svipc_id
, msqid
);
938 msqid
= IPCID_TO_IX(msqid
);
940 if (msqid
< 0 || msqid
>= msginfo
.msgmni
) {
942 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid
,
949 msqptr
= &msqids
[msqid
];
950 if (msqptr
->msg_qbytes
== 0) {
952 printf("no such message queue id\n");
957 if (msqptr
->msg_perm
.seq
!= IPCID_TO_SEQ(uap
->msqid
)) {
959 printf("wrong sequence number\n");
965 if ((eval
= ipcperm(kauth_cred_get(), &msqptr
->msg_perm
, IPC_R
))) {
967 printf("requester doesn't have read access\n");
973 while (msghdr
== NULL
) {
975 msghdr
= msqptr
->msg_first
;
976 if (msghdr
!= NULL
) {
977 if (msgsz
< msghdr
->msg_ts
&&
978 (msgflg
& MSG_NOERROR
) == 0) {
980 printf("first message on the queue is too big (want %d, got %d)\n",
981 msgsz
, msghdr
->msg_ts
);
986 if (msqptr
->msg_first
== msqptr
->msg_last
) {
987 msqptr
->msg_first
= NULL
;
988 msqptr
->msg_last
= NULL
;
990 msqptr
->msg_first
= msghdr
->msg_next
;
991 if (msqptr
->msg_first
== NULL
)
992 panic("msg_first/last messed up #1");
996 struct msg
*previous
;
1000 prev
= &(msqptr
->msg_first
);
1001 while ((msghdr
= *prev
) != NULL
) {
1003 * Is this message's type an exact match or is
1004 * this message's type less than or equal to
1005 * the absolute value of a negative msgtyp?
1006 * Note that the second half of this test can
1007 * NEVER be true if msgtyp is positive since
1008 * msg_type is always positive!
1011 if (msgtyp
== msghdr
->msg_type
||
1012 msghdr
->msg_type
<= -msgtyp
) {
1014 printf("found message type %d, requested %d\n",
1015 msghdr
->msg_type
, msgtyp
);
1017 if (msgsz
< msghdr
->msg_ts
&&
1018 (msgflg
& MSG_NOERROR
) == 0) {
1020 printf("requested message on the queue is too big (want %d, got %d)\n",
1021 msgsz
, msghdr
->msg_ts
);
1026 *prev
= msghdr
->msg_next
;
1027 if (msghdr
== msqptr
->msg_last
) {
1028 if (previous
== NULL
) {
1031 panic("msg_first/last messed up #2");
1039 panic("msg_first/last messed up #3");
1047 prev
= &(msghdr
->msg_next
);
1052 * We've either extracted the msghdr for the appropriate
1053 * message or there isn't one.
1054 * If there is one then bail out of this loop.
1061 * Hmph! No message found. Does the user want to wait?
1064 if ((msgflg
& IPC_NOWAIT
) != 0) {
1066 printf("no appropriate message found (msgtyp=%d)\n",
1069 /* The SVID says to return ENOMSG. */
1073 /* Unfortunately, BSD doesn't define that code yet! */
1080 * Wait for something to happen
1084 printf("msgrcv: goodnight\n");
1086 eval
= msleep((caddr_t
)msqptr
, &sysv_msg_subsys_mutex
, (PZERO
- 4) | PCATCH
, "msgwait",
1089 printf("msgrcv: good morning (eval=%d)\n", eval
);
1094 printf("msgsnd: interrupted system call\n");
1101 * Make sure that the msq queue still exists
1104 if (msqptr
->msg_qbytes
== 0 ||
1105 msqptr
->msg_perm
.seq
!= IPCID_TO_SEQ(uap
->msqid
)) {
1107 printf("msqid deleted\n");
1109 /* The SVID says to return EIDRM. */
1113 /* Unfortunately, BSD doesn't define that code yet! */
1121 * Return the message to the user.
1123 * First, do the bookkeeping (before we risk being interrupted).
1126 msqptr
->msg_cbytes
-= msghdr
->msg_ts
;
1128 msqptr
->msg_lrpid
= p
->p_pid
;
1129 msqptr
->msg_rtime
= sysv_msgtime();
1132 * Make msgsz the actual amount that we'll be returning.
1133 * Note that this effectively truncates the message if it is too long
1134 * (since msgsz is never increased).
1138 printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz
,
1141 if (msgsz
> msghdr
->msg_ts
)
1142 msgsz
= msghdr
->msg_ts
;
1145 * Return the type to the user.
1149 * Copy out the message type. For a 64 bit process, this is 64 bits,
1150 * but we only ever use the low 32 bits, so the cast is OK.
1152 if (IS_64BIT_PROCESS(p
)) {
1153 msgtype
= msghdr
->msg_type
;
1154 SYSV_MSG_SUBSYS_UNLOCK();
1155 eval
= copyout(&msgtype
, user_msgp
, sizeof(msgtype
));
1156 SYSV_MSG_SUBSYS_LOCK();
1157 user_msgp
= user_msgp
+ sizeof(msgtype
); /* ptr math */
1159 msg_type_long
= msghdr
->msg_type
;
1160 SYSV_MSG_SUBSYS_UNLOCK();
1161 eval
= copyout(&msg_type_long
, user_msgp
, sizeof(long));
1162 SYSV_MSG_SUBSYS_LOCK();
1163 user_msgp
= user_msgp
+ sizeof(long); /* ptr math */
1168 printf("error (%d) copying out message type\n", eval
);
1170 msg_freehdr(msghdr
);
1171 wakeup((caddr_t
)msqptr
);
1178 * Return the segments to the user
1181 next
= msghdr
->msg_spot
;
1182 for (len
= 0; len
< msgsz
; len
+= msginfo
.msgssz
) {
1185 /* compare input (size_t) value against restrict (int) value */
1186 if (msgsz
> (size_t)msginfo
.msgssz
)
1187 tlen
= msginfo
.msgssz
;
1191 panic("next too low #3");
1192 if (next
>= msginfo
.msgseg
)
1193 panic("next out of range #3");
1194 SYSV_MSG_SUBSYS_UNLOCK();
1195 eval
= copyout(&msgpool
[next
* msginfo
.msgssz
],
1197 SYSV_MSG_SUBSYS_LOCK();
1200 printf("error (%d) copying out message segment\n",
1203 msg_freehdr(msghdr
);
1204 wakeup((caddr_t
)msqptr
);
1207 user_msgp
= user_msgp
+ tlen
; /* ptr math */
1208 next
= msgmaps
[next
].next
;
1212 * Done, return the actual number of bytes copied out.
1215 msg_freehdr(msghdr
);
1216 wakeup((caddr_t
)msqptr
);
1220 SYSV_MSG_SUBSYS_UNLOCK();
1225 IPCS_msg_sysctl(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
1226 __unused
int arg2
, struct sysctl_req
*req
)
1231 struct IPCS_command u32
;
1232 struct user_IPCS_command u64
;
1234 struct msqid_ds msqid_ds32
; /* post conversion, 32 bit version */
1236 size_t ipcs_sz
= sizeof(struct user_IPCS_command
);
1237 size_t msqid_ds_sz
= sizeof(struct user_msqid_ds
);
1238 struct proc
*p
= current_proc();
1240 if (!IS_64BIT_PROCESS(p
)) {
1241 ipcs_sz
= sizeof(struct IPCS_command
);
1242 msqid_ds_sz
= sizeof(struct msqid_ds
);
1245 /* Copy in the command structure */
1246 if ((error
= SYSCTL_IN(req
, &ipcs
, ipcs_sz
)) != 0) {
1250 if (!IS_64BIT_PROCESS(p
)) /* convert in place */
1251 ipcs
.u64
.ipcs_data
= CAST_USER_ADDR_T(ipcs
.u32
.ipcs_data
);
1253 /* Let us version this interface... */
1254 if (ipcs
.u64
.ipcs_magic
!= IPCS_MAGIC
) {
1258 SYSV_MSG_SUBSYS_LOCK();
1260 switch(ipcs
.u64
.ipcs_op
) {
1261 case IPCS_MSG_CONF
: /* Obtain global configuration data */
1262 if (ipcs
.u64
.ipcs_datalen
!= sizeof(struct msginfo
)) {
1266 if (ipcs
.u64
.ipcs_cursor
!= 0) { /* fwd. compat. */
1270 SYSV_MSG_SUBSYS_UNLOCK();
1271 error
= copyout(&msginfo
, ipcs
.u64
.ipcs_data
, ipcs
.u64
.ipcs_datalen
);
1272 SYSV_MSG_SUBSYS_LOCK();
1275 case IPCS_MSG_ITER
: /* Iterate over existing segments */
1276 /* Not done up top so we can set limits via sysctl (later) */
1279 cursor
= ipcs
.u64
.ipcs_cursor
;
1280 if (cursor
< 0 || cursor
>= msginfo
.msgmni
) {
1284 if (ipcs
.u64
.ipcs_datalen
!= (int)msqid_ds_sz
) {
1288 for( ; cursor
< msginfo
.msgmni
; cursor
++) {
1289 if (msqids
[cursor
].msg_qbytes
!= 0) /* allocated */
1293 if (cursor
== msginfo
.msgmni
) {
1298 msqid_dsp
= &msqids
[cursor
]; /* default: 64 bit */
1301 * If necessary, convert the 64 bit kernel segment
1302 * descriptor to a 32 bit user one.
1304 if (!IS_64BIT_PROCESS(p
)) {
1305 msqid_ds_64to32(msqid_dsp
, &msqid_ds32
);
1306 msqid_dsp
= &msqid_ds32
;
1308 SYSV_MSG_SUBSYS_UNLOCK();
1309 error
= copyout(msqid_dsp
, ipcs
.u64
.ipcs_data
, ipcs
.u64
.ipcs_datalen
);
1312 ipcs
.u64
.ipcs_cursor
= cursor
+ 1;
1314 if (!IS_64BIT_PROCESS(p
)) /* convert in place */
1315 ipcs
.u32
.ipcs_data
= CAST_DOWN(void *,ipcs
.u64
.ipcs_data
);
1316 error
= SYSCTL_OUT(req
, &ipcs
, ipcs_sz
);
1318 SYSV_MSG_SUBSYS_LOCK();
1326 SYSV_MSG_SUBSYS_UNLOCK();
1330 SYSCTL_DECL(_kern_sysv_ipcs
);
1331 SYSCTL_PROC(_kern_sysv_ipcs
, OID_AUTO
, msg
, CTLFLAG_RW
|CTLFLAG_ANYBODY
,
1332 0, 0, IPCS_msg_sysctl
,
1333 "S,IPCS_msg_command",
1334 "ipcs msg command interface");