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