3 * Copyright (C) 1992 Krishna Balasubramanian
5 * Removed all the remaining kerneld mess
6 * Catch the -EFAULT stuff properly
7 * Use GFP_KERNEL for messages as in 1.2
8 * Fixed up the unchecked user space derefs
9 * Copyright (C) 1998 Alan Cox & Andi Kleen
13 #include <linux/errno.h>
14 #include <linux/sched.h>
15 #include <linux/msg.h>
16 #include <linux/stat.h>
17 #include <linux/malloc.h>
18 #include <linux/interrupt.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21 #include <linux/init.h>
23 #include <asm/uaccess.h>
25 extern int ipcperms (struct ipc_perm
*ipcp
, short msgflg
);
27 static void freeque (int id
);
28 static int newque (key_t key
, int msgflg
);
29 static int findkey (key_t key
);
31 static struct msqid_ds
*msgque
[MSGMNI
];
32 static int msgbytes
= 0;
33 static int msghdrs
= 0;
34 static unsigned short msg_seq
= 0;
35 static int used_queues
= 0;
36 static int max_msqid
= 0;
37 static struct wait_queue
*msg_lock
= NULL
;
39 void __init
msg_init (void)
43 for (id
= 0; id
< MSGMNI
; id
++)
44 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
45 msgbytes
= msghdrs
= msg_seq
= max_msqid
= used_queues
= 0;
50 static int real_msgsnd (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, int msgflg
)
54 struct ipc_perm
*ipcp
;
58 if (msgsz
> MSGMAX
|| (long) msgsz
< 0 || msqid
< 0)
60 if (get_user(mtype
, &msgp
->mtype
))
64 id
= (unsigned int) msqid
% MSGMNI
;
66 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
68 ipcp
= &msq
->msg_perm
;
71 if (msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
)
74 if (ipcperms(ipcp
, S_IWUGO
))
77 if (msgsz
+ msq
->msg_cbytes
> msq
->msg_qbytes
) {
78 if (msgsz
+ msq
->msg_cbytes
> msq
->msg_qbytes
) {
79 /* still no space in queue */
80 if (msgflg
& IPC_NOWAIT
)
82 if (signal_pending(current
))
84 interruptible_sleep_on (&msq
->wwait
);
89 /* allocate message header and text space*/
90 msgh
= (struct msg
*) kmalloc (sizeof(*msgh
) + msgsz
, GFP_KERNEL
);
93 msgh
->msg_spot
= (char *) (msgh
+ 1);
95 if (copy_from_user(msgh
->msg_spot
, msgp
->mtext
, msgsz
))
101 if (msgque
[id
] == IPC_UNUSED
|| msgque
[id
] == IPC_NOID
102 || msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
) {
107 msgh
->msg_next
= NULL
;
108 msgh
->msg_ts
= msgsz
;
109 msgh
->msg_type
= mtype
;
110 msgh
->msg_stime
= CURRENT_TIME
;
113 msq
->msg_first
= msq
->msg_last
= msgh
;
115 msq
->msg_last
->msg_next
= msgh
;
116 msq
->msg_last
= msgh
;
118 msq
->msg_cbytes
+= msgsz
;
122 msq
->msg_lspid
= current
->pid
;
123 msq
->msg_stime
= CURRENT_TIME
;
124 wake_up (&msq
->rwait
);
128 static int real_msgrcv (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, long msgtyp
, int msgflg
)
130 struct msqid_ds
*msq
;
131 struct ipc_perm
*ipcp
;
132 struct msg
*tmsg
, *leastp
= NULL
;
133 struct msg
*nmsg
= NULL
;
136 if (msqid
< 0 || (long) msgsz
< 0)
139 id
= (unsigned int) msqid
% MSGMNI
;
141 if (msq
== IPC_NOID
|| msq
== IPC_UNUSED
)
143 ipcp
= &msq
->msg_perm
;
146 * find message of correct type.
147 * msgtyp = 0 => get first.
148 * msgtyp > 0 => get first message of matching type.
149 * msgtyp < 0 => get message with least type must be < abs(msgtype).
152 if (msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
) {
155 if (ipcperms (ipcp
, S_IRUGO
)) {
160 nmsg
= msq
->msg_first
;
161 else if (msgtyp
> 0) {
162 if (msgflg
& MSG_EXCEPT
) {
163 for (tmsg
= msq
->msg_first
; tmsg
;
164 tmsg
= tmsg
->msg_next
)
165 if (tmsg
->msg_type
!= msgtyp
)
169 for (tmsg
= msq
->msg_first
; tmsg
;
170 tmsg
= tmsg
->msg_next
)
171 if (tmsg
->msg_type
== msgtyp
)
176 for (leastp
= tmsg
= msq
->msg_first
; tmsg
;
177 tmsg
= tmsg
->msg_next
)
178 if (tmsg
->msg_type
< leastp
->msg_type
)
180 if (leastp
&& leastp
->msg_type
<= - msgtyp
)
184 if (nmsg
) { /* done finding a message */
185 if ((msgsz
< nmsg
->msg_ts
) && !(msgflg
& MSG_NOERROR
)) {
188 msgsz
= (msgsz
> nmsg
->msg_ts
)? nmsg
->msg_ts
: msgsz
;
189 if (nmsg
== msq
->msg_first
)
190 msq
->msg_first
= nmsg
->msg_next
;
192 for (tmsg
= msq
->msg_first
; tmsg
;
193 tmsg
= tmsg
->msg_next
)
194 if (tmsg
->msg_next
== nmsg
)
196 tmsg
->msg_next
= nmsg
->msg_next
;
197 if (nmsg
== msq
->msg_last
)
198 msq
->msg_last
= tmsg
;
200 if (!(--msq
->msg_qnum
))
201 msq
->msg_last
= msq
->msg_first
= NULL
;
203 msq
->msg_rtime
= CURRENT_TIME
;
204 msq
->msg_lrpid
= current
->pid
;
205 msgbytes
-= nmsg
->msg_ts
;
207 msq
->msg_cbytes
-= nmsg
->msg_ts
;
208 wake_up (&msq
->wwait
);
209 if (put_user (nmsg
->msg_type
, &msgp
->mtype
) ||
210 copy_to_user (msgp
->mtext
, nmsg
->msg_spot
, msgsz
))
214 } else { /* did not find a message */
215 if (msgflg
& IPC_NOWAIT
) {
218 if (signal_pending(current
)) {
221 interruptible_sleep_on (&msq
->rwait
);
227 asmlinkage
int sys_msgsnd (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, int msgflg
)
232 ret
= real_msgsnd(msqid
, msgp
, msgsz
, msgflg
);
237 asmlinkage
int sys_msgrcv (int msqid
, struct msgbuf
*msgp
, size_t msgsz
,
238 long msgtyp
, int msgflg
)
243 ret
= real_msgrcv (msqid
, msgp
, msgsz
, msgtyp
, msgflg
);
248 static int findkey (key_t key
)
251 struct msqid_ds
*msq
;
253 for (id
= 0; id
<= max_msqid
; id
++) {
254 while ((msq
= msgque
[id
]) == IPC_NOID
)
255 interruptible_sleep_on (&msg_lock
);
256 if (msq
== IPC_UNUSED
)
258 if (key
== msq
->msg_perm
.key
)
264 static int newque (key_t key
, int msgflg
)
267 struct msqid_ds
*msq
;
268 struct ipc_perm
*ipcp
;
270 for (id
= 0; id
< MSGMNI
; id
++)
271 if (msgque
[id
] == IPC_UNUSED
) {
272 msgque
[id
] = (struct msqid_ds
*) IPC_NOID
;
278 msq
= (struct msqid_ds
*) kmalloc (sizeof (*msq
), GFP_KERNEL
);
280 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
284 ipcp
= &msq
->msg_perm
;
285 ipcp
->mode
= (msgflg
& S_IRWXUGO
);
287 ipcp
->cuid
= ipcp
->uid
= current
->euid
;
288 ipcp
->gid
= ipcp
->cgid
= current
->egid
;
289 msq
->msg_perm
.seq
= msg_seq
;
290 msq
->msg_first
= msq
->msg_last
= NULL
;
291 msq
->rwait
= msq
->wwait
= NULL
;
292 msq
->msg_cbytes
= msq
->msg_qnum
= 0;
293 msq
->msg_lspid
= msq
->msg_lrpid
= 0;
294 msq
->msg_stime
= msq
->msg_rtime
= 0;
295 msq
->msg_qbytes
= MSGMNB
;
296 msq
->msg_ctime
= CURRENT_TIME
;
302 return (unsigned int) msq
->msg_perm
.seq
* MSGMNI
+ id
;
305 asmlinkage
int sys_msgget (key_t key
, int msgflg
)
307 int id
, ret
= -EPERM
;
308 struct msqid_ds
*msq
;
311 if (key
== IPC_PRIVATE
)
312 ret
= newque(key
, msgflg
);
313 else if ((id
= findkey (key
)) == -1) { /* key not used */
314 if (!(msgflg
& IPC_CREAT
))
317 ret
= newque(key
, msgflg
);
318 } else if (msgflg
& IPC_CREAT
&& msgflg
& IPC_EXCL
) {
322 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
324 else if (ipcperms(&msq
->msg_perm
, msgflg
))
327 ret
= (unsigned int) msq
->msg_perm
.seq
* MSGMNI
+ id
;
333 static void freeque (int id
)
335 struct msqid_ds
*msq
= msgque
[id
];
336 struct msg
*msgp
, *msgh
;
339 msg_seq
= (msg_seq
+1) % ((unsigned)(1<<31)/MSGMNI
); /* increment, but avoid overflow */
340 msgbytes
-= msq
->msg_cbytes
;
342 while (max_msqid
&& (msgque
[--max_msqid
] == IPC_UNUSED
));
343 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
345 while (waitqueue_active(&msq
->rwait
) || waitqueue_active(&msq
->wwait
)) {
346 wake_up (&msq
->rwait
);
347 wake_up (&msq
->wwait
);
350 for (msgp
= msq
->msg_first
; msgp
; msgp
= msgh
) {
351 msgh
= msgp
->msg_next
;
358 asmlinkage
int sys_msgctl (int msqid
, int cmd
, struct msqid_ds
*buf
)
360 int id
, err
= -EINVAL
;
361 struct msqid_ds
*msq
;
362 struct msqid_ds tbuf
;
363 struct ipc_perm
*ipcp
;
366 if (msqid
< 0 || cmd
< 0)
375 struct msginfo msginfo
;
376 msginfo
.msgmni
= MSGMNI
;
377 msginfo
.msgmax
= MSGMAX
;
378 msginfo
.msgmnb
= MSGMNB
;
379 msginfo
.msgmap
= MSGMAP
;
380 msginfo
.msgpool
= MSGPOOL
;
381 msginfo
.msgtql
= MSGTQL
;
382 msginfo
.msgssz
= MSGSSZ
;
383 msginfo
.msgseg
= MSGSEG
;
384 if (cmd
== MSG_INFO
) {
385 msginfo
.msgpool
= used_queues
;
386 msginfo
.msgmap
= msghdrs
;
387 msginfo
.msgtql
= msgbytes
;
391 if (copy_to_user (buf
, &msginfo
, sizeof(struct msginfo
)))
400 if (msqid
> max_msqid
)
403 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
406 if (ipcperms (&msq
->msg_perm
, S_IRUGO
))
408 id
= (unsigned int) msq
->msg_perm
.seq
* MSGMNI
+ msqid
;
409 tbuf
.msg_perm
= msq
->msg_perm
;
410 tbuf
.msg_stime
= msq
->msg_stime
;
411 tbuf
.msg_rtime
= msq
->msg_rtime
;
412 tbuf
.msg_ctime
= msq
->msg_ctime
;
413 tbuf
.msg_cbytes
= msq
->msg_cbytes
;
414 tbuf
.msg_qnum
= msq
->msg_qnum
;
415 tbuf
.msg_qbytes
= msq
->msg_qbytes
;
416 tbuf
.msg_lspid
= msq
->msg_lspid
;
417 tbuf
.msg_lrpid
= msq
->msg_lrpid
;
419 if (copy_to_user (buf
, &tbuf
, sizeof(*buf
)))
427 if (!copy_from_user (&tbuf
, buf
, sizeof (*buf
)))
436 id
= (unsigned int) msqid
% MSGMNI
;
439 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
442 if (msq
->msg_perm
.seq
!= (unsigned int) msqid
/ MSGMNI
)
444 ipcp
= &msq
->msg_perm
;
449 if (ipcperms (ipcp
, S_IRUGO
))
451 tbuf
.msg_perm
= msq
->msg_perm
;
452 tbuf
.msg_stime
= msq
->msg_stime
;
453 tbuf
.msg_rtime
= msq
->msg_rtime
;
454 tbuf
.msg_ctime
= msq
->msg_ctime
;
455 tbuf
.msg_cbytes
= msq
->msg_cbytes
;
456 tbuf
.msg_qnum
= msq
->msg_qnum
;
457 tbuf
.msg_qbytes
= msq
->msg_qbytes
;
458 tbuf
.msg_lspid
= msq
->msg_lspid
;
459 tbuf
.msg_lrpid
= msq
->msg_lrpid
;
461 if (!copy_to_user (buf
, &tbuf
, sizeof (*buf
)))
466 if (current
->euid
!= ipcp
->cuid
&&
467 current
->euid
!= ipcp
->uid
&& !capable(CAP_SYS_ADMIN
))
468 /* We _could_ check for CAP_CHOWN above, but we don't */
470 if (tbuf
.msg_qbytes
> MSGMNB
&& !capable(CAP_SYS_RESOURCE
))
472 msq
->msg_qbytes
= tbuf
.msg_qbytes
;
473 ipcp
->uid
= tbuf
.msg_perm
.uid
;
474 ipcp
->gid
= tbuf
.msg_perm
.gid
;
475 ipcp
->mode
= (ipcp
->mode
& ~S_IRWXUGO
) |
476 (S_IRWXUGO
& tbuf
.msg_perm
.mode
);
477 msq
->msg_ctime
= CURRENT_TIME
;
482 if (current
->euid
!= ipcp
->cuid
&&
483 current
->euid
!= ipcp
->uid
&& !capable(CAP_SYS_ADMIN
))