|
|
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 <sys/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:
184: if (mykey == qp->msg_perm.key) { /* found! */
185: if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
186: u.u_error = EEXIST; /* We cannot creat */
187: return -1; /* exclusive queue */
188: }
189:
190: /* PERMISSIONS */
191: /* For super-user or if mode is 0 */
192: if (u.u_uid == 0 || !rwmode)
193: return qp->msg_perm.seq;
194:
195: /* For owner or creator */
196: T_MSGQ(0x02, printf("Q%o", qp->msg_perm.mode));
197: if (u.u_uid == qp->msg_perm.uid
198: || u.u_uid == qp->msg_perm.cuid) {
199: if ((rwmode & 0600) & (qp->msg_perm.mode & 0600))
200: return qp->msg_perm.seq;
201: else {
202: u.u_error = EACCES;
203: return -1;
204: }
205: }
206:
207: /* For group */
208: if (u.u_gid == qp->msg_perm.gid
209: || u.u_gid == qp->msg_perm.cgid) {
210: if ((rwmode & 060) & (qp->msg_perm.mode & 060))
211: return qp->msg_perm.seq;
212: else {
213: u.u_error = EACCES;
214: return -1;
215: }
216: }
217:
218: /* For the rest of the world */
219: if ((rwmode & 06) & (qp->msg_perm.mode & 06))
220: return qp->msg_perm.seq;
221: else {
222: u.u_error = EACCES;
223: return -1;
224: }
225: }
226: }
227:
228: /* Creat a new queue */
229: if (!(msgflg & IPC_CREAT)) {
230: u.u_error = ENOENT;
231: return -1;
232: }
233: if ((qp = freeidp) == NULL) {
234: u.u_error = ENOSPC;
235: return -1;
236: }
237: /* Set new queue */
238: qp->msg_ctime = timer.t_time;
239: qp->msg_perm.cuid = qp->msg_perm.uid = u.u_uid;
240: qp->msg_perm.cgid = qp->msg_perm.gid = u.u_gid;
241: qp->msg_perm.mode = rwmode | IPC_ALLOC;
242: qp->msg_qnum = qp->msg_lspid = qp->msg_lrpid = qp->msg_stime
243: = qp->msg_rtime = 0;
244: qp->msg_perm.key = mykey;
245:
246: return qp->msg_perm.seq;
247: }
248:
249: /*
250: * Allocate space for the message queues and gates.
251: * Initialize message queue headers
252: * Return -1 on error.
253: */
254: msginit()
255: {
256: struct msqid_ds *qp;
257:
258: T_MSGQ(0x01, printf("A%d",dballoc += sizeof(struct msqid_ds) * NMSQID));
259:
260: /* Allocate space for message headers */
261: if ((msqs =
262: (struct msqid_ds *) kalloc(sizeof(struct msqid_ds) * NMSQID)) == NULL)
263: return -1;
264:
265: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(GATE) * NMSQID));
266:
267: /* Allocate space for message gates */
268: if ((msg_gate = (GATE *) kalloc(sizeof(GATE) * NMSQID)) == NULL) {
269: kfree(msqs);
270: msqs = NULL;
271: return -1;
272: }
273:
274: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(char *) * NMSQID * NMSG));
275:
276: /* Allocate space for the message map */
277: if ((msg_map = kalloc(sizeof(char *) * NMSQID * NMSG)) == NULL) {
278: kfree(msqs);
279: msqs = NULL;
280: kfree(msg_gate);
281: return -1;
282: }
283: /* Clear gate and map areas */
284: kclear(msg_gate, sizeof(GATE) * NMSQID);
285: kclear(msg_map, sizeof(char *) * NMSQID * NMSG);
286: /* Set initial queue values */
287: for (qp = msqs; qp < msqs + NMSQID; qp++) {
288: qp->msg_first = NULL; /* First and last pointers to */
289: qp->msg_last = NULL; /* message queue */
290: qp->msg_cbytes = 0; /* Number of bytes in queue */
291: qp->msg_qnum = 0; /* Number of messages in queue */
292: qp->msg_qbytes = NMSQB; /* Max size of a queue */
293: qp->msg_lspid = 0; /* Pid of last msgsnd */
294: qp->msg_lrpid = 0; /* Pid of last msgrcv */
295: qp->msg_stime = 0; /* Last msgsnd time */
296: qp->msg_rtime = 0; /* Last msgrcv time */
297: qp->msg_ctime = timer.t_time; /* Last change time */
298: qp->msg_perm.seq = qp - msqs;
299: qp->msg_perm.mode = 0;
300: }
301: return 0;
302: }
303:
304: /*
305: * Remove the message. Clear message text and header. Reset values in
306: * message map.
307: */
308: msgfree(mp)
309: struct msg *mp; /* Message header to be remove */
310: {
311:
312: kfree(msg_map[mp->msg_spot]);
313: msg_map[mp->msg_spot] = NULL;
314: kfree(mp);
315: T_MSGQ(0x01, printf("F%d", dballoc-=(mp->msg_ts + sizeof(struct msg))));
316: }
317:
318: /*
319: * Send a Message
320: */
321: umsgsnd(qid, bufp, msgsz, msgflg)
322: int qid; /* queue id */
323: struct msgbuf *bufp; /* message buffer */
324: int msgsz, /* message size */
325: msgflg; /* flags */
326: {
327: register struct msqid_ds *qp; /* message queue */
328: register struct msg *mp, /* message struct */
329: *tmp;
330: int q_num; /* number of a queue */
331: int i_spot; /* # of empty entry in map */
332:
333: /* Validate queue identifier. */
334: for (qp = msqs; qp < msqs + NMSQID; qp++)
335: if (qp->msg_perm.seq == qid) /* found */
336: break;
337:
338: q_num = qp - msqs;
339: /* qid is not a valid qid identifier */
340: if (q_num >= NMSQID) {
341: u.u_error = EINVAL;
342: return -1;
343: }
344:
345: if (!(ipcaccess(&qp->msg_perm) & MSG_W)) { /* can't send mesg */
346: u.u_error = EACCES;
347: return -1;
348: }
349:
350: /* Check if message has a valid message type and size.
351: * The comparisson with NMSQB was done because user could
352: * reduce this value.
353: */
354: if (bufp->mtype < 1 || msgsz < 0 || msgsz > NMSC || msgsz > NMSQB) {
355: u.u_error = EACCES;
356: return -1;
357: }
358:
359: /* Now we have a valid message. Check if we can send it. */
360: lock(msg_gate[q_num]); /* Lock it to avoid race condition */
361: while (qp->msg_qnum >= NMSG ||
362: qp->msg_qbytes < (qp->msg_cbytes + msgsz)) {
363: if (msgflg & IPC_NOWAIT) {
364: u.u_error = EAGAIN;
365: unlock(msg_gate[q_num]);
366: return -1;
367: }
368: /* We have to wait here */
369: qp->msg_perm.mode |= MSG_WWAIT;
370: unlock(msg_gate[q_num]);
371:
372: if (x_sleep (qp, pritty, slpriSigCatch, "umsgsnd")
373: == PROCESS_SIGNALLED) {
374: /* Abort if a signal was received */
375: u.u_error = EINTR;
376: return -1;
377: }
378:
379: /* Abort if the message queue was removed. */
380: if (qid != qp->msg_perm.seq) {
381: u.u_error = EINVAL;
382: return -1;
383: }
384: lock(msg_gate[q_num]);
385: }
386:
387: /* Find empty entry in message map */
388: for (i_spot = 0; i_spot < NMSQID * NMSG; i_spot++)
389: if (msg_map[i_spot] == NULL)
390: break;
391: /* It cannot happen when we do not have empty entry in map,
392: * but let check it.
393: */
394: if (i_spot >= NMSQID * NMSG) {
395: u.u_error = ENOSPC;
396: return -1;
397: }
398:
399: T_MSGQ(0x01, printf("A%d", dballoc += sizeof(struct msg)));
400:
401: /* Get space for the message header */
402: if ((mp = kalloc(sizeof(struct msg))) == NULL) {
403: unlock(msg_gate[q_num]);
404: u.u_error = ENOSPC;
405: return -1;
406: }
407:
408: T_MSGQ(0x01, printf("A%d", dballoc += msgsz));
409:
410: /* Alloc space for the message text */
411: if ((msg_map[i_spot] = kalloc(msgsz)) == NULL) {
412: kfree(mp);
413: unlock(msg_gate[q_num]);
414: u.u_error = ENOSPC;
415: return -1;
416: }
417:
418: mp->msg_next = NULL;
419: mp->msg_ts = msgsz;
420: /* The map address is a number of msg_map array element */
421: mp->msg_spot = i_spot;
422:
423: /* Transfer the message type and text.*/
424: if (ukcopy(&(bufp->mtype), &(mp->msg_type), sizeof(mp->msg_type)) !=
425: sizeof(mp->msg_type))
426: u.u_error = EFAULT;
427: if (ukcopy(&bufp->mtext[0], msg_map[i_spot], msgsz) != msgsz)
428: u.u_error = EFAULT;
429: if (u.u_error) {
430: msgfree(mp);
431: unlock(msg_gate[q_num]);
432: return -1;
433: }
434:
435: /* Move the message to the desired queue. */
436: if (qp->msg_first == NULL) /* This is the first message per queue */
437: qp->msg_first = qp->msg_last = mp;
438: else { /* There are messages */
439: /* Find last message in gueue */
440: for (tmp = qp->msg_first; ; tmp = tmp->msg_next)
441: if (tmp->msg_next == NULL)
442: break;
443: qp->msg_last = tmp->msg_next = mp;
444: }
445: mp->msg_next = NULL;
446:
447: /* Update queue statistics. */
448: qp->msg_cbytes += msgsz;
449: qp->msg_qnum++;
450: qp->msg_lspid = SELF->p_pid;
451: qp->msg_stime = timer.t_time;
452:
453: /* Unlock queue and wake processes waiting to receive. */
454: unlock(msg_gate[q_num]);
455: if (qp->msg_perm.mode & MSG_RWAIT) {
456: qp->msg_perm.mode &= ~MSG_RWAIT;
457: wakeup(qp);
458: }
459: return 0;
460: }
461:
462: /*
463: * Receive a Message
464: */
465: umsgrcv(qid, bufp, msgsz, msgtyp, msgflg)
466: int qid; /* Message queue id */
467: struct msgbuf *bufp; /* Message buffer */
468: int msgsz; /* Message text size */
469: long msgtyp; /* Message type */
470: int msgflg; /* Message flag */
471: {
472: register struct msqid_ds *qp; /* queue headers */
473: register struct msg *mp, /* message headers */
474: *prev;
475: int q_num; /* queue number */
476: int i_spot;
477:
478: /* Validate queue identifier. */
479: if (qid < 0 || msqs == NULL) {
480: u.u_error = EINVAL;
481: return -1;
482: }
483: q_num = qid % NMSQID;
484: qp = &msqs[q_num];
485:
486: /* Validate queue existence.*/
487: if (qp->msg_perm.seq != qid || (qp->msg_perm.mode & IPC_ALLOC) == 0) {
488: u.u_error = EINVAL;
489: return -1;
490: }
491:
492: /* Permission denied */
493: if ((ipcaccess(&qp->msg_perm) & MSG_R) == 0) {
494: u.u_error = EACCES;
495: return -1;
496: }
497:
498: /* Wait for message */
499: lock(msg_gate[q_num]);
500: for (;;) {
501: prev = NULL;
502: mp = qp->msg_first;
503: /* Find mesg of type <= abs(msgtyp) */
504: if (msgtyp < 0) {
505: struct msg *qmin; /* Message with lowest mtype */
506: struct msg *xprev; /* Previous message */
507:
508: qmin = NULL;
509: xprev = prev;
510: msgtyp = -msgtyp;
511:
512: for (; mp != NULL; prev = mp, mp = mp->msg_next) {
513: if (mp->msg_type > msgtyp)
514: continue;
515: if (qmin == NULL
516: || mp->msg_type < qmin->msg_type) {
517: xprev = prev;
518: qmin = mp;
519: }
520: }
521: prev = xprev;
522: mp = qmin;
523: msgtyp = -msgtyp;
524: } else if (msgtyp > 0) { /* Find message of type == msgtyp */
525: while (mp != NULL && mp->msg_type != msgtyp) {
526: prev = mp;
527: mp = mp->msg_next;
528: }
529: } else /* Else take first message */
530: mp = qp->msg_first;
531:
532: if (mp != NULL) /* Found */
533: break;
534:
535: /* Can't wait to receive mesg */
536: if (msgflg & IPC_NOWAIT) {
537: u.u_error = ENOMSG;
538: unlock(msg_gate[q_num]);
539: return -1;
540: }
541:
542: /* We can go sleep now */
543: qp->msg_perm.mode |= MSG_RWAIT;
544: unlock(msg_gate[q_num]);
545: if (x_sleep (qp, pritty, slpriSigCatch, "umsgrcv")
546: == PROCESS_SIGNALLED) {
547: u.u_error = EINTR;
548: return -1;
549: }
550:
551: /* Not same q anymore */
552: if (qid != qp->msg_perm.seq) {
553: u.u_error = EINVAL;
554: return -1;
555: }
556: lock(msg_gate[q_num]);
557: }
558:
559: /* Ensure entire message can be transferred, or MSG_NOERROR asserted.*/
560: if (msgsz < mp->msg_ts && (msgflg & MSG_NOERROR) == 0) {
561: unlock(msg_gate[q_num]);
562: u.u_error = E2BIG;
563: return -1;
564: }
565:
566: /* Transfer message data */
567: if (msgsz > mp->msg_ts)
568: msgsz = mp->msg_ts;
569:
570: kucopy(&(mp->msg_type), &(bufp->mtype), sizeof(mp->msg_type));
571:
572: i_spot = mp->msg_spot;
573: if (kucopy(msg_map[i_spot], bufp->mtext, msgsz) != msgsz)
574: u.u_error = EFAULT;
575:
576: /* Abort if address fault occurred during transfer. */
577: if (u.u_error) {
578: unlock(msg_gate[q_num]);
579: return -1;
580: }
581: /* Remove message from queue */
582: if (prev != NULL)
583: prev->msg_next = mp->msg_next;
584: else
585: qp->msg_first = mp->msg_next;
586:
587: if (qp->msg_last == mp)
588: qp->msg_last = prev;
589:
590:
591: /* Update queue statistics */
592: qp->msg_cbytes -= mp->msg_ts;
593: qp->msg_qnum--;
594: qp->msg_lrpid = SELF->p_pid;
595: qp->msg_rtime = timer.t_time;
596:
597: /* free message */
598: msgfree(mp);
599:
600: unlock(msg_gate[q_num]);
601: /* Wakeup processes waiting to send. */
602: if (qp->msg_perm.mode & MSG_WWAIT) {
603: qp->msg_perm.mode &= ~MSG_WWAIT;
604: wakeup(qp);
605: }
606: return msgsz;
607: }
608:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.