Annotation of sys/kern/sysv_msg.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sysv_msg.c,v 1.19 2005/12/13 10:33:14 jsg Exp $ */
2: /* $NetBSD: sysv_msg.c,v 1.19 1996/02/09 19:00:18 christos Exp $ */
3:
4: /*
5: * Implementation of SVID messages
6: *
7: * Author: Daniel Boulet
8: *
9: * Copyright 1993 Daniel Boulet and RTMX Inc.
10: *
11: * This system call was implemented by Daniel Boulet under contract from RTMX.
12: *
13: * Redistribution and use in source forms, with and without modification,
14: * are permitted provided that this entire comment appears intact.
15: *
16: * Redistribution in binary form may occur without any restrictions.
17: * Obviously, it would be nice if you gave credit where credit is due
18: * but requiring it would be too onerous.
19: *
20: * This software is provided ``AS IS'' without any warranties of any kind.
21: */
22:
23: #include <sys/param.h>
24: #include <sys/systm.h>
25: #include <sys/kernel.h>
26: #include <sys/proc.h>
27: #include <sys/msg.h>
28: #include <sys/malloc.h>
29:
30: #include <sys/mount.h>
31: #include <sys/syscallargs.h>
32:
33: #ifdef MSG_DEBUG
34: #define DPRINTF(x) printf x
35: #else
36: #define DPRINTF(x)
37: #endif
38:
39: /* XXX - OpenBSD doesn't have EIDRM or ENOMSG */
40: #ifndef EIDRM
41: #define EIDRM EINVAL
42: #endif
43: #ifndef ENOMSG
44: #define ENOMSG EAGAIN
45: #endif
46:
47: int nfree_msgmaps; /* # of free map entries */
48: short free_msgmaps; /* head of linked list of free map entries */
49: struct msg *free_msghdrs; /* list of free msg headers */
50: char *msgpool; /* MSGMAX byte long msg buffer pool */
51: struct msgmap *msgmaps; /* MSGSEG msgmap structures */
52: struct msg *msghdrs; /* MSGTQL msg headers */
53: struct msqid_ds *msqids; /* MSGMNI msqid_ds struct's */
54:
55: void msg_freehdr(struct msg *);
56:
57: void
58: msginit(void)
59: {
60: int i;
61:
62: /*
63: * msginfo.msgssz should be a power of two for efficiency reasons.
64: * It is also pretty silly if msginfo.msgssz is less than 8
65: * or greater than about 256 so ...
66: */
67:
68: i = 8;
69: while (i < 1024 && i != msginfo.msgssz)
70: i <<= 1;
71:
72: if (i != msginfo.msgssz)
73: panic("msginfo.msgssz %d not a small power of 2", msginfo.msgssz);
74: if (msginfo.msgseg > 32767)
75: panic("msginfo.msgseg %d > 32767", msginfo.msgseg);
76:
77: if (msgmaps == NULL)
78: panic("msgmaps is NULL");
79:
80: for (i = 0; i < msginfo.msgseg; i++) {
81: if (i > 0)
82: msgmaps[i-1].next = i;
83: msgmaps[i].next = -1; /* implies entry is available */
84: }
85: free_msgmaps = 0;
86: nfree_msgmaps = msginfo.msgseg;
87:
88: if (msghdrs == NULL)
89: panic("msghdrs is NULL");
90:
91: for (i = 0; i < msginfo.msgtql; i++) {
92: msghdrs[i].msg_type = 0;
93: if (i > 0)
94: msghdrs[i-1].msg_next = &msghdrs[i];
95: msghdrs[i].msg_next = NULL;
96: }
97: free_msghdrs = &msghdrs[0];
98:
99: if (msqids == NULL)
100: panic("msqids is NULL");
101:
102: for (i = 0; i < msginfo.msgmni; i++) {
103: msqids[i].msg_qbytes = 0; /* implies entry is available */
104: msqids[i].msg_perm.seq = 0; /* reset to a known value */
105: }
106: }
107:
108: void
109: msg_freehdr(struct msg *msghdr)
110: {
111: while (msghdr->msg_ts > 0) {
112: short next;
113:
114: #ifdef DIAGNOSTIC
115: if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
116: panic("msghdr->msg_spot out of range");
117: #endif
118: next = msgmaps[msghdr->msg_spot].next;
119: msgmaps[msghdr->msg_spot].next = free_msgmaps;
120: free_msgmaps = msghdr->msg_spot;
121: nfree_msgmaps++;
122: msghdr->msg_spot = next;
123: if (msghdr->msg_ts >= msginfo.msgssz)
124: msghdr->msg_ts -= msginfo.msgssz;
125: else
126: msghdr->msg_ts = 0;
127: }
128: #ifdef DIAGNOSTIC
129: if (msghdr->msg_spot != -1)
130: panic("msghdr->msg_spot != -1");
131: #endif
132: msghdr->msg_next = free_msghdrs;
133: free_msghdrs = msghdr;
134: }
135:
136: int
137: sys_msgctl(struct proc *p, void *v, register_t *retval)
138: {
139: struct sys_msgctl_args /* {
140: syscallarg(int) msqid;
141: syscallarg(int) cmd;
142: syscallarg(struct msqid_ds *) buf;
143: } */ *uap = v;
144:
145: return (msgctl1(p, SCARG(uap, msqid), SCARG(uap, cmd),
146: (caddr_t)SCARG(uap, buf), copyin, copyout));
147: }
148:
149: int
150: msgctl1(struct proc *p, int msqid, int cmd, caddr_t buf,
151: int (*ds_copyin)(const void *, void *, size_t),
152: int (*ds_copyout)(const void *, void *, size_t))
153: {
154: struct ucred *cred = p->p_ucred;
155: struct msqid_ds msqbuf, *msqptr;
156: struct msg *msghdr;
157: int ix, error = 0;
158:
159: DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, buf));
160:
161: ix = IPCID_TO_IX(msqid);
162:
163: if (ix < 0 || ix >= msginfo.msgmni) {
164: DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", ix,
165: msginfo.msgmni));
166: return (EINVAL);
167: }
168:
169: msqptr = &msqids[ix];
170:
171: if (msqptr->msg_qbytes == 0) {
172: DPRINTF(("no such msqid\n"));
173: return (EINVAL);
174: }
175: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(msqid)) {
176: DPRINTF(("wrong sequence number\n"));
177: return (EINVAL);
178: }
179:
180: switch (cmd) {
181: case IPC_RMID:
182: if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)) != 0)
183: return (error);
184: /* Free the message headers */
185: msghdr = msqptr->msg_first;
186: while (msghdr != NULL) {
187: struct msg *msghdr_tmp;
188:
189: /* Free the segments of each message */
190: msqptr->msg_cbytes -= msghdr->msg_ts;
191: msqptr->msg_qnum--;
192: msghdr_tmp = msghdr;
193: msghdr = msghdr->msg_next;
194: msg_freehdr(msghdr_tmp);
195: }
196:
197: #ifdef DIAGNOSTIC
198: if (msqptr->msg_cbytes != 0)
199: panic("sys_msgctl: msg_cbytes is screwed up");
200: if (msqptr->msg_qnum != 0)
201: panic("sys_msgctl: msg_qnum is screwed up");
202: #endif
203: msqptr->msg_qbytes = 0; /* Mark it as free */
204: wakeup(msqptr);
205: break;
206:
207: case IPC_SET:
208: if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
209: return (error);
210: if ((error = ds_copyin(buf, &msqbuf, sizeof(msqbuf))) != 0)
211: return (error);
212: if (msqbuf.msg_qbytes > msqptr->msg_qbytes &&
213: cred->cr_uid != 0)
214: return (EPERM);
215: if (msqbuf.msg_qbytes > msginfo.msgmnb) {
216: DPRINTF(("can't increase msg_qbytes beyond %d "
217: "(truncating)\n", msginfo.msgmnb));
218: /* silently restrict qbytes to system limit */
219: msqbuf.msg_qbytes = msginfo.msgmnb;
220: }
221: if (msqbuf.msg_qbytes == 0) {
222: DPRINTF(("can't reduce msg_qbytes to 0\n"));
223: return (EINVAL); /* non-standard errno! */
224: }
225: msqptr->msg_perm.uid = msqbuf.msg_perm.uid;
226: msqptr->msg_perm.gid = msqbuf.msg_perm.gid;
227: msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
228: (msqbuf.msg_perm.mode & 0777);
229: msqptr->msg_qbytes = msqbuf.msg_qbytes;
230: msqptr->msg_ctime = time_second;
231: break;
232:
233: case IPC_STAT:
234: if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
235: DPRINTF(("requester doesn't have read access\n"));
236: return (error);
237: }
238: error = ds_copyout(msqptr, buf, sizeof(struct msqid_ds));
239: break;
240:
241: default:
242: DPRINTF(("invalid command %d\n", cmd));
243: return (EINVAL);
244: }
245: return (error);
246: }
247:
248: int
249: sys_msgget(struct proc *p, void *v, register_t *retval)
250: {
251: struct sys_msgget_args /* {
252: syscallarg(key_t) key;
253: syscallarg(int) msgflg;
254: } */ *uap = v;
255: int msqid, eval;
256: int key = SCARG(uap, key);
257: int msgflg = SCARG(uap, msgflg);
258: struct ucred *cred = p->p_ucred;
259: struct msqid_ds *msqptr = NULL;
260:
261: DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
262:
263: if (key != IPC_PRIVATE) {
264: for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
265: msqptr = &msqids[msqid];
266: if (msqptr->msg_qbytes != 0 &&
267: msqptr->msg_perm.key == key)
268: break;
269: }
270: if (msqid < msginfo.msgmni) {
271: DPRINTF(("found public key\n"));
272: if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
273: DPRINTF(("not exclusive\n"));
274: return (EEXIST);
275: }
276: if ((eval = ipcperm(cred, &msqptr->msg_perm, msgflg & 0700 ))) {
277: DPRINTF(("requester doesn't have 0%o access\n",
278: msgflg & 0700));
279: return (eval);
280: }
281: goto found;
282: }
283: }
284:
285: DPRINTF(("need to allocate the msqid_ds\n"));
286: if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
287: for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
288: /*
289: * Look for an unallocated and unlocked msqid_ds.
290: * msqid_ds's can be locked by msgsnd or msgrcv while
291: * they are copying the message in/out. We can't
292: * re-use the entry until they release it.
293: */
294: msqptr = &msqids[msqid];
295: if (msqptr->msg_qbytes == 0 &&
296: (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
297: break;
298: }
299: if (msqid == msginfo.msgmni) {
300: DPRINTF(("no more msqid_ds's available\n"));
301: return (ENOSPC);
302: }
303: DPRINTF(("msqid %d is available\n", msqid));
304: msqptr->msg_perm.key = key;
305: msqptr->msg_perm.cuid = cred->cr_uid;
306: msqptr->msg_perm.uid = cred->cr_uid;
307: msqptr->msg_perm.cgid = cred->cr_gid;
308: msqptr->msg_perm.gid = cred->cr_gid;
309: msqptr->msg_perm.mode = (msgflg & 0777);
310: /* Make sure that the returned msqid is unique */
311: msqptr->msg_perm.seq = (msqptr->msg_perm.seq + 1) & 0x7fff;
312: msqptr->msg_first = NULL;
313: msqptr->msg_last = NULL;
314: msqptr->msg_cbytes = 0;
315: msqptr->msg_qnum = 0;
316: msqptr->msg_qbytes = msginfo.msgmnb;
317: msqptr->msg_lspid = 0;
318: msqptr->msg_lrpid = 0;
319: msqptr->msg_stime = 0;
320: msqptr->msg_rtime = 0;
321: msqptr->msg_ctime = time_second;
322: } else {
323: DPRINTF(("didn't find it and wasn't asked to create it\n"));
324: return (ENOENT);
325: }
326:
327: found:
328: /* Construct the unique msqid */
329: *retval = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
330: return (0);
331: }
332:
333: int
334: sys_msgsnd(struct proc *p, void *v, register_t *retval)
335: {
336: struct sys_msgsnd_args /* {
337: syscallarg(int) msqid;
338: syscallarg(const void *) msgp;
339: syscallarg(size_t) msgsz;
340: syscallarg(int) msgflg;
341: } */ *uap = v;
342: int msqid = SCARG(uap, msqid);
343: const char *user_msgp = SCARG(uap, msgp);
344: size_t msgsz = SCARG(uap, msgsz);
345: int msgflg = SCARG(uap, msgflg);
346: int segs_needed, eval;
347: struct ucred *cred = p->p_ucred;
348: struct msqid_ds *msqptr;
349: struct msg *msghdr;
350: short next;
351:
352: DPRINTF(("call to msgsnd(%d, %p, %d, %d)\n", msqid, user_msgp, msgsz,
353: msgflg));
354:
355: msqid = IPCID_TO_IX(msqid);
356:
357: if (msqid < 0 || msqid >= msginfo.msgmni) {
358: DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
359: msginfo.msgmni));
360: return (EINVAL);
361: }
362:
363: msqptr = &msqids[msqid];
364: if (msqptr->msg_qbytes == 0) {
365: DPRINTF(("no such message queue id\n"));
366: return (EINVAL);
367: }
368: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(SCARG(uap, msqid))) {
369: DPRINTF(("wrong sequence number\n"));
370: return (EINVAL);
371: }
372:
373: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
374: DPRINTF(("requester doesn't have write access\n"));
375: return (eval);
376: }
377:
378: segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
379: DPRINTF(("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz,
380: msginfo.msgssz, segs_needed));
381: for (;;) {
382: int need_more_resources = 0;
383:
384: /*
385: * check msgsz [cannot be negative since it is unsigned]
386: * (inside this loop in case msg_qbytes changes while we sleep)
387: */
388:
389: if (msgsz > msqptr->msg_qbytes) {
390: DPRINTF(("msgsz > msqptr->msg_qbytes\n"));
391: return (EINVAL);
392: }
393:
394: if (msqptr->msg_perm.mode & MSG_LOCKED) {
395: DPRINTF(("msqid is locked\n"));
396: need_more_resources = 1;
397: }
398: if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
399: DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
400: need_more_resources = 1;
401: }
402: if (segs_needed > nfree_msgmaps) {
403: DPRINTF(("segs_needed > nfree_msgmaps\n"));
404: need_more_resources = 1;
405: }
406: if (free_msghdrs == NULL) {
407: DPRINTF(("no more msghdrs\n"));
408: need_more_resources = 1;
409: }
410:
411: if (need_more_resources) {
412: int we_own_it;
413:
414: if ((msgflg & IPC_NOWAIT) != 0) {
415: DPRINTF(("need more resources but caller "
416: "doesn't want to wait\n"));
417: return (EAGAIN);
418: }
419:
420: if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
421: DPRINTF(("we don't own the msqid_ds\n"));
422: we_own_it = 0;
423: } else {
424: /* Force later arrivals to wait for our
425: request */
426: DPRINTF(("we own the msqid_ds\n"));
427: msqptr->msg_perm.mode |= MSG_LOCKED;
428: we_own_it = 1;
429: }
430: DPRINTF(("goodnight\n"));
431: eval = tsleep(msqptr, (PZERO - 4) | PCATCH,
432: "msgwait", 0);
433: DPRINTF(("good morning, eval=%d\n", eval));
434: if (we_own_it)
435: msqptr->msg_perm.mode &= ~MSG_LOCKED;
436: if (eval != 0) {
437: DPRINTF(("msgsnd: interrupted system call\n"));
438: return (EINTR);
439: }
440:
441: /*
442: * Make sure that the msq queue still exists
443: */
444:
445: if (msqptr->msg_qbytes == 0) {
446: DPRINTF(("msqid deleted\n"));
447: return (EIDRM);
448: }
449:
450: } else {
451: DPRINTF(("got all the resources that we need\n"));
452: break;
453: }
454: }
455:
456: /*
457: * We have the resources that we need.
458: * Make sure!
459: */
460:
461: #ifdef DIAGNOSTIC
462: if (msqptr->msg_perm.mode & MSG_LOCKED)
463: panic("msg_perm.mode & MSG_LOCKED");
464: if (segs_needed > nfree_msgmaps)
465: panic("segs_needed > nfree_msgmaps");
466: if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
467: panic("msgsz + msg_cbytes > msg_qbytes");
468: if (free_msghdrs == NULL)
469: panic("no more msghdrs");
470: #endif
471:
472: /*
473: * Re-lock the msqid_ds in case we page-fault when copying in the
474: * message
475: */
476:
477: #ifdef DIAGNOSTIC
478: if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
479: panic("msqid_ds is already locked");
480: #endif
481: msqptr->msg_perm.mode |= MSG_LOCKED;
482:
483: /*
484: * Allocate a message header
485: */
486:
487: msghdr = free_msghdrs;
488: free_msghdrs = msghdr->msg_next;
489: msghdr->msg_spot = -1;
490: msghdr->msg_ts = msgsz;
491:
492: /*
493: * Allocate space for the message
494: */
495:
496: while (segs_needed > 0) {
497: #ifdef DIAGNOSTIC
498: if (nfree_msgmaps <= 0)
499: panic("not enough msgmaps");
500: if (free_msgmaps == -1)
501: panic("nil free_msgmaps");
502: #endif
503: next = free_msgmaps;
504: #ifdef DIAGNOSTIC
505: if (next <= -1)
506: panic("next too low #1");
507: if (next >= msginfo.msgseg)
508: panic("next out of range #1");
509: #endif
510: DPRINTF(("allocating segment %d to message\n", next));
511: free_msgmaps = msgmaps[next].next;
512: nfree_msgmaps--;
513: msgmaps[next].next = msghdr->msg_spot;
514: msghdr->msg_spot = next;
515: segs_needed--;
516: }
517:
518: /*
519: * Copy in the message type
520: */
521:
522: if ((eval = copyin(user_msgp, &msghdr->msg_type,
523: sizeof(msghdr->msg_type))) != 0) {
524: DPRINTF(("error %d copying the message type\n", eval));
525: msg_freehdr(msghdr);
526: msqptr->msg_perm.mode &= ~MSG_LOCKED;
527: wakeup(msqptr);
528: return (eval);
529: }
530: user_msgp += sizeof(msghdr->msg_type);
531:
532: /*
533: * Validate the message type
534: */
535:
536: if (msghdr->msg_type < 1) {
537: msg_freehdr(msghdr);
538: msqptr->msg_perm.mode &= ~MSG_LOCKED;
539: wakeup(msqptr);
540: DPRINTF(("mtype (%d) < 1\n", msghdr->msg_type));
541: return (EINVAL);
542: }
543:
544: /*
545: * Copy in the message body
546: */
547:
548: next = msghdr->msg_spot;
549: while (msgsz > 0) {
550: size_t tlen;
551: if (msgsz > msginfo.msgssz)
552: tlen = msginfo.msgssz;
553: else
554: tlen = msgsz;
555: #ifdef DIAGNOSTIC
556: if (next <= -1)
557: panic("next too low #2");
558: if (next >= msginfo.msgseg)
559: panic("next out of range #2");
560: #endif
561: if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
562: tlen)) != 0) {
563: DPRINTF(("error %d copying in message segment\n",
564: eval));
565: msg_freehdr(msghdr);
566: msqptr->msg_perm.mode &= ~MSG_LOCKED;
567: wakeup(msqptr);
568: return (eval);
569: }
570: msgsz -= tlen;
571: user_msgp += tlen;
572: next = msgmaps[next].next;
573: }
574: #ifdef DIAGNOSTIC
575: if (next != -1)
576: panic("didn't use all the msg segments");
577: #endif
578: /*
579: * We've got the message. Unlock the msqid_ds.
580: */
581:
582: msqptr->msg_perm.mode &= ~MSG_LOCKED;
583:
584: /*
585: * Make sure that the msqid_ds is still allocated.
586: */
587:
588: if (msqptr->msg_qbytes == 0) {
589: msg_freehdr(msghdr);
590: wakeup(msqptr);
591: return (EIDRM);
592: }
593:
594: /*
595: * Put the message into the queue
596: */
597:
598: if (msqptr->msg_first == NULL) {
599: msqptr->msg_first = msghdr;
600: msqptr->msg_last = msghdr;
601: } else {
602: msqptr->msg_last->msg_next = msghdr;
603: msqptr->msg_last = msghdr;
604: }
605: msqptr->msg_last->msg_next = NULL;
606:
607: msqptr->msg_cbytes += msghdr->msg_ts;
608: msqptr->msg_qnum++;
609: msqptr->msg_lspid = p->p_pid;
610: msqptr->msg_stime = time_second;
611:
612: wakeup(msqptr);
613: *retval = 0;
614: return (0);
615: }
616:
617: int
618: sys_msgrcv(struct proc *p, void *v, register_t *retval)
619: {
620: struct sys_msgrcv_args /* {
621: syscallarg(int) msqid;
622: syscallarg(void *) msgp;
623: syscallarg(size_t) msgsz;
624: syscallarg(long) msgtyp;
625: syscallarg(int) msgflg;
626: } */ *uap = v;
627: int msqid = SCARG(uap, msqid);
628: char *user_msgp = SCARG(uap, msgp);
629: size_t msgsz = SCARG(uap, msgsz);
630: long msgtyp = SCARG(uap, msgtyp);
631: int msgflg = SCARG(uap, msgflg);
632: size_t len;
633: struct ucred *cred = p->p_ucred;
634: struct msqid_ds *msqptr;
635: struct msg *msghdr;
636: int eval;
637: short next;
638:
639: DPRINTF(("call to msgrcv(%d, %p, %d, %ld, %d)\n", msqid, user_msgp,
640: msgsz, msgtyp, msgflg));
641:
642: msqid = IPCID_TO_IX(msqid);
643:
644: if (msqid < 0 || msqid >= msginfo.msgmni) {
645: DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
646: msginfo.msgmni));
647: return (EINVAL);
648: }
649:
650: msqptr = &msqids[msqid];
651: if (msqptr->msg_qbytes == 0) {
652: DPRINTF(("no such message queue id\n"));
653: return (EINVAL);
654: }
655: if (msqptr->msg_perm.seq != IPCID_TO_SEQ(SCARG(uap, msqid))) {
656: DPRINTF(("wrong sequence number\n"));
657: return (EINVAL);
658: }
659:
660: if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
661: DPRINTF(("requester doesn't have read access\n"));
662: return (eval);
663: }
664:
665: #if 0
666: /* cannot happen, msgsz is unsigned */
667: if (msgsz < 0) {
668: DPRINTF(("msgsz < 0\n"));
669: return (EINVAL);
670: }
671: #endif
672:
673: msghdr = NULL;
674: while (msghdr == NULL) {
675: if (msgtyp == 0) {
676: msghdr = msqptr->msg_first;
677: if (msghdr != NULL) {
678: if (msgsz < msghdr->msg_ts &&
679: (msgflg & MSG_NOERROR) == 0) {
680: DPRINTF(("first message on the queue "
681: "is too big (want %d, got %d)\n",
682: msgsz, msghdr->msg_ts));
683: return (E2BIG);
684: }
685: if (msqptr->msg_first == msqptr->msg_last) {
686: msqptr->msg_first = NULL;
687: msqptr->msg_last = NULL;
688: } else {
689: msqptr->msg_first = msghdr->msg_next;
690: #ifdef DIAGNOSTIC
691: if (msqptr->msg_first == NULL)
692: panic("msg_first/last screwed up #1");
693: #endif
694: }
695: }
696: } else {
697: struct msg *previous;
698: struct msg **prev;
699:
700: for (previous = NULL, prev = &msqptr->msg_first;
701: (msghdr = *prev) != NULL;
702: previous = msghdr, prev = &msghdr->msg_next) {
703: /*
704: * Is this message's type an exact match or is
705: * this message's type less than or equal to
706: * the absolute value of a negative msgtyp?
707: * Note that the second half of this test can
708: * NEVER be true if msgtyp is positive since
709: * msg_type is always positive!
710: */
711:
712: if (msgtyp == msghdr->msg_type ||
713: msghdr->msg_type <= -msgtyp) {
714: DPRINTF(("found message type %d, "
715: "requested %d\n", msghdr->msg_type,
716: msgtyp));
717: if (msgsz < msghdr->msg_ts &&
718: (msgflg & MSG_NOERROR) == 0) {
719: DPRINTF(("requested message on "
720: "the queue is too big "
721: "(want %d, got %d)\n",
722: msgsz, msghdr->msg_ts));
723: return (E2BIG);
724: }
725: *prev = msghdr->msg_next;
726: if (msghdr == msqptr->msg_last) {
727: if (previous == NULL) {
728: #ifdef DIAGNOSTIC
729: if (prev !=
730: &msqptr->msg_first)
731: panic("msg_first/last screwed up #2");
732: #endif
733: msqptr->msg_first =
734: NULL;
735: msqptr->msg_last =
736: NULL;
737: } else {
738: #ifdef DIAGNOSTIC
739: if (prev ==
740: &msqptr->msg_first)
741: panic("msg_first/last screwed up #3");
742: #endif
743: msqptr->msg_last =
744: previous;
745: }
746: }
747: break;
748: }
749: }
750: }
751:
752: /*
753: * We've either extracted the msghdr for the appropriate
754: * message or there isn't one.
755: * If there is one then bail out of this loop.
756: */
757:
758: if (msghdr != NULL)
759: break;
760:
761: /*
762: * Hmph! No message found. Does the user want to wait?
763: */
764:
765: if ((msgflg & IPC_NOWAIT) != 0) {
766: DPRINTF(("no appropriate message found (msgtyp=%d)\n",
767: msgtyp));
768: return (ENOMSG);
769: }
770:
771: /*
772: * Wait for something to happen
773: */
774:
775: DPRINTF(("msgrcv: goodnight\n"));
776: eval = tsleep(msqptr, (PZERO - 4) | PCATCH, "msgwait",
777: 0);
778: DPRINTF(("msgrcv: good morning (eval=%d)\n", eval));
779:
780: if (eval != 0) {
781: DPRINTF(("msgsnd: interrupted system call\n"));
782: return (EINTR);
783: }
784:
785: /*
786: * Make sure that the msq queue still exists
787: */
788:
789: if (msqptr->msg_qbytes == 0 ||
790: msqptr->msg_perm.seq != IPCID_TO_SEQ(SCARG(uap, msqid))) {
791: DPRINTF(("msqid deleted\n"));
792: return (EIDRM);
793: }
794: }
795:
796: /*
797: * Return the message to the user.
798: *
799: * First, do the bookkeeping (before we risk being interrupted).
800: */
801:
802: msqptr->msg_cbytes -= msghdr->msg_ts;
803: msqptr->msg_qnum--;
804: msqptr->msg_lrpid = p->p_pid;
805: msqptr->msg_rtime = time_second;
806:
807: /*
808: * Make msgsz the actual amount that we'll be returning.
809: * Note that this effectively truncates the message if it is too long
810: * (since msgsz is never increased).
811: */
812:
813: DPRINTF(("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
814: msghdr->msg_ts));
815: if (msgsz > msghdr->msg_ts)
816: msgsz = msghdr->msg_ts;
817:
818: /*
819: * Return the type to the user.
820: */
821:
822: eval = copyout(&msghdr->msg_type, user_msgp,
823: sizeof(msghdr->msg_type));
824: if (eval != 0) {
825: DPRINTF(("error (%d) copying out message type\n", eval));
826: msg_freehdr(msghdr);
827: wakeup(msqptr);
828: return (eval);
829: }
830: user_msgp += sizeof(msghdr->msg_type);
831:
832: /*
833: * Return the segments to the user
834: */
835:
836: next = msghdr->msg_spot;
837: for (len = 0; len < msgsz; len += msginfo.msgssz) {
838: size_t tlen;
839:
840: if (msgsz - len > msginfo.msgssz)
841: tlen = msginfo.msgssz;
842: else
843: tlen = msgsz - len;
844: #ifdef DIAGNOSTIC
845: if (next <= -1)
846: panic("next too low #3");
847: if (next >= msginfo.msgseg)
848: panic("next out of range #3");
849: #endif
850: eval = copyout(&msgpool[next * msginfo.msgssz],
851: user_msgp, tlen);
852: if (eval != 0) {
853: DPRINTF(("error (%d) copying out message segment\n",
854: eval));
855: msg_freehdr(msghdr);
856: wakeup(msqptr);
857: return (eval);
858: }
859: user_msgp += tlen;
860: next = msgmaps[next].next;
861: }
862:
863: /*
864: * Done, return the actual number of bytes copied out.
865: */
866:
867: msg_freehdr(msghdr);
868: wakeup(msqptr);
869: *retval = msgsz;
870: return (0);
871: }
CVSweb