This source file includes following definitions.
- msg_init
- sys_msgsnd
- sys_msgrcv
- findkey
- newque
- sys_msgget
- freeque
- sys_msgctl
1
2
3
4
5
6 #include <linux/errno.h>
7 #include <linux/sched.h>
8 #include <linux/msg.h>
9 #include <linux/stat.h>
10 #include <linux/malloc.h>
11
12 #include <asm/segment.h>
13
14 extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
15
16 static void freeque (int id);
17 static int newque (key_t key, int msgflg);
18 static int findkey (key_t key);
19
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;
27
28 void msg_init (void)
29 {
30 int id;
31
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;
35 msg_lock = NULL;
36 return;
37 }
38
39 asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
40 {
41 int id, err;
42 struct msqid_ds *msq;
43 struct ipc_perm *ipcp;
44 struct msg *msgh;
45 long mtype;
46
47 if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
48 return -EINVAL;
49 if (!msgp)
50 return -EFAULT;
51 err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
52 if (err)
53 return err;
54 if ((mtype = get_user (&msgp->mtype)) < 1)
55 return -EINVAL;
56 id = (unsigned int) msqid % MSGMNI;
57 msq = msgque [id];
58 if (msq == IPC_UNUSED || msq == IPC_NOID)
59 return -EINVAL;
60 ipcp = &msq->msg_perm;
61
62 slept:
63 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
64 return -EIDRM;
65 if (ipcperms(ipcp, S_IWUGO))
66 return -EACCES;
67
68 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
69
70 if (msgflg & IPC_NOWAIT)
71 return -EAGAIN;
72 if (current->signal & ~current->blocked)
73 return -EINTR;
74 interruptible_sleep_on (&msq->wwait);
75 goto slept;
76 }
77
78
79 msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_USER);
80 if (!msgh)
81 return -ENOMEM;
82 msgh->msg_spot = (char *) (msgh + 1);
83 memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz);
84
85 if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
86 || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
87 kfree(msgh);
88 return -EIDRM;
89 }
90
91 msgh->msg_next = NULL;
92 if (!msq->msg_first)
93 msq->msg_first = msq->msg_last = msgh;
94 else {
95 msq->msg_last->msg_next = msgh;
96 msq->msg_last = msgh;
97 }
98 msgh->msg_ts = msgsz;
99 msgh->msg_type = mtype;
100 msq->msg_cbytes += msgsz;
101 msgbytes += msgsz;
102 msghdrs++;
103 msq->msg_qnum++;
104 msq->msg_lspid = current->pid;
105 msq->msg_stime = CURRENT_TIME;
106 if (msq->rwait)
107 wake_up (&msq->rwait);
108 return 0;
109 }
110
111 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp,
112 int msgflg)
113 {
114 struct msqid_ds *msq;
115 struct ipc_perm *ipcp;
116 struct msg *tmsg, *leastp = NULL;
117 struct msg *nmsg = NULL;
118 int id, err;
119
120 if (msqid < 0 || (long) msgsz < 0)
121 return -EINVAL;
122 if (!msgp || !msgp->mtext)
123 return -EFAULT;
124 err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
125 if (err)
126 return err;
127
128 id = (unsigned int) msqid % MSGMNI;
129 msq = msgque [id];
130 if (msq == IPC_NOID || msq == IPC_UNUSED)
131 return -EINVAL;
132 ipcp = &msq->msg_perm;
133
134
135
136
137
138
139
140 while (!nmsg) {
141 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
142 return -EIDRM;
143 if (ipcperms (ipcp, S_IRUGO))
144 return -EACCES;
145 if (msgtyp == 0)
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)
152 break;
153 nmsg = tmsg;
154 } else {
155 for (tmsg = msq->msg_first; tmsg;
156 tmsg = tmsg->msg_next)
157 if (tmsg->msg_type == msgtyp)
158 break;
159 nmsg = tmsg;
160 }
161 } else {
162 for (leastp = tmsg = msq->msg_first; tmsg;
163 tmsg = tmsg->msg_next)
164 if (tmsg->msg_type < leastp->msg_type)
165 leastp = tmsg;
166 if (leastp && leastp->msg_type <= - msgtyp)
167 nmsg = leastp;
168 }
169
170 if (nmsg) {
171 if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
172 return -E2BIG;
173 msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
174 if (nmsg == msq->msg_first)
175 msq->msg_first = nmsg->msg_next;
176 else {
177 for (tmsg = msq->msg_first; tmsg;
178 tmsg = tmsg->msg_next)
179 if (tmsg->msg_next == nmsg)
180 break;
181 tmsg->msg_next = nmsg->msg_next;
182 if (nmsg == msq->msg_last)
183 msq->msg_last = tmsg;
184 }
185 if (!(--msq->msg_qnum))
186 msq->msg_last = msq->msg_first = NULL;
187
188 msq->msg_rtime = CURRENT_TIME;
189 msq->msg_lrpid = current->pid;
190 msgbytes -= nmsg->msg_ts;
191 msghdrs--;
192 msq->msg_cbytes -= nmsg->msg_ts;
193 if (msq->wwait)
194 wake_up (&msq->wwait);
195 put_user (nmsg->msg_type, &msgp->mtype);
196 memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
197 kfree(nmsg);
198 return msgsz;
199 } else {
200 if (msgflg & IPC_NOWAIT)
201 return -ENOMSG;
202 if (current->signal & ~current->blocked)
203 return -EINTR;
204 interruptible_sleep_on (&msq->rwait);
205 }
206 }
207 return -1;
208 }
209
210
211 static int findkey (key_t key)
212 {
213 int id;
214 struct msqid_ds *msq;
215
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)
220 continue;
221 if (key == msq->msg_perm.key)
222 return id;
223 }
224 return -1;
225 }
226
227 static int newque (key_t key, int msgflg)
228 {
229 int id;
230 struct msqid_ds *msq;
231 struct ipc_perm *ipcp;
232
233 for (id = 0; id < MSGMNI; id++)
234 if (msgque[id] == IPC_UNUSED) {
235 msgque[id] = (struct msqid_ds *) IPC_NOID;
236 goto found;
237 }
238 return -ENOSPC;
239
240 found:
241 msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
242 if (!msq) {
243 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
244 if (msg_lock)
245 wake_up (&msg_lock);
246 return -ENOMEM;
247 }
248 ipcp = &msq->msg_perm;
249 ipcp->mode = (msgflg & S_IRWXUGO);
250 ipcp->key = key;
251 ipcp->cuid = ipcp->uid = current->euid;
252 ipcp->gid = ipcp->cgid = current->egid;
253 msq->msg_perm.seq = msg_seq;
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;
261 if (id > max_msqid)
262 max_msqid = id;
263 msgque[id] = msq;
264 used_queues++;
265 if (msg_lock)
266 wake_up (&msg_lock);
267 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
268 }
269
270 asmlinkage int sys_msgget (key_t key, int msgflg)
271 {
272 int id;
273 struct msqid_ds *msq;
274
275 if (key == IPC_PRIVATE)
276 return newque(key, msgflg);
277 if ((id = findkey (key)) == -1) {
278 if (!(msgflg & IPC_CREAT))
279 return -ENOENT;
280 return newque(key, msgflg);
281 }
282 if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
283 return -EEXIST;
284 msq = msgque[id];
285 if (msq == IPC_UNUSED || msq == IPC_NOID)
286 return -EIDRM;
287 if (ipcperms(&msq->msg_perm, msgflg))
288 return -EACCES;
289 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
290 }
291
292 static void freeque (int id)
293 {
294 struct msqid_ds *msq = msgque[id];
295 struct msg *msgp, *msgh;
296
297 msq->msg_perm.seq++;
298 msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI);
299 msgbytes -= msq->msg_cbytes;
300 if (id == max_msqid)
301 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
302 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
303 used_queues--;
304 while (msq->rwait || msq->wwait) {
305 if (msq->rwait)
306 wake_up (&msq->rwait);
307 if (msq->wwait)
308 wake_up (&msq->wwait);
309 schedule();
310 }
311 for (msgp = msq->msg_first; msgp; msgp = msgh ) {
312 msgh = msgp->msg_next;
313 msghdrs--;
314 kfree(msgp);
315 }
316 kfree(msq);
317 }
318
319 asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
320 {
321 int id, err;
322 struct msqid_ds *msq;
323 struct msqid_ds tbuf;
324 struct ipc_perm *ipcp;
325
326 if (msqid < 0 || cmd < 0)
327 return -EINVAL;
328 switch (cmd) {
329 case IPC_INFO:
330 case MSG_INFO:
331 if (!buf)
332 return -EFAULT;
333 {
334 struct msginfo msginfo;
335 msginfo.msgmni = MSGMNI;
336 msginfo.msgmax = MSGMAX;
337 msginfo.msgmnb = MSGMNB;
338 msginfo.msgmap = MSGMAP;
339 msginfo.msgpool = MSGPOOL;
340 msginfo.msgtql = MSGTQL;
341 msginfo.msgssz = MSGSSZ;
342 msginfo.msgseg = MSGSEG;
343 if (cmd == MSG_INFO) {
344 msginfo.msgpool = used_queues;
345 msginfo.msgmap = msghdrs;
346 msginfo.msgtql = msgbytes;
347 }
348 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
349 if (err)
350 return err;
351 memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
352 return max_msqid;
353 }
354 case MSG_STAT:
355 if (!buf)
356 return -EFAULT;
357 err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
358 if (err)
359 return err;
360 if (msqid > max_msqid)
361 return -EINVAL;
362 msq = msgque[msqid];
363 if (msq == IPC_UNUSED || msq == IPC_NOID)
364 return -EINVAL;
365 if (ipcperms (&msq->msg_perm, S_IRUGO))
366 return -EACCES;
367 id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
368 tbuf.msg_perm = msq->msg_perm;
369 tbuf.msg_stime = msq->msg_stime;
370 tbuf.msg_rtime = msq->msg_rtime;
371 tbuf.msg_ctime = msq->msg_ctime;
372 tbuf.msg_cbytes = msq->msg_cbytes;
373 tbuf.msg_qnum = msq->msg_qnum;
374 tbuf.msg_qbytes = msq->msg_qbytes;
375 tbuf.msg_lspid = msq->msg_lspid;
376 tbuf.msg_lrpid = msq->msg_lrpid;
377 memcpy_tofs (buf, &tbuf, sizeof(*buf));
378 return id;
379 case IPC_SET:
380 if (!buf)
381 return -EFAULT;
382 err = verify_area (VERIFY_READ, buf, sizeof (*buf));
383 if (err)
384 return err;
385 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
386 break;
387 case IPC_STAT:
388 if (!buf)
389 return -EFAULT;
390 err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
391 if (err)
392 return err;
393 break;
394 }
395
396 id = (unsigned int) msqid % MSGMNI;
397 msq = msgque [id];
398 if (msq == IPC_UNUSED || msq == IPC_NOID)
399 return -EINVAL;
400 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
401 return -EIDRM;
402 ipcp = &msq->msg_perm;
403
404 switch (cmd) {
405 case IPC_STAT:
406 if (ipcperms (ipcp, S_IRUGO))
407 return -EACCES;
408 tbuf.msg_perm = msq->msg_perm;
409 tbuf.msg_stime = msq->msg_stime;
410 tbuf.msg_rtime = msq->msg_rtime;
411 tbuf.msg_ctime = msq->msg_ctime;
412 tbuf.msg_cbytes = msq->msg_cbytes;
413 tbuf.msg_qnum = msq->msg_qnum;
414 tbuf.msg_qbytes = msq->msg_qbytes;
415 tbuf.msg_lspid = msq->msg_lspid;
416 tbuf.msg_lrpid = msq->msg_lrpid;
417 memcpy_tofs (buf, &tbuf, sizeof (*buf));
418 return 0;
419 case IPC_SET:
420 if (!suser() && current->euid != ipcp->cuid &&
421 current->euid != ipcp->uid)
422 return -EPERM;
423 if (tbuf.msg_qbytes > MSGMNB && !suser())
424 return -EPERM;
425 msq->msg_qbytes = tbuf.msg_qbytes;
426 ipcp->uid = tbuf.msg_perm.uid;
427 ipcp->gid = tbuf.msg_perm.gid;
428 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
429 (S_IRWXUGO & tbuf.msg_perm.mode);
430 msq->msg_ctime = CURRENT_TIME;
431 return 0;
432 case IPC_RMID:
433 if (!suser() && current->euid != ipcp->cuid &&
434 current->euid != ipcp->uid)
435 return -EPERM;
436 freeque (id);
437 return 0;
438 default:
439 return -EINVAL;
440 }
441 }