This source file includes following definitions.
- msg_init
- real_msgsnd
- real_msgrcv
- sys_msgsnd
- sys_msgrcv
- findkey
- newque
- sys_msgget
- freeque
- sys_msgctl
- kerneld_exit
- kerneld_send
1
2
3
4
5
6
7
8
9 #include <linux/config.h>
10 #include <linux/errno.h>
11 #include <linux/sched.h>
12 #include <linux/msg.h>
13 #include <linux/stat.h>
14 #include <linux/malloc.h>
15 #include <linux/kerneld.h>
16
17 #include <asm/segment.h>
18
19 extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
20
21 static void freeque (int id);
22 static int newque (key_t key, int msgflg);
23 static int findkey (key_t key);
24
25 static struct msqid_ds *msgque[MSGMNI];
26 static int msgbytes = 0;
27 static int msghdrs = 0;
28 static unsigned short msg_seq = 0;
29 static int used_queues = 0;
30 static int max_msqid = 0;
31 static struct wait_queue *msg_lock = NULL;
32 static int kerneld_msqid = -1;
33 static int kerneld_pid;
34
35 void msg_init (void)
36 {
37 int id;
38
39 for (id = 0; id < MSGMNI; id++)
40 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
41 msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
42 msg_lock = NULL;
43 return;
44 }
45
46 static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
47 {
48 int id, err;
49 struct msqid_ds *msq;
50 struct ipc_perm *ipcp;
51 struct msg *msgh;
52 long mtype;
53
54 if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
55 return -EINVAL;
56 if (!msgp)
57 return -EFAULT;
58
59
60
61
62 if ((msgflg & IPC_KERNELD))
63 mtype = msgp->mtype;
64 else {
65 err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
66 if (err)
67 return err;
68 if ((mtype = get_user (&msgp->mtype)) < 1)
69 return -EINVAL;
70 }
71 id = (unsigned int) msqid % MSGMNI;
72 msq = msgque [id];
73 if (msq == IPC_UNUSED || msq == IPC_NOID)
74 return -EINVAL;
75 ipcp = &msq->msg_perm;
76
77 slept:
78 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
79 return -EIDRM;
80
81
82
83
84
85 if ((msgflg & IPC_KERNELD) == 0)
86 if (ipcperms(ipcp, S_IWUGO))
87 return -EACCES;
88
89 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
90
91 if (msgflg & IPC_NOWAIT)
92 return -EAGAIN;
93 if (current->signal & ~current->blocked)
94 return -EINTR;
95 if (intr_count) {
96
97 printk("Ouch, kerneld:msgsnd wants to sleep at interrupt!\n");
98 return -EINTR;
99 }
100 interruptible_sleep_on (&msq->wwait);
101 goto slept;
102 }
103
104
105 msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_USER);
106 if (!msgh)
107 return -ENOMEM;
108 msgh->msg_spot = (char *) (msgh + 1);
109
110
111
112
113
114 if (msgflg & IPC_KERNELD) {
115 struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
116
117
118
119
120
121 memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long));
122 memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
123 msgsz - sizeof(long));
124 }
125 else
126 memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz);
127
128 if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
129 || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
130 kfree(msgh);
131 return -EIDRM;
132 }
133
134 msgh->msg_next = NULL;
135 if (!msq->msg_first)
136 msq->msg_first = msq->msg_last = msgh;
137 else {
138 msq->msg_last->msg_next = msgh;
139 msq->msg_last = msgh;
140 }
141 msgh->msg_ts = msgsz;
142 msgh->msg_type = mtype;
143 msq->msg_cbytes += msgsz;
144 msgbytes += msgsz;
145 msghdrs++;
146 msq->msg_qnum++;
147 msq->msg_lspid = current->pid;
148 msq->msg_stime = CURRENT_TIME;
149 if (msq->rwait)
150 wake_up (&msq->rwait);
151 return 0;
152 }
153
154 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
155 {
156 struct msqid_ds *msq;
157 struct ipc_perm *ipcp;
158 struct msg *tmsg, *leastp = NULL;
159 struct msg *nmsg = NULL;
160 int id, err;
161
162 if (msqid < 0 || (long) msgsz < 0)
163 return -EINVAL;
164 if (!msgp || !msgp->mtext)
165 return -EFAULT;
166
167
168
169
170 if ((msgflg & IPC_KERNELD) == 0) {
171 err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
172 if (err)
173 return err;
174 }
175
176 id = (unsigned int) msqid % MSGMNI;
177 msq = msgque [id];
178 if (msq == IPC_NOID || msq == IPC_UNUSED)
179 return -EINVAL;
180 ipcp = &msq->msg_perm;
181
182
183
184
185
186
187
188 while (!nmsg) {
189 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
190 return -EIDRM;
191 if ((msgflg & IPC_KERNELD) == 0)
192
193
194
195
196
197 if (ipcperms (ipcp, S_IRUGO))
198 return -EACCES;
199 if (msgtyp == 0)
200 nmsg = msq->msg_first;
201 else if (msgtyp > 0) {
202 if (msgflg & MSG_EXCEPT) {
203 for (tmsg = msq->msg_first; tmsg;
204 tmsg = tmsg->msg_next)
205 if (tmsg->msg_type != msgtyp)
206 break;
207 nmsg = tmsg;
208 } else {
209 for (tmsg = msq->msg_first; tmsg;
210 tmsg = tmsg->msg_next)
211 if (tmsg->msg_type == msgtyp)
212 break;
213 nmsg = tmsg;
214 }
215 } else {
216 for (leastp = tmsg = msq->msg_first; tmsg;
217 tmsg = tmsg->msg_next)
218 if (tmsg->msg_type < leastp->msg_type)
219 leastp = tmsg;
220 if (leastp && leastp->msg_type <= - msgtyp)
221 nmsg = leastp;
222 }
223
224 if (nmsg) {
225 if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
226 return -E2BIG;
227 msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
228 if (nmsg == msq->msg_first)
229 msq->msg_first = nmsg->msg_next;
230 else {
231 for (tmsg = msq->msg_first; tmsg;
232 tmsg = tmsg->msg_next)
233 if (tmsg->msg_next == nmsg)
234 break;
235 tmsg->msg_next = nmsg->msg_next;
236 if (nmsg == msq->msg_last)
237 msq->msg_last = tmsg;
238 }
239 if (!(--msq->msg_qnum))
240 msq->msg_last = msq->msg_first = NULL;
241
242 msq->msg_rtime = CURRENT_TIME;
243 msq->msg_lrpid = current->pid;
244 msgbytes -= nmsg->msg_ts;
245 msghdrs--;
246 msq->msg_cbytes -= nmsg->msg_ts;
247 if (msq->wwait)
248 wake_up (&msq->wwait);
249
250
251
252
253 if (msgflg & IPC_KERNELD) {
254 struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
255
256 memcpy((char *)(&(kdmp->id)),
257 nmsg->msg_spot,
258 sizeof(long));
259
260
261
262
263 if ((msgsz > sizeof(long)) && kdmp->text)
264 memcpy(kdmp->text,
265 nmsg->msg_spot + sizeof(long),
266 msgsz - sizeof(long));
267 }
268 else {
269 put_user (nmsg->msg_type, &msgp->mtype);
270 memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
271 }
272 kfree(nmsg);
273 return msgsz;
274 } else {
275 if (msgflg & IPC_NOWAIT)
276 return -ENOMSG;
277 if (current->signal & ~current->blocked)
278 return -EINTR;
279 if (intr_count) {
280
281 printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
282 return -EINTR;
283 }
284 interruptible_sleep_on (&msq->rwait);
285 }
286 }
287 return -1;
288 }
289
290 asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
291 {
292
293 return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
294 }
295
296 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
297 long msgtyp, int msgflg)
298 {
299
300 return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
301 }
302
303 static int findkey (key_t key)
304 {
305 int id;
306 struct msqid_ds *msq;
307
308 for (id = 0; id <= max_msqid; id++) {
309 while ((msq = msgque[id]) == IPC_NOID)
310 interruptible_sleep_on (&msg_lock);
311 if (msq == IPC_UNUSED)
312 continue;
313 if (key == msq->msg_perm.key)
314 return id;
315 }
316 return -1;
317 }
318
319 static int newque (key_t key, int msgflg)
320 {
321 int id;
322 struct msqid_ds *msq;
323 struct ipc_perm *ipcp;
324
325 for (id = 0; id < MSGMNI; id++)
326 if (msgque[id] == IPC_UNUSED) {
327 msgque[id] = (struct msqid_ds *) IPC_NOID;
328 goto found;
329 }
330 return -ENOSPC;
331
332 found:
333 msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
334 if (!msq) {
335 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
336 if (msg_lock)
337 wake_up (&msg_lock);
338 return -ENOMEM;
339 }
340 ipcp = &msq->msg_perm;
341 ipcp->mode = (msgflg & S_IRWXUGO);
342 ipcp->key = key;
343 ipcp->cuid = ipcp->uid = current->euid;
344 ipcp->gid = ipcp->cgid = current->egid;
345 msq->msg_perm.seq = msg_seq;
346 msq->msg_first = msq->msg_last = NULL;
347 msq->rwait = msq->wwait = NULL;
348 msq->msg_cbytes = msq->msg_qnum = 0;
349 msq->msg_lspid = msq->msg_lrpid = 0;
350 msq->msg_stime = msq->msg_rtime = 0;
351 msq->msg_qbytes = MSGMNB;
352 msq->msg_ctime = CURRENT_TIME;
353 if (id > max_msqid)
354 max_msqid = id;
355 msgque[id] = msq;
356 used_queues++;
357 if (msg_lock)
358 wake_up (&msg_lock);
359 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
360 }
361
362 asmlinkage int sys_msgget (key_t key, int msgflg)
363 {
364 int id;
365 struct msqid_ds *msq;
366
367
368
369
370
371 if ((msgflg & IPC_KERNELD)) {
372 if (!suser())
373 return -EPERM;
374 if ((kerneld_msqid == -1) && (kerneld_msqid =
375 newque(IPC_PRIVATE, msgflg & S_IRWXU)) >= 0)
376 kerneld_pid = current->pid;
377 return kerneld_msqid;
378 }
379
380 if (key == IPC_PRIVATE)
381 return newque(key, msgflg);
382 if ((id = findkey (key)) == -1) {
383 if (!(msgflg & IPC_CREAT))
384 return -ENOENT;
385 return newque(key, msgflg);
386 }
387 if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
388 return -EEXIST;
389 msq = msgque[id];
390 if (msq == IPC_UNUSED || msq == IPC_NOID)
391 return -EIDRM;
392 if (ipcperms(&msq->msg_perm, msgflg))
393 return -EACCES;
394 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
395 }
396
397 static void freeque (int id)
398 {
399 struct msqid_ds *msq = msgque[id];
400 struct msg *msgp, *msgh;
401
402 msq->msg_perm.seq++;
403 msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI);
404 msgbytes -= msq->msg_cbytes;
405 if (id == max_msqid)
406 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
407 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
408 used_queues--;
409 while (msq->rwait || msq->wwait) {
410 if (msq->rwait)
411 wake_up (&msq->rwait);
412 if (msq->wwait)
413 wake_up (&msq->wwait);
414 schedule();
415 }
416 for (msgp = msq->msg_first; msgp; msgp = msgh ) {
417 msgh = msgp->msg_next;
418 msghdrs--;
419 kfree(msgp);
420 }
421 kfree(msq);
422 }
423
424 asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
425 {
426 int id, err;
427 struct msqid_ds *msq;
428 struct msqid_ds tbuf;
429 struct ipc_perm *ipcp;
430
431 if (msqid < 0 || cmd < 0)
432 return -EINVAL;
433 switch (cmd) {
434 case IPC_INFO:
435 case MSG_INFO:
436 if (!buf)
437 return -EFAULT;
438 {
439 struct msginfo msginfo;
440 msginfo.msgmni = MSGMNI;
441 msginfo.msgmax = MSGMAX;
442 msginfo.msgmnb = MSGMNB;
443 msginfo.msgmap = MSGMAP;
444 msginfo.msgpool = MSGPOOL;
445 msginfo.msgtql = MSGTQL;
446 msginfo.msgssz = MSGSSZ;
447 msginfo.msgseg = MSGSEG;
448 if (cmd == MSG_INFO) {
449 msginfo.msgpool = used_queues;
450 msginfo.msgmap = msghdrs;
451 msginfo.msgtql = msgbytes;
452 }
453 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
454 if (err)
455 return err;
456 memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
457 return max_msqid;
458 }
459 case MSG_STAT:
460 if (!buf)
461 return -EFAULT;
462 err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
463 if (err)
464 return err;
465 if (msqid > max_msqid)
466 return -EINVAL;
467 msq = msgque[msqid];
468 if (msq == IPC_UNUSED || msq == IPC_NOID)
469 return -EINVAL;
470 if (ipcperms (&msq->msg_perm, S_IRUGO))
471 return -EACCES;
472 id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
473 tbuf.msg_perm = msq->msg_perm;
474 tbuf.msg_stime = msq->msg_stime;
475 tbuf.msg_rtime = msq->msg_rtime;
476 tbuf.msg_ctime = msq->msg_ctime;
477 tbuf.msg_cbytes = msq->msg_cbytes;
478 tbuf.msg_qnum = msq->msg_qnum;
479 tbuf.msg_qbytes = msq->msg_qbytes;
480 tbuf.msg_lspid = msq->msg_lspid;
481 tbuf.msg_lrpid = msq->msg_lrpid;
482 memcpy_tofs (buf, &tbuf, sizeof(*buf));
483 return id;
484 case IPC_SET:
485 if (!buf)
486 return -EFAULT;
487 err = verify_area (VERIFY_READ, buf, sizeof (*buf));
488 if (err)
489 return err;
490 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
491 break;
492 case IPC_STAT:
493 if (!buf)
494 return -EFAULT;
495 err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
496 if (err)
497 return err;
498 break;
499 }
500
501 id = (unsigned int) msqid % MSGMNI;
502 msq = msgque [id];
503 if (msq == IPC_UNUSED || msq == IPC_NOID)
504 return -EINVAL;
505 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
506 return -EIDRM;
507 ipcp = &msq->msg_perm;
508
509 switch (cmd) {
510 case IPC_STAT:
511 if (ipcperms (ipcp, S_IRUGO))
512 return -EACCES;
513 tbuf.msg_perm = msq->msg_perm;
514 tbuf.msg_stime = msq->msg_stime;
515 tbuf.msg_rtime = msq->msg_rtime;
516 tbuf.msg_ctime = msq->msg_ctime;
517 tbuf.msg_cbytes = msq->msg_cbytes;
518 tbuf.msg_qnum = msq->msg_qnum;
519 tbuf.msg_qbytes = msq->msg_qbytes;
520 tbuf.msg_lspid = msq->msg_lspid;
521 tbuf.msg_lrpid = msq->msg_lrpid;
522 memcpy_tofs (buf, &tbuf, sizeof (*buf));
523 return 0;
524 case IPC_SET:
525 if (!suser() && current->euid != ipcp->cuid &&
526 current->euid != ipcp->uid)
527 return -EPERM;
528 if (tbuf.msg_qbytes > MSGMNB && !suser())
529 return -EPERM;
530 msq->msg_qbytes = tbuf.msg_qbytes;
531 ipcp->uid = tbuf.msg_perm.uid;
532 ipcp->gid = tbuf.msg_perm.gid;
533 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
534 (S_IRWXUGO & tbuf.msg_perm.mode);
535 msq->msg_ctime = CURRENT_TIME;
536 return 0;
537 case IPC_RMID:
538 if (!suser() && current->euid != ipcp->cuid &&
539 current->euid != ipcp->uid)
540 return -EPERM;
541
542
543
544
545 if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
546 kerneld_pid = kerneld_msqid = -1;
547 freeque (id);
548 return 0;
549 default:
550 return -EINVAL;
551 }
552 }
553
554
555
556
557
558
559
560
561 void kerneld_exit(void)
562 {
563 if ((current->pid == kerneld_pid) && (kerneld_msqid != -1))
564 sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
565 }
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599 int kerneld_send(int msgtype, int ret_size, int msgsz,
600 const char *text, const char *ret_val)
601 {
602 int status = -ENOSYS;
603 #ifdef CONFIG_KERNELD
604 static int id = KERNELD_MINSEQ;
605 struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
606 int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
607
608 msgsz += sizeof(long);
609 if (ret_size & KERNELD_WAIT) {
610 if (++id <= 0)
611 id = KERNELD_MINSEQ;
612 kmsp.id = id;
613 }
614
615 if (kerneld_msqid == -1)
616 return -ENODEV;
617
618 status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
619 if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
620 ret_size &= ~KERNELD_WAIT;
621 if (intr_count) {
622
623
624
625
626
627
628 return 0;
629 }
630
631 kmsp.text = (char *)ret_val;
632 status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
633 sizeof(long) + ((ret_val)?ret_size:0),
634 kmsp.id, msgflg);
635 if (status > 0)
636 status = kmsp.id;
637 }
638
639 #endif
640 return status;
641 }