|
|
1.1 root 1: /*
2: * System V Compatible Messaging
3: *
4: * This module provides System V compatible messaging operations.
5: */
6: #include <sys/coherent.h>
7: #include <sys/sched.h>
8: #include <sys/types.h>
9: #include <sys/uproc.h>
10: #include <errno.h>
11: #include <sys/stat.h>
12: #include <sys/con.h>
13: #include <sys/seg.h>
14: #include <sys/msg.h>
15:
16: /*
17: * Global Message Parameters. We want them to be patchable.
18: */
19: unsigned NMSQID = 50; /* maximum number of message queues */
20: unsigned NMSQB = 4096; /* default maximum queue size in bytes */
21: unsigned NMSG = 40; /* maximum number of messages per queue */
22: unsigned NMSC = 2048; /* message text size */
23:
24: #ifdef TRACER
25: int dballoc = 0; /* For debug only */
26: int dbfree = 0;
27: #endif
28:
29: /* Message Information */
30: struct msqid_ds *msqs = NULL; /* Array of message queues */
31: GATE *msg_gate; /* Message gates */
32: char **msg_map; /* Memory map */
33:
34: /*
35: * Msgctl - Message Control Operations.
36: */
37: umsgctl(qid, cmd, buf)
38: int qid;
39: int cmd;
40: struct msqid_ds *buf;
41: {
42: register struct msqid_ds *qp; /* message queues */
43: register struct msg *mp; /* single message queue */
44: unsigned short n; /* temporary variable */
45:
46: /* Validate qid */
47: if (qid < 0) {
48: u.u_error = EINVAL;
49: return -1;
50: }
51: qp = &msqs[qid % NMSQID];
52:
53: /* Validate queue existence.*/
54: if (qp->msg_perm.seq != qid || (qp->msg_perm.mode & IPC_ALLOC) == 0) {
55: u.u_error = EINVAL;
56: return -1;
57: }
58:
59: switch (cmd) {
60: case IPC_STAT:
61: /* Validate access authority. */
62: if ((ipcaccess(&qp->msg_perm) & MSG_R) == 0) {
63: u.u_error = EACCES;
64: break;
65: }
66:
67: /* Copy queue info to user buffer */
68: kucopy(qp, buf, sizeof(struct msqid_ds));
69: break;
70: case IPC_SET:
71: /* Validate modify authority. */
72: if ((u.u_uid != 0) && (u.u_uid != qp->msg_perm.uid)) {
73: u.u_error = EPERM;
74: break;
75: }
76:
77: /*
78: * Get desired queue size.
79: */
80: n = getusd(&(buf->msg_qbytes));
81: if (u.u_error)
82: break;
83:
84: /*
85: * Only super-user can increase queue size.
86: */
87: if ((u.u_uid != 0) && (n > qp->msg_qbytes)) {
88: u.u_error = EPERM;
89: break;
90: }
91:
92: /*
93: * Set queue parameters.
94: */
95: qp->msg_perm.uid = getusd(&(buf->msg_perm.uid));
96: qp->msg_perm.gid = getusd(&(buf->msg_perm.gid));
97: qp->msg_perm.mode &= ~0777;
98: qp->msg_perm.mode |= getusd(&(buf->msg_perm.mode)) & 0777;
99: /* We may want to change the max size of a single message too.
100: * It is not obvious how to do it. There is no
101: * description in SVID. So it is possible that at some point
102: * the size of the single message happens to be greater than
103: * the size of message queue ;-(
104: */
105: qp->msg_qbytes = NMSQB = n;
106: break;
107:
108: case IPC_RMID:
109: /* Validate removal authority. */
110: if ((u.u_uid != 0) && (u.u_uid != qp->msg_perm.uid)) {
111: u.u_error = EPERM;
112: break;
113: }
114: /* Free all messages on the queue being removed. */
115: while (mp = qp->msg_first) {
116: qp->msg_first = mp->msg_next;
117: T_MSGQ(0x01, dballoc -= sizeof(struct msg));
118: msgfree(mp);
119: }
120: T_MSGQ(0x01, printf("F%d", dballoc));
121:
122: /* Reset queue parameters. */
123: qp->msg_last = NULL;
124: qp->msg_qnum = 0;
125: qp->msg_cbytes = 0;
126: qp->msg_perm.mode = 0;
127: /* Set last change time */
128: qp->msg_ctime = timer.t_time;
129: /* We have to pick up a new unique sequence number.
130: * There is a "wrap around bug". But, it is BCS.
131: */
132: qp->msg_perm.seq += (unsigned short) 50;
133: break;
134: default:
135: u.u_error = EINVAL;
136: }
137:
138: if (u.u_error)
139: return -1;
140:
141: return 0;
142: }
143:
144: /*
145: * Msgget - Get set of messages
146: */
147: umsgget(mykey, msgflg)
148: key_t mykey;
149: int msgflg;
150: {
151: register struct msqid_ds *qp;
152: register struct msqid_ds *freeidp = NULL;
153: int rwmode;
154:
155: /* Init message queues on the first msgget */
156: if (msqs == NULL)
157: if (msginit()) {
158: u.u_error = ENOSPC;
159: return -1;
160: }
161: /* Extract desired access mode from flags. */
162: rwmode = msgflg & 0777; /* 0666 ??? */
163: T_MSGQ(0x02, printf("U%o", rwmode));
164: /* Search for desired message queue [also for first free queue]. */
165: for (qp = msqs; qp < msqs + NMSQID; qp++) {
166: /* Look for an older free queue */
167: if (!(qp->msg_perm.mode & IPC_ALLOC)) {
168: if (freeidp == NULL
169: || freeidp->msg_ctime > qp->msg_ctime)
170: freeidp = qp;
171: continue;
172: }
173: if (mykey == IPC_PRIVATE) { /* creat a new queue */
174: if (msgflg & IPC_EXCL) /* unique new queue */
175: if (mykey == qp->msg_perm.key) {
176: u.u_error = EEXIST;/* We cannot creat */
177: return -1; /* exclusive queue */
178: }
179: continue;
180: }
181: if (qp->msg_perm.key != mykey)
182: continue;
183: if (mykey == qp->msg_perm.key) { /* found! */
184: if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
185: u.u_error = EEXIST; /* We cannot creat */
186: return -1; /* exclusive queue */
187: }
188: /* PERMISSIONS */
189: /* For super-user or if mode is 0 */
190: if (u.u_uid == 0 || !rwmode)
191: return qp->msg_perm.seq;
192: /* For owner or creator */
193: T_MSGQ(0x02, printf("Q%o", qp->msg_perm.mode));
194: if (u.u_uid == qp->msg_perm.uid
195: || u.u_uid == qp->msg_perm.cuid)
196: if (
197: ((rwmode & 0600)<=(qp->msg_perm.mode & 0600))
198: &&((rwmode & 060)<=(qp->msg_perm.mode & 060))
199: &&((rwmode & 06)<=(qp->msg_perm.mode & 06)))
200: return qp->msg_perm.seq;
201: else {
202: u.u_error = EACCES;
203: return -1;
204: }
205: /* For group */
206: if (u.u_gid == qp->msg_perm.gid
207: || u.u_gid == qp->msg_perm.cgid)
208: if (((rwmode & 0660)<=(qp->msg_perm.mode & 060))
209: &&((rwmode & 06)<=(qp->msg_perm.mode & 06)))
210: return qp->msg_perm.seq;
211: else {
212: u.u_error = EACCES;
213: return -1;
214: }
215: /* For the rest of the world */
216: if ((rwmode & 0666) <= (qp->msg_perm.mode & 06))
217: return qp->msg_perm.seq;
218: else {
219: u.u_error = EACCES;
220: return -1;
221: }
222: }
223: }
224:
225: /* Creat a new queue */
226: if (!(msgflg & IPC_CREAT)) {
227: u.u_error = ENOENT;
228: return -1;
229: }
230: if ((qp = freeidp) == NULL) {
231: u.u_error = ENOSPC;
232: return -1;
233: }
234: /* Set new queue */
235: qp->msg_ctime = timer.t_time;
236: qp->msg_perm.cuid = qp->msg_perm.uid = u.u_uid;
237: qp->msg_perm.cgid = qp->msg_perm.gid = u.u_gid;
238: qp->msg_perm.mode = rwmode | IPC_ALLOC;
239: qp->msg_qnum = qp->msg_lspid = qp->msg_lrpid = qp->msg_stime
240: = qp->msg_rtime = 0;
241: qp->msg_perm.key = mykey;
242:
243: return qp->msg_perm.seq;
244: }
245:
246: /*
247: * Allocate space for the message queues and gates.
248: * Initialize message queue headers
249: * Return -1 on error.
250: */
251: msginit()
252: {
253: struct msqid_ds *qp;
254:
255: T_MSGQ(0x01, printf("A%d",dballoc += sizeof(struct msqid_ds) * NMSQID));
256:
257: /* Allocate space for message headers */
258: if ((msqs =
259: (struct msqid_ds *) kalloc(sizeof(struct msqid_ds) * NMSQID)) == NULL)
260: return -1;
261:
262: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(GATE) * NMSQID));
263:
264: /* Allocate space for message gates */
265: if ((msg_gate = (GATE *) kalloc(sizeof(GATE) * NMSQID)) == NULL) {
266: kfree(msqs);
267: msqs = NULL;
268: return -1;
269: }
270:
271: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(char *) * NMSQID * NMSG));
272:
273: /* Allocate space for the message map */
274: if ((msg_map = kalloc(sizeof(char *) * NMSQID * NMSG)) == NULL) {
275: kfree(msqs);
276: msqs = NULL;
277: kfree(msg_gate);
278: return -1;
279: }
280: /* Clear gate and map areas */
281: kclear(msg_gate, sizeof(GATE) * NMSQID);
282: kclear(msg_map, sizeof(char *) * NMSQID * NMSG);
283: /* Set initial queue values */
284: for (qp = msqs; qp < msqs + NMSQID; qp++) {
285: qp->msg_first = NULL; /* First and last pointers to */
286: qp->msg_last = NULL; /* message queue */
287: qp->msg_cbytes = 0; /* Number of bytes in queue */
288: qp->msg_qnum = 0; /* Number of messages in queue */
289: qp->msg_qbytes = NMSQB; /* Max size of a queue */
290: qp->msg_lspid = 0; /* Pid of last msgsnd */
291: qp->msg_lrpid = 0; /* Pid of last msgrcv */
292: qp->msg_stime = 0; /* Last msgsnd time */
293: qp->msg_rtime = 0; /* Last msgrcv time */
294: qp->msg_ctime = timer.t_time; /* Last change time */
295: qp->msg_perm.seq = qp - msqs;
296: qp->msg_perm.mode = 0;
297: }
298: return 0;
299: }
300:
301: /*
302: * Remove the message. Clear message text and header. Reset values in
303: * message map.
304: */
305: msgfree(mp)
306: struct msg *mp; /* Message header to be remove */
307: {
308:
309: kfree(msg_map[mp->msg_spot]);
310: msg_map[mp->msg_spot] = NULL;
311: kfree(mp);
312: T_MSGQ(0x01, printf("F%d", dballoc-=(mp->msg_ts + sizeof(struct msg))));
313: }
314:
315: /*
316: * Send a Message
317: */
318: umsgsnd(qid, bufp, msgsz, msgflg)
319: int qid; /* queue id */
320: struct msgbuf *bufp; /* message buffer */
321: int msgsz, /* message size */
322: msgflg; /* flags */
323: {
324: register struct msqid_ds *qp; /* message queue */
325: register struct msg *mp, /* message struct */
326: *tmp;
327: int q_num; /* number of a queue */
328: int i_spot; /* # of empty entry in map */
329:
330: /* Validate queue identifier. */
331: for (qp = msqs; qp < msqs + NMSQID; qp++)
332: if (qp->msg_perm.seq == qid) /* found */
333: break;
334:
335: q_num = qp - msqs;
336: /* qid is not a valid qid identifier */
337: if (q_num >= NMSQID) {
338: u.u_error = EINVAL;
339: return -1;
340: }
341:
342: if (!(ipcaccess(&qp->msg_perm) & MSG_W)) { /* can't send mesg */
343: u.u_error = EACCES;
344: return -1;
345: }
346:
347: /* Check if message has a valid message type and size.
348: * The comparisson with NMSQB was done because user could
349: * reduce this value.
350: */
351: if (bufp->mtype < 1 || msgsz < 0 || msgsz > NMSC || msgsz > NMSQB) {
352: u.u_error = EACCES;
353: return -1;
354: }
355:
356: /* Now we have a valid message. Check if we can send it. */
357: lock(msg_gate[q_num]); /* Lock it to avoid race condition */
358: while (qp->msg_qnum >= NMSG ||
359: qp->msg_qbytes < (qp->msg_cbytes + msgsz)) {
360: if (msgflg & IPC_NOWAIT) {
361: u.u_error = EAGAIN;
362: unlock(msg_gate[q_num]);
363: return -1;
364: }
365: /* We have to wait here */
366: qp->msg_perm.mode |= MSG_WWAIT;
367: unlock(msg_gate[q_num]);
368: x_sleep(qp, pritty, slpriSigCatch, "umsgsnd");
369:
370: /* Abort if a signal was received */
371: if (SELF->p_ssig && nondsig()) {
372: u.u_error = EINTR;
373: return -1;
374: }
375:
376: /* Abort if the message queue was removed. */
377: if (qid != qp->msg_perm.seq) {
378: u.u_error = EINVAL;
379: return -1;
380: }
381: lock(msg_gate[q_num]);
382: }
383:
384: /* Find empty entry in message map */
385: for (i_spot = 0; i_spot < NMSQID * NMSG; i_spot++)
386: if (msg_map[i_spot] == NULL)
387: break;
388: /* It cannot happen when we do not have empty entry in map,
389: * but let check it.
390: */
391: if (i_spot >= NMSQID * NMSG) {
392: u.u_error = ENOSPC;
393: return -1;
394: }
395:
396: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(struct msg)));
397:
398: /* Get space for the message header */
399: if ((mp = kalloc(sizeof(struct msg))) == NULL) {
400: unlock(msg_gate[q_num]);
401: u.u_error = ENOSPC;
402: return -1;
403: }
404:
405: T_MSGQ(0x01, printf("A%d", dballoc += msgsz));
406:
407: /* Alloc space for the message text */
408: if ((msg_map[i_spot] = kalloc(msgsz)) == NULL) {
409: kfree(mp);
410: unlock(msg_gate[q_num]);
411: u.u_error = ENOSPC;
412: return -1;
413: }
414:
415: mp->msg_next = NULL;
416: mp->msg_ts = msgsz;
417: /* The map address is a number of msg_map array element */
418: mp->msg_spot = i_spot;
419:
420: /* Transfer the message type and text.*/
421: if (ukcopy(&(bufp->mtype), &(mp->msg_type), sizeof(mp->msg_type)) !=
422: sizeof(mp->msg_type))
423: u.u_error = EFAULT;
424: if (ukcopy(&bufp->mtext[0], msg_map[i_spot], msgsz) != msgsz)
425: u.u_error = EFAULT;
426: if (u.u_error) {
427: msgfree(mp);
428: unlock(msg_gate[q_num]);
429: return -1;
430: }
431:
432: /* Move the message to the desired queue. */
433: if (qp->msg_first == NULL) /* This is the first message per queue */
434: qp->msg_first = qp->msg_last = mp;
435: else { /* There are messages */
436: /* Find last message in gueue */
437: for (tmp = qp->msg_first; ; tmp = tmp->msg_next)
438: if (tmp->msg_next == NULL)
439: break;
440: qp->msg_last = tmp->msg_next = mp;
441: }
442: mp->msg_next = NULL;
443:
444: /* Update queue statistics. */
445: qp->msg_cbytes += msgsz;
446: qp->msg_qnum++;
447: qp->msg_lspid = SELF->p_pid;
448: qp->msg_stime = timer.t_time;
449:
450: /* Unlock queue and wake processes waiting to receive. */
451: unlock(msg_gate[q_num]);
452: if (qp->msg_perm.mode & MSG_RWAIT) {
453: qp->msg_perm.mode &= ~MSG_RWAIT;
454: wakeup(qp);
455: }
456: return 0;
457: }
458:
459: /*
460: * Receive a Message
461: */
462: umsgrcv(qid, bufp, msgsz, msgtyp, msgflg)
463: int qid; /* Message queue id */
464: struct msgbuf *bufp; /* Message buffer */
465: int msgsz; /* Message text size */
466: long msgtyp; /* Message type */
467: int msgflg; /* Message flag */
468: {
469: register struct msqid_ds *qp; /* queue headers */
470: register struct msg *mp, /* message headers */
471: *prev;
472: int q_num; /* queue number */
473: int i_spot;
474:
475: /* Validate queue identifier. */
476: if (qid < 0 || msqs == NULL) {
477: u.u_error = EINVAL;
478: return -1;
479: }
480: q_num = qid % NMSQID;
481: qp = &msqs[q_num];
482:
483: /* Validate queue existence.*/
484: if (qp->msg_perm.seq != qid || (qp->msg_perm.mode & IPC_ALLOC) == 0) {
485: u.u_error = EINVAL;
486: return -1;
487: }
488:
489: /* Permission denied */
490: if ((ipcaccess(&qp->msg_perm) & MSG_R) == 0) {
491: u.u_error = EACCES;
492: return -1;
493: }
494:
495: /* Wait for message */
496: lock(msg_gate[q_num]);
497: for (;;) {
498: prev = NULL;
499: mp = qp->msg_first;
500: /* Find mesg of type <= abs(msgtyp) */
501: if (msgtyp < 0) {
502: struct msg *qmin; /* Message with lowest mtype */
503: struct msg *xprev; /* Previous message */
504:
505: qmin = NULL;
506: xprev = prev;
507: msgtyp = -msgtyp;
508:
509: for (; mp != NULL; prev = mp, mp = mp->msg_next) {
510: if (mp->msg_type > msgtyp)
511: continue;
512: if (qmin == NULL
513: || mp->msg_type < qmin->msg_type) {
514: xprev = prev;
515: qmin = mp;
516: }
517: }
518: prev = xprev;
519: mp = qmin;
520: msgtyp = -msgtyp;
521: } else if (msgtyp > 0) { /* Find message of type == msgtyp */
522: while (mp != NULL && mp->msg_type != msgtyp) {
523: prev = mp;
524: mp = mp->msg_next;
525: }
526: } else /* Else take first message */
527: mp = qp->msg_first;
528:
529: if (mp != NULL) /* Found */
530: break;
531:
532: /* Can't wait to receive mesg */
533: if (msgflg & IPC_NOWAIT) {
534: u.u_error = EAGAIN;
535: unlock(msg_gate[q_num]);
536: return -1;
537: }
538:
539: /* We can go sleep now */
540: qp->msg_perm.mode |= MSG_RWAIT;
541: unlock(msg_gate[q_num]);
542: x_sleep(qp, pritty, slpriSigCatch, "umsgrcv");
543:
544: /* Signal received */
545: if (SELF->p_ssig && nondsig()) {
546: u.u_error = EINTR;
547: return -1;
548: }
549:
550: /* Not same q anymore */
551: if (qid != qp->msg_perm.seq) {
552: u.u_error = EINVAL;
553: return -1;
554: }
555: lock(msg_gate[q_num]);
556: }
557:
558: /* Ensure entire message can be transferred, or MSG_NOERROR asserted.*/
559: if (msgsz < mp->msg_ts && (msgflg & MSG_NOERROR) == 0) {
560: unlock(msg_gate[q_num]);
561: u.u_error = E2BIG;
562: return -1;
563: }
564:
565: /* Transfer message data */
566: if (msgsz > mp->msg_ts)
567: msgsz = mp->msg_ts;
568:
569: kucopy(&(mp->msg_type), &(bufp->mtype), sizeof(mp->msg_type));
570:
571: i_spot = mp->msg_spot;
572: if (kucopy(msg_map[i_spot], bufp->mtext, msgsz) != msgsz)
573: u.u_error = EFAULT;
574:
575: /* Abort if address fault occurred during transfer. */
576: if (u.u_error) {
577: unlock(msg_gate[q_num]);
578: return -1;
579: }
580: /* Remove message from queue */
581: if (prev != NULL)
582: prev->msg_next = mp->msg_next;
583: else
584: qp->msg_first = mp->msg_next;
585:
586: if (qp->msg_last == mp)
587: qp->msg_last = prev;
588:
589:
590: /* Update queue statistics */
591: qp->msg_cbytes -= mp->msg_ts;
592: qp->msg_qnum--;
593: qp->msg_lrpid = SELF->p_pid;
594: qp->msg_rtime = timer.t_time;
595:
596: /* free message */
597: msgfree(mp);
598:
599: unlock(msg_gate[q_num]);
600: /* Wakeup processes waiting to send. */
601: if (qp->msg_perm.mode & MSG_WWAIT) {
602: qp->msg_perm.mode &= ~MSG_WWAIT;
603: wakeup(qp);
604: }
605: return msgsz;
606: }
607:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.