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>
12 #include <asm/segment.h>
14 extern int ipcperms (struct ipc_perm
*ipcp
, short msgflg
);
16 static void freeque (int id
);
17 static int newque (key_t key
, int msgflg
);
18 static int findkey (key_t key
);
20 static struct msqid_ds
*msgque
[MSGMNI
];
21 static int msgbytes
= 0;
22 static int msghdrs
= 0;
23 static unsigned short msg_seq
= 0;
24 static int used_queues
= 0;
25 static int max_msqid
= 0;
26 static struct wait_queue
*msg_lock
= NULL
;
32 for (id
=0; id
< MSGMNI
; id
++)
33 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
34 msgbytes
= msghdrs
= msg_seq
= max_msqid
= used_queues
= 0;
39 int sys_msgsnd (int msqid
, struct msgbuf
*msgp
, int msgsz
, int msgflg
)
43 struct ipc_perm
*ipcp
;
47 if (msgsz
> MSGMAX
|| msgsz
< 0 || msqid
< 0)
51 err
= verify_area (VERIFY_READ
, msgp
->mtext
, msgsz
);
54 if ((mtype
= get_fs_long (&msgp
->mtype
)) < 1)
58 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
60 ipcp
= &msq
->msg_perm
;
63 if (ipcp
->seq
!= (msqid
/ MSGMNI
))
65 if (ipcperms(ipcp
, S_IWUGO
))
68 if (msgsz
+ msq
->msg_cbytes
> msq
->msg_qbytes
) {
69 /* no space in queue */
70 if (msgflg
& IPC_NOWAIT
)
72 if (current
->signal
& ~current
->blocked
)
74 interruptible_sleep_on (&msq
->wwait
);
78 /* allocate message header and text space*/
79 msgh
= (struct msg
*) kmalloc (sizeof(*msgh
) + msgsz
, GFP_USER
);
82 msgh
->msg_spot
= (char *) (msgh
+ 1);
83 memcpy_fromfs (msgh
->msg_spot
, msgp
->mtext
, msgsz
);
85 if (msgque
[id
] == IPC_UNUSED
|| msgque
[id
] == IPC_NOID
86 || ipcp
->seq
!= msqid
/ MSGMNI
) {
87 kfree_s (msgh
, sizeof(*msgh
) + msgsz
);
91 msgh
->msg_next
= NULL
;
93 msq
->msg_first
= msq
->msg_last
= msgh
;
95 msq
->msg_last
->msg_next
= msgh
;
99 msgh
->msg_type
= mtype
;
100 msq
->msg_cbytes
+= msgsz
;
104 msq
->msg_lspid
= current
->pid
;
105 msq
->msg_stime
= CURRENT_TIME
;
107 wake_up (&msq
->rwait
);
111 int sys_msgrcv (int msqid
, struct msgbuf
*msgp
, int msgsz
, long msgtyp
,
114 struct msqid_ds
*msq
;
115 struct ipc_perm
*ipcp
;
116 struct msg
*tmsg
, *leastp
= NULL
;
117 struct msg
*nmsg
= NULL
;
120 if (msqid
< 0 || msgsz
< 0)
122 if (!msgp
|| !msgp
->mtext
)
124 err
= verify_area (VERIFY_WRITE
, msgp
->mtext
, msgsz
);
130 if (msq
== IPC_NOID
|| msq
== IPC_UNUSED
)
132 ipcp
= &msq
->msg_perm
;
135 * find message of correct type.
136 * msgtyp = 0 => get first.
137 * msgtyp > 0 => get first message of matching type.
138 * msgtyp < 0 => get message with least type must be < abs(msgtype).
141 if(ipcp
->seq
!= msqid
/ MSGMNI
)
143 if (ipcperms (ipcp
, S_IRUGO
))
146 nmsg
= msq
->msg_first
;
147 else if (msgtyp
> 0) {
148 if (msgflg
& MSG_EXCEPT
) {
149 for (tmsg
= msq
->msg_first
; tmsg
;
150 tmsg
= tmsg
->msg_next
)
151 if (tmsg
->msg_type
!= msgtyp
)
155 for (tmsg
= msq
->msg_first
; tmsg
;
156 tmsg
= tmsg
->msg_next
)
157 if (tmsg
->msg_type
== msgtyp
)
162 for (leastp
= tmsg
= msq
->msg_first
; tmsg
;
163 tmsg
= tmsg
->msg_next
)
164 if (tmsg
->msg_type
< leastp
->msg_type
)
166 if (leastp
&& leastp
->msg_type
<= - msgtyp
)
170 if (nmsg
) { /* done finding a message */
171 if ((msgsz
< nmsg
->msg_ts
) && !(msgflg
& MSG_NOERROR
))
173 msgsz
= (msgsz
> nmsg
->msg_ts
)? nmsg
->msg_ts
: msgsz
;
174 if (nmsg
== msq
->msg_first
)
175 msq
->msg_first
= nmsg
->msg_next
;
177 for (tmsg
= msq
->msg_first
; tmsg
;
178 tmsg
= tmsg
->msg_next
)
179 if (tmsg
->msg_next
== nmsg
)
181 tmsg
->msg_next
= nmsg
->msg_next
;
182 if (nmsg
== msq
->msg_last
)
183 msq
->msg_last
= tmsg
;
185 if (!(--msq
->msg_qnum
))
186 msq
->msg_last
= msq
->msg_first
= NULL
;
188 msq
->msg_rtime
= CURRENT_TIME
;
189 msq
->msg_lrpid
= current
->pid
;
190 msgbytes
-= nmsg
->msg_ts
;
192 msq
->msg_cbytes
-= nmsg
->msg_ts
;
194 wake_up (&msq
->wwait
);
195 put_fs_long (nmsg
->msg_type
, &msgp
->mtype
);
196 memcpy_tofs (msgp
->mtext
, nmsg
->msg_spot
, msgsz
);
197 kfree_s (nmsg
, sizeof(*nmsg
) + msgsz
);
199 } else { /* did not find a message */
200 if (msgflg
& IPC_NOWAIT
)
202 if (current
->signal
& ~current
->blocked
)
204 interruptible_sleep_on (&msq
->rwait
);
211 static int findkey (key_t key
)
214 struct msqid_ds
*msq
;
216 for (id
=0; id
<= max_msqid
; id
++) {
217 while ((msq
= msgque
[id
]) == IPC_NOID
)
218 interruptible_sleep_on (&msg_lock
);
219 if (msq
== IPC_UNUSED
)
221 if (key
== msq
->msg_perm
.key
)
227 static int newque (key_t key
, int msgflg
)
230 struct msqid_ds
*msq
;
231 struct ipc_perm
*ipcp
;
233 for (id
=0; id
< MSGMNI
; id
++)
234 if (msgque
[id
] == IPC_UNUSED
) {
235 msgque
[id
] = (struct msqid_ds
*) IPC_NOID
;
241 msq
= (struct msqid_ds
*) kmalloc (sizeof (*msq
), GFP_KERNEL
);
243 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
248 ipcp
= &msq
->msg_perm
;
249 ipcp
->mode
= (msgflg
& S_IRWXUGO
);
251 ipcp
->cuid
= ipcp
->uid
= current
->euid
;
252 ipcp
->gid
= ipcp
->cgid
= current
->egid
;
254 msq
->msg_first
= msq
->msg_last
= NULL
;
255 msq
->rwait
= msq
->wwait
= NULL
;
256 msq
->msg_cbytes
= msq
->msg_qnum
= 0;
257 msq
->msg_lspid
= msq
->msg_lrpid
= 0;
258 msq
->msg_stime
= msq
->msg_rtime
= 0;
259 msq
->msg_qbytes
= MSGMNB
;
260 msq
->msg_ctime
= CURRENT_TIME
;
267 return (int) msg_seq
* MSGMNI
+ id
;
270 int sys_msgget (key_t key
, int msgflg
)
273 struct msqid_ds
*msq
;
275 if (key
== IPC_PRIVATE
)
276 return newque(key
, msgflg
);
277 if ((id
= findkey (key
)) == -1) { /* key not used */
278 if (!(msgflg
& IPC_CREAT
))
280 return newque(key
, msgflg
);
282 if (msgflg
& IPC_CREAT
&& msgflg
& IPC_EXCL
)
285 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
287 if (ipcperms(&msq
->msg_perm
, msgflg
))
289 return msq
->msg_perm
.seq
* MSGMNI
+id
;
292 static void freeque (int id
)
294 struct msqid_ds
*msq
= msgque
[id
];
295 struct msg
*msgp
, *msgh
;
299 msgbytes
-= msq
->msg_cbytes
;
301 while (max_msqid
&& (msgque
[--max_msqid
] == IPC_UNUSED
));
302 msgque
[id
] = (struct msqid_ds
*) IPC_UNUSED
;
304 while (msq
->rwait
|| msq
->wwait
) {
306 wake_up (&msq
->rwait
);
308 wake_up (&msq
->wwait
);
311 for (msgp
= msq
->msg_first
; msgp
; msgp
= msgh
) {
312 msgh
= msgp
->msg_next
;
314 kfree_s (msgp
, sizeof(*msgp
) + msgp
->msg_ts
);
316 kfree_s (msq
, sizeof (*msq
));
319 int sys_msgctl (int msqid
, int cmd
, struct msqid_ds
*buf
)
322 struct msqid_ds
*msq
, tbuf
;
323 struct ipc_perm
*ipcp
;
325 if (msqid
< 0 || cmd
< 0)
333 struct msginfo msginfo
;
334 msginfo
.msgmni
= MSGMNI
;
335 msginfo
.msgmax
= MSGMAX
;
336 msginfo
.msgmnb
= MSGMNB
;
337 msginfo
.msgmap
= MSGMAP
;
338 msginfo
.msgpool
= MSGPOOL
;
339 msginfo
.msgtql
= MSGTQL
;
340 msginfo
.msgssz
= MSGSSZ
;
341 msginfo
.msgseg
= MSGSEG
;
342 if (cmd
== MSG_INFO
) {
343 msginfo
.msgpool
= used_queues
;
344 msginfo
.msgmap
= msghdrs
;
345 msginfo
.msgtql
= msgbytes
;
347 err
= verify_area (VERIFY_WRITE
, buf
, sizeof (struct msginfo
));
350 memcpy_tofs (buf
, &msginfo
, sizeof(struct msginfo
));
356 err
= verify_area (VERIFY_WRITE
, buf
, sizeof (*msq
));
359 if (msqid
> max_msqid
)
362 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
364 if (ipcperms (&msq
->msg_perm
, S_IRUGO
))
366 id
= msqid
+ msq
->msg_perm
.seq
* MSGMNI
;
367 memcpy_tofs (buf
, msq
, sizeof(*msq
));
372 memcpy_fromfs (&tbuf
, buf
, sizeof (*buf
));
377 err
= verify_area (VERIFY_WRITE
, buf
, sizeof(*msq
));
385 if (msq
== IPC_UNUSED
|| msq
== IPC_NOID
)
387 ipcp
= &msq
->msg_perm
;
388 if (ipcp
->seq
!= msqid
/ MSGMNI
)
393 if (ipcperms (ipcp
, S_IRUGO
))
395 memcpy_tofs (buf
, msq
, sizeof (*msq
));
398 case IPC_RMID
: case IPC_SET
:
399 if (!suser() && current
->euid
!= ipcp
->cuid
&&
400 current
->euid
!= ipcp
->uid
)
402 if (cmd
== IPC_RMID
) {
406 if (tbuf
.msg_qbytes
> MSGMNB
&& !suser())
408 msq
->msg_qbytes
= tbuf
.msg_qbytes
;
409 ipcp
->uid
= tbuf
.msg_perm
.uid
;
410 ipcp
->gid
= tbuf
.msg_perm
.gid
;
411 ipcp
->mode
= (ipcp
->mode
& ~S_IRWXUGO
) |
412 (S_IRWXUGO
& tbuf
.msg_perm
.mode
);
413 msq
->msg_ctime
= CURRENT_TIME
;