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