]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/sysv_msg.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / kern / sysv_msg.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
37839358
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Implementation of SVID messages
24 *
25 * Author: Daniel Boulet
26 *
27 * Copyright 1993 Daniel Boulet and RTMX Inc.
28 *
29 * This system call was implemented by Daniel Boulet under contract from RTMX.
30 *
31 * Redistribution and use in source forms, with and without modification,
32 * are permitted provided that this entire comment appears intact.
33 *
34 * Redistribution in binary form may occur without any restrictions.
35 * Obviously, it would be nice if you gave credit where credit is due
36 * but requiring it would be too onerous.
37 *
38 * This software is provided ``AS IS'' without any warranties of any kind.
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
1c79356b 43#include <sys/kernel.h>
91447636
A
44#include <sys/proc_internal.h>
45#include <sys/kauth.h>
1c79356b 46#include <sys/msg.h>
91447636
A
47#include <sys/malloc.h>
48#include <mach/mach_types.h>
e5568f75
A
49
50#include <bsm/audit_kernel.h>
1c79356b 51
91447636
A
52#include <sys/filedesc.h>
53#include <sys/file_internal.h>
54#include <sys/sysctl.h>
55#include <sys/sysproto.h>
56#include <sys/ipcs.h>
57
58static void msginit(void *);
1c79356b
A
59
60#define MSG_DEBUG
61#undef MSG_DEBUG_OK
62
91447636
A
63static void msg_freehdr(struct msg *msghdr);
64
65typedef int sy_call_t(struct proc *, void *, int *);
1c79356b
A
66
67/* XXX casting to (sy_call_t *) is bogus, as usual. */
68static sy_call_t *msgcalls[] = {
69 (sy_call_t *)msgctl, (sy_call_t *)msgget,
70 (sy_call_t *)msgsnd, (sy_call_t *)msgrcv
71};
72
91447636
A
73static int nfree_msgmaps; /* # of free map entries */
74static short free_msgmaps; /* free map entries list head */
75static struct msg *free_msghdrs; /* list of free msg headers */
76char *msgpool; /* MSGMAX byte long msg buffer pool */
77struct msgmap *msgmaps; /* MSGSEG msgmap structures */
78struct msg *msghdrs; /* MSGTQL msg headers */
79struct user_msqid_ds *msqids; /* MSGMNI user_msqid_ds struct's */
80
81static lck_grp_t *sysv_msg_subsys_lck_grp;
82static lck_grp_attr_t *sysv_msg_subsys_lck_grp_attr;
83static lck_attr_t *sysv_msg_subsys_lck_attr;
84static lck_mtx_t sysv_msg_subsys_mutex;
85
86#define SYSV_MSG_SUBSYS_LOCK() lck_mtx_lock(&sysv_msg_subsys_mutex)
87#define SYSV_MSG_SUBSYS_UNLOCK() lck_mtx_unlock(&sysv_msg_subsys_mutex)
88
89void sysv_msg_lock_init(void);
90
91
92#ifdef __APPLE_API_PRIVATE
93struct msginfo msginfo = {
94 MSGMAX, /* = (MSGSSZ*MSGSEG) : max chars in a message */
95 MSGMNI, /* = 40 : max message queue identifiers */
96 MSGMNB, /* = 2048 : max chars in a queue */
97 MSGTQL, /* = 40 : max messages in system */
98 MSGSSZ, /* = 8 : size of a message segment (2^N long) */
99 MSGSEG /* = 2048 : number of message segments */
100};
101#endif /* __APPLE_API_PRIVATE */
102
103/* Initialize the mutex governing access to the SysV msg subsystem */
104__private_extern__ void
105sysv_msg_lock_init( void )
106{
107 sysv_msg_subsys_lck_grp_attr = lck_grp_attr_alloc_init();
91447636
A
108
109 sysv_msg_subsys_lck_grp = lck_grp_alloc_init("sysv_msg_subsys_lock", sysv_msg_subsys_lck_grp_attr);
110
111 sysv_msg_subsys_lck_attr = lck_attr_alloc_init();
91447636
A
112 lck_mtx_init(&sysv_msg_subsys_mutex, sysv_msg_subsys_lck_grp, sysv_msg_subsys_lck_attr);
113}
114
115static __inline__ user_time_t
116sysv_msgtime(void)
117{
118 struct timeval tv;
119 microtime(&tv);
120 return (tv.tv_sec);
121}
122
123/*
124 * NOTE: Source and target may *NOT* overlap! (target is smaller)
125 */
126static void
127msqid_ds_64to32(struct user_msqid_ds *in, struct msqid_ds *out)
128{
129 out->msg_perm = in->msg_perm;
130 out->msg_qnum = in->msg_qnum;
131 out->msg_cbytes = in->msg_cbytes; /* for ipcs */
132 out->msg_qbytes = in->msg_qbytes;
133 out->msg_lspid = in->msg_lspid;
134 out->msg_lrpid = in->msg_lrpid;
135 out->msg_stime = in->msg_stime; /* XXX loss of range */
136 out->msg_rtime = in->msg_rtime; /* XXX loss of range */
137 out->msg_ctime = in->msg_ctime; /* XXX loss of range */
138}
139
140/*
141 * NOTE: Source and target may are permitted to overlap! (source is smaller);
142 * this works because we copy fields in order from the end of the struct to
143 * the beginning.
144 */
145static void
146msqid_ds_32to64(struct msqid_ds *in, struct user_msqid_ds *out)
147{
148 out->msg_ctime = in->msg_ctime;
149 out->msg_rtime = in->msg_rtime;
150 out->msg_stime = in->msg_stime;
151 out->msg_lrpid = in->msg_lrpid;
152 out->msg_lspid = in->msg_lspid;
153 out->msg_qbytes = in->msg_qbytes;
154 out->msg_cbytes = in->msg_cbytes; /* for ipcs */
155 out->msg_qnum = in->msg_qnum;
156 out->msg_perm = in->msg_perm;
157}
158
159/* This routine assumes the system is locked prior to calling this routine */
160void
161msginit(__unused void *dummy)
1c79356b 162{
91447636 163 static int initted = 0;
1c79356b
A
164 register int i;
165
91447636
A
166 /* Lazy initialization on first system call; we don't have SYSINIT(). */
167 if (initted)
168 return;
169 initted = 1;
170
171 msgpool = (char *)_MALLOC(msginfo.msgmax, M_SHM, M_WAITOK);
172 MALLOC(msgmaps, struct msgmap *,
173 sizeof(struct msgmap) * msginfo.msgseg,
174 M_SHM, M_WAITOK);
175 MALLOC(msghdrs, struct msg *,
176 sizeof(struct msg) * msginfo.msgtql,
177 M_SHM, M_WAITOK);
178 MALLOC(msqids, struct user_msqid_ds *,
179 sizeof(struct user_msqid_ds) * msginfo.msgmni,
180 M_SHM, M_WAITOK);
181
1c79356b
A
182 /*
183 * msginfo.msgssz should be a power of two for efficiency reasons.
184 * It is also pretty silly if msginfo.msgssz is less than 8
185 * or greater than about 256 so ...
186 */
187
188 i = 8;
189 while (i < 1024 && i != msginfo.msgssz)
190 i <<= 1;
191 if (i != msginfo.msgssz) {
192 printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
193 msginfo.msgssz);
194 panic("msginfo.msgssz not a small power of 2");
195 }
196
197 if (msginfo.msgseg > 32767) {
198 printf("msginfo.msgseg=%d\n", msginfo.msgseg);
199 panic("msginfo.msgseg > 32767");
200 }
201
202 if (msgmaps == NULL)
203 panic("msgmaps is NULL");
204
205 for (i = 0; i < msginfo.msgseg; i++) {
206 if (i > 0)
207 msgmaps[i-1].next = i;
208 msgmaps[i].next = -1; /* implies entry is available */
209 }
210 free_msgmaps = 0;
211 nfree_msgmaps = msginfo.msgseg;
212
213 if (msghdrs == NULL)
214 panic("msghdrs is NULL");
215
216 for (i = 0; i < msginfo.msgtql; i++) {
217 msghdrs[i].msg_type = 0;
218 if (i > 0)
219 msghdrs[i-1].msg_next = &msghdrs[i];
220 msghdrs[i].msg_next = NULL;
221 }
222 free_msghdrs = &msghdrs[0];
223
224 if (msqids == NULL)
225 panic("msqids is NULL");
226
227 for (i = 0; i < msginfo.msgmni; i++) {
228 msqids[i].msg_qbytes = 0; /* implies entry is available */
229 msqids[i].msg_perm.seq = 0; /* reset to a known value */
230 }
231}
232
233/*
234 * Entry point for all MSG calls
235 */
1c79356b 236 /* XXX actually varargs. */
91447636
A
237int
238msgsys(struct proc *p, struct msgsys_args *uap, register_t *retval)
1c79356b 239{
1c79356b
A
240 if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
241 return (EINVAL);
91447636 242 return ((*msgcalls[uap->which])(p, &uap->a2, retval));
1c79356b
A
243}
244
245static void
91447636 246msg_freehdr(struct msg *msghdr)
1c79356b
A
247{
248 while (msghdr->msg_ts > 0) {
249 short next;
250 if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
251 panic("msghdr->msg_spot out of range");
252 next = msgmaps[msghdr->msg_spot].next;
253 msgmaps[msghdr->msg_spot].next = free_msgmaps;
254 free_msgmaps = msghdr->msg_spot;
255 nfree_msgmaps++;
256 msghdr->msg_spot = next;
257 if (msghdr->msg_ts >= msginfo.msgssz)
258 msghdr->msg_ts -= msginfo.msgssz;
259 else
260 msghdr->msg_ts = 0;
261 }
262 if (msghdr->msg_spot != -1)
263 panic("msghdr->msg_spot != -1");
264 msghdr->msg_next = free_msghdrs;
265 free_msghdrs = msghdr;
266}
267
1c79356b 268int
91447636 269msgctl(struct proc *p, struct msgctl_args *uap, register_t *retval)
1c79356b
A
270{
271 int msqid = uap->msqid;
272 int cmd = uap->cmd;
91447636 273 kauth_cred_t cred = kauth_cred_get();
1c79356b 274 int rval, eval;
91447636
A
275 struct user_msqid_ds msqbuf;
276 struct user_msqid_ds *msqptr;
277 struct user_msqid_ds umsds;
278
279 SYSV_MSG_SUBSYS_LOCK();
280
281 msginit( 0);
1c79356b
A
282
283#ifdef MSG_DEBUG_OK
91447636 284 printf("call to msgctl(%d, %d, 0x%qx)\n", msqid, cmd, uap->buf);
1c79356b
A
285#endif
286
55e303ae
A
287 AUDIT_ARG(svipc_cmd, cmd);
288 AUDIT_ARG(svipc_id, msqid);
1c79356b
A
289 msqid = IPCID_TO_IX(msqid);
290
291 if (msqid < 0 || msqid >= msginfo.msgmni) {
292#ifdef MSG_DEBUG_OK
293 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
294 msginfo.msgmni);
295#endif
91447636
A
296 eval = EINVAL;
297 goto msgctlout;
1c79356b
A
298 }
299
300 msqptr = &msqids[msqid];
301
302 if (msqptr->msg_qbytes == 0) {
303#ifdef MSG_DEBUG_OK
304 printf("no such msqid\n");
305#endif
91447636
A
306 eval = EINVAL;
307 goto msgctlout;
1c79356b
A
308 }
309 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
310#ifdef MSG_DEBUG_OK
311 printf("wrong sequence number\n");
312#endif
91447636
A
313 eval = EINVAL;
314 goto msgctlout;
1c79356b
A
315 }
316
317 eval = 0;
318 rval = 0;
319
320 switch (cmd) {
321
322 case IPC_RMID:
323 {
324 struct msg *msghdr;
325 if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
91447636
A
326 goto msgctlout;
327
1c79356b
A
328 /* Free the message headers */
329 msghdr = msqptr->msg_first;
330 while (msghdr != NULL) {
331 struct msg *msghdr_tmp;
332
333 /* Free the segments of each message */
334 msqptr->msg_cbytes -= msghdr->msg_ts;
335 msqptr->msg_qnum--;
336 msghdr_tmp = msghdr;
337 msghdr = msghdr->msg_next;
338 msg_freehdr(msghdr_tmp);
339 }
340
341 if (msqptr->msg_cbytes != 0)
342 panic("msg_cbytes is messed up");
343 if (msqptr->msg_qnum != 0)
344 panic("msg_qnum is messed up");
345
346 msqptr->msg_qbytes = 0; /* Mark it as free */
347
348 wakeup((caddr_t)msqptr);
349 }
350
351 break;
352
353 case IPC_SET:
354 if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
91447636
A
355 goto msgctlout;
356
357 SYSV_MSG_SUBSYS_UNLOCK();
358
359 if (IS_64BIT_PROCESS(p)) {
360 eval = copyin(uap->buf, &msqbuf, sizeof(struct user_msqid_ds));
361 } else {
362 eval = copyin(uap->buf, &msqbuf, sizeof(struct msqid_ds));
363 /* convert in place; ugly, but safe */
364 msqid_ds_32to64((struct msqid_ds *)&msqbuf, &msqbuf);
365 }
366 if (eval)
1c79356b 367 return(eval);
91447636
A
368
369 SYSV_MSG_SUBSYS_LOCK();
370
1c79356b
A
371 if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
372 eval = suser(cred, &p->p_acflag);
373 if (eval)
91447636 374 goto msgctlout;
1c79356b 375 }
91447636
A
376
377
378 /* compare (msglen_t) value against restrict (int) value */
379 if (msqbuf.msg_qbytes > (msglen_t)msginfo.msgmnb) {
1c79356b
A
380#ifdef MSG_DEBUG_OK
381 printf("can't increase msg_qbytes beyond %d (truncating)\n",
382 msginfo.msgmnb);
383#endif
384 msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */
385 }
386 if (msqbuf.msg_qbytes == 0) {
387#ifdef MSG_DEBUG_OK
388 printf("can't reduce msg_qbytes to 0\n");
389#endif
91447636
A
390 eval = EINVAL;
391 goto msgctlout;
1c79356b
A
392 }
393 msqptr->msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */
394 msqptr->msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */
395 msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
396 (msqbuf.msg_perm.mode & 0777);
397 msqptr->msg_qbytes = msqbuf.msg_qbytes;
91447636 398 msqptr->msg_ctime = sysv_msgtime();
1c79356b
A
399 break;
400
401 case IPC_STAT:
402 if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
403#ifdef MSG_DEBUG_OK
404 printf("requester doesn't have read access\n");
405#endif
91447636
A
406 goto msgctlout;
407 }
408
409 bcopy(msqptr, &umsds, sizeof(struct user_msqid_ds));
410
411 SYSV_MSG_SUBSYS_UNLOCK();
412 if (IS_64BIT_PROCESS(p)) {
413 eval = copyout(&umsds, uap->buf, sizeof(struct user_msqid_ds));
414 } else {
415 struct msqid_ds msqid_ds32;
416 msqid_ds_64to32(&umsds, &msqid_ds32);
417 eval = copyout(&msqid_ds32, uap->buf, sizeof(struct msqid_ds));
1c79356b 418 }
91447636 419 SYSV_MSG_SUBSYS_LOCK();
1c79356b
A
420 break;
421
422 default:
423#ifdef MSG_DEBUG_OK
424 printf("invalid command %d\n", cmd);
425#endif
91447636
A
426 eval = EINVAL;
427 goto msgctlout;
1c79356b
A
428 }
429
430 if (eval == 0)
91447636
A
431 *retval = rval;
432msgctlout:
433 SYSV_MSG_SUBSYS_UNLOCK();
1c79356b
A
434 return(eval);
435}
436
1c79356b 437int
91447636 438msgget(__unused struct proc *p, struct msgget_args *uap, register_t *retval)
1c79356b
A
439{
440 int msqid, eval;
441 int key = uap->key;
442 int msgflg = uap->msgflg;
91447636
A
443 kauth_cred_t cred = kauth_cred_get();
444 struct user_msqid_ds *msqptr = NULL;
445
446 SYSV_MSG_SUBSYS_LOCK();
447 msginit( 0);
1c79356b
A
448
449#ifdef MSG_DEBUG_OK
450 printf("msgget(0x%x, 0%o)\n", key, msgflg);
451#endif
452
453 if (key != IPC_PRIVATE) {
454 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
455 msqptr = &msqids[msqid];
456 if (msqptr->msg_qbytes != 0 &&
457 msqptr->msg_perm.key == key)
458 break;
459 }
460 if (msqid < msginfo.msgmni) {
461#ifdef MSG_DEBUG_OK
462 printf("found public key\n");
463#endif
464 if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
465#ifdef MSG_DEBUG_OK
466 printf("not exclusive\n");
467#endif
91447636
A
468 eval = EEXIST;
469 goto msggetout;
1c79356b
A
470 }
471 if ((eval = ipcperm(cred, &msqptr->msg_perm, msgflg & 0700 ))) {
472#ifdef MSG_DEBUG_OK
473 printf("requester doesn't have 0%o access\n",
474 msgflg & 0700);
475#endif
91447636 476 goto msggetout;
1c79356b
A
477 }
478 goto found;
479 }
480 }
481
482#ifdef MSG_DEBUG_OK
91447636 483 printf("need to allocate the user_msqid_ds\n");
1c79356b
A
484#endif
485 if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
486 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
487 /*
91447636
A
488 * Look for an unallocated and unlocked user_msqid_ds.
489 * user_msqid_ds's can be locked by msgsnd or msgrcv
490 * while they are copying the message in/out. We
491 * can't re-use the entry until they release it.
1c79356b
A
492 */
493 msqptr = &msqids[msqid];
494 if (msqptr->msg_qbytes == 0 &&
495 (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
496 break;
497 }
498 if (msqid == msginfo.msgmni) {
499#ifdef MSG_DEBUG_OK
91447636 500 printf("no more user_msqid_ds's available\n");
1c79356b 501#endif
91447636
A
502 eval = ENOSPC;
503 goto msggetout;
1c79356b
A
504 }
505#ifdef MSG_DEBUG_OK
506 printf("msqid %d is available\n", msqid);
507#endif
508 msqptr->msg_perm.key = key;
91447636
A
509 msqptr->msg_perm.cuid = kauth_cred_getuid(cred);
510 msqptr->msg_perm.uid = kauth_cred_getuid(cred);
1c79356b
A
511 msqptr->msg_perm.cgid = cred->cr_gid;
512 msqptr->msg_perm.gid = cred->cr_gid;
513 msqptr->msg_perm.mode = (msgflg & 0777);
514 /* Make sure that the returned msqid is unique */
515 msqptr->msg_perm.seq++;
516 msqptr->msg_first = NULL;
517 msqptr->msg_last = NULL;
518 msqptr->msg_cbytes = 0;
519 msqptr->msg_qnum = 0;
520 msqptr->msg_qbytes = msginfo.msgmnb;
521 msqptr->msg_lspid = 0;
522 msqptr->msg_lrpid = 0;
523 msqptr->msg_stime = 0;
524 msqptr->msg_rtime = 0;
91447636 525 msqptr->msg_ctime = sysv_msgtime();
1c79356b
A
526 } else {
527#ifdef MSG_DEBUG_OK
528 printf("didn't find it and wasn't asked to create it\n");
529#endif
91447636
A
530 eval = ENOENT;
531 goto msggetout;
1c79356b
A
532 }
533
534found:
535 /* Construct the unique msqid */
91447636
A
536 *retval = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
537 AUDIT_ARG(svipc_id, *retval);
538 eval = 0;
539msggetout:
540 SYSV_MSG_SUBSYS_UNLOCK();
541 return(eval);
1c79356b
A
542}
543
1c79356b
A
544
545int
91447636 546msgsnd(struct proc *p, struct msgsnd_args *uap, register_t *retval)
1c79356b
A
547{
548 int msqid = uap->msqid;
91447636
A
549 user_addr_t user_msgp = uap->msgp;
550 size_t msgsz = (size_t)uap->msgsz; /* limit to 4G */
1c79356b
A
551 int msgflg = uap->msgflg;
552 int segs_needed, eval;
91447636
A
553 struct user_msqid_ds *msqptr;
554 struct msg *msghdr;
1c79356b 555 short next;
91447636
A
556 user_long_t msgtype;
557
558
559 SYSV_MSG_SUBSYS_LOCK();
560 msginit( 0);
1c79356b
A
561
562#ifdef MSG_DEBUG_OK
91447636 563 printf("call to msgsnd(%d, 0x%qx, %d, %d)\n", msqid, user_msgp, msgsz,
1c79356b
A
564 msgflg);
565#endif
566
55e303ae 567 AUDIT_ARG(svipc_id, msqid);
1c79356b
A
568 msqid = IPCID_TO_IX(msqid);
569
570 if (msqid < 0 || msqid >= msginfo.msgmni) {
571#ifdef MSG_DEBUG_OK
572 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
573 msginfo.msgmni);
574#endif
91447636
A
575 eval = EINVAL;
576 goto msgsndout;
1c79356b
A
577 }
578
579 msqptr = &msqids[msqid];
580 if (msqptr->msg_qbytes == 0) {
581#ifdef MSG_DEBUG_OK
582 printf("no such message queue id\n");
583#endif
91447636
A
584 eval = EINVAL;
585 goto msgsndout;
1c79356b
A
586 }
587 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
588#ifdef MSG_DEBUG_OK
589 printf("wrong sequence number\n");
590#endif
91447636
A
591 eval = EINVAL;
592 goto msgsndout;
1c79356b
A
593 }
594
91447636 595 if ((eval = ipcperm(kauth_cred_get(), &msqptr->msg_perm, IPC_W))) {
1c79356b
A
596#ifdef MSG_DEBUG_OK
597 printf("requester doesn't have write access\n");
598#endif
91447636 599 goto msgsndout;
1c79356b
A
600 }
601
602 segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
603#ifdef MSG_DEBUG_OK
604 printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
605 segs_needed);
606#endif
607 for (;;) {
608 int need_more_resources = 0;
609
610 /*
611 * check msgsz
612 * (inside this loop in case msg_qbytes changes while we sleep)
613 */
614
615 if (msgsz > msqptr->msg_qbytes) {
616#ifdef MSG_DEBUG_OK
617 printf("msgsz > msqptr->msg_qbytes\n");
618#endif
91447636
A
619 eval = EINVAL;
620 goto msgsndout;
1c79356b
A
621 }
622
623 if (msqptr->msg_perm.mode & MSG_LOCKED) {
624#ifdef MSG_DEBUG_OK
625 printf("msqid is locked\n");
626#endif
627 need_more_resources = 1;
628 }
629 if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
630#ifdef MSG_DEBUG_OK
631 printf("msgsz + msg_cbytes > msg_qbytes\n");
632#endif
633 need_more_resources = 1;
634 }
635 if (segs_needed > nfree_msgmaps) {
636#ifdef MSG_DEBUG_OK
637 printf("segs_needed > nfree_msgmaps\n");
638#endif
639 need_more_resources = 1;
640 }
641 if (free_msghdrs == NULL) {
642#ifdef MSG_DEBUG_OK
643 printf("no more msghdrs\n");
644#endif
645 need_more_resources = 1;
646 }
647
648 if (need_more_resources) {
649 int we_own_it;
650
651 if ((msgflg & IPC_NOWAIT) != 0) {
652#ifdef MSG_DEBUG_OK
653 printf("need more resources but caller doesn't want to wait\n");
654#endif
91447636
A
655 eval = EAGAIN;
656 goto msgsndout;
1c79356b
A
657 }
658
659 if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
660#ifdef MSG_DEBUG_OK
91447636 661 printf("we don't own the user_msqid_ds\n");
1c79356b
A
662#endif
663 we_own_it = 0;
664 } else {
665 /* Force later arrivals to wait for our
666 request */
667#ifdef MSG_DEBUG_OK
91447636 668 printf("we own the user_msqid_ds\n");
1c79356b
A
669#endif
670 msqptr->msg_perm.mode |= MSG_LOCKED;
671 we_own_it = 1;
672 }
673#ifdef MSG_DEBUG_OK
674 printf("goodnight\n");
675#endif
91447636 676 eval = msleep((caddr_t)msqptr, &sysv_msg_subsys_mutex, (PZERO - 4) | PCATCH,
1c79356b
A
677 "msgwait", 0);
678#ifdef MSG_DEBUG_OK
679 printf("good morning, eval=%d\n", eval);
680#endif
681 if (we_own_it)
682 msqptr->msg_perm.mode &= ~MSG_LOCKED;
683 if (eval != 0) {
684#ifdef MSG_DEBUG_OK
685 printf("msgsnd: interrupted system call\n");
686#endif
91447636
A
687 eval = EINTR;
688 goto msgsndout;
1c79356b
A
689 }
690
691 /*
692 * Make sure that the msq queue still exists
693 */
694
695 if (msqptr->msg_qbytes == 0) {
696#ifdef MSG_DEBUG_OK
697 printf("msqid deleted\n");
698#endif
699 /* The SVID says to return EIDRM. */
700#ifdef EIDRM
91447636 701 eval = EIDRM;
1c79356b
A
702#else
703 /* Unfortunately, BSD doesn't define that code
704 yet! */
91447636 705 eval = EINVAL;
1c79356b 706#endif
91447636
A
707 goto msgsndout;
708
1c79356b
A
709 }
710
711 } else {
712#ifdef MSG_DEBUG_OK
713 printf("got all the resources that we need\n");
714#endif
715 break;
716 }
717 }
718
719 /*
720 * We have the resources that we need.
721 * Make sure!
722 */
723
724 if (msqptr->msg_perm.mode & MSG_LOCKED)
725 panic("msg_perm.mode & MSG_LOCKED");
726 if (segs_needed > nfree_msgmaps)
727 panic("segs_needed > nfree_msgmaps");
728 if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
729 panic("msgsz + msg_cbytes > msg_qbytes");
730 if (free_msghdrs == NULL)
731 panic("no more msghdrs");
732
733 /*
91447636
A
734 * Re-lock the user_msqid_ds in case we page-fault when copying in
735 * the message
1c79356b
A
736 */
737
738 if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
91447636 739 panic("user_msqid_ds is already locked");
1c79356b
A
740 msqptr->msg_perm.mode |= MSG_LOCKED;
741
742 /*
743 * Allocate a message header
744 */
745
746 msghdr = free_msghdrs;
747 free_msghdrs = msghdr->msg_next;
748 msghdr->msg_spot = -1;
749 msghdr->msg_ts = msgsz;
750
751 /*
752 * Allocate space for the message
753 */
754
755 while (segs_needed > 0) {
756 if (nfree_msgmaps <= 0)
757 panic("not enough msgmaps");
758 if (free_msgmaps == -1)
759 panic("nil free_msgmaps");
760 next = free_msgmaps;
761 if (next <= -1)
762 panic("next too low #1");
763 if (next >= msginfo.msgseg)
764 panic("next out of range #1");
765#ifdef MSG_DEBUG_OK
766 printf("allocating segment %d to message\n", next);
767#endif
768 free_msgmaps = msgmaps[next].next;
769 nfree_msgmaps--;
770 msgmaps[next].next = msghdr->msg_spot;
771 msghdr->msg_spot = next;
772 segs_needed--;
773 }
774
775 /*
91447636
A
776 * Copy in the message type. For a 64 bit process, this is 64 bits,
777 * but we only ever use the low 32 bits, so the cast is OK.
1c79356b 778 */
91447636
A
779 if (IS_64BIT_PROCESS(p)) {
780 SYSV_MSG_SUBSYS_UNLOCK();
781 eval = copyin(user_msgp, &msgtype, sizeof(msgtype));
782 SYSV_MSG_SUBSYS_LOCK();
783 msghdr->msg_type = CAST_DOWN(long,msgtype);
784 user_msgp = user_msgp + sizeof(msgtype); /* ptr math */
785 } else {
786 SYSV_MSG_SUBSYS_UNLOCK();
787 eval = copyin(user_msgp, &msghdr->msg_type, sizeof(long));
788 SYSV_MSG_SUBSYS_LOCK();
789 user_msgp = user_msgp + sizeof(long); /* ptr math */
790 }
1c79356b 791
91447636 792 if (eval != 0) {
1c79356b
A
793#ifdef MSG_DEBUG_OK
794 printf("error %d copying the message type\n", eval);
795#endif
796 msg_freehdr(msghdr);
797 msqptr->msg_perm.mode &= ~MSG_LOCKED;
798 wakeup((caddr_t)msqptr);
91447636 799 goto msgsndout;
1c79356b 800 }
91447636 801
1c79356b
A
802
803 /*
804 * Validate the message type
805 */
1c79356b
A
806 if (msghdr->msg_type < 1) {
807 msg_freehdr(msghdr);
808 msqptr->msg_perm.mode &= ~MSG_LOCKED;
809 wakeup((caddr_t)msqptr);
810#ifdef MSG_DEBUG_OK
811 printf("mtype (%d) < 1\n", msghdr->msg_type);
812#endif
91447636
A
813 eval = EINVAL;
814 goto msgsndout;
1c79356b
A
815 }
816
817 /*
818 * Copy in the message body
819 */
1c79356b
A
820 next = msghdr->msg_spot;
821 while (msgsz > 0) {
822 size_t tlen;
91447636
A
823 /* compare input (size_t) value against restrict (int) value */
824 if (msgsz > (size_t)msginfo.msgssz)
1c79356b
A
825 tlen = msginfo.msgssz;
826 else
827 tlen = msgsz;
828 if (next <= -1)
829 panic("next too low #2");
830 if (next >= msginfo.msgseg)
831 panic("next out of range #2");
91447636
A
832
833 SYSV_MSG_SUBSYS_UNLOCK();
834 eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz], tlen);
835 SYSV_MSG_SUBSYS_LOCK();
836
837 if (eval != 0) {
1c79356b
A
838#ifdef MSG_DEBUG_OK
839 printf("error %d copying in message segment\n", eval);
840#endif
841 msg_freehdr(msghdr);
842 msqptr->msg_perm.mode &= ~MSG_LOCKED;
843 wakeup((caddr_t)msqptr);
91447636
A
844
845 goto msgsndout;
1c79356b
A
846 }
847 msgsz -= tlen;
91447636 848 user_msgp = user_msgp + tlen; /* ptr math */
1c79356b
A
849 next = msgmaps[next].next;
850 }
851 if (next != -1)
852 panic("didn't use all the msg segments");
853
854 /*
91447636 855 * We've got the message. Unlock the user_msqid_ds.
1c79356b
A
856 */
857
858 msqptr->msg_perm.mode &= ~MSG_LOCKED;
859
860 /*
91447636 861 * Make sure that the user_msqid_ds is still allocated.
1c79356b
A
862 */
863
864 if (msqptr->msg_qbytes == 0) {
865 msg_freehdr(msghdr);
866 wakeup((caddr_t)msqptr);
867 /* The SVID says to return EIDRM. */
868#ifdef EIDRM
91447636 869 eval = EIDRM;
1c79356b
A
870#else
871 /* Unfortunately, BSD doesn't define that code yet! */
91447636 872 eval = EINVAL;
1c79356b 873#endif
91447636 874 goto msgsndout;
1c79356b
A
875 }
876
877 /*
878 * Put the message into the queue
879 */
880
881 if (msqptr->msg_first == NULL) {
882 msqptr->msg_first = msghdr;
883 msqptr->msg_last = msghdr;
884 } else {
885 msqptr->msg_last->msg_next = msghdr;
886 msqptr->msg_last = msghdr;
887 }
888 msqptr->msg_last->msg_next = NULL;
889
890 msqptr->msg_cbytes += msghdr->msg_ts;
891 msqptr->msg_qnum++;
892 msqptr->msg_lspid = p->p_pid;
91447636 893 msqptr->msg_stime = sysv_msgtime();
1c79356b
A
894
895 wakeup((caddr_t)msqptr);
91447636
A
896 *retval = 0;
897 eval = 0;
898
899msgsndout:
900 SYSV_MSG_SUBSYS_UNLOCK();
901 return(eval);
1c79356b
A
902}
903
1c79356b
A
904
905int
91447636 906msgrcv(struct proc *p, struct msgrcv_args *uap, user_ssize_t *retval)
1c79356b
A
907{
908 int msqid = uap->msqid;
91447636
A
909 user_addr_t user_msgp = uap->msgp;
910 size_t msgsz = (size_t)uap->msgsz; /* limit to 4G */
911 long msgtyp = (long)uap->msgtyp; /* limit to 32 bits */
1c79356b
A
912 int msgflg = uap->msgflg;
913 size_t len;
91447636
A
914 struct user_msqid_ds *msqptr;
915 struct msg *msghdr;
1c79356b
A
916 int eval;
917 short next;
91447636
A
918 user_long_t msgtype;
919 long msg_type_long;
920
921 SYSV_MSG_SUBSYS_LOCK();
922 msginit( 0);
1c79356b
A
923
924#ifdef MSG_DEBUG_OK
91447636 925 printf("call to msgrcv(%d, 0x%qx, %d, %ld, %d)\n", msqid, user_msgp,
1c79356b
A
926 msgsz, msgtyp, msgflg);
927#endif
928
55e303ae 929 AUDIT_ARG(svipc_id, msqid);
1c79356b
A
930 msqid = IPCID_TO_IX(msqid);
931
932 if (msqid < 0 || msqid >= msginfo.msgmni) {
933#ifdef MSG_DEBUG_OK
934 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
935 msginfo.msgmni);
936#endif
91447636
A
937 eval = EINVAL;
938 goto msgrcvout;
1c79356b
A
939 }
940
941 msqptr = &msqids[msqid];
942 if (msqptr->msg_qbytes == 0) {
943#ifdef MSG_DEBUG_OK
944 printf("no such message queue id\n");
945#endif
91447636
A
946 eval = EINVAL;
947 goto msgrcvout;
1c79356b
A
948 }
949 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
950#ifdef MSG_DEBUG_OK
951 printf("wrong sequence number\n");
952#endif
91447636
A
953 eval = EINVAL;
954 goto msgrcvout;
1c79356b
A
955 }
956
91447636 957 if ((eval = ipcperm(kauth_cred_get(), &msqptr->msg_perm, IPC_R))) {
1c79356b
A
958#ifdef MSG_DEBUG_OK
959 printf("requester doesn't have read access\n");
960#endif
91447636 961 goto msgrcvout;
1c79356b
A
962 }
963
964 msghdr = NULL;
965 while (msghdr == NULL) {
966 if (msgtyp == 0) {
967 msghdr = msqptr->msg_first;
968 if (msghdr != NULL) {
969 if (msgsz < msghdr->msg_ts &&
970 (msgflg & MSG_NOERROR) == 0) {
971#ifdef MSG_DEBUG_OK
972 printf("first message on the queue is too big (want %d, got %d)\n",
973 msgsz, msghdr->msg_ts);
974#endif
91447636
A
975 eval = E2BIG;
976 goto msgrcvout;
1c79356b
A
977 }
978 if (msqptr->msg_first == msqptr->msg_last) {
979 msqptr->msg_first = NULL;
980 msqptr->msg_last = NULL;
981 } else {
982 msqptr->msg_first = msghdr->msg_next;
983 if (msqptr->msg_first == NULL)
984 panic("msg_first/last messed up #1");
985 }
986 }
987 } else {
988 struct msg *previous;
989 struct msg **prev;
990
991 previous = NULL;
992 prev = &(msqptr->msg_first);
993 while ((msghdr = *prev) != NULL) {
994 /*
995 * Is this message's type an exact match or is
996 * this message's type less than or equal to
997 * the absolute value of a negative msgtyp?
998 * Note that the second half of this test can
999 * NEVER be true if msgtyp is positive since
1000 * msg_type is always positive!
1001 */
1002
1003 if (msgtyp == msghdr->msg_type ||
1004 msghdr->msg_type <= -msgtyp) {
1005#ifdef MSG_DEBUG_OK
1006 printf("found message type %d, requested %d\n",
1007 msghdr->msg_type, msgtyp);
1008#endif
1009 if (msgsz < msghdr->msg_ts &&
1010 (msgflg & MSG_NOERROR) == 0) {
1011#ifdef MSG_DEBUG_OK
1012 printf("requested message on the queue is too big (want %d, got %d)\n",
1013 msgsz, msghdr->msg_ts);
1014#endif
91447636
A
1015 eval = E2BIG;
1016 goto msgrcvout;
1c79356b
A
1017 }
1018 *prev = msghdr->msg_next;
1019 if (msghdr == msqptr->msg_last) {
1020 if (previous == NULL) {
1021 if (prev !=
1022 &msqptr->msg_first)
1023 panic("msg_first/last messed up #2");
1024 msqptr->msg_first =
1025 NULL;
1026 msqptr->msg_last =
1027 NULL;
1028 } else {
1029 if (prev ==
1030 &msqptr->msg_first)
1031 panic("msg_first/last messed up #3");
1032 msqptr->msg_last =
1033 previous;
1034 }
1035 }
1036 break;
1037 }
1038 previous = msghdr;
1039 prev = &(msghdr->msg_next);
1040 }
1041 }
1042
1043 /*
1044 * We've either extracted the msghdr for the appropriate
1045 * message or there isn't one.
1046 * If there is one then bail out of this loop.
1047 */
1048
1049 if (msghdr != NULL)
1050 break;
1051
1052 /*
1053 * Hmph! No message found. Does the user want to wait?
1054 */
1055
1056 if ((msgflg & IPC_NOWAIT) != 0) {
1057#ifdef MSG_DEBUG_OK
1058 printf("no appropriate message found (msgtyp=%d)\n",
1059 msgtyp);
1060#endif
1061 /* The SVID says to return ENOMSG. */
1062#ifdef ENOMSG
91447636 1063 eval = ENOMSG;
1c79356b
A
1064#else
1065 /* Unfortunately, BSD doesn't define that code yet! */
91447636 1066 eval = EAGAIN;
1c79356b 1067#endif
91447636 1068 goto msgrcvout;
1c79356b
A
1069 }
1070
1071 /*
1072 * Wait for something to happen
1073 */
1074
1075#ifdef MSG_DEBUG_OK
1076 printf("msgrcv: goodnight\n");
1077#endif
91447636 1078 eval = msleep((caddr_t)msqptr, &sysv_msg_subsys_mutex, (PZERO - 4) | PCATCH, "msgwait",
1c79356b
A
1079 0);
1080#ifdef MSG_DEBUG_OK
1081 printf("msgrcv: good morning (eval=%d)\n", eval);
1082#endif
1083
1084 if (eval != 0) {
1085#ifdef MSG_DEBUG_OK
1086 printf("msgsnd: interrupted system call\n");
1087#endif
91447636
A
1088 eval = EINTR;
1089 goto msgrcvout;
1c79356b
A
1090 }
1091
1092 /*
1093 * Make sure that the msq queue still exists
1094 */
1095
1096 if (msqptr->msg_qbytes == 0 ||
1097 msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
1098#ifdef MSG_DEBUG_OK
1099 printf("msqid deleted\n");
1100#endif
1101 /* The SVID says to return EIDRM. */
1102#ifdef EIDRM
91447636 1103 eval = EIDRM;
1c79356b
A
1104#else
1105 /* Unfortunately, BSD doesn't define that code yet! */
91447636 1106 eval = EINVAL;
1c79356b 1107#endif
91447636 1108 goto msgrcvout;
1c79356b
A
1109 }
1110 }
1111
1112 /*
1113 * Return the message to the user.
1114 *
1115 * First, do the bookkeeping (before we risk being interrupted).
1116 */
1117
1118 msqptr->msg_cbytes -= msghdr->msg_ts;
1119 msqptr->msg_qnum--;
1120 msqptr->msg_lrpid = p->p_pid;
91447636 1121 msqptr->msg_rtime = sysv_msgtime();
1c79356b
A
1122
1123 /*
1124 * Make msgsz the actual amount that we'll be returning.
1125 * Note that this effectively truncates the message if it is too long
1126 * (since msgsz is never increased).
1127 */
1128
1129#ifdef MSG_DEBUG_OK
1130 printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
1131 msghdr->msg_ts);
1132#endif
1133 if (msgsz > msghdr->msg_ts)
1134 msgsz = msghdr->msg_ts;
1135
1136 /*
1137 * Return the type to the user.
1138 */
1139
91447636
A
1140 /*
1141 * Copy out the message type. For a 64 bit process, this is 64 bits,
1142 * but we only ever use the low 32 bits, so the cast is OK.
1143 */
1144 if (IS_64BIT_PROCESS(p)) {
1145 msgtype = msghdr->msg_type;
1146 SYSV_MSG_SUBSYS_UNLOCK();
1147 eval = copyout(&msgtype, user_msgp, sizeof(msgtype));
1148 SYSV_MSG_SUBSYS_LOCK();
1149 user_msgp = user_msgp + sizeof(msgtype); /* ptr math */
1150 } else {
1151 msg_type_long = msghdr->msg_type;
1152 SYSV_MSG_SUBSYS_UNLOCK();
1153 eval = copyout(&msg_type_long, user_msgp, sizeof(long));
1154 SYSV_MSG_SUBSYS_LOCK();
1155 user_msgp = user_msgp + sizeof(long); /* ptr math */
1156 }
1157
1c79356b
A
1158 if (eval != 0) {
1159#ifdef MSG_DEBUG_OK
1160 printf("error (%d) copying out message type\n", eval);
1161#endif
1162 msg_freehdr(msghdr);
1163 wakeup((caddr_t)msqptr);
91447636
A
1164
1165 goto msgrcvout;
1c79356b 1166 }
91447636 1167
1c79356b
A
1168
1169 /*
1170 * Return the segments to the user
1171 */
1172
1173 next = msghdr->msg_spot;
1174 for (len = 0; len < msgsz; len += msginfo.msgssz) {
1175 size_t tlen;
1176
91447636
A
1177 /* compare input (size_t) value against restrict (int) value */
1178 if (msgsz > (size_t)msginfo.msgssz)
1c79356b
A
1179 tlen = msginfo.msgssz;
1180 else
1181 tlen = msgsz;
1182 if (next <= -1)
1183 panic("next too low #3");
1184 if (next >= msginfo.msgseg)
1185 panic("next out of range #3");
91447636
A
1186 SYSV_MSG_SUBSYS_UNLOCK();
1187 eval = copyout(&msgpool[next * msginfo.msgssz],
1c79356b 1188 user_msgp, tlen);
91447636 1189 SYSV_MSG_SUBSYS_LOCK();
1c79356b
A
1190 if (eval != 0) {
1191#ifdef MSG_DEBUG_OK
1192 printf("error (%d) copying out message segment\n",
1193 eval);
1194#endif
1195 msg_freehdr(msghdr);
1196 wakeup((caddr_t)msqptr);
91447636 1197 goto msgrcvout;
1c79356b 1198 }
91447636 1199 user_msgp = user_msgp + tlen; /* ptr math */
1c79356b
A
1200 next = msgmaps[next].next;
1201 }
1202
1203 /*
1204 * Done, return the actual number of bytes copied out.
1205 */
1206
1207 msg_freehdr(msghdr);
1208 wakeup((caddr_t)msqptr);
91447636
A
1209 *retval = msgsz;
1210 eval = 0;
1211msgrcvout:
1212 SYSV_MSG_SUBSYS_UNLOCK();
1213 return(eval);
1214}
1215
1216static int
1217IPCS_msg_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
1218 __unused int arg2, struct sysctl_req *req)
1219{
1220 int error;
1221 int cursor;
1222 union {
1223 struct IPCS_command u32;
1224 struct user_IPCS_command u64;
1225 } ipcs;
1226 struct msqid_ds msqid_ds32; /* post conversion, 32 bit version */
1227 void *msqid_dsp;
1228 size_t ipcs_sz = sizeof(struct user_IPCS_command);
1229 size_t msqid_ds_sz = sizeof(struct user_msqid_ds);
1230 struct proc *p = current_proc();
1231
1232 if (!IS_64BIT_PROCESS(p)) {
1233 ipcs_sz = sizeof(struct IPCS_command);
1234 msqid_ds_sz = sizeof(struct msqid_ds);
1235 }
1236
1237 /* Copy in the command structure */
1238 if ((error = SYSCTL_IN(req, &ipcs, ipcs_sz)) != 0) {
1239 return(error);
1240 }
1241
1242 if (!IS_64BIT_PROCESS(p)) /* convert in place */
1243 ipcs.u64.ipcs_data = CAST_USER_ADDR_T(ipcs.u32.ipcs_data);
1244
1245 /* Let us version this interface... */
1246 if (ipcs.u64.ipcs_magic != IPCS_MAGIC) {
1247 return(EINVAL);
1248 }
1249
1250 SYSV_MSG_SUBSYS_LOCK();
1251
1252 switch(ipcs.u64.ipcs_op) {
1253 case IPCS_MSG_CONF: /* Obtain global configuration data */
1254 if (ipcs.u64.ipcs_datalen != sizeof(struct msginfo)) {
1255 error = ERANGE;
1256 break;
1257 }
1258 if (ipcs.u64.ipcs_cursor != 0) { /* fwd. compat. */
1259 error = EINVAL;
1260 break;
1261 }
1262 SYSV_MSG_SUBSYS_UNLOCK();
1263 error = copyout(&msginfo, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
1264 SYSV_MSG_SUBSYS_LOCK();
1265 break;
1266
1267 case IPCS_MSG_ITER: /* Iterate over existing segments */
1268 /* Not done up top so we can set limits via sysctl (later) */
1269 msginit( 0);
1270
1271 cursor = ipcs.u64.ipcs_cursor;
1272 if (cursor < 0 || cursor >= msginfo.msgmni) {
1273 error = ERANGE;
1274 break;
1275 }
1276 if (ipcs.u64.ipcs_datalen != (int)msqid_ds_sz) {
1277 error = ENOMEM;
1278 break;
1279 }
1280 for( ; cursor < msginfo.msgmni; cursor++) {
1281 if (msqids[cursor].msg_qbytes != 0) /* allocated */
1282 break;
1283 continue;
1284 }
1285 if (cursor == msginfo.msgmni) {
1286 error = ENOENT;
1287 break;
1288 }
1289
1290 msqid_dsp = &msqids[cursor]; /* default: 64 bit */
1291
1292 /*
1293 * If necessary, convert the 64 bit kernel segment
1294 * descriptor to a 32 bit user one.
1295 */
1296 if (!IS_64BIT_PROCESS(p)) {
1297 msqid_ds_64to32(msqid_dsp, &msqid_ds32);
1298 msqid_dsp = &msqid_ds32;
1299 }
1300 SYSV_MSG_SUBSYS_UNLOCK();
1301 error = copyout(msqid_dsp, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
1302 if (!error) {
1303 /* update cursor */
1304 ipcs.u64.ipcs_cursor = cursor + 1;
1305
1306 if (!IS_64BIT_PROCESS(p)) /* convert in place */
1307 ipcs.u32.ipcs_data = CAST_DOWN(void *,ipcs.u64.ipcs_data);
1308 error = SYSCTL_OUT(req, &ipcs, ipcs_sz);
1309 }
1310 SYSV_MSG_SUBSYS_LOCK();
1311 break;
1312
1313 default:
1314 error = EINVAL;
1315 break;
1316 }
1317
1318 SYSV_MSG_SUBSYS_UNLOCK();
1319 return(error);
1c79356b 1320}
91447636
A
1321
1322SYSCTL_DECL(_kern_sysv_ipcs);
1323SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, msg, CTLFLAG_RW|CTLFLAG_ANYBODY,
1324 0, 0, IPCS_msg_sysctl,
1325 "S,IPCS_msg_command",
1326 "ipcs msg command interface");