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