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 int sys_msgsnd (int msqid, struct msgbuf *msgp, int 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 || 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_fs_long (&msgp->mtype)) < 1)
55 return -EINVAL;
56 id = 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 (ipcp->seq != (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 || ipcp->seq != 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 msgsz;
109 }
110
111 int sys_msgrcv (int msqid, struct msgbuf *msgp, int 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 || 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 = 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(ipcp->seq != 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_fs_long (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 ipcp->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 (int) msg_seq * MSGMNI + id;
268 }
269
270 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 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++;
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 int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
320 {
321 int id, err;
322 struct msqid_ds *msq, tbuf;
323 struct ipc_perm *ipcp;
324
325 if (msqid < 0 || cmd < 0)
326 return -EINVAL;
327 switch (cmd) {
328 case IPC_INFO:
329 case MSG_INFO:
330 if (!buf)
331 return -EFAULT;
332 {
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;
346 }
347 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
348 if (err)
349 return err;
350 memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
351 return max_msqid;
352 }
353 case MSG_STAT:
354 if (!buf)
355 return -EFAULT;
356 err = verify_area (VERIFY_WRITE, buf, sizeof (*msq));
357 if (err)
358 return err;
359 if (msqid > max_msqid)
360 return -EINVAL;
361 msq = msgque[msqid];
362 if (msq == IPC_UNUSED || msq == IPC_NOID)
363 return -EINVAL;
364 if (ipcperms (&msq->msg_perm, S_IRUGO))
365 return -EACCES;
366 id = msqid + msq->msg_perm.seq * MSGMNI;
367 memcpy_tofs (buf, msq, sizeof(*msq));
368 return id;
369 case IPC_SET:
370 if (!buf)
371 return -EFAULT;
372 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
373 break;
374 case IPC_STAT:
375 if (!buf)
376 return -EFAULT;
377 err = verify_area (VERIFY_WRITE, buf, sizeof(*msq));
378 if (err)
379 return err;
380 break;
381 }
382
383 id = msqid % MSGMNI;
384 msq = msgque [id];
385 if (msq == IPC_UNUSED || msq == IPC_NOID)
386 return -EINVAL;
387 ipcp = &msq->msg_perm;
388 if (ipcp->seq != msqid / MSGMNI)
389 return -EIDRM;
390
391 switch (cmd) {
392 case IPC_STAT:
393 if (ipcperms (ipcp, S_IRUGO))
394 return -EACCES;
395 memcpy_tofs (buf, msq, sizeof (*msq));
396 return 0;
397 break;
398 case IPC_RMID: case IPC_SET:
399 if (!suser() && current->euid != ipcp->cuid &&
400 current->euid != ipcp->uid)
401 return -EPERM;
402 if (cmd == IPC_RMID) {
403 freeque (id);
404 return 0;
405 }
406 if (tbuf.msg_qbytes > MSGMNB && !suser())
407 return -EPERM;
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;
414 break;
415 default:
416 return -EINVAL;
417 break;
418 }
419 return 0;
420 }