1
2
3
4
5
6
7
8
9
10#include <linux/config.h>
11#include <linux/errno.h>
12#include <linux/sched.h>
13#include <linux/msg.h>
14#include <linux/stat.h>
15#include <linux/malloc.h>
16#include <linux/kerneld.h>
17#include <linux/interrupt.h>
18#include <linux/smp.h>
19#include <linux/smp_lock.h>
20#include <linux/init.h>
21
22#include <asm/uaccess.h>
23
24extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
25
26static void freeque (int id);
27static int newque (key_t key, int msgflg);
28static int findkey (key_t key);
29
30static struct msqid_ds *msgque[MSGMNI];
31static int msgbytes = 0;
32static int msghdrs = 0;
33static unsigned short msg_seq = 0;
34static int used_queues = 0;
35static int max_msqid = 0;
36static struct wait_queue *msg_lock = NULL;
37static int kerneld_msqid = -1;
38
39#define MAX_KERNELDS 20
40static int kerneld_arr[MAX_KERNELDS];
41static int n_kernelds = 0;
42
43__initfunc(void msg_init (void))
44{
45 int id;
46
47 for (id = 0; id < MSGMNI; id++)
48 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
49 msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
50 msg_lock = NULL;
51 return;
52}
53
54
55
56
57
58#define MSG_FLUSH_TIME 10
59static void flush_msg(struct msqid_ds *msq)
60{
61 struct msg *nmsg;
62 unsigned long flags;
63 int flushed = 0;
64
65 save_flags(flags);
66 cli();
67
68
69 while ( (nmsg = msq->msg_first) &&
70 ((CURRENT_TIME - nmsg->msg_stime) > MSG_FLUSH_TIME)) {
71 msgbytes -= nmsg->msg_ts;
72 msghdrs--;
73 msq->msg_cbytes -= nmsg->msg_ts;
74 msq->msg_qnum--;
75 msq->msg_first = nmsg->msg_next;
76 ++flushed;
77 kfree(nmsg);
78 }
79
80 if (msq->msg_qnum == 0)
81 msq->msg_first = msq->msg_last = NULL;
82 restore_flags(flags);
83 if (flushed)
84 printk(KERN_WARNING "flushed %d old SYSVIPC messages", flushed);
85}
86
87static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
88{
89 int id, err;
90 struct msqid_ds *msq;
91 struct ipc_perm *ipcp;
92 struct msg *msgh;
93 long mtype;
94 unsigned long flags;
95
96 if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
97 return -EINVAL;
98 if (!msgp)
99 return -EFAULT;
100
101
102
103
104 if ((msgflg & IPC_KERNELD))
105 mtype = msgp->mtype;
106 else {
107 err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
108 if (err)
109 return err;
110 get_user(mtype, &msgp->mtype);
111 if (mtype < 1)
112 return -EINVAL;
113 }
114 id = (unsigned int) msqid % MSGMNI;
115 msq = msgque [id];
116 if (msq == IPC_UNUSED || msq == IPC_NOID)
117 return -EINVAL;
118 ipcp = &msq->msg_perm;
119
120 slept:
121 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
122 return -EIDRM;
123
124
125
126
127
128 if ((msgflg & IPC_KERNELD) == 0)
129 if (ipcperms(ipcp, S_IWUGO))
130 return -EACCES;
131
132 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
133 if ((kerneld_msqid != -1) && (kerneld_msqid == msqid))
134 flush_msg(msq);
135 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
136
137 if (msgflg & IPC_NOWAIT)
138 return -EAGAIN;
139 if (current->signal & ~current->blocked)
140 return -EINTR;
141 if (in_interrupt()) {
142
143 printk(KERN_WARNING "Ouch, kerneld:msgsnd buffers full!\n");
144 return -EINTR;
145 }
146 interruptible_sleep_on (&msq->wwait);
147 goto slept;
148 }
149 }
150
151
152 msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_ATOMIC);
153 if (!msgh)
154 return -ENOMEM;
155 msgh->msg_spot = (char *) (msgh + 1);
156
157
158
159
160
161 if (msgflg & IPC_KERNELD) {
162 struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
163
164
165
166
167
168 memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), KDHDR);
169 memcpy(msgh->msg_spot + KDHDR, kdmp->text, msgsz - KDHDR);
170 }
171 else
172 copy_from_user (msgh->msg_spot, msgp->mtext, msgsz);
173
174 if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
175 || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
176 kfree(msgh);
177 return -EIDRM;
178 }
179
180 msgh->msg_next = NULL;
181 msgh->msg_ts = msgsz;
182 msgh->msg_type = mtype;
183 msgh->msg_stime = CURRENT_TIME;
184
185 save_flags(flags);
186 cli();
187 if (!msq->msg_first)
188 msq->msg_first = msq->msg_last = msgh;
189 else {
190 msq->msg_last->msg_next = msgh;
191 msq->msg_last = msgh;
192 }
193 msq->msg_cbytes += msgsz;
194 msgbytes += msgsz;
195 msghdrs++;
196 msq->msg_qnum++;
197 msq->msg_lspid = current->pid;
198 msq->msg_stime = CURRENT_TIME;
199 restore_flags(flags);
200 wake_up (&msq->rwait);
201 return 0;
202}
203
204
205
206
207#define KERNELD_TIMEOUT 1 * (HZ)
208#define DROP_TIMER del_timer(&kd_timer)
209
210
211static void kd_timeout(unsigned long msgid)
212{
213 struct msqid_ds *msq;
214 struct msg *tmsg;
215 unsigned long flags;
216
217 msq = msgque [ (unsigned int) kerneld_msqid % MSGMNI ];
218 if (msq == IPC_NOID || msq == IPC_UNUSED)
219 return;
220
221 save_flags(flags);
222 cli();
223 for (tmsg = msq->msg_first; tmsg; tmsg = tmsg->msg_next)
224 if (*(long *)(tmsg->msg_spot) == msgid)
225 break;
226 restore_flags(flags);
227 if (tmsg) {
228 struct kerneld_msg kmsp = { msgid, NULL_KDHDR, "" };
229
230 printk(KERN_ALERT "Ouch, no kerneld for message %ld\n", msgid);
231 kmsp.id = -ENODEV;
232 real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, KDHDR,
233 S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR);
234 }
235}
236
237static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
238{
239 struct timer_list kd_timer = { NULL, NULL, 0, 0, 0};
240 struct msqid_ds *msq;
241 struct ipc_perm *ipcp;
242 struct msg *tmsg, *leastp = NULL;
243 struct msg *nmsg = NULL;
244 int id, err;
245 unsigned long flags;
246
247 if (msqid < 0 || (long) msgsz < 0)
248 return -EINVAL;
249 if (!msgp || !msgp->mtext)
250 return -EFAULT;
251
252
253
254
255 if ((msgflg & IPC_KERNELD) == 0) {
256 err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
257 if (err)
258 return err;
259 }
260
261 id = (unsigned int) msqid % MSGMNI;
262 msq = msgque [id];
263 if (msq == IPC_NOID || msq == IPC_UNUSED)
264 return -EINVAL;
265 ipcp = &msq->msg_perm;
266
267
268
269
270 if (msgflg & IPC_KERNELD) {
271 kd_timer.data = (unsigned long)msgtyp;
272 kd_timer.expires = jiffies + KERNELD_TIMEOUT;
273 kd_timer.function = kd_timeout;
274 add_timer(&kd_timer);
275 }
276
277
278
279
280
281
282
283 while (!nmsg) {
284 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
285 DROP_TIMER;
286 return -EIDRM;
287 }
288 if ((msgflg & IPC_KERNELD) == 0) {
289
290
291
292
293
294 if (ipcperms (ipcp, S_IRUGO)) {
295 DROP_TIMER;
296 return -EACCES;
297 }
298 }
299
300 save_flags(flags);
301 cli();
302 if (msgtyp == 0)
303 nmsg = msq->msg_first;
304 else if (msgtyp > 0) {
305 if (msgflg & MSG_EXCEPT) {
306 for (tmsg = msq->msg_first; tmsg;
307 tmsg = tmsg->msg_next)
308 if (tmsg->msg_type != msgtyp)
309 break;
310 nmsg = tmsg;
311 } else {
312 for (tmsg = msq->msg_first; tmsg;
313 tmsg = tmsg->msg_next)
314 if (tmsg->msg_type == msgtyp)
315 break;
316 nmsg = tmsg;
317 }
318 } else {
319 for (leastp = tmsg = msq->msg_first; tmsg;
320 tmsg = tmsg->msg_next)
321 if (tmsg->msg_type < leastp->msg_type)
322 leastp = tmsg;
323 if (leastp && leastp->msg_type <= - msgtyp)
324 nmsg = leastp;
325 }
326 restore_flags(flags);
327
328 if (nmsg) {
329 DROP_TIMER;
330 if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
331 return -E2BIG;
332 }
333 msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
334 save_flags(flags);
335 cli();
336 if (nmsg == msq->msg_first)
337 msq->msg_first = nmsg->msg_next;
338 else {
339 for (tmsg = msq->msg_first; tmsg;
340 tmsg = tmsg->msg_next)
341 if (tmsg->msg_next == nmsg)
342 break;
343 tmsg->msg_next = nmsg->msg_next;
344 if (nmsg == msq->msg_last)
345 msq->msg_last = tmsg;
346 }
347 if (!(--msq->msg_qnum))
348 msq->msg_last = msq->msg_first = NULL;
349
350 msq->msg_rtime = CURRENT_TIME;
351 msq->msg_lrpid = current->pid;
352 msgbytes -= nmsg->msg_ts;
353 msghdrs--;
354 msq->msg_cbytes -= nmsg->msg_ts;
355 restore_flags(flags);
356 wake_up (&msq->wwait);
357
358
359
360
361 if (msgflg & IPC_KERNELD) {
362 struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
363
364 memcpy((char *)(&(kdmp->id)),
365 nmsg->msg_spot, KDHDR);
366
367
368
369
370 if ((msgsz > KDHDR) && kdmp->text)
371 memcpy(kdmp->text,
372 nmsg->msg_spot + KDHDR,
373 msgsz - KDHDR);
374 }
375 else {
376 put_user (nmsg->msg_type, &msgp->mtype);
377 copy_to_user (msgp->mtext, nmsg->msg_spot, msgsz);
378 }
379 kfree(nmsg);
380 return msgsz;
381 } else {
382 if (msgflg & IPC_NOWAIT) {
383 DROP_TIMER;
384 return -ENOMSG;
385 }
386 if (current->signal & ~current->blocked) {
387 DROP_TIMER;
388 return -EINTR;
389 }
390 interruptible_sleep_on (&msq->rwait);
391 }
392 }
393 DROP_TIMER;
394 return -1;
395}
396
397asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
398{
399 int ret;
400
401
402 lock_kernel();
403 ret = real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
404 unlock_kernel();
405 return ret;
406}
407
408asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
409 long msgtyp, int msgflg)
410{
411 int ret;
412
413
414 lock_kernel();
415 ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
416 unlock_kernel();
417 return ret;
418}
419
420static int findkey (key_t key)
421{
422 int id;
423 struct msqid_ds *msq;
424
425 for (id = 0; id <= max_msqid; id++) {
426 while ((msq = msgque[id]) == IPC_NOID)
427 interruptible_sleep_on (&msg_lock);
428 if (msq == IPC_UNUSED)
429 continue;
430 if (key == msq->msg_perm.key)
431 return id;
432 }
433 return -1;
434}
435
436static int newque (key_t key, int msgflg)
437{
438 int id;
439 struct msqid_ds *msq;
440 struct ipc_perm *ipcp;
441
442 for (id = 0; id < MSGMNI; id++)
443 if (msgque[id] == IPC_UNUSED) {
444 msgque[id] = (struct msqid_ds *) IPC_NOID;
445 goto found;
446 }
447 return -ENOSPC;
448
449found:
450 msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
451 if (!msq) {
452 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
453 wake_up (&msg_lock);
454 return -ENOMEM;
455 }
456 ipcp = &msq->msg_perm;
457 ipcp->mode = (msgflg & S_IRWXUGO);
458 ipcp->key = key;
459 ipcp->cuid = ipcp->uid = current->euid;
460 ipcp->gid = ipcp->cgid = current->egid;
461 msq->msg_perm.seq = msg_seq;
462 msq->msg_first = msq->msg_last = NULL;
463 msq->rwait = msq->wwait = NULL;
464 msq->msg_cbytes = msq->msg_qnum = 0;
465 msq->msg_lspid = msq->msg_lrpid = 0;
466 msq->msg_stime = msq->msg_rtime = 0;
467 msq->msg_qbytes = MSGMNB;
468 msq->msg_ctime = CURRENT_TIME;
469 if (id > max_msqid)
470 max_msqid = id;
471 msgque[id] = msq;
472 used_queues++;
473 wake_up (&msg_lock);
474 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
475}
476
477asmlinkage int sys_msgget (key_t key, int msgflg)
478{
479 int id, ret = -EPERM;
480 struct msqid_ds *msq;
481
482
483
484
485
486 lock_kernel();
487 if ((msgflg & IPC_KERNELD)) {
488 int i;
489 if (!suser())
490 goto out;
491#ifdef NEW_KERNELD_PROTOCOL
492 if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) {
493 printk(KERN_ALERT "Please recompile your kerneld daemons!\n");
494 goto out;
495 }
496#endif
497 ret = -ENOSPC;
498 if ((kerneld_msqid == -1) && (kerneld_msqid =
499 newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
500 goto out;
501 for (i = 0; i < MAX_KERNELDS; ++i) {
502 if (kerneld_arr[i] == 0) {
503 kerneld_arr[i] = current->pid;
504 ++n_kernelds;
505 ret = kerneld_msqid;
506 goto out;
507 }
508 }
509 goto out;
510 }
511
512 if (key == IPC_PRIVATE)
513 ret = newque(key, msgflg);
514 else if ((id = findkey (key)) == -1) {
515 if (!(msgflg & IPC_CREAT))
516 ret = -ENOENT;
517 else
518 ret = newque(key, msgflg);
519 } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
520 ret = -EEXIST;
521 } else {
522 msq = msgque[id];
523 if (msq == IPC_UNUSED || msq == IPC_NOID)
524 ret = -EIDRM;
525 else if (ipcperms(&msq->msg_perm, msgflg))
526 ret = -EACCES;
527 else
528 ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id;
529 }
530out:
531 unlock_kernel();
532 return ret;
533}
534
535static void freeque (int id)
536{
537 struct msqid_ds *msq = msgque[id];
538 struct msg *msgp, *msgh;
539
540 msq->msg_perm.seq++;
541 msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI);
542 msgbytes -= msq->msg_cbytes;
543 if (id == max_msqid)
544 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
545 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
546 used_queues--;
547 while (waitqueue_active(&msq->rwait) || waitqueue_active(&msq->wwait)) {
548 wake_up (&msq->rwait);
549 wake_up (&msq->wwait);
550 schedule();
551 }
552 for (msgp = msq->msg_first; msgp; msgp = msgh ) {
553 msgh = msgp->msg_next;
554 msghdrs--;
555 kfree(msgp);
556 }
557 kfree(msq);
558}
559
560asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
561{
562 int id, err = -EINVAL;
563 struct msqid_ds *msq;
564 struct msqid_ds tbuf;
565 struct ipc_perm *ipcp;
566
567 lock_kernel();
568 if (msqid < 0 || cmd < 0)
569 goto out;
570 err = -EFAULT;
571 switch (cmd) {
572 case IPC_INFO:
573 case MSG_INFO:
574 if (!buf)
575 goto out;
576 {
577 struct msginfo msginfo;
578 msginfo.msgmni = MSGMNI;
579 msginfo.msgmax = MSGMAX;
580 msginfo.msgmnb = MSGMNB;
581 msginfo.msgmap = MSGMAP;
582 msginfo.msgpool = MSGPOOL;
583 msginfo.msgtql = MSGTQL;
584 msginfo.msgssz = MSGSSZ;
585 msginfo.msgseg = MSGSEG;
586 if (cmd == MSG_INFO) {
587 msginfo.msgpool = used_queues;
588 msginfo.msgmap = msghdrs;
589 msginfo.msgtql = msgbytes;
590 }
591 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
592 if (err)
593 goto out;
594 copy_to_user (buf, &msginfo, sizeof(struct msginfo));
595 err = max_msqid;
596 goto out;
597 }
598 case MSG_STAT:
599 if (!buf)
600 goto out;
601 err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
602 if (err)
603 goto out;
604 err = -EINVAL;
605 if (msqid > max_msqid)
606 goto out;
607 msq = msgque[msqid];
608 if (msq == IPC_UNUSED || msq == IPC_NOID)
609 goto out;
610 err = -EACCES;
611 if (ipcperms (&msq->msg_perm, S_IRUGO))
612 goto out;
613 id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
614 tbuf.msg_perm = msq->msg_perm;
615 tbuf.msg_stime = msq->msg_stime;
616 tbuf.msg_rtime = msq->msg_rtime;
617 tbuf.msg_ctime = msq->msg_ctime;
618 tbuf.msg_cbytes = msq->msg_cbytes;
619 tbuf.msg_qnum = msq->msg_qnum;
620 tbuf.msg_qbytes = msq->msg_qbytes;
621 tbuf.msg_lspid = msq->msg_lspid;
622 tbuf.msg_lrpid = msq->msg_lrpid;
623 copy_to_user (buf, &tbuf, sizeof(*buf));
624 err = id;
625 goto out;
626 case IPC_SET:
627 if (!buf)
628 goto out;
629 err = verify_area (VERIFY_READ, buf, sizeof (*buf));
630 if (err)
631 goto out;
632 copy_from_user (&tbuf, buf, sizeof (*buf));
633 break;
634 case IPC_STAT:
635 if (!buf)
636 goto out;
637 err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
638 if (err)
639 goto out;
640 break;
641 }
642
643 id = (unsigned int) msqid % MSGMNI;
644 msq = msgque [id];
645 err = -EINVAL;
646 if (msq == IPC_UNUSED || msq == IPC_NOID)
647 goto out;
648 err = -EIDRM;
649 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
650 goto out;
651 ipcp = &msq->msg_perm;
652
653 switch (cmd) {
654 case IPC_STAT:
655 err = -EACCES;
656 if (ipcperms (ipcp, S_IRUGO))
657 goto out;
658 tbuf.msg_perm = msq->msg_perm;
659 tbuf.msg_stime = msq->msg_stime;
660 tbuf.msg_rtime = msq->msg_rtime;
661 tbuf.msg_ctime = msq->msg_ctime;
662 tbuf.msg_cbytes = msq->msg_cbytes;
663 tbuf.msg_qnum = msq->msg_qnum;
664 tbuf.msg_qbytes = msq->msg_qbytes;
665 tbuf.msg_lspid = msq->msg_lspid;
666 tbuf.msg_lrpid = msq->msg_lrpid;
667 copy_to_user (buf, &tbuf, sizeof (*buf));
668 err = 0;
669 goto out;
670 case IPC_SET:
671 err = -EPERM;
672 if (!suser() && current->euid != ipcp->cuid &&
673 current->euid != ipcp->uid)
674 goto out;
675 if (tbuf.msg_qbytes > MSGMNB && !suser())
676 goto out;
677 msq->msg_qbytes = tbuf.msg_qbytes;
678 ipcp->uid = tbuf.msg_perm.uid;
679 ipcp->gid = tbuf.msg_perm.gid;
680 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
681 (S_IRWXUGO & tbuf.msg_perm.mode);
682 msq->msg_ctime = CURRENT_TIME;
683 err = 0;
684 goto out;
685 case IPC_RMID:
686 err = -EPERM;
687 if (!suser() && current->euid != ipcp->cuid &&
688 current->euid != ipcp->uid)
689 goto out;
690
691
692
693
694 if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
695 kerneld_msqid = -1;
696 freeque (id);
697 err = 0;
698 goto out;
699 default:
700 err = -EINVAL;
701 goto out;
702 }
703out:
704 unlock_kernel();
705 return err;
706}
707
708
709
710
711
712
713
714
715void kerneld_exit(void)
716{
717 int i;
718
719 if (kerneld_msqid == -1)
720 return;
721 for (i = 0; i < MAX_KERNELDS; ++i) {
722 if (kerneld_arr[i] == current->pid) {
723 kerneld_arr[i] = 0;
724 --n_kernelds;
725 if (n_kernelds == 0)
726 sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
727 break;
728 }
729 }
730}
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764int kerneld_send(int msgtype, int ret_size, int msgsz,
765 const char *text, const char *ret_val)
766{
767 int status = -ENOSYS;
768#ifdef CONFIG_KERNELD
769 static int id = KERNELD_MINSEQ;
770 struct kerneld_msg kmsp = { msgtype, NULL_KDHDR, (char *)text };
771 int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
772 unsigned long flags;
773
774 if (kerneld_msqid == -1)
775 return -ENODEV;
776
777
778 if (in_interrupt())
779 ret_size &= ~KERNELD_WAIT;
780#ifdef NEW_KERNELD_PROTOCOL
781 else
782 kmsp.pid = current->pid;
783#endif
784
785 msgsz += KDHDR;
786 if (ret_size & KERNELD_WAIT) {
787 save_flags(flags);
788 cli();
789 if (++id <= 0)
790 id = KERNELD_MINSEQ;
791 kmsp.id = id;
792 restore_flags(flags);
793 }
794
795 status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
796 if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
797 ret_size &= ~KERNELD_WAIT;
798 kmsp.text = (char *)ret_val;
799 status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
800 KDHDR + ((ret_val)?ret_size:0),
801 kmsp.id, msgflg);
802 if (status > 0)
803 status = kmsp.id;
804 }
805
806#endif
807 return status;
808}
809