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 int 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_s (msgh, sizeof(*msgh) + msgsz);
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_s (nmsg, sizeof(*nmsg) + msgsz);
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 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 if ((int)((++msg_seq + 1) * MSGMNI) < 0)
299 msg_seq = 0;
300 msgbytes -= msq->msg_cbytes;
301 if (id == max_msqid)
302 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
303 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
304 used_queues--;
305 while (msq->rwait || msq->wwait) {
306 if (msq->rwait)
307 wake_up (&msq->rwait);
308 if (msq->wwait)
309 wake_up (&msq->wwait);
310 schedule();
311 }
312 for (msgp = msq->msg_first; msgp; msgp = msgh ) {
313 msgh = msgp->msg_next;
314 msghdrs--;
315 kfree_s (msgp, sizeof(*msgp) + msgp->msg_ts);
316 }
317 kfree_s (msq, sizeof (*msq));
318 }
319
320 int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
321 {
322 int id, err;
323 struct msqid_ds *msq, 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 (*msq));
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 = msqid + msq->msg_perm.seq * MSGMNI;
368 memcpy_tofs (buf, msq, sizeof(*msq));
369 return id;
370 case IPC_SET:
371 if (!buf)
372 return -EFAULT;
373 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
374 break;
375 case IPC_STAT:
376 if (!buf)
377 return -EFAULT;
378 err = verify_area (VERIFY_WRITE, buf, sizeof(*msq));
379 if (err)
380 return err;
381 break;
382 }
383
384 id = msqid % MSGMNI;
385 msq = msgque [id];
386 if (msq == IPC_UNUSED || msq == IPC_NOID)
387 return -EINVAL;
388 ipcp = &msq->msg_perm;
389 if (ipcp->seq != msqid / MSGMNI)
390 return -EIDRM;
391
392 switch (cmd) {
393 case IPC_STAT:
394 if (ipcperms (ipcp, S_IRUGO))
395 return -EACCES;
396 memcpy_tofs (buf, msq, sizeof (*msq));
397 return 0;
398 break;
399 case IPC_RMID: case IPC_SET:
400 if (!suser() && current->euid != ipcp->cuid &&
401 current->euid != ipcp->uid)
402 return -EPERM;
403 if (cmd == IPC_RMID) {
404 freeque (id);
405 return 0;
406 }
407 if (tbuf.msg_qbytes > MSGMNB && !suser())
408 return -EPERM;
409 msq->msg_qbytes = tbuf.msg_qbytes;
410 ipcp->uid = tbuf.msg_perm.uid;
411 ipcp->gid = tbuf.msg_perm.gid;
412 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
413 (S_IRWXUGO & tbuf.msg_perm.mode);
414 msq->msg_ctime = CURRENT_TIME;
415 break;
416 default:
417 return -EINVAL;
418 break;
419 }
420 return 0;
421 }