3 * Copyright (C) 1992 Krishna Balasubramanian
6 #include <linux/errno.h>
7 #include <linux/sched.h>
9 #include <linux/stat.h>
10 #include <linux/malloc.h>
11 #include <linux/interrupt.h>
12 #include <linux/smp.h>
13 #include <linux/smp_lock.h>
14 #include <linux/init.h>
16 #include <asm/uaccess.h>
18 extern int ipcperms (struct ipc_perm
*ipcp
, short msgflg
);
20 static void freeque (int id
);
21 static int newque (key_t key
, int msgflg
);
22 static int findkey (key_t key
);
24 static struct msqid_ds
*msgque
[MSGMNI
];
25 static int msgbytes
= 0;
26 static int msghdrs
= 0;
27 static unsigned short msg_seq
= 0;
28 static int used_queues
= 0;
29 static int max_msqid
= 0;
30 static struct wait_queue
*msg_lock
= NULL
;
32 __initfunc(void msg_init (void))
36 for (id
= 0; id
< MSGMNI
; id
++)
37 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
38 msgbytes
= msghdrs
= msg_seq
= max_msqid
= used_queues
= 0;
43 static int real_msgsnd (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, int msgflg
)
47 struct ipc_perm
*ipcp
;
52 if (msgsz
> MSGMAX
|| (long) msgsz
< 0 || msqid
< 0)
56 err
= verify_area (VERIFY_READ
, msgp
->mtext
, msgsz
);
59 get_user(mtype
, &msgp
->mtype
);
62 id
= (unsigned int) msqid
% MSGMNI
;
64 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
66 ipcp
= &msq
->msg_perm
;
69 if (msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
)
72 if (ipcperms(ipcp
, S_IWUGO
))
75 if (msgsz
+ msq
->msg_cbytes
> msq
->msg_qbytes
) {
76 if (msgsz
+ msq
->msg_cbytes
> msq
->msg_qbytes
) {
77 /* still no space in queue */
78 if (msgflg
& IPC_NOWAIT
)
80 if (signal_pending(current
))
82 interruptible_sleep_on (&msq
->wwait
);
87 /* allocate message header and text space*/
88 msgh
= (struct msg
*) kmalloc (sizeof(*msgh
) + msgsz
, GFP_ATOMIC
);
91 msgh
->msg_spot
= (char *) (msgh
+ 1);
93 copy_from_user (msgh
->msg_spot
, msgp
->mtext
, msgsz
);
95 if (msgque
[id
] == IPC_UNUSED
|| msgque
[id
] == IPC_NOID
96 || msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
) {
101 msgh
->msg_next
= NULL
;
102 msgh
->msg_ts
= msgsz
;
103 msgh
->msg_type
= mtype
;
104 msgh
->msg_stime
= CURRENT_TIME
;
109 msq
->msg_first
= msq
->msg_last
= msgh
;
111 msq
->msg_last
->msg_next
= msgh
;
112 msq
->msg_last
= msgh
;
114 msq
->msg_cbytes
+= msgsz
;
118 msq
->msg_lspid
= current
->pid
;
119 msq
->msg_stime
= CURRENT_TIME
;
120 restore_flags(flags
);
121 wake_up (&msq
->rwait
);
125 static int real_msgrcv (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, long msgtyp
, int msgflg
)
127 struct msqid_ds
*msq
;
128 struct ipc_perm
*ipcp
;
129 struct msg
*tmsg
, *leastp
= NULL
;
130 struct msg
*nmsg
= NULL
;
134 if (msqid
< 0 || (long) msgsz
< 0)
136 if (!msgp
|| !msgp
->mtext
)
139 err
= verify_area (VERIFY_WRITE
, msgp
->mtext
, msgsz
);
143 id
= (unsigned int) msqid
% MSGMNI
;
145 if (msq
== IPC_NOID
|| msq
== IPC_UNUSED
)
147 ipcp
= &msq
->msg_perm
;
150 * find message of correct type.
151 * msgtyp = 0 => get first.
152 * msgtyp > 0 => get first message of matching type.
153 * msgtyp < 0 => get message with least type must be < abs(msgtype).
156 if (msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
) {
159 if (ipcperms (ipcp
, S_IRUGO
)) {
166 nmsg
= msq
->msg_first
;
167 else if (msgtyp
> 0) {
168 if (msgflg
& MSG_EXCEPT
) {
169 for (tmsg
= msq
->msg_first
; tmsg
;
170 tmsg
= tmsg
->msg_next
)
171 if (tmsg
->msg_type
!= msgtyp
)
175 for (tmsg
= msq
->msg_first
; tmsg
;
176 tmsg
= tmsg
->msg_next
)
177 if (tmsg
->msg_type
== msgtyp
)
182 for (leastp
= tmsg
= msq
->msg_first
; tmsg
;
183 tmsg
= tmsg
->msg_next
)
184 if (tmsg
->msg_type
< leastp
->msg_type
)
186 if (leastp
&& leastp
->msg_type
<= - msgtyp
)
189 restore_flags(flags
);
191 if (nmsg
) { /* done finding a message */
192 if ((msgsz
< nmsg
->msg_ts
) && !(msgflg
& MSG_NOERROR
)) {
195 msgsz
= (msgsz
> nmsg
->msg_ts
)? nmsg
->msg_ts
: msgsz
;
198 if (nmsg
== msq
->msg_first
)
199 msq
->msg_first
= nmsg
->msg_next
;
201 for (tmsg
= msq
->msg_first
; tmsg
;
202 tmsg
= tmsg
->msg_next
)
203 if (tmsg
->msg_next
== nmsg
)
205 tmsg
->msg_next
= nmsg
->msg_next
;
206 if (nmsg
== msq
->msg_last
)
207 msq
->msg_last
= tmsg
;
209 if (!(--msq
->msg_qnum
))
210 msq
->msg_last
= msq
->msg_first
= NULL
;
212 msq
->msg_rtime
= CURRENT_TIME
;
213 msq
->msg_lrpid
= current
->pid
;
214 msgbytes
-= nmsg
->msg_ts
;
216 msq
->msg_cbytes
-= nmsg
->msg_ts
;
217 restore_flags(flags
);
218 wake_up (&msq
->wwait
);
219 put_user (nmsg
->msg_type
, &msgp
->mtype
);
220 copy_to_user (msgp
->mtext
, nmsg
->msg_spot
, msgsz
);
223 } else { /* did not find a message */
224 if (msgflg
& IPC_NOWAIT
) {
227 if (signal_pending(current
)) {
230 interruptible_sleep_on (&msq
->rwait
);
236 asmlinkage
int sys_msgsnd (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, int msgflg
)
241 ret
= real_msgsnd(msqid
, msgp
, msgsz
, msgflg
);
246 asmlinkage
int sys_msgrcv (int msqid
, struct msgbuf
*msgp
, size_t msgsz
,
247 long msgtyp
, int msgflg
)
252 ret
= real_msgrcv (msqid
, msgp
, msgsz
, msgtyp
, msgflg
);
257 static int findkey (key_t key
)
260 struct msqid_ds
*msq
;
262 for (id
= 0; id
<= max_msqid
; id
++) {
263 while ((msq
= msgque
[id
]) == IPC_NOID
)
264 interruptible_sleep_on (&msg_lock
);
265 if (msq
== IPC_UNUSED
)
267 if (key
== msq
->msg_perm
.key
)
273 static int newque (key_t key
, int msgflg
)
276 struct msqid_ds
*msq
;
277 struct ipc_perm
*ipcp
;
279 for (id
= 0; id
< MSGMNI
; id
++)
280 if (msgque
[id
] == IPC_UNUSED
) {
281 msgque
[id
] = (struct msqid_ds
*) IPC_NOID
;
287 msq
= (struct msqid_ds
*) kmalloc (sizeof (*msq
), GFP_KERNEL
);
289 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
293 ipcp
= &msq
->msg_perm
;
294 ipcp
->mode
= (msgflg
& S_IRWXUGO
);
296 ipcp
->cuid
= ipcp
->uid
= current
->euid
;
297 ipcp
->gid
= ipcp
->cgid
= current
->egid
;
298 msq
->msg_perm
.seq
= msg_seq
;
299 msq
->msg_first
= msq
->msg_last
= NULL
;
300 msq
->rwait
= msq
->wwait
= NULL
;
301 msq
->msg_cbytes
= msq
->msg_qnum
= 0;
302 msq
->msg_lspid
= msq
->msg_lrpid
= 0;
303 msq
->msg_stime
= msq
->msg_rtime
= 0;
304 msq
->msg_qbytes
= MSGMNB
;
305 msq
->msg_ctime
= CURRENT_TIME
;
311 return (unsigned int) msq
->msg_perm
.seq
* MSGMNI
+ id
;
314 asmlinkage
int sys_msgget (key_t key
, int msgflg
)
316 int id
, ret
= -EPERM
;
317 struct msqid_ds
*msq
;
320 if (key
== IPC_PRIVATE
)
321 ret
= newque(key
, msgflg
);
322 else if ((id
= findkey (key
)) == -1) { /* key not used */
323 if (!(msgflg
& IPC_CREAT
))
326 ret
= newque(key
, msgflg
);
327 } else if (msgflg
& IPC_CREAT
&& msgflg
& IPC_EXCL
) {
331 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
333 else if (ipcperms(&msq
->msg_perm
, msgflg
))
336 ret
= (unsigned int) msq
->msg_perm
.seq
* MSGMNI
+ id
;
342 static void freeque (int id
)
344 struct msqid_ds
*msq
= msgque
[id
];
345 struct msg
*msgp
, *msgh
;
348 msg_seq
= (msg_seq
+1) % ((unsigned)(1<<31)/MSGMNI
); /* increment, but avoid overflow */
349 msgbytes
-= msq
->msg_cbytes
;
351 while (max_msqid
&& (msgque
[--max_msqid
] == IPC_UNUSED
));
352 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
354 while (waitqueue_active(&msq
->rwait
) || waitqueue_active(&msq
->wwait
)) {
355 wake_up (&msq
->rwait
);
356 wake_up (&msq
->wwait
);
359 for (msgp
= msq
->msg_first
; msgp
; msgp
= msgh
) {
360 msgh
= msgp
->msg_next
;
367 asmlinkage
int sys_msgctl (int msqid
, int cmd
, struct msqid_ds
*buf
)
369 int id
, err
= -EINVAL
;
370 struct msqid_ds
*msq
;
371 struct msqid_ds tbuf
;
372 struct ipc_perm
*ipcp
;
375 if (msqid
< 0 || cmd
< 0)
384 struct msginfo msginfo
;
385 msginfo
.msgmni
= MSGMNI
;
386 msginfo
.msgmax
= MSGMAX
;
387 msginfo
.msgmnb
= MSGMNB
;
388 msginfo
.msgmap
= MSGMAP
;
389 msginfo
.msgpool
= MSGPOOL
;
390 msginfo
.msgtql
= MSGTQL
;
391 msginfo
.msgssz
= MSGSSZ
;
392 msginfo
.msgseg
= MSGSEG
;
393 if (cmd
== MSG_INFO
) {
394 msginfo
.msgpool
= used_queues
;
395 msginfo
.msgmap
= msghdrs
;
396 msginfo
.msgtql
= msgbytes
;
398 err
= verify_area (VERIFY_WRITE
, buf
, sizeof (struct msginfo
));
401 copy_to_user (buf
, &msginfo
, sizeof(struct msginfo
));
408 err
= verify_area (VERIFY_WRITE
, buf
, sizeof (*buf
));
412 if (msqid
> max_msqid
)
415 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
418 if (ipcperms (&msq
->msg_perm
, S_IRUGO
))
420 id
= (unsigned int) msq
->msg_perm
.seq
* MSGMNI
+ msqid
;
421 tbuf
.msg_perm
= msq
->msg_perm
;
422 tbuf
.msg_stime
= msq
->msg_stime
;
423 tbuf
.msg_rtime
= msq
->msg_rtime
;
424 tbuf
.msg_ctime
= msq
->msg_ctime
;
425 tbuf
.msg_cbytes
= msq
->msg_cbytes
;
426 tbuf
.msg_qnum
= msq
->msg_qnum
;
427 tbuf
.msg_qbytes
= msq
->msg_qbytes
;
428 tbuf
.msg_lspid
= msq
->msg_lspid
;
429 tbuf
.msg_lrpid
= msq
->msg_lrpid
;
430 copy_to_user (buf
, &tbuf
, sizeof(*buf
));
436 err
= verify_area (VERIFY_READ
, buf
, sizeof (*buf
));
439 copy_from_user (&tbuf
, buf
, sizeof (*buf
));
444 err
= verify_area (VERIFY_WRITE
, buf
, sizeof(*buf
));
450 id
= (unsigned int) msqid
% MSGMNI
;
453 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
456 if (msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
)
458 ipcp
= &msq
->msg_perm
;
463 if (ipcperms (ipcp
, S_IRUGO
))
465 tbuf
.msg_perm
= msq
->msg_perm
;
466 tbuf
.msg_stime
= msq
->msg_stime
;
467 tbuf
.msg_rtime
= msq
->msg_rtime
;
468 tbuf
.msg_ctime
= msq
->msg_ctime
;
469 tbuf
.msg_cbytes
= msq
->msg_cbytes
;
470 tbuf
.msg_qnum
= msq
->msg_qnum
;
471 tbuf
.msg_qbytes
= msq
->msg_qbytes
;
472 tbuf
.msg_lspid
= msq
->msg_lspid
;
473 tbuf
.msg_lrpid
= msq
->msg_lrpid
;
474 copy_to_user (buf
, &tbuf
, sizeof (*buf
));
479 if (current
->euid
!= ipcp
->cuid
&&
480 current
->euid
!= ipcp
->uid
&& !capable(CAP_SYS_ADMIN
))
481 /* We _could_ check for CAP_CHOWN above, but we don't */
483 if (tbuf
.msg_qbytes
> MSGMNB
&& !capable(CAP_SYS_RESOURCE
))
485 msq
->msg_qbytes
= tbuf
.msg_qbytes
;
486 ipcp
->uid
= tbuf
.msg_perm
.uid
;
487 ipcp
->gid
= tbuf
.msg_perm
.gid
;
488 ipcp
->mode
= (ipcp
->mode
& ~S_IRWXUGO
) |
489 (S_IRWXUGO
& tbuf
.msg_perm
.mode
);
490 msq
->msg_ctime
= CURRENT_TIME
;
495 if (current
->euid
!= ipcp
->cuid
&&
496 current
->euid
!= ipcp
->uid
&& !capable(CAP_SYS_ADMIN
))