|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.
11: *
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
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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>
43: #include <sys/sysproto.h>
44: #include <sys/kernel.h>
45: #include <sys/proc.h>
46: #include <sys/msg.h>
47: #include <sys/sysent.h>
48:
49: static void msginit __P((void *));
50: SYSINIT(sysv_msg, SI_SUB_SYSV_MSG, SI_ORDER_FIRST, msginit, NULL)
51:
52: #define MSG_DEBUG
53: #undef MSG_DEBUG_OK
54:
55: #ifndef _SYS_SYSPROTO_H_
56: struct msgctl_args;
57: int msgctl __P((struct proc *p, struct msgctl_args *uap));
58: struct msgget_args;
59: int msgget __P((struct proc *p, struct msgget_args *uap));
60: struct msgsnd_args;
61: int msgsnd __P((struct proc *p, struct msgsnd_args *uap));
62: struct msgrcv_args;
63: int msgrcv __P((struct proc *p, struct msgrcv_args *uap));
64: #endif
65: static void msg_freehdr __P((struct msg *msghdr));
66:
67: /* XXX casting to (sy_call_t *) is bogus, as usual. */
68: static sy_call_t *msgcalls[] = {
69: (sy_call_t *)msgctl, (sy_call_t *)msgget,
70: (sy_call_t *)msgsnd, (sy_call_t *)msgrcv
71: };
72:
73: static int nfree_msgmaps; /* # of free map entries */
74: static short free_msgmaps; /* head of linked list of free map entries */
75: static struct msg *free_msghdrs; /* list of free msg headers */
76: char *msgpool; /* MSGMAX byte long msg buffer pool */
77: struct msgmap *msgmaps; /* MSGSEG msgmap structures */
78: struct msg *msghdrs; /* MSGTQL msg headers */
79: struct msqid_ds *msqids; /* MSGMNI msqid_ds struct's */
80:
81: void
82: msginit(dummy)
83: void *dummy;
84: {
85: register int i;
86:
87: /*
88: * msginfo.msgssz should be a power of two for efficiency reasons.
89: * It is also pretty silly if msginfo.msgssz is less than 8
90: * or greater than about 256 so ...
91: */
92:
93: i = 8;
94: while (i < 1024 && i != msginfo.msgssz)
95: i <<= 1;
96: if (i != msginfo.msgssz) {
97: printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
98: msginfo.msgssz);
99: panic("msginfo.msgssz not a small power of 2");
100: }
101:
102: if (msginfo.msgseg > 32767) {
103: printf("msginfo.msgseg=%d\n", msginfo.msgseg);
104: panic("msginfo.msgseg > 32767");
105: }
106:
107: if (msgmaps == NULL)
108: panic("msgmaps is NULL");
109:
110: for (i = 0; i < msginfo.msgseg; i++) {
111: if (i > 0)
112: msgmaps[i-1].next = i;
113: msgmaps[i].next = -1; /* implies entry is available */
114: }
115: free_msgmaps = 0;
116: nfree_msgmaps = msginfo.msgseg;
117:
118: if (msghdrs == NULL)
119: panic("msghdrs is NULL");
120:
121: for (i = 0; i < msginfo.msgtql; i++) {
122: msghdrs[i].msg_type = 0;
123: if (i > 0)
124: msghdrs[i-1].msg_next = &msghdrs[i];
125: msghdrs[i].msg_next = NULL;
126: }
127: free_msghdrs = &msghdrs[0];
128:
129: if (msqids == NULL)
130: panic("msqids is NULL");
131:
132: for (i = 0; i < msginfo.msgmni; i++) {
133: msqids[i].msg_qbytes = 0; /* implies entry is available */
134: msqids[i].msg_perm.seq = 0; /* reset to a known value */
135: }
136: }
137:
138: /*
139: * Entry point for all MSG calls
140: */
141: int
142: msgsys(p, uap)
143: struct proc *p;
144: /* XXX actually varargs. */
145: struct msgsys_args /* {
146: u_int which;
147: int a2;
148: int a3;
149: int a4;
150: int a5;
151: int a6;
152: } */ *uap;
153: {
154:
155: if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
156: return (EINVAL);
157: return ((*msgcalls[uap->which])(p, &uap->a2));
158: }
159:
160: static void
161: msg_freehdr(msghdr)
162: struct msg *msghdr;
163: {
164: while (msghdr->msg_ts > 0) {
165: short next;
166: if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
167: panic("msghdr->msg_spot out of range");
168: next = msgmaps[msghdr->msg_spot].next;
169: msgmaps[msghdr->msg_spot].next = free_msgmaps;
170: free_msgmaps = msghdr->msg_spot;
171: nfree_msgmaps++;
172: msghdr->msg_spot = next;
173: if (msghdr->msg_ts >= msginfo.msgssz)
174: msghdr->msg_ts -= msginfo.msgssz;
175: else
176: msghdr->msg_ts = 0;
177: }
178: if (msghdr->msg_spot != -1)
179: panic("msghdr->msg_spot != -1");
180: msghdr->msg_next = free_msghdrs;
181: free_msghdrs = msghdr;
182: }
183:
184: #ifndef _SYS_SYSPROTO_H_
185: struct msgctl_args {
186: int msqid;
187: int cmd;
188: struct msqid_ds *buf;
189: };
190: #endif
191:
192: int
193: msgctl(p, uap)
194: struct proc *p;
195: register struct msgctl_args *uap;
196: {
197: int msqid = uap->msqid;
198: int cmd = uap->cmd;
199: struct msqid_ds *user_msqptr = uap->buf;
200: struct ucred *cred = p->p_ucred;
201: int rval, eval;
202: struct msqid_ds msqbuf;
203: register struct msqid_ds *msqptr;
204:
205: #ifdef MSG_DEBUG_OK
206: printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr);
207: #endif
208:
209: msqid = IPCID_TO_IX(msqid);
210:
211: if (msqid < 0 || msqid >= msginfo.msgmni) {
212: #ifdef MSG_DEBUG_OK
213: printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
214: msginfo.msgmni);
215: #endif
216: return(EINVAL);
217: }
218:
219: msqptr = &msqids[msqid];
220:
221: if (msqptr->msg_qbytes == 0) {
222: #ifdef MSG_DEBUG_OK
223: printf("no such msqid\n");
224: #endif
225: return(EINVAL);
226: }
227: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
228: #ifdef MSG_DEBUG_OK
229: printf("wrong sequence number\n");
230: #endif
231: return(EINVAL);
232: }
233:
234: eval = 0;
235: rval = 0;
236:
237: switch (cmd) {
238:
239: case IPC_RMID:
240: {
241: struct msg *msghdr;
242: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
243: return(eval);
244: /* Free the message headers */
245: msghdr = msqptr->msg_first;
246: while (msghdr != NULL) {
247: struct msg *msghdr_tmp;
248:
249: /* Free the segments of each message */
250: msqptr->msg_cbytes -= msghdr->msg_ts;
251: msqptr->msg_qnum--;
252: msghdr_tmp = msghdr;
253: msghdr = msghdr->msg_next;
254: msg_freehdr(msghdr_tmp);
255: }
256:
257: if (msqptr->msg_cbytes != 0)
258: panic("msg_cbytes is messed up");
259: if (msqptr->msg_qnum != 0)
260: panic("msg_qnum is messed up");
261:
262: msqptr->msg_qbytes = 0; /* Mark it as free */
263:
264: wakeup((caddr_t)msqptr);
265: }
266:
267: break;
268:
269: case IPC_SET:
270: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
271: return(eval);
272: if ((eval = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
273: return(eval);
274: if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
275: eval = suser(cred, &p->p_acflag);
276: if (eval)
277: return(eval);
278: }
279: if (msqbuf.msg_qbytes > msginfo.msgmnb) {
280: #ifdef MSG_DEBUG_OK
281: printf("can't increase msg_qbytes beyond %d (truncating)\n",
282: msginfo.msgmnb);
283: #endif
284: msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */
285: }
286: if (msqbuf.msg_qbytes == 0) {
287: #ifdef MSG_DEBUG_OK
288: printf("can't reduce msg_qbytes to 0\n");
289: #endif
290: return(EINVAL); /* non-standard errno! */
291: }
292: msqptr->msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */
293: msqptr->msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */
294: msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
295: (msqbuf.msg_perm.mode & 0777);
296: msqptr->msg_qbytes = msqbuf.msg_qbytes;
297: msqptr->msg_ctime = time_second;
298: break;
299:
300: case IPC_STAT:
301: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
302: #ifdef MSG_DEBUG_OK
303: printf("requester doesn't have read access\n");
304: #endif
305: return(eval);
306: }
307: eval = copyout((caddr_t)msqptr, user_msqptr,
308: sizeof(struct msqid_ds));
309: break;
310:
311: default:
312: #ifdef MSG_DEBUG_OK
313: printf("invalid command %d\n", cmd);
314: #endif
315: return(EINVAL);
316: }
317:
318: if (eval == 0)
319: p->p_retval[0] = rval;
320: return(eval);
321: }
322:
323: #ifndef _SYS_SYSPROTO_H_
324: struct msgget_args {
325: key_t key;
326: int msgflg;
327: };
328: #endif
329:
330: int
331: msgget(p, uap)
332: struct proc *p;
333: register struct msgget_args *uap;
334: {
335: int msqid, eval;
336: int key = uap->key;
337: int msgflg = uap->msgflg;
338: struct ucred *cred = p->p_ucred;
339: register struct msqid_ds *msqptr = NULL;
340:
341: #ifdef MSG_DEBUG_OK
342: printf("msgget(0x%x, 0%o)\n", key, msgflg);
343: #endif
344:
345: if (key != IPC_PRIVATE) {
346: for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
347: msqptr = &msqids[msqid];
348: if (msqptr->msg_qbytes != 0 &&
349: msqptr->msg_perm.key == key)
350: break;
351: }
352: if (msqid < msginfo.msgmni) {
353: #ifdef MSG_DEBUG_OK
354: printf("found public key\n");
355: #endif
356: if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
357: #ifdef MSG_DEBUG_OK
358: printf("not exclusive\n");
359: #endif
360: return(EEXIST);
361: }
362: if ((eval = ipcperm(cred, &msqptr->msg_perm, msgflg & 0700 ))) {
363: #ifdef MSG_DEBUG_OK
364: printf("requester doesn't have 0%o access\n",
365: msgflg & 0700);
366: #endif
367: return(eval);
368: }
369: goto found;
370: }
371: }
372:
373: #ifdef MSG_DEBUG_OK
374: printf("need to allocate the msqid_ds\n");
375: #endif
376: if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
377: for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
378: /*
379: * Look for an unallocated and unlocked msqid_ds.
380: * msqid_ds's can be locked by msgsnd or msgrcv while
381: * they are copying the message in/out. We can't
382: * re-use the entry until they release it.
383: */
384: msqptr = &msqids[msqid];
385: if (msqptr->msg_qbytes == 0 &&
386: (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
387: break;
388: }
389: if (msqid == msginfo.msgmni) {
390: #ifdef MSG_DEBUG_OK
391: printf("no more msqid_ds's available\n");
392: #endif
393: return(ENOSPC);
394: }
395: #ifdef MSG_DEBUG_OK
396: printf("msqid %d is available\n", msqid);
397: #endif
398: msqptr->msg_perm.key = key;
399: msqptr->msg_perm.cuid = cred->cr_uid;
400: msqptr->msg_perm.uid = cred->cr_uid;
401: msqptr->msg_perm.cgid = cred->cr_gid;
402: msqptr->msg_perm.gid = cred->cr_gid;
403: msqptr->msg_perm.mode = (msgflg & 0777);
404: /* Make sure that the returned msqid is unique */
405: msqptr->msg_perm.seq++;
406: msqptr->msg_first = NULL;
407: msqptr->msg_last = NULL;
408: msqptr->msg_cbytes = 0;
409: msqptr->msg_qnum = 0;
410: msqptr->msg_qbytes = msginfo.msgmnb;
411: msqptr->msg_lspid = 0;
412: msqptr->msg_lrpid = 0;
413: msqptr->msg_stime = 0;
414: msqptr->msg_rtime = 0;
415: msqptr->msg_ctime = time_second;
416: } else {
417: #ifdef MSG_DEBUG_OK
418: printf("didn't find it and wasn't asked to create it\n");
419: #endif
420: return(ENOENT);
421: }
422:
423: found:
424: /* Construct the unique msqid */
425: p->p_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
426: return(0);
427: }
428:
429: #ifndef _SYS_SYSPROTO_H_
430: struct msgsnd_args {
431: int msqid;
432: void *msgp;
433: size_t msgsz;
434: int msgflg;
435: };
436: #endif
437:
438: int
439: msgsnd(p, uap)
440: struct proc *p;
441: register struct msgsnd_args *uap;
442: {
443: int msqid = uap->msqid;
444: void *user_msgp = uap->msgp;
445: size_t msgsz = uap->msgsz;
446: int msgflg = uap->msgflg;
447: int segs_needed, eval;
448: struct ucred *cred = p->p_ucred;
449: register struct msqid_ds *msqptr;
450: register struct msg *msghdr;
451: short next;
452:
453: #ifdef MSG_DEBUG_OK
454: printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
455: msgflg);
456: #endif
457:
458: msqid = IPCID_TO_IX(msqid);
459:
460: if (msqid < 0 || msqid >= msginfo.msgmni) {
461: #ifdef MSG_DEBUG_OK
462: printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
463: msginfo.msgmni);
464: #endif
465: return(EINVAL);
466: }
467:
468: msqptr = &msqids[msqid];
469: if (msqptr->msg_qbytes == 0) {
470: #ifdef MSG_DEBUG_OK
471: printf("no such message queue id\n");
472: #endif
473: return(EINVAL);
474: }
475: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
476: #ifdef MSG_DEBUG_OK
477: printf("wrong sequence number\n");
478: #endif
479: return(EINVAL);
480: }
481:
482: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
483: #ifdef MSG_DEBUG_OK
484: printf("requester doesn't have write access\n");
485: #endif
486: return(eval);
487: }
488:
489: segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
490: #ifdef MSG_DEBUG_OK
491: printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
492: segs_needed);
493: #endif
494: for (;;) {
495: int need_more_resources = 0;
496:
497: /*
498: * check msgsz
499: * (inside this loop in case msg_qbytes changes while we sleep)
500: */
501:
502: if (msgsz > msqptr->msg_qbytes) {
503: #ifdef MSG_DEBUG_OK
504: printf("msgsz > msqptr->msg_qbytes\n");
505: #endif
506: return(EINVAL);
507: }
508:
509: if (msqptr->msg_perm.mode & MSG_LOCKED) {
510: #ifdef MSG_DEBUG_OK
511: printf("msqid is locked\n");
512: #endif
513: need_more_resources = 1;
514: }
515: if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
516: #ifdef MSG_DEBUG_OK
517: printf("msgsz + msg_cbytes > msg_qbytes\n");
518: #endif
519: need_more_resources = 1;
520: }
521: if (segs_needed > nfree_msgmaps) {
522: #ifdef MSG_DEBUG_OK
523: printf("segs_needed > nfree_msgmaps\n");
524: #endif
525: need_more_resources = 1;
526: }
527: if (free_msghdrs == NULL) {
528: #ifdef MSG_DEBUG_OK
529: printf("no more msghdrs\n");
530: #endif
531: need_more_resources = 1;
532: }
533:
534: if (need_more_resources) {
535: int we_own_it;
536:
537: if ((msgflg & IPC_NOWAIT) != 0) {
538: #ifdef MSG_DEBUG_OK
539: printf("need more resources but caller doesn't want to wait\n");
540: #endif
541: return(EAGAIN);
542: }
543:
544: if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
545: #ifdef MSG_DEBUG_OK
546: printf("we don't own the msqid_ds\n");
547: #endif
548: we_own_it = 0;
549: } else {
550: /* Force later arrivals to wait for our
551: request */
552: #ifdef MSG_DEBUG_OK
553: printf("we own the msqid_ds\n");
554: #endif
555: msqptr->msg_perm.mode |= MSG_LOCKED;
556: we_own_it = 1;
557: }
558: #ifdef MSG_DEBUG_OK
559: printf("goodnight\n");
560: #endif
561: eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH,
562: "msgwait", 0);
563: #ifdef MSG_DEBUG_OK
564: printf("good morning, eval=%d\n", eval);
565: #endif
566: if (we_own_it)
567: msqptr->msg_perm.mode &= ~MSG_LOCKED;
568: if (eval != 0) {
569: #ifdef MSG_DEBUG_OK
570: printf("msgsnd: interrupted system call\n");
571: #endif
572: return(EINTR);
573: }
574:
575: /*
576: * Make sure that the msq queue still exists
577: */
578:
579: if (msqptr->msg_qbytes == 0) {
580: #ifdef MSG_DEBUG_OK
581: printf("msqid deleted\n");
582: #endif
583: /* The SVID says to return EIDRM. */
584: #ifdef EIDRM
585: return(EIDRM);
586: #else
587: /* Unfortunately, BSD doesn't define that code
588: yet! */
589: return(EINVAL);
590: #endif
591: }
592:
593: } else {
594: #ifdef MSG_DEBUG_OK
595: printf("got all the resources that we need\n");
596: #endif
597: break;
598: }
599: }
600:
601: /*
602: * We have the resources that we need.
603: * Make sure!
604: */
605:
606: if (msqptr->msg_perm.mode & MSG_LOCKED)
607: panic("msg_perm.mode & MSG_LOCKED");
608: if (segs_needed > nfree_msgmaps)
609: panic("segs_needed > nfree_msgmaps");
610: if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
611: panic("msgsz + msg_cbytes > msg_qbytes");
612: if (free_msghdrs == NULL)
613: panic("no more msghdrs");
614:
615: /*
616: * Re-lock the msqid_ds in case we page-fault when copying in the
617: * message
618: */
619:
620: if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
621: panic("msqid_ds is already locked");
622: msqptr->msg_perm.mode |= MSG_LOCKED;
623:
624: /*
625: * Allocate a message header
626: */
627:
628: msghdr = free_msghdrs;
629: free_msghdrs = msghdr->msg_next;
630: msghdr->msg_spot = -1;
631: msghdr->msg_ts = msgsz;
632:
633: /*
634: * Allocate space for the message
635: */
636:
637: while (segs_needed > 0) {
638: if (nfree_msgmaps <= 0)
639: panic("not enough msgmaps");
640: if (free_msgmaps == -1)
641: panic("nil free_msgmaps");
642: next = free_msgmaps;
643: if (next <= -1)
644: panic("next too low #1");
645: if (next >= msginfo.msgseg)
646: panic("next out of range #1");
647: #ifdef MSG_DEBUG_OK
648: printf("allocating segment %d to message\n", next);
649: #endif
650: free_msgmaps = msgmaps[next].next;
651: nfree_msgmaps--;
652: msgmaps[next].next = msghdr->msg_spot;
653: msghdr->msg_spot = next;
654: segs_needed--;
655: }
656:
657: /*
658: * Copy in the message type
659: */
660:
661: if ((eval = copyin(user_msgp, &msghdr->msg_type,
662: sizeof(msghdr->msg_type))) != 0) {
663: #ifdef MSG_DEBUG_OK
664: printf("error %d copying the message type\n", eval);
665: #endif
666: msg_freehdr(msghdr);
667: msqptr->msg_perm.mode &= ~MSG_LOCKED;
668: wakeup((caddr_t)msqptr);
669: return(eval);
670: }
671: user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
672:
673: /*
674: * Validate the message type
675: */
676:
677: if (msghdr->msg_type < 1) {
678: msg_freehdr(msghdr);
679: msqptr->msg_perm.mode &= ~MSG_LOCKED;
680: wakeup((caddr_t)msqptr);
681: #ifdef MSG_DEBUG_OK
682: printf("mtype (%d) < 1\n", msghdr->msg_type);
683: #endif
684: return(EINVAL);
685: }
686:
687: /*
688: * Copy in the message body
689: */
690:
691: next = msghdr->msg_spot;
692: while (msgsz > 0) {
693: size_t tlen;
694: if (msgsz > msginfo.msgssz)
695: tlen = msginfo.msgssz;
696: else
697: tlen = msgsz;
698: if (next <= -1)
699: panic("next too low #2");
700: if (next >= msginfo.msgseg)
701: panic("next out of range #2");
702: if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
703: tlen)) != 0) {
704: #ifdef MSG_DEBUG_OK
705: printf("error %d copying in message segment\n", eval);
706: #endif
707: msg_freehdr(msghdr);
708: msqptr->msg_perm.mode &= ~MSG_LOCKED;
709: wakeup((caddr_t)msqptr);
710: return(eval);
711: }
712: msgsz -= tlen;
713: user_msgp = (char *)user_msgp + tlen;
714: next = msgmaps[next].next;
715: }
716: if (next != -1)
717: panic("didn't use all the msg segments");
718:
719: /*
720: * We've got the message. Unlock the msqid_ds.
721: */
722:
723: msqptr->msg_perm.mode &= ~MSG_LOCKED;
724:
725: /*
726: * Make sure that the msqid_ds is still allocated.
727: */
728:
729: if (msqptr->msg_qbytes == 0) {
730: msg_freehdr(msghdr);
731: wakeup((caddr_t)msqptr);
732: /* The SVID says to return EIDRM. */
733: #ifdef EIDRM
734: return(EIDRM);
735: #else
736: /* Unfortunately, BSD doesn't define that code yet! */
737: return(EINVAL);
738: #endif
739: }
740:
741: /*
742: * Put the message into the queue
743: */
744:
745: if (msqptr->msg_first == NULL) {
746: msqptr->msg_first = msghdr;
747: msqptr->msg_last = msghdr;
748: } else {
749: msqptr->msg_last->msg_next = msghdr;
750: msqptr->msg_last = msghdr;
751: }
752: msqptr->msg_last->msg_next = NULL;
753:
754: msqptr->msg_cbytes += msghdr->msg_ts;
755: msqptr->msg_qnum++;
756: msqptr->msg_lspid = p->p_pid;
757: msqptr->msg_stime = time_second;
758:
759: wakeup((caddr_t)msqptr);
760: p->p_retval[0] = 0;
761: return(0);
762: }
763:
764: #ifndef _SYS_SYSPROTO_H_
765: struct msgrcv_args {
766: int msqid;
767: void *msgp;
768: size_t msgsz;
769: long msgtyp;
770: int msgflg;
771: };
772: #endif
773:
774: int
775: msgrcv(p, uap)
776: struct proc *p;
777: register struct msgrcv_args *uap;
778: {
779: int msqid = uap->msqid;
780: void *user_msgp = uap->msgp;
781: size_t msgsz = uap->msgsz;
782: long msgtyp = uap->msgtyp;
783: int msgflg = uap->msgflg;
784: size_t len;
785: struct ucred *cred = p->p_ucred;
786: register struct msqid_ds *msqptr;
787: register struct msg *msghdr;
788: int eval;
789: short next;
790:
791: #ifdef MSG_DEBUG_OK
792: printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
793: msgsz, msgtyp, msgflg);
794: #endif
795:
796: msqid = IPCID_TO_IX(msqid);
797:
798: if (msqid < 0 || msqid >= msginfo.msgmni) {
799: #ifdef MSG_DEBUG_OK
800: printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
801: msginfo.msgmni);
802: #endif
803: return(EINVAL);
804: }
805:
806: msqptr = &msqids[msqid];
807: if (msqptr->msg_qbytes == 0) {
808: #ifdef MSG_DEBUG_OK
809: printf("no such message queue id\n");
810: #endif
811: return(EINVAL);
812: }
813: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
814: #ifdef MSG_DEBUG_OK
815: printf("wrong sequence number\n");
816: #endif
817: return(EINVAL);
818: }
819:
820: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
821: #ifdef MSG_DEBUG_OK
822: printf("requester doesn't have read access\n");
823: #endif
824: return(eval);
825: }
826:
827: msghdr = NULL;
828: while (msghdr == NULL) {
829: if (msgtyp == 0) {
830: msghdr = msqptr->msg_first;
831: if (msghdr != NULL) {
832: if (msgsz < msghdr->msg_ts &&
833: (msgflg & MSG_NOERROR) == 0) {
834: #ifdef MSG_DEBUG_OK
835: printf("first message on the queue is too big (want %d, got %d)\n",
836: msgsz, msghdr->msg_ts);
837: #endif
838: return(E2BIG);
839: }
840: if (msqptr->msg_first == msqptr->msg_last) {
841: msqptr->msg_first = NULL;
842: msqptr->msg_last = NULL;
843: } else {
844: msqptr->msg_first = msghdr->msg_next;
845: if (msqptr->msg_first == NULL)
846: panic("msg_first/last messed up #1");
847: }
848: }
849: } else {
850: struct msg *previous;
851: struct msg **prev;
852:
853: previous = NULL;
854: prev = &(msqptr->msg_first);
855: while ((msghdr = *prev) != NULL) {
856: /*
857: * Is this message's type an exact match or is
858: * this message's type less than or equal to
859: * the absolute value of a negative msgtyp?
860: * Note that the second half of this test can
861: * NEVER be true if msgtyp is positive since
862: * msg_type is always positive!
863: */
864:
865: if (msgtyp == msghdr->msg_type ||
866: msghdr->msg_type <= -msgtyp) {
867: #ifdef MSG_DEBUG_OK
868: printf("found message type %d, requested %d\n",
869: msghdr->msg_type, msgtyp);
870: #endif
871: if (msgsz < msghdr->msg_ts &&
872: (msgflg & MSG_NOERROR) == 0) {
873: #ifdef MSG_DEBUG_OK
874: printf("requested message on the queue is too big (want %d, got %d)\n",
875: msgsz, msghdr->msg_ts);
876: #endif
877: return(E2BIG);
878: }
879: *prev = msghdr->msg_next;
880: if (msghdr == msqptr->msg_last) {
881: if (previous == NULL) {
882: if (prev !=
883: &msqptr->msg_first)
884: panic("msg_first/last messed up #2");
885: msqptr->msg_first =
886: NULL;
887: msqptr->msg_last =
888: NULL;
889: } else {
890: if (prev ==
891: &msqptr->msg_first)
892: panic("msg_first/last messed up #3");
893: msqptr->msg_last =
894: previous;
895: }
896: }
897: break;
898: }
899: previous = msghdr;
900: prev = &(msghdr->msg_next);
901: }
902: }
903:
904: /*
905: * We've either extracted the msghdr for the appropriate
906: * message or there isn't one.
907: * If there is one then bail out of this loop.
908: */
909:
910: if (msghdr != NULL)
911: break;
912:
913: /*
914: * Hmph! No message found. Does the user want to wait?
915: */
916:
917: if ((msgflg & IPC_NOWAIT) != 0) {
918: #ifdef MSG_DEBUG_OK
919: printf("no appropriate message found (msgtyp=%d)\n",
920: msgtyp);
921: #endif
922: /* The SVID says to return ENOMSG. */
923: #ifdef ENOMSG
924: return(ENOMSG);
925: #else
926: /* Unfortunately, BSD doesn't define that code yet! */
927: return(EAGAIN);
928: #endif
929: }
930:
931: /*
932: * Wait for something to happen
933: */
934:
935: #ifdef MSG_DEBUG_OK
936: printf("msgrcv: goodnight\n");
937: #endif
938: eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, "msgwait",
939: 0);
940: #ifdef MSG_DEBUG_OK
941: printf("msgrcv: good morning (eval=%d)\n", eval);
942: #endif
943:
944: if (eval != 0) {
945: #ifdef MSG_DEBUG_OK
946: printf("msgsnd: interrupted system call\n");
947: #endif
948: return(EINTR);
949: }
950:
951: /*
952: * Make sure that the msq queue still exists
953: */
954:
955: if (msqptr->msg_qbytes == 0 ||
956: msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
957: #ifdef MSG_DEBUG_OK
958: printf("msqid deleted\n");
959: #endif
960: /* The SVID says to return EIDRM. */
961: #ifdef EIDRM
962: return(EIDRM);
963: #else
964: /* Unfortunately, BSD doesn't define that code yet! */
965: return(EINVAL);
966: #endif
967: }
968: }
969:
970: /*
971: * Return the message to the user.
972: *
973: * First, do the bookkeeping (before we risk being interrupted).
974: */
975:
976: msqptr->msg_cbytes -= msghdr->msg_ts;
977: msqptr->msg_qnum--;
978: msqptr->msg_lrpid = p->p_pid;
979: msqptr->msg_rtime = time_second;
980:
981: /*
982: * Make msgsz the actual amount that we'll be returning.
983: * Note that this effectively truncates the message if it is too long
984: * (since msgsz is never increased).
985: */
986:
987: #ifdef MSG_DEBUG_OK
988: printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
989: msghdr->msg_ts);
990: #endif
991: if (msgsz > msghdr->msg_ts)
992: msgsz = msghdr->msg_ts;
993:
994: /*
995: * Return the type to the user.
996: */
997:
998: eval = copyout((caddr_t)&(msghdr->msg_type), user_msgp,
999: sizeof(msghdr->msg_type));
1000: if (eval != 0) {
1001: #ifdef MSG_DEBUG_OK
1002: printf("error (%d) copying out message type\n", eval);
1003: #endif
1004: msg_freehdr(msghdr);
1005: wakeup((caddr_t)msqptr);
1006: return(eval);
1007: }
1008: user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
1009:
1010: /*
1011: * Return the segments to the user
1012: */
1013:
1014: next = msghdr->msg_spot;
1015: for (len = 0; len < msgsz; len += msginfo.msgssz) {
1016: size_t tlen;
1017:
1018: if (msgsz > msginfo.msgssz)
1019: tlen = msginfo.msgssz;
1020: else
1021: tlen = msgsz;
1022: if (next <= -1)
1023: panic("next too low #3");
1024: if (next >= msginfo.msgseg)
1025: panic("next out of range #3");
1026: eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz],
1027: user_msgp, tlen);
1028: if (eval != 0) {
1029: #ifdef MSG_DEBUG_OK
1030: printf("error (%d) copying out message segment\n",
1031: eval);
1032: #endif
1033: msg_freehdr(msghdr);
1034: wakeup((caddr_t)msqptr);
1035: return(eval);
1036: }
1037: user_msgp = (char *)user_msgp + tlen;
1038: next = msgmaps[next].next;
1039: }
1040:
1041: /*
1042: * Done, return the actual number of bytes copied out.
1043: */
1044:
1045: msg_freehdr(msghdr);
1046: wakeup((caddr_t)msqptr);
1047: p->p_retval[0] = msgsz;
1048: return(0);
1049: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.