Deleted Added
full compact
sysv_msg.c (80670) sysv_msg.c (82607)
1/* $FreeBSD: head/sys/kern/sysv_msg.c 80670 2001-07-30 19:28:02Z asmodai $ */
1/* $FreeBSD: head/sys/kern/sysv_msg.c 82607 2001-08-31 00:02:18Z dillon $ */
2
3/*
4 * Implementation of SVID messages
5 *
6 * Author: Daniel Boulet
7 *
8 * Copyright 1993 Daniel Boulet and RTMX Inc.
9 *
10 * This system call was implemented by Daniel Boulet under contract from RTMX.
11 *
12 * Redistribution and use in source forms, with and without modification,
13 * are permitted provided that this entire comment appears intact.
14 *
15 * Redistribution in binary form may occur without any restrictions.
16 * Obviously, it would be nice if you gave credit where credit is due
17 * but requiring it would be too onerous.
18 *
19 * This software is provided ``AS IS'' without any warranties of any kind.
20 */
21
22#include "opt_sysvipc.h"
23
24#include <sys/param.h>
25#include <sys/systm.h>
26#include <sys/sysproto.h>
27#include <sys/kernel.h>
28#include <sys/proc.h>
2
3/*
4 * Implementation of SVID messages
5 *
6 * Author: Daniel Boulet
7 *
8 * Copyright 1993 Daniel Boulet and RTMX Inc.
9 *
10 * This system call was implemented by Daniel Boulet under contract from RTMX.
11 *
12 * Redistribution and use in source forms, with and without modification,
13 * are permitted provided that this entire comment appears intact.
14 *
15 * Redistribution in binary form may occur without any restrictions.
16 * Obviously, it would be nice if you gave credit where credit is due
17 * but requiring it would be too onerous.
18 *
19 * This software is provided ``AS IS'' without any warranties of any kind.
20 */
21
22#include "opt_sysvipc.h"
23
24#include <sys/param.h>
25#include <sys/systm.h>
26#include <sys/sysproto.h>
27#include <sys/kernel.h>
28#include <sys/proc.h>
29#include <sys/lock.h>
30#include <sys/mutex.h>
29#include <sys/msg.h>
30#include <sys/syscall.h>
31#include <sys/sysent.h>
32#include <sys/sysctl.h>
33#include <sys/malloc.h>
34#include <sys/jail.h>
35
36static MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
37
38static void msginit __P((void));
39static int msgunload __P((void));
40static int sysvmsg_modload __P((struct module *, int, void *));
41
42#define MSG_DEBUG
43#undef MSG_DEBUG_OK
44
45static void msg_freehdr __P((struct msg *msghdr));
46
47/* XXX casting to (sy_call_t *) is bogus, as usual. */
48static sy_call_t *msgcalls[] = {
49 (sy_call_t *)msgctl, (sy_call_t *)msgget,
50 (sy_call_t *)msgsnd, (sy_call_t *)msgrcv
51};
52
53struct msg {
54 struct msg *msg_next; /* next msg in the chain */
55 long msg_type; /* type of this message */
56 /* >0 -> type of this message */
57 /* 0 -> free header */
58 u_short msg_ts; /* size of this message */
59 short msg_spot; /* location of start of msg in buffer */
60};
61
62
63#ifndef MSGSSZ
64#define MSGSSZ 8 /* Each segment must be 2^N long */
65#endif
66#ifndef MSGSEG
67#define MSGSEG 2048 /* must be less than 32767 */
68#endif
69#define MSGMAX (MSGSSZ*MSGSEG)
70#ifndef MSGMNB
71#define MSGMNB 2048 /* max # of bytes in a queue */
72#endif
73#ifndef MSGMNI
74#define MSGMNI 40
75#endif
76#ifndef MSGTQL
77#define MSGTQL 40
78#endif
79
80/*
81 * Based on the configuration parameters described in an SVR2 (yes, two)
82 * config(1m) man page.
83 *
84 * Each message is broken up and stored in segments that are msgssz bytes
85 * long. For efficiency reasons, this should be a power of two. Also,
86 * it doesn't make sense if it is less than 8 or greater than about 256.
87 * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
88 * two between 8 and 1024 inclusive (and panic's if it isn't).
89 */
90struct msginfo msginfo = {
91 MSGMAX, /* max chars in a message */
92 MSGMNI, /* # of message queue identifiers */
93 MSGMNB, /* max chars in a queue */
94 MSGTQL, /* max messages in system */
95 MSGSSZ, /* size of a message segment */
96 /* (must be small power of 2 greater than 4) */
97 MSGSEG /* number of message segments */
98};
99
100/*
101 * macros to convert between msqid_ds's and msqid's.
102 * (specific to this implementation)
103 */
104#define MSQID(ix,ds) ((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
105#define MSQID_IX(id) ((id) & 0xffff)
106#define MSQID_SEQ(id) (((id) >> 16) & 0xffff)
107
108/*
109 * The rest of this file is specific to this particular implementation.
110 */
111
112struct msgmap {
113 short next; /* next segment in buffer */
114 /* -1 -> available */
115 /* 0..(MSGSEG-1) -> index of next segment */
116};
117
118#define MSG_LOCKED 01000 /* Is this msqid_ds locked? */
119
120static int nfree_msgmaps; /* # of free map entries */
121static short free_msgmaps; /* head of linked list of free map entries */
122static struct msg *free_msghdrs;/* list of free msg headers */
123static char *msgpool; /* MSGMAX byte long msg buffer pool */
124static struct msgmap *msgmaps; /* MSGSEG msgmap structures */
125static struct msg *msghdrs; /* MSGTQL msg headers */
126static struct msqid_ds *msqids; /* MSGMNI msqid_ds struct's */
127
128static void
129msginit()
130{
131 register int i;
132
133 msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
134 if (msgpool == NULL)
135 panic("msgpool is NULL");
136 msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
137 if (msgmaps == NULL)
138 panic("msgmaps is NULL");
139 msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
140 if (msghdrs == NULL)
141 panic("msghdrs is NULL");
142 msqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni, M_MSG, M_WAITOK);
143 if (msqids == NULL)
144 panic("msqids is NULL");
145
146 /*
147 * msginfo.msgssz should be a power of two for efficiency reasons.
148 * It is also pretty silly if msginfo.msgssz is less than 8
149 * or greater than about 256 so ...
150 */
151
152 i = 8;
153 while (i < 1024 && i != msginfo.msgssz)
154 i <<= 1;
155 if (i != msginfo.msgssz) {
156 printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
157 msginfo.msgssz);
158 panic("msginfo.msgssz not a small power of 2");
159 }
160
161 if (msginfo.msgseg > 32767) {
162 printf("msginfo.msgseg=%d\n", msginfo.msgseg);
163 panic("msginfo.msgseg > 32767");
164 }
165
166 if (msgmaps == NULL)
167 panic("msgmaps is NULL");
168
169 for (i = 0; i < msginfo.msgseg; i++) {
170 if (i > 0)
171 msgmaps[i-1].next = i;
172 msgmaps[i].next = -1; /* implies entry is available */
173 }
174 free_msgmaps = 0;
175 nfree_msgmaps = msginfo.msgseg;
176
177 if (msghdrs == NULL)
178 panic("msghdrs is NULL");
179
180 for (i = 0; i < msginfo.msgtql; i++) {
181 msghdrs[i].msg_type = 0;
182 if (i > 0)
183 msghdrs[i-1].msg_next = &msghdrs[i];
184 msghdrs[i].msg_next = NULL;
185 }
186 free_msghdrs = &msghdrs[0];
187
188 if (msqids == NULL)
189 panic("msqids is NULL");
190
191 for (i = 0; i < msginfo.msgmni; i++) {
192 msqids[i].msg_qbytes = 0; /* implies entry is available */
193 msqids[i].msg_perm.seq = 0; /* reset to a known value */
194 msqids[i].msg_perm.mode = 0;
195 }
196}
197
198static int
199msgunload()
200{
201 struct msqid_ds *msqptr;
202 int msqid;
203
204 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
205 /*
206 * Look for an unallocated and unlocked msqid_ds.
207 * msqid_ds's can be locked by msgsnd or msgrcv while
208 * they are copying the message in/out. We can't
209 * re-use the entry until they release it.
210 */
211 msqptr = &msqids[msqid];
212 if (msqptr->msg_qbytes != 0 ||
213 (msqptr->msg_perm.mode & MSG_LOCKED) != 0)
214 break;
215 }
216 if (msqid != msginfo.msgmni)
217 return (EBUSY);
218
219 free(msgpool, M_MSG);
220 free(msgmaps, M_MSG);
221 free(msghdrs, M_MSG);
222 free(msqids, M_MSG);
223 return (0);
224}
225
226
227static int
228sysvmsg_modload(struct module *module, int cmd, void *arg)
229{
230 int error = 0;
231
232 switch (cmd) {
233 case MOD_LOAD:
234 msginit();
235 break;
236 case MOD_UNLOAD:
237 error = msgunload();
238 break;
239 case MOD_SHUTDOWN:
240 break;
241 default:
242 error = EINVAL;
243 break;
244 }
245 return (error);
246}
247
248static moduledata_t sysvmsg_mod = {
249 "sysvmsg",
250 &sysvmsg_modload,
251 NULL
252};
253
254SYSCALL_MODULE_HELPER(msgsys, 6);
255SYSCALL_MODULE_HELPER(msgctl, 3);
256SYSCALL_MODULE_HELPER(msgget, 2);
257SYSCALL_MODULE_HELPER(msgsnd, 4);
258SYSCALL_MODULE_HELPER(msgrcv, 5);
259
260DECLARE_MODULE(sysvmsg, sysvmsg_mod,
261 SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
262MODULE_VERSION(sysvmsg, 1);
263
264/*
265 * Entry point for all MSG calls
31#include <sys/msg.h>
32#include <sys/syscall.h>
33#include <sys/sysent.h>
34#include <sys/sysctl.h>
35#include <sys/malloc.h>
36#include <sys/jail.h>
37
38static MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
39
40static void msginit __P((void));
41static int msgunload __P((void));
42static int sysvmsg_modload __P((struct module *, int, void *));
43
44#define MSG_DEBUG
45#undef MSG_DEBUG_OK
46
47static void msg_freehdr __P((struct msg *msghdr));
48
49/* XXX casting to (sy_call_t *) is bogus, as usual. */
50static sy_call_t *msgcalls[] = {
51 (sy_call_t *)msgctl, (sy_call_t *)msgget,
52 (sy_call_t *)msgsnd, (sy_call_t *)msgrcv
53};
54
55struct msg {
56 struct msg *msg_next; /* next msg in the chain */
57 long msg_type; /* type of this message */
58 /* >0 -> type of this message */
59 /* 0 -> free header */
60 u_short msg_ts; /* size of this message */
61 short msg_spot; /* location of start of msg in buffer */
62};
63
64
65#ifndef MSGSSZ
66#define MSGSSZ 8 /* Each segment must be 2^N long */
67#endif
68#ifndef MSGSEG
69#define MSGSEG 2048 /* must be less than 32767 */
70#endif
71#define MSGMAX (MSGSSZ*MSGSEG)
72#ifndef MSGMNB
73#define MSGMNB 2048 /* max # of bytes in a queue */
74#endif
75#ifndef MSGMNI
76#define MSGMNI 40
77#endif
78#ifndef MSGTQL
79#define MSGTQL 40
80#endif
81
82/*
83 * Based on the configuration parameters described in an SVR2 (yes, two)
84 * config(1m) man page.
85 *
86 * Each message is broken up and stored in segments that are msgssz bytes
87 * long. For efficiency reasons, this should be a power of two. Also,
88 * it doesn't make sense if it is less than 8 or greater than about 256.
89 * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
90 * two between 8 and 1024 inclusive (and panic's if it isn't).
91 */
92struct msginfo msginfo = {
93 MSGMAX, /* max chars in a message */
94 MSGMNI, /* # of message queue identifiers */
95 MSGMNB, /* max chars in a queue */
96 MSGTQL, /* max messages in system */
97 MSGSSZ, /* size of a message segment */
98 /* (must be small power of 2 greater than 4) */
99 MSGSEG /* number of message segments */
100};
101
102/*
103 * macros to convert between msqid_ds's and msqid's.
104 * (specific to this implementation)
105 */
106#define MSQID(ix,ds) ((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
107#define MSQID_IX(id) ((id) & 0xffff)
108#define MSQID_SEQ(id) (((id) >> 16) & 0xffff)
109
110/*
111 * The rest of this file is specific to this particular implementation.
112 */
113
114struct msgmap {
115 short next; /* next segment in buffer */
116 /* -1 -> available */
117 /* 0..(MSGSEG-1) -> index of next segment */
118};
119
120#define MSG_LOCKED 01000 /* Is this msqid_ds locked? */
121
122static int nfree_msgmaps; /* # of free map entries */
123static short free_msgmaps; /* head of linked list of free map entries */
124static struct msg *free_msghdrs;/* list of free msg headers */
125static char *msgpool; /* MSGMAX byte long msg buffer pool */
126static struct msgmap *msgmaps; /* MSGSEG msgmap structures */
127static struct msg *msghdrs; /* MSGTQL msg headers */
128static struct msqid_ds *msqids; /* MSGMNI msqid_ds struct's */
129
130static void
131msginit()
132{
133 register int i;
134
135 msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
136 if (msgpool == NULL)
137 panic("msgpool is NULL");
138 msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
139 if (msgmaps == NULL)
140 panic("msgmaps is NULL");
141 msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
142 if (msghdrs == NULL)
143 panic("msghdrs is NULL");
144 msqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni, M_MSG, M_WAITOK);
145 if (msqids == NULL)
146 panic("msqids is NULL");
147
148 /*
149 * msginfo.msgssz should be a power of two for efficiency reasons.
150 * It is also pretty silly if msginfo.msgssz is less than 8
151 * or greater than about 256 so ...
152 */
153
154 i = 8;
155 while (i < 1024 && i != msginfo.msgssz)
156 i <<= 1;
157 if (i != msginfo.msgssz) {
158 printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
159 msginfo.msgssz);
160 panic("msginfo.msgssz not a small power of 2");
161 }
162
163 if (msginfo.msgseg > 32767) {
164 printf("msginfo.msgseg=%d\n", msginfo.msgseg);
165 panic("msginfo.msgseg > 32767");
166 }
167
168 if (msgmaps == NULL)
169 panic("msgmaps is NULL");
170
171 for (i = 0; i < msginfo.msgseg; i++) {
172 if (i > 0)
173 msgmaps[i-1].next = i;
174 msgmaps[i].next = -1; /* implies entry is available */
175 }
176 free_msgmaps = 0;
177 nfree_msgmaps = msginfo.msgseg;
178
179 if (msghdrs == NULL)
180 panic("msghdrs is NULL");
181
182 for (i = 0; i < msginfo.msgtql; i++) {
183 msghdrs[i].msg_type = 0;
184 if (i > 0)
185 msghdrs[i-1].msg_next = &msghdrs[i];
186 msghdrs[i].msg_next = NULL;
187 }
188 free_msghdrs = &msghdrs[0];
189
190 if (msqids == NULL)
191 panic("msqids is NULL");
192
193 for (i = 0; i < msginfo.msgmni; i++) {
194 msqids[i].msg_qbytes = 0; /* implies entry is available */
195 msqids[i].msg_perm.seq = 0; /* reset to a known value */
196 msqids[i].msg_perm.mode = 0;
197 }
198}
199
200static int
201msgunload()
202{
203 struct msqid_ds *msqptr;
204 int msqid;
205
206 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
207 /*
208 * Look for an unallocated and unlocked msqid_ds.
209 * msqid_ds's can be locked by msgsnd or msgrcv while
210 * they are copying the message in/out. We can't
211 * re-use the entry until they release it.
212 */
213 msqptr = &msqids[msqid];
214 if (msqptr->msg_qbytes != 0 ||
215 (msqptr->msg_perm.mode & MSG_LOCKED) != 0)
216 break;
217 }
218 if (msqid != msginfo.msgmni)
219 return (EBUSY);
220
221 free(msgpool, M_MSG);
222 free(msgmaps, M_MSG);
223 free(msghdrs, M_MSG);
224 free(msqids, M_MSG);
225 return (0);
226}
227
228
229static int
230sysvmsg_modload(struct module *module, int cmd, void *arg)
231{
232 int error = 0;
233
234 switch (cmd) {
235 case MOD_LOAD:
236 msginit();
237 break;
238 case MOD_UNLOAD:
239 error = msgunload();
240 break;
241 case MOD_SHUTDOWN:
242 break;
243 default:
244 error = EINVAL;
245 break;
246 }
247 return (error);
248}
249
250static moduledata_t sysvmsg_mod = {
251 "sysvmsg",
252 &sysvmsg_modload,
253 NULL
254};
255
256SYSCALL_MODULE_HELPER(msgsys, 6);
257SYSCALL_MODULE_HELPER(msgctl, 3);
258SYSCALL_MODULE_HELPER(msgget, 2);
259SYSCALL_MODULE_HELPER(msgsnd, 4);
260SYSCALL_MODULE_HELPER(msgrcv, 5);
261
262DECLARE_MODULE(sysvmsg, sysvmsg_mod,
263 SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
264MODULE_VERSION(sysvmsg, 1);
265
266/*
267 * Entry point for all MSG calls
268 *
269 * MPSAFE
266 */
267int
268msgsys(p, uap)
269 struct proc *p;
270 /* XXX actually varargs. */
271 struct msgsys_args /* {
272 u_int which;
273 int a2;
274 int a3;
275 int a4;
276 int a5;
277 int a6;
278 } */ *uap;
279{
270 */
271int
272msgsys(p, uap)
273 struct proc *p;
274 /* XXX actually varargs. */
275 struct msgsys_args /* {
276 u_int which;
277 int a2;
278 int a3;
279 int a4;
280 int a5;
281 int a6;
282 } */ *uap;
283{
284 int error;
280
285
281 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
282 return (ENOSYS);
286 mtx_lock(&Giant);
283
287
284 if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
285 return (EINVAL);
286 return ((*msgcalls[uap->which])(p, &uap->a2));
288 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) {
289 error = ENOSYS;
290 goto done2;
291 }
292 if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0])) {
293 error = EINVAL;
294 goto done2;
295 }
296 error = (*msgcalls[uap->which])(p, &uap->a2);
297done2:
298 mtx_unlock(&Giant);
299 return (error);
287}
288
289static void
290msg_freehdr(msghdr)
291 struct msg *msghdr;
292{
293 while (msghdr->msg_ts > 0) {
294 short next;
295 if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
296 panic("msghdr->msg_spot out of range");
297 next = msgmaps[msghdr->msg_spot].next;
298 msgmaps[msghdr->msg_spot].next = free_msgmaps;
299 free_msgmaps = msghdr->msg_spot;
300 nfree_msgmaps++;
301 msghdr->msg_spot = next;
302 if (msghdr->msg_ts >= msginfo.msgssz)
303 msghdr->msg_ts -= msginfo.msgssz;
304 else
305 msghdr->msg_ts = 0;
306 }
307 if (msghdr->msg_spot != -1)
308 panic("msghdr->msg_spot != -1");
309 msghdr->msg_next = free_msghdrs;
310 free_msghdrs = msghdr;
311}
312
313#ifndef _SYS_SYSPROTO_H_
314struct msgctl_args {
315 int msqid;
316 int cmd;
317 struct msqid_ds *buf;
318};
319#endif
320
300}
301
302static void
303msg_freehdr(msghdr)
304 struct msg *msghdr;
305{
306 while (msghdr->msg_ts > 0) {
307 short next;
308 if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
309 panic("msghdr->msg_spot out of range");
310 next = msgmaps[msghdr->msg_spot].next;
311 msgmaps[msghdr->msg_spot].next = free_msgmaps;
312 free_msgmaps = msghdr->msg_spot;
313 nfree_msgmaps++;
314 msghdr->msg_spot = next;
315 if (msghdr->msg_ts >= msginfo.msgssz)
316 msghdr->msg_ts -= msginfo.msgssz;
317 else
318 msghdr->msg_ts = 0;
319 }
320 if (msghdr->msg_spot != -1)
321 panic("msghdr->msg_spot != -1");
322 msghdr->msg_next = free_msghdrs;
323 free_msghdrs = msghdr;
324}
325
326#ifndef _SYS_SYSPROTO_H_
327struct msgctl_args {
328 int msqid;
329 int cmd;
330 struct msqid_ds *buf;
331};
332#endif
333
334/*
335 * MPSAFE
336 */
321int
322msgctl(p, uap)
323 struct proc *p;
324 register struct msgctl_args *uap;
325{
326 int msqid = uap->msqid;
327 int cmd = uap->cmd;
328 struct msqid_ds *user_msqptr = uap->buf;
337int
338msgctl(p, uap)
339 struct proc *p;
340 register struct msgctl_args *uap;
341{
342 int msqid = uap->msqid;
343 int cmd = uap->cmd;
344 struct msqid_ds *user_msqptr = uap->buf;
329 int rval, eval;
345 int rval, error;
330 struct msqid_ds msqbuf;
331 register struct msqid_ds *msqptr;
332
333#ifdef MSG_DEBUG_OK
334 printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr);
335#endif
346 struct msqid_ds msqbuf;
347 register struct msqid_ds *msqptr;
348
349#ifdef MSG_DEBUG_OK
350 printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr);
351#endif
352 mtx_lock(&Giant);
336
353
337 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
338 return (ENOSYS);
354 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) {
355 error = ENOSYS;
356 goto done2;
357 }
339
340 msqid = IPCID_TO_IX(msqid);
341
342 if (msqid < 0 || msqid >= msginfo.msgmni) {
343#ifdef MSG_DEBUG_OK
344 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
345 msginfo.msgmni);
346#endif
358
359 msqid = IPCID_TO_IX(msqid);
360
361 if (msqid < 0 || msqid >= msginfo.msgmni) {
362#ifdef MSG_DEBUG_OK
363 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
364 msginfo.msgmni);
365#endif
347 return(EINVAL);
366 error = EINVAL;
367 goto done2;
348 }
349
350 msqptr = &msqids[msqid];
351
352 if (msqptr->msg_qbytes == 0) {
353#ifdef MSG_DEBUG_OK
354 printf("no such msqid\n");
355#endif
368 }
369
370 msqptr = &msqids[msqid];
371
372 if (msqptr->msg_qbytes == 0) {
373#ifdef MSG_DEBUG_OK
374 printf("no such msqid\n");
375#endif
356 return(EINVAL);
376 error = EINVAL;
377 goto done2;
357 }
358 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
359#ifdef MSG_DEBUG_OK
360 printf("wrong sequence number\n");
361#endif
378 }
379 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
380#ifdef MSG_DEBUG_OK
381 printf("wrong sequence number\n");
382#endif
362 return(EINVAL);
383 error = EINVAL;
384 goto done2;
363 }
364
385 }
386
365 eval = 0;
387 error = 0;
366 rval = 0;
367
368 switch (cmd) {
369
370 case IPC_RMID:
371 {
372 struct msg *msghdr;
388 rval = 0;
389
390 switch (cmd) {
391
392 case IPC_RMID:
393 {
394 struct msg *msghdr;
373 if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_M)))
374 return(eval);
395 if ((error = ipcperm(p, &msqptr->msg_perm, IPC_M)))
396 goto done2;
375 /* Free the message headers */
376 msghdr = msqptr->msg_first;
377 while (msghdr != NULL) {
378 struct msg *msghdr_tmp;
379
380 /* Free the segments of each message */
381 msqptr->msg_cbytes -= msghdr->msg_ts;
382 msqptr->msg_qnum--;
383 msghdr_tmp = msghdr;
384 msghdr = msghdr->msg_next;
385 msg_freehdr(msghdr_tmp);
386 }
387
388 if (msqptr->msg_cbytes != 0)
389 panic("msg_cbytes is screwed up");
390 if (msqptr->msg_qnum != 0)
391 panic("msg_qnum is screwed up");
392
393 msqptr->msg_qbytes = 0; /* Mark it as free */
394
395 wakeup((caddr_t)msqptr);
396 }
397
398 break;
399
400 case IPC_SET:
397 /* Free the message headers */
398 msghdr = msqptr->msg_first;
399 while (msghdr != NULL) {
400 struct msg *msghdr_tmp;
401
402 /* Free the segments of each message */
403 msqptr->msg_cbytes -= msghdr->msg_ts;
404 msqptr->msg_qnum--;
405 msghdr_tmp = msghdr;
406 msghdr = msghdr->msg_next;
407 msg_freehdr(msghdr_tmp);
408 }
409
410 if (msqptr->msg_cbytes != 0)
411 panic("msg_cbytes is screwed up");
412 if (msqptr->msg_qnum != 0)
413 panic("msg_qnum is screwed up");
414
415 msqptr->msg_qbytes = 0; /* Mark it as free */
416
417 wakeup((caddr_t)msqptr);
418 }
419
420 break;
421
422 case IPC_SET:
401 if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_M)))
402 return(eval);
403 if ((eval = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
404 return(eval);
423 if ((error = ipcperm(p, &msqptr->msg_perm, IPC_M)))
424 goto done2;
425 if ((error = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0)
426 goto done2;
405 if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
427 if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
406 eval = suser(p);
407 if (eval)
408 return(eval);
428 error = suser(p);
429 if (error)
430 goto done2;
409 }
410 if (msqbuf.msg_qbytes > msginfo.msgmnb) {
411#ifdef MSG_DEBUG_OK
412 printf("can't increase msg_qbytes beyond %d (truncating)\n",
413 msginfo.msgmnb);
414#endif
415 msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */
416 }
417 if (msqbuf.msg_qbytes == 0) {
418#ifdef MSG_DEBUG_OK
419 printf("can't reduce msg_qbytes to 0\n");
420#endif
431 }
432 if (msqbuf.msg_qbytes > msginfo.msgmnb) {
433#ifdef MSG_DEBUG_OK
434 printf("can't increase msg_qbytes beyond %d (truncating)\n",
435 msginfo.msgmnb);
436#endif
437 msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */
438 }
439 if (msqbuf.msg_qbytes == 0) {
440#ifdef MSG_DEBUG_OK
441 printf("can't reduce msg_qbytes to 0\n");
442#endif
421 return(EINVAL); /* non-standard errno! */
443 error = EINVAL; /* non-standard errno! */
444 goto done2;
422 }
423 msqptr->msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */
424 msqptr->msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */
425 msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
426 (msqbuf.msg_perm.mode & 0777);
427 msqptr->msg_qbytes = msqbuf.msg_qbytes;
428 msqptr->msg_ctime = time_second;
429 break;
430
431 case IPC_STAT:
445 }
446 msqptr->msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */
447 msqptr->msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */
448 msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
449 (msqbuf.msg_perm.mode & 0777);
450 msqptr->msg_qbytes = msqbuf.msg_qbytes;
451 msqptr->msg_ctime = time_second;
452 break;
453
454 case IPC_STAT:
432 if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
455 if ((error = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
433#ifdef MSG_DEBUG_OK
434 printf("requester doesn't have read access\n");
435#endif
456#ifdef MSG_DEBUG_OK
457 printf("requester doesn't have read access\n");
458#endif
436 return(eval);
459 goto done2;
437 }
460 }
438 eval = copyout((caddr_t)msqptr, user_msqptr,
461 error = copyout((caddr_t)msqptr, user_msqptr,
439 sizeof(struct msqid_ds));
440 break;
441
442 default:
443#ifdef MSG_DEBUG_OK
444 printf("invalid command %d\n", cmd);
445#endif
462 sizeof(struct msqid_ds));
463 break;
464
465 default:
466#ifdef MSG_DEBUG_OK
467 printf("invalid command %d\n", cmd);
468#endif
446 return(EINVAL);
469 error = EINVAL;
470 goto done2;
447 }
448
471 }
472
449 if (eval == 0)
473 if (error == 0)
450 p->p_retval[0] = rval;
474 p->p_retval[0] = rval;
451 return(eval);
475done2:
476 mtx_unlock(&Giant);
477 return(error);
452}
453
454#ifndef _SYS_SYSPROTO_H_
455struct msgget_args {
456 key_t key;
457 int msgflg;
458};
459#endif
460
478}
479
480#ifndef _SYS_SYSPROTO_H_
481struct msgget_args {
482 key_t key;
483 int msgflg;
484};
485#endif
486
487/*
488 * MPSAFE
489 */
461int
462msgget(p, uap)
463 struct proc *p;
464 register struct msgget_args *uap;
465{
490int
491msgget(p, uap)
492 struct proc *p;
493 register struct msgget_args *uap;
494{
466 int msqid, eval;
495 int msqid, error = 0;
467 int key = uap->key;
468 int msgflg = uap->msgflg;
469 struct ucred *cred = p->p_ucred;
470 register struct msqid_ds *msqptr = NULL;
471
472#ifdef MSG_DEBUG_OK
473 printf("msgget(0x%x, 0%o)\n", key, msgflg);
474#endif
475
496 int key = uap->key;
497 int msgflg = uap->msgflg;
498 struct ucred *cred = p->p_ucred;
499 register struct msqid_ds *msqptr = NULL;
500
501#ifdef MSG_DEBUG_OK
502 printf("msgget(0x%x, 0%o)\n", key, msgflg);
503#endif
504
476 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
477 return (ENOSYS);
505 mtx_lock(&Giant);
478
506
507 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) {
508 error = ENOSYS;
509 goto done2;
510 }
511
479 if (key != IPC_PRIVATE) {
480 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
481 msqptr = &msqids[msqid];
482 if (msqptr->msg_qbytes != 0 &&
483 msqptr->msg_perm.key == key)
484 break;
485 }
486 if (msqid < msginfo.msgmni) {
487#ifdef MSG_DEBUG_OK
488 printf("found public key\n");
489#endif
490 if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
491#ifdef MSG_DEBUG_OK
492 printf("not exclusive\n");
493#endif
512 if (key != IPC_PRIVATE) {
513 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
514 msqptr = &msqids[msqid];
515 if (msqptr->msg_qbytes != 0 &&
516 msqptr->msg_perm.key == key)
517 break;
518 }
519 if (msqid < msginfo.msgmni) {
520#ifdef MSG_DEBUG_OK
521 printf("found public key\n");
522#endif
523 if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
524#ifdef MSG_DEBUG_OK
525 printf("not exclusive\n");
526#endif
494 return(EEXIST);
527 error = EEXIST;
528 goto done2;
495 }
529 }
496 if ((eval = ipcperm(p, &msqptr->msg_perm, msgflg & 0700 ))) {
530 if ((error = ipcperm(p, &msqptr->msg_perm, msgflg & 0700 ))) {
497#ifdef MSG_DEBUG_OK
498 printf("requester doesn't have 0%o access\n",
499 msgflg & 0700);
500#endif
531#ifdef MSG_DEBUG_OK
532 printf("requester doesn't have 0%o access\n",
533 msgflg & 0700);
534#endif
501 return(eval);
535 goto done2;
502 }
503 goto found;
504 }
505 }
506
507#ifdef MSG_DEBUG_OK
508 printf("need to allocate the msqid_ds\n");
509#endif
510 if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
511 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
512 /*
513 * Look for an unallocated and unlocked msqid_ds.
514 * msqid_ds's can be locked by msgsnd or msgrcv while
515 * they are copying the message in/out. We can't
516 * re-use the entry until they release it.
517 */
518 msqptr = &msqids[msqid];
519 if (msqptr->msg_qbytes == 0 &&
520 (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
521 break;
522 }
523 if (msqid == msginfo.msgmni) {
524#ifdef MSG_DEBUG_OK
525 printf("no more msqid_ds's available\n");
526#endif
536 }
537 goto found;
538 }
539 }
540
541#ifdef MSG_DEBUG_OK
542 printf("need to allocate the msqid_ds\n");
543#endif
544 if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
545 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
546 /*
547 * Look for an unallocated and unlocked msqid_ds.
548 * msqid_ds's can be locked by msgsnd or msgrcv while
549 * they are copying the message in/out. We can't
550 * re-use the entry until they release it.
551 */
552 msqptr = &msqids[msqid];
553 if (msqptr->msg_qbytes == 0 &&
554 (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
555 break;
556 }
557 if (msqid == msginfo.msgmni) {
558#ifdef MSG_DEBUG_OK
559 printf("no more msqid_ds's available\n");
560#endif
527 return(ENOSPC);
561 error = ENOSPC;
562 goto done2;
528 }
529#ifdef MSG_DEBUG_OK
530 printf("msqid %d is available\n", msqid);
531#endif
532 msqptr->msg_perm.key = key;
533 msqptr->msg_perm.cuid = cred->cr_uid;
534 msqptr->msg_perm.uid = cred->cr_uid;
535 msqptr->msg_perm.cgid = cred->cr_gid;
536 msqptr->msg_perm.gid = cred->cr_gid;
537 msqptr->msg_perm.mode = (msgflg & 0777);
538 /* Make sure that the returned msqid is unique */
539 msqptr->msg_perm.seq++;
540 msqptr->msg_first = NULL;
541 msqptr->msg_last = NULL;
542 msqptr->msg_cbytes = 0;
543 msqptr->msg_qnum = 0;
544 msqptr->msg_qbytes = msginfo.msgmnb;
545 msqptr->msg_lspid = 0;
546 msqptr->msg_lrpid = 0;
547 msqptr->msg_stime = 0;
548 msqptr->msg_rtime = 0;
549 msqptr->msg_ctime = time_second;
550 } else {
551#ifdef MSG_DEBUG_OK
552 printf("didn't find it and wasn't asked to create it\n");
553#endif
563 }
564#ifdef MSG_DEBUG_OK
565 printf("msqid %d is available\n", msqid);
566#endif
567 msqptr->msg_perm.key = key;
568 msqptr->msg_perm.cuid = cred->cr_uid;
569 msqptr->msg_perm.uid = cred->cr_uid;
570 msqptr->msg_perm.cgid = cred->cr_gid;
571 msqptr->msg_perm.gid = cred->cr_gid;
572 msqptr->msg_perm.mode = (msgflg & 0777);
573 /* Make sure that the returned msqid is unique */
574 msqptr->msg_perm.seq++;
575 msqptr->msg_first = NULL;
576 msqptr->msg_last = NULL;
577 msqptr->msg_cbytes = 0;
578 msqptr->msg_qnum = 0;
579 msqptr->msg_qbytes = msginfo.msgmnb;
580 msqptr->msg_lspid = 0;
581 msqptr->msg_lrpid = 0;
582 msqptr->msg_stime = 0;
583 msqptr->msg_rtime = 0;
584 msqptr->msg_ctime = time_second;
585 } else {
586#ifdef MSG_DEBUG_OK
587 printf("didn't find it and wasn't asked to create it\n");
588#endif
554 return(ENOENT);
589 error = ENOENT;
590 goto done2;
555 }
556
557found:
558 /* Construct the unique msqid */
559 p->p_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
591 }
592
593found:
594 /* Construct the unique msqid */
595 p->p_retval[0] = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
560 return(0);
596done2:
597 mtx_unlock(&Giant);
598 return (error);
561}
562
563#ifndef _SYS_SYSPROTO_H_
564struct msgsnd_args {
565 int msqid;
566 void *msgp;
567 size_t msgsz;
568 int msgflg;
569};
570#endif
571
599}
600
601#ifndef _SYS_SYSPROTO_H_
602struct msgsnd_args {
603 int msqid;
604 void *msgp;
605 size_t msgsz;
606 int msgflg;
607};
608#endif
609
610/*
611 * MPSAFE
612 */
572int
573msgsnd(p, uap)
574 struct proc *p;
575 register struct msgsnd_args *uap;
576{
577 int msqid = uap->msqid;
578 void *user_msgp = uap->msgp;
579 size_t msgsz = uap->msgsz;
580 int msgflg = uap->msgflg;
613int
614msgsnd(p, uap)
615 struct proc *p;
616 register struct msgsnd_args *uap;
617{
618 int msqid = uap->msqid;
619 void *user_msgp = uap->msgp;
620 size_t msgsz = uap->msgsz;
621 int msgflg = uap->msgflg;
581 int segs_needed, eval;
622 int segs_needed, error = 0;
582 register struct msqid_ds *msqptr;
583 register struct msg *msghdr;
584 short next;
585
586#ifdef MSG_DEBUG_OK
587 printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
588 msgflg);
589#endif
623 register struct msqid_ds *msqptr;
624 register struct msg *msghdr;
625 short next;
626
627#ifdef MSG_DEBUG_OK
628 printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
629 msgflg);
630#endif
631 mtx_lock(&Giant);
590
632
591 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
592 return (ENOSYS);
633 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) {
634 error = ENOSYS;
635 goto done2;
636 }
593
594 msqid = IPCID_TO_IX(msqid);
595
596 if (msqid < 0 || msqid >= msginfo.msgmni) {
597#ifdef MSG_DEBUG_OK
598 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
599 msginfo.msgmni);
600#endif
637
638 msqid = IPCID_TO_IX(msqid);
639
640 if (msqid < 0 || msqid >= msginfo.msgmni) {
641#ifdef MSG_DEBUG_OK
642 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
643 msginfo.msgmni);
644#endif
601 return(EINVAL);
645 error = EINVAL;
646 goto done2;
602 }
603
604 msqptr = &msqids[msqid];
605 if (msqptr->msg_qbytes == 0) {
606#ifdef MSG_DEBUG_OK
607 printf("no such message queue id\n");
608#endif
647 }
648
649 msqptr = &msqids[msqid];
650 if (msqptr->msg_qbytes == 0) {
651#ifdef MSG_DEBUG_OK
652 printf("no such message queue id\n");
653#endif
609 return(EINVAL);
654 error = EINVAL;
655 goto done2;
610 }
611 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
612#ifdef MSG_DEBUG_OK
613 printf("wrong sequence number\n");
614#endif
656 }
657 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
658#ifdef MSG_DEBUG_OK
659 printf("wrong sequence number\n");
660#endif
615 return(EINVAL);
661 error = EINVAL;
662 goto done2;
616 }
617
663 }
664
618 if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_W))) {
665 if ((error = ipcperm(p, &msqptr->msg_perm, IPC_W))) {
619#ifdef MSG_DEBUG_OK
620 printf("requester doesn't have write access\n");
621#endif
666#ifdef MSG_DEBUG_OK
667 printf("requester doesn't have write access\n");
668#endif
622 return(eval);
669 goto done2;
623 }
624
625 segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
626#ifdef MSG_DEBUG_OK
627 printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
628 segs_needed);
629#endif
630 for (;;) {
631 int need_more_resources = 0;
632
633 /*
634 * check msgsz
635 * (inside this loop in case msg_qbytes changes while we sleep)
636 */
637
638 if (msgsz > msqptr->msg_qbytes) {
639#ifdef MSG_DEBUG_OK
640 printf("msgsz > msqptr->msg_qbytes\n");
641#endif
670 }
671
672 segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
673#ifdef MSG_DEBUG_OK
674 printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
675 segs_needed);
676#endif
677 for (;;) {
678 int need_more_resources = 0;
679
680 /*
681 * check msgsz
682 * (inside this loop in case msg_qbytes changes while we sleep)
683 */
684
685 if (msgsz > msqptr->msg_qbytes) {
686#ifdef MSG_DEBUG_OK
687 printf("msgsz > msqptr->msg_qbytes\n");
688#endif
642 return(EINVAL);
689 error = EINVAL;
690 goto done2;
643 }
644
645 if (msqptr->msg_perm.mode & MSG_LOCKED) {
646#ifdef MSG_DEBUG_OK
647 printf("msqid is locked\n");
648#endif
649 need_more_resources = 1;
650 }
651 if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
652#ifdef MSG_DEBUG_OK
653 printf("msgsz + msg_cbytes > msg_qbytes\n");
654#endif
655 need_more_resources = 1;
656 }
657 if (segs_needed > nfree_msgmaps) {
658#ifdef MSG_DEBUG_OK
659 printf("segs_needed > nfree_msgmaps\n");
660#endif
661 need_more_resources = 1;
662 }
663 if (free_msghdrs == NULL) {
664#ifdef MSG_DEBUG_OK
665 printf("no more msghdrs\n");
666#endif
667 need_more_resources = 1;
668 }
669
670 if (need_more_resources) {
671 int we_own_it;
672
673 if ((msgflg & IPC_NOWAIT) != 0) {
674#ifdef MSG_DEBUG_OK
675 printf("need more resources but caller doesn't want to wait\n");
676#endif
691 }
692
693 if (msqptr->msg_perm.mode & MSG_LOCKED) {
694#ifdef MSG_DEBUG_OK
695 printf("msqid is locked\n");
696#endif
697 need_more_resources = 1;
698 }
699 if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) {
700#ifdef MSG_DEBUG_OK
701 printf("msgsz + msg_cbytes > msg_qbytes\n");
702#endif
703 need_more_resources = 1;
704 }
705 if (segs_needed > nfree_msgmaps) {
706#ifdef MSG_DEBUG_OK
707 printf("segs_needed > nfree_msgmaps\n");
708#endif
709 need_more_resources = 1;
710 }
711 if (free_msghdrs == NULL) {
712#ifdef MSG_DEBUG_OK
713 printf("no more msghdrs\n");
714#endif
715 need_more_resources = 1;
716 }
717
718 if (need_more_resources) {
719 int we_own_it;
720
721 if ((msgflg & IPC_NOWAIT) != 0) {
722#ifdef MSG_DEBUG_OK
723 printf("need more resources but caller doesn't want to wait\n");
724#endif
677 return(EAGAIN);
725 error = EAGAIN;
726 goto done2;
678 }
679
680 if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
681#ifdef MSG_DEBUG_OK
682 printf("we don't own the msqid_ds\n");
683#endif
684 we_own_it = 0;
685 } else {
686 /* Force later arrivals to wait for our
687 request */
688#ifdef MSG_DEBUG_OK
689 printf("we own the msqid_ds\n");
690#endif
691 msqptr->msg_perm.mode |= MSG_LOCKED;
692 we_own_it = 1;
693 }
694#ifdef MSG_DEBUG_OK
695 printf("goodnight\n");
696#endif
727 }
728
729 if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
730#ifdef MSG_DEBUG_OK
731 printf("we don't own the msqid_ds\n");
732#endif
733 we_own_it = 0;
734 } else {
735 /* Force later arrivals to wait for our
736 request */
737#ifdef MSG_DEBUG_OK
738 printf("we own the msqid_ds\n");
739#endif
740 msqptr->msg_perm.mode |= MSG_LOCKED;
741 we_own_it = 1;
742 }
743#ifdef MSG_DEBUG_OK
744 printf("goodnight\n");
745#endif
697 eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH,
746 error = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH,
698 "msgwait", 0);
699#ifdef MSG_DEBUG_OK
747 "msgwait", 0);
748#ifdef MSG_DEBUG_OK
700 printf("good morning, eval=%d\n", eval);
749 printf("good morning, error=%d\n", error);
701#endif
702 if (we_own_it)
703 msqptr->msg_perm.mode &= ~MSG_LOCKED;
750#endif
751 if (we_own_it)
752 msqptr->msg_perm.mode &= ~MSG_LOCKED;
704 if (eval != 0) {
753 if (error != 0) {
705#ifdef MSG_DEBUG_OK
706 printf("msgsnd: interrupted system call\n");
707#endif
754#ifdef MSG_DEBUG_OK
755 printf("msgsnd: interrupted system call\n");
756#endif
708 return(EINTR);
757 error = EINTR;
758 goto done2;
709 }
710
711 /*
712 * Make sure that the msq queue still exists
713 */
714
715 if (msqptr->msg_qbytes == 0) {
716#ifdef MSG_DEBUG_OK
717 printf("msqid deleted\n");
718#endif
759 }
760
761 /*
762 * Make sure that the msq queue still exists
763 */
764
765 if (msqptr->msg_qbytes == 0) {
766#ifdef MSG_DEBUG_OK
767 printf("msqid deleted\n");
768#endif
719 return(EIDRM);
769 error = EIDRM;
770 goto done2;
720 }
721
722 } else {
723#ifdef MSG_DEBUG_OK
724 printf("got all the resources that we need\n");
725#endif
726 break;
727 }
728 }
729
730 /*
731 * We have the resources that we need.
732 * Make sure!
733 */
734
735 if (msqptr->msg_perm.mode & MSG_LOCKED)
736 panic("msg_perm.mode & MSG_LOCKED");
737 if (segs_needed > nfree_msgmaps)
738 panic("segs_needed > nfree_msgmaps");
739 if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
740 panic("msgsz + msg_cbytes > msg_qbytes");
741 if (free_msghdrs == NULL)
742 panic("no more msghdrs");
743
744 /*
745 * Re-lock the msqid_ds in case we page-fault when copying in the
746 * message
747 */
748
749 if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
750 panic("msqid_ds is already locked");
751 msqptr->msg_perm.mode |= MSG_LOCKED;
752
753 /*
754 * Allocate a message header
755 */
756
757 msghdr = free_msghdrs;
758 free_msghdrs = msghdr->msg_next;
759 msghdr->msg_spot = -1;
760 msghdr->msg_ts = msgsz;
761
762 /*
763 * Allocate space for the message
764 */
765
766 while (segs_needed > 0) {
767 if (nfree_msgmaps <= 0)
768 panic("not enough msgmaps");
769 if (free_msgmaps == -1)
770 panic("nil free_msgmaps");
771 next = free_msgmaps;
772 if (next <= -1)
773 panic("next too low #1");
774 if (next >= msginfo.msgseg)
775 panic("next out of range #1");
776#ifdef MSG_DEBUG_OK
777 printf("allocating segment %d to message\n", next);
778#endif
779 free_msgmaps = msgmaps[next].next;
780 nfree_msgmaps--;
781 msgmaps[next].next = msghdr->msg_spot;
782 msghdr->msg_spot = next;
783 segs_needed--;
784 }
785
786 /*
787 * Copy in the message type
788 */
789
771 }
772
773 } else {
774#ifdef MSG_DEBUG_OK
775 printf("got all the resources that we need\n");
776#endif
777 break;
778 }
779 }
780
781 /*
782 * We have the resources that we need.
783 * Make sure!
784 */
785
786 if (msqptr->msg_perm.mode & MSG_LOCKED)
787 panic("msg_perm.mode & MSG_LOCKED");
788 if (segs_needed > nfree_msgmaps)
789 panic("segs_needed > nfree_msgmaps");
790 if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
791 panic("msgsz + msg_cbytes > msg_qbytes");
792 if (free_msghdrs == NULL)
793 panic("no more msghdrs");
794
795 /*
796 * Re-lock the msqid_ds in case we page-fault when copying in the
797 * message
798 */
799
800 if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
801 panic("msqid_ds is already locked");
802 msqptr->msg_perm.mode |= MSG_LOCKED;
803
804 /*
805 * Allocate a message header
806 */
807
808 msghdr = free_msghdrs;
809 free_msghdrs = msghdr->msg_next;
810 msghdr->msg_spot = -1;
811 msghdr->msg_ts = msgsz;
812
813 /*
814 * Allocate space for the message
815 */
816
817 while (segs_needed > 0) {
818 if (nfree_msgmaps <= 0)
819 panic("not enough msgmaps");
820 if (free_msgmaps == -1)
821 panic("nil free_msgmaps");
822 next = free_msgmaps;
823 if (next <= -1)
824 panic("next too low #1");
825 if (next >= msginfo.msgseg)
826 panic("next out of range #1");
827#ifdef MSG_DEBUG_OK
828 printf("allocating segment %d to message\n", next);
829#endif
830 free_msgmaps = msgmaps[next].next;
831 nfree_msgmaps--;
832 msgmaps[next].next = msghdr->msg_spot;
833 msghdr->msg_spot = next;
834 segs_needed--;
835 }
836
837 /*
838 * Copy in the message type
839 */
840
790 if ((eval = copyin(user_msgp, &msghdr->msg_type,
841 if ((error = copyin(user_msgp, &msghdr->msg_type,
791 sizeof(msghdr->msg_type))) != 0) {
792#ifdef MSG_DEBUG_OK
842 sizeof(msghdr->msg_type))) != 0) {
843#ifdef MSG_DEBUG_OK
793 printf("error %d copying the message type\n", eval);
844 printf("error %d copying the message type\n", error);
794#endif
795 msg_freehdr(msghdr);
796 msqptr->msg_perm.mode &= ~MSG_LOCKED;
797 wakeup((caddr_t)msqptr);
845#endif
846 msg_freehdr(msghdr);
847 msqptr->msg_perm.mode &= ~MSG_LOCKED;
848 wakeup((caddr_t)msqptr);
798 return(eval);
849 goto done2;
799 }
800 user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
801
802 /*
803 * Validate the message type
804 */
805
806 if (msghdr->msg_type < 1) {
807 msg_freehdr(msghdr);
808 msqptr->msg_perm.mode &= ~MSG_LOCKED;
809 wakeup((caddr_t)msqptr);
810#ifdef MSG_DEBUG_OK
811 printf("mtype (%d) < 1\n", msghdr->msg_type);
812#endif
850 }
851 user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
852
853 /*
854 * Validate the message type
855 */
856
857 if (msghdr->msg_type < 1) {
858 msg_freehdr(msghdr);
859 msqptr->msg_perm.mode &= ~MSG_LOCKED;
860 wakeup((caddr_t)msqptr);
861#ifdef MSG_DEBUG_OK
862 printf("mtype (%d) < 1\n", msghdr->msg_type);
863#endif
813 return(EINVAL);
864 error = EINVAL;
865 goto done2;
814 }
815
816 /*
817 * Copy in the message body
818 */
819
820 next = msghdr->msg_spot;
821 while (msgsz > 0) {
822 size_t tlen;
823 if (msgsz > msginfo.msgssz)
824 tlen = msginfo.msgssz;
825 else
826 tlen = msgsz;
827 if (next <= -1)
828 panic("next too low #2");
829 if (next >= msginfo.msgseg)
830 panic("next out of range #2");
866 }
867
868 /*
869 * Copy in the message body
870 */
871
872 next = msghdr->msg_spot;
873 while (msgsz > 0) {
874 size_t tlen;
875 if (msgsz > msginfo.msgssz)
876 tlen = msginfo.msgssz;
877 else
878 tlen = msgsz;
879 if (next <= -1)
880 panic("next too low #2");
881 if (next >= msginfo.msgseg)
882 panic("next out of range #2");
831 if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
883 if ((error = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
832 tlen)) != 0) {
833#ifdef MSG_DEBUG_OK
884 tlen)) != 0) {
885#ifdef MSG_DEBUG_OK
834 printf("error %d copying in message segment\n", eval);
886 printf("error %d copying in message segment\n", error);
835#endif
836 msg_freehdr(msghdr);
837 msqptr->msg_perm.mode &= ~MSG_LOCKED;
838 wakeup((caddr_t)msqptr);
887#endif
888 msg_freehdr(msghdr);
889 msqptr->msg_perm.mode &= ~MSG_LOCKED;
890 wakeup((caddr_t)msqptr);
839 return(eval);
891 goto done2;
840 }
841 msgsz -= tlen;
842 user_msgp = (char *)user_msgp + tlen;
843 next = msgmaps[next].next;
844 }
845 if (next != -1)
846 panic("didn't use all the msg segments");
847
848 /*
849 * We've got the message. Unlock the msqid_ds.
850 */
851
852 msqptr->msg_perm.mode &= ~MSG_LOCKED;
853
854 /*
855 * Make sure that the msqid_ds is still allocated.
856 */
857
858 if (msqptr->msg_qbytes == 0) {
859 msg_freehdr(msghdr);
860 wakeup((caddr_t)msqptr);
892 }
893 msgsz -= tlen;
894 user_msgp = (char *)user_msgp + tlen;
895 next = msgmaps[next].next;
896 }
897 if (next != -1)
898 panic("didn't use all the msg segments");
899
900 /*
901 * We've got the message. Unlock the msqid_ds.
902 */
903
904 msqptr->msg_perm.mode &= ~MSG_LOCKED;
905
906 /*
907 * Make sure that the msqid_ds is still allocated.
908 */
909
910 if (msqptr->msg_qbytes == 0) {
911 msg_freehdr(msghdr);
912 wakeup((caddr_t)msqptr);
861 return(EIDRM);
913 error = EIDRM;
914 goto done2;
862 }
863
864 /*
865 * Put the message into the queue
866 */
867
868 if (msqptr->msg_first == NULL) {
869 msqptr->msg_first = msghdr;
870 msqptr->msg_last = msghdr;
871 } else {
872 msqptr->msg_last->msg_next = msghdr;
873 msqptr->msg_last = msghdr;
874 }
875 msqptr->msg_last->msg_next = NULL;
876
877 msqptr->msg_cbytes += msghdr->msg_ts;
878 msqptr->msg_qnum++;
879 msqptr->msg_lspid = p->p_pid;
880 msqptr->msg_stime = time_second;
881
882 wakeup((caddr_t)msqptr);
883 p->p_retval[0] = 0;
915 }
916
917 /*
918 * Put the message into the queue
919 */
920
921 if (msqptr->msg_first == NULL) {
922 msqptr->msg_first = msghdr;
923 msqptr->msg_last = msghdr;
924 } else {
925 msqptr->msg_last->msg_next = msghdr;
926 msqptr->msg_last = msghdr;
927 }
928 msqptr->msg_last->msg_next = NULL;
929
930 msqptr->msg_cbytes += msghdr->msg_ts;
931 msqptr->msg_qnum++;
932 msqptr->msg_lspid = p->p_pid;
933 msqptr->msg_stime = time_second;
934
935 wakeup((caddr_t)msqptr);
936 p->p_retval[0] = 0;
884 return(0);
937done2:
938 mtx_unlock(&Giant);
939 return (error);
885}
886
887#ifndef _SYS_SYSPROTO_H_
888struct msgrcv_args {
889 int msqid;
890 void *msgp;
891 size_t msgsz;
892 long msgtyp;
893 int msgflg;
894};
895#endif
896
940}
941
942#ifndef _SYS_SYSPROTO_H_
943struct msgrcv_args {
944 int msqid;
945 void *msgp;
946 size_t msgsz;
947 long msgtyp;
948 int msgflg;
949};
950#endif
951
952/*
953 * MPSAFE
954 */
897int
898msgrcv(p, uap)
899 struct proc *p;
900 register struct msgrcv_args *uap;
901{
902 int msqid = uap->msqid;
903 void *user_msgp = uap->msgp;
904 size_t msgsz = uap->msgsz;
905 long msgtyp = uap->msgtyp;
906 int msgflg = uap->msgflg;
907 size_t len;
908 register struct msqid_ds *msqptr;
909 register struct msg *msghdr;
955int
956msgrcv(p, uap)
957 struct proc *p;
958 register struct msgrcv_args *uap;
959{
960 int msqid = uap->msqid;
961 void *user_msgp = uap->msgp;
962 size_t msgsz = uap->msgsz;
963 long msgtyp = uap->msgtyp;
964 int msgflg = uap->msgflg;
965 size_t len;
966 register struct msqid_ds *msqptr;
967 register struct msg *msghdr;
910 int eval;
968 int error = 0;
911 short next;
912
913#ifdef MSG_DEBUG_OK
914 printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
915 msgsz, msgtyp, msgflg);
916#endif
917
969 short next;
970
971#ifdef MSG_DEBUG_OK
972 printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
973 msgsz, msgtyp, msgflg);
974#endif
975
918 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
919 return (ENOSYS);
976 mtx_lock(&Giant);
920
977
978 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) {
979 error = ENOSYS;
980 goto done2;
981 }
982
921 msqid = IPCID_TO_IX(msqid);
922
923 if (msqid < 0 || msqid >= msginfo.msgmni) {
924#ifdef MSG_DEBUG_OK
925 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
926 msginfo.msgmni);
927#endif
983 msqid = IPCID_TO_IX(msqid);
984
985 if (msqid < 0 || msqid >= msginfo.msgmni) {
986#ifdef MSG_DEBUG_OK
987 printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
988 msginfo.msgmni);
989#endif
928 return(EINVAL);
990 error = EINVAL;
991 goto done2;
929 }
930
931 msqptr = &msqids[msqid];
932 if (msqptr->msg_qbytes == 0) {
933#ifdef MSG_DEBUG_OK
934 printf("no such message queue id\n");
935#endif
992 }
993
994 msqptr = &msqids[msqid];
995 if (msqptr->msg_qbytes == 0) {
996#ifdef MSG_DEBUG_OK
997 printf("no such message queue id\n");
998#endif
936 return(EINVAL);
999 error = EINVAL;
1000 goto done2;
937 }
938 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
939#ifdef MSG_DEBUG_OK
940 printf("wrong sequence number\n");
941#endif
1001 }
1002 if (msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
1003#ifdef MSG_DEBUG_OK
1004 printf("wrong sequence number\n");
1005#endif
942 return(EINVAL);
1006 error = EINVAL;
1007 goto done2;
943 }
944
1008 }
1009
945 if ((eval = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
1010 if ((error = ipcperm(p, &msqptr->msg_perm, IPC_R))) {
946#ifdef MSG_DEBUG_OK
947 printf("requester doesn't have read access\n");
948#endif
1011#ifdef MSG_DEBUG_OK
1012 printf("requester doesn't have read access\n");
1013#endif
949 return(eval);
1014 goto done2;
950 }
951
952 msghdr = NULL;
953 while (msghdr == NULL) {
954 if (msgtyp == 0) {
955 msghdr = msqptr->msg_first;
956 if (msghdr != NULL) {
957 if (msgsz < msghdr->msg_ts &&
958 (msgflg & MSG_NOERROR) == 0) {
959#ifdef MSG_DEBUG_OK
960 printf("first message on the queue is too big (want %d, got %d)\n",
961 msgsz, msghdr->msg_ts);
962#endif
1015 }
1016
1017 msghdr = NULL;
1018 while (msghdr == NULL) {
1019 if (msgtyp == 0) {
1020 msghdr = msqptr->msg_first;
1021 if (msghdr != NULL) {
1022 if (msgsz < msghdr->msg_ts &&
1023 (msgflg & MSG_NOERROR) == 0) {
1024#ifdef MSG_DEBUG_OK
1025 printf("first message on the queue is too big (want %d, got %d)\n",
1026 msgsz, msghdr->msg_ts);
1027#endif
963 return(E2BIG);
1028 error = E2BIG;
1029 goto done2;
964 }
965 if (msqptr->msg_first == msqptr->msg_last) {
966 msqptr->msg_first = NULL;
967 msqptr->msg_last = NULL;
968 } else {
969 msqptr->msg_first = msghdr->msg_next;
970 if (msqptr->msg_first == NULL)
971 panic("msg_first/last screwed up #1");
972 }
973 }
974 } else {
975 struct msg *previous;
976 struct msg **prev;
977
978 previous = NULL;
979 prev = &(msqptr->msg_first);
980 while ((msghdr = *prev) != NULL) {
981 /*
982 * Is this message's type an exact match or is
983 * this message's type less than or equal to
984 * the absolute value of a negative msgtyp?
985 * Note that the second half of this test can
986 * NEVER be true if msgtyp is positive since
987 * msg_type is always positive!
988 */
989
990 if (msgtyp == msghdr->msg_type ||
991 msghdr->msg_type <= -msgtyp) {
992#ifdef MSG_DEBUG_OK
993 printf("found message type %d, requested %d\n",
994 msghdr->msg_type, msgtyp);
995#endif
996 if (msgsz < msghdr->msg_ts &&
997 (msgflg & MSG_NOERROR) == 0) {
998#ifdef MSG_DEBUG_OK
999 printf("requested message on the queue is too big (want %d, got %d)\n",
1000 msgsz, msghdr->msg_ts);
1001#endif
1030 }
1031 if (msqptr->msg_first == msqptr->msg_last) {
1032 msqptr->msg_first = NULL;
1033 msqptr->msg_last = NULL;
1034 } else {
1035 msqptr->msg_first = msghdr->msg_next;
1036 if (msqptr->msg_first == NULL)
1037 panic("msg_first/last screwed up #1");
1038 }
1039 }
1040 } else {
1041 struct msg *previous;
1042 struct msg **prev;
1043
1044 previous = NULL;
1045 prev = &(msqptr->msg_first);
1046 while ((msghdr = *prev) != NULL) {
1047 /*
1048 * Is this message's type an exact match or is
1049 * this message's type less than or equal to
1050 * the absolute value of a negative msgtyp?
1051 * Note that the second half of this test can
1052 * NEVER be true if msgtyp is positive since
1053 * msg_type is always positive!
1054 */
1055
1056 if (msgtyp == msghdr->msg_type ||
1057 msghdr->msg_type <= -msgtyp) {
1058#ifdef MSG_DEBUG_OK
1059 printf("found message type %d, requested %d\n",
1060 msghdr->msg_type, msgtyp);
1061#endif
1062 if (msgsz < msghdr->msg_ts &&
1063 (msgflg & MSG_NOERROR) == 0) {
1064#ifdef MSG_DEBUG_OK
1065 printf("requested message on the queue is too big (want %d, got %d)\n",
1066 msgsz, msghdr->msg_ts);
1067#endif
1002 return(E2BIG);
1068 error = E2BIG;
1069 goto done2;
1003 }
1004 *prev = msghdr->msg_next;
1005 if (msghdr == msqptr->msg_last) {
1006 if (previous == NULL) {
1007 if (prev !=
1008 &msqptr->msg_first)
1009 panic("msg_first/last screwed up #2");
1010 msqptr->msg_first =
1011 NULL;
1012 msqptr->msg_last =
1013 NULL;
1014 } else {
1015 if (prev ==
1016 &msqptr->msg_first)
1017 panic("msg_first/last screwed up #3");
1018 msqptr->msg_last =
1019 previous;
1020 }
1021 }
1022 break;
1023 }
1024 previous = msghdr;
1025 prev = &(msghdr->msg_next);
1026 }
1027 }
1028
1029 /*
1030 * We've either extracted the msghdr for the appropriate
1031 * message or there isn't one.
1032 * If there is one then bail out of this loop.
1033 */
1034
1035 if (msghdr != NULL)
1036 break;
1037
1038 /*
1039 * Hmph! No message found. Does the user want to wait?
1040 */
1041
1042 if ((msgflg & IPC_NOWAIT) != 0) {
1043#ifdef MSG_DEBUG_OK
1044 printf("no appropriate message found (msgtyp=%d)\n",
1045 msgtyp);
1046#endif
1047 /* The SVID says to return ENOMSG. */
1070 }
1071 *prev = msghdr->msg_next;
1072 if (msghdr == msqptr->msg_last) {
1073 if (previous == NULL) {
1074 if (prev !=
1075 &msqptr->msg_first)
1076 panic("msg_first/last screwed up #2");
1077 msqptr->msg_first =
1078 NULL;
1079 msqptr->msg_last =
1080 NULL;
1081 } else {
1082 if (prev ==
1083 &msqptr->msg_first)
1084 panic("msg_first/last screwed up #3");
1085 msqptr->msg_last =
1086 previous;
1087 }
1088 }
1089 break;
1090 }
1091 previous = msghdr;
1092 prev = &(msghdr->msg_next);
1093 }
1094 }
1095
1096 /*
1097 * We've either extracted the msghdr for the appropriate
1098 * message or there isn't one.
1099 * If there is one then bail out of this loop.
1100 */
1101
1102 if (msghdr != NULL)
1103 break;
1104
1105 /*
1106 * Hmph! No message found. Does the user want to wait?
1107 */
1108
1109 if ((msgflg & IPC_NOWAIT) != 0) {
1110#ifdef MSG_DEBUG_OK
1111 printf("no appropriate message found (msgtyp=%d)\n",
1112 msgtyp);
1113#endif
1114 /* The SVID says to return ENOMSG. */
1048 return(ENOMSG);
1115 error = ENOMSG;
1116 goto done2;
1049 }
1050
1051 /*
1052 * Wait for something to happen
1053 */
1054
1055#ifdef MSG_DEBUG_OK
1056 printf("msgrcv: goodnight\n");
1057#endif
1117 }
1118
1119 /*
1120 * Wait for something to happen
1121 */
1122
1123#ifdef MSG_DEBUG_OK
1124 printf("msgrcv: goodnight\n");
1125#endif
1058 eval = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, "msgwait",
1126 error = tsleep((caddr_t)msqptr, (PZERO - 4) | PCATCH, "msgwait",
1059 0);
1060#ifdef MSG_DEBUG_OK
1127 0);
1128#ifdef MSG_DEBUG_OK
1061 printf("msgrcv: good morning (eval=%d)\n", eval);
1129 printf("msgrcv: good morning (error=%d)\n", error);
1062#endif
1063
1130#endif
1131
1064 if (eval != 0) {
1132 if (error != 0) {
1065#ifdef MSG_DEBUG_OK
1066 printf("msgsnd: interrupted system call\n");
1067#endif
1133#ifdef MSG_DEBUG_OK
1134 printf("msgsnd: interrupted system call\n");
1135#endif
1068 return(EINTR);
1136 error = EINTR;
1137 goto done2;
1069 }
1070
1071 /*
1072 * Make sure that the msq queue still exists
1073 */
1074
1075 if (msqptr->msg_qbytes == 0 ||
1076 msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
1077#ifdef MSG_DEBUG_OK
1078 printf("msqid deleted\n");
1079#endif
1138 }
1139
1140 /*
1141 * Make sure that the msq queue still exists
1142 */
1143
1144 if (msqptr->msg_qbytes == 0 ||
1145 msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid)) {
1146#ifdef MSG_DEBUG_OK
1147 printf("msqid deleted\n");
1148#endif
1080 return(EIDRM);
1149 error = EIDRM;
1150 goto done2;
1081 }
1082 }
1083
1084 /*
1085 * Return the message to the user.
1086 *
1087 * First, do the bookkeeping (before we risk being interrupted).
1088 */
1089
1090 msqptr->msg_cbytes -= msghdr->msg_ts;
1091 msqptr->msg_qnum--;
1092 msqptr->msg_lrpid = p->p_pid;
1093 msqptr->msg_rtime = time_second;
1094
1095 /*
1096 * Make msgsz the actual amount that we'll be returning.
1097 * Note that this effectively truncates the message if it is too long
1098 * (since msgsz is never increased).
1099 */
1100
1101#ifdef MSG_DEBUG_OK
1102 printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
1103 msghdr->msg_ts);
1104#endif
1105 if (msgsz > msghdr->msg_ts)
1106 msgsz = msghdr->msg_ts;
1107
1108 /*
1109 * Return the type to the user.
1110 */
1111
1151 }
1152 }
1153
1154 /*
1155 * Return the message to the user.
1156 *
1157 * First, do the bookkeeping (before we risk being interrupted).
1158 */
1159
1160 msqptr->msg_cbytes -= msghdr->msg_ts;
1161 msqptr->msg_qnum--;
1162 msqptr->msg_lrpid = p->p_pid;
1163 msqptr->msg_rtime = time_second;
1164
1165 /*
1166 * Make msgsz the actual amount that we'll be returning.
1167 * Note that this effectively truncates the message if it is too long
1168 * (since msgsz is never increased).
1169 */
1170
1171#ifdef MSG_DEBUG_OK
1172 printf("found a message, msgsz=%d, msg_ts=%d\n", msgsz,
1173 msghdr->msg_ts);
1174#endif
1175 if (msgsz > msghdr->msg_ts)
1176 msgsz = msghdr->msg_ts;
1177
1178 /*
1179 * Return the type to the user.
1180 */
1181
1112 eval = copyout((caddr_t)&(msghdr->msg_type), user_msgp,
1182 error = copyout((caddr_t)&(msghdr->msg_type), user_msgp,
1113 sizeof(msghdr->msg_type));
1183 sizeof(msghdr->msg_type));
1114 if (eval != 0) {
1184 if (error != 0) {
1115#ifdef MSG_DEBUG_OK
1185#ifdef MSG_DEBUG_OK
1116 printf("error (%d) copying out message type\n", eval);
1186 printf("error (%d) copying out message type\n", error);
1117#endif
1118 msg_freehdr(msghdr);
1119 wakeup((caddr_t)msqptr);
1187#endif
1188 msg_freehdr(msghdr);
1189 wakeup((caddr_t)msqptr);
1120 return(eval);
1190 goto done2;
1121 }
1122 user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
1123
1124 /*
1125 * Return the segments to the user
1126 */
1127
1128 next = msghdr->msg_spot;
1129 for (len = 0; len < msgsz; len += msginfo.msgssz) {
1130 size_t tlen;
1131
1132 if (msgsz - len > msginfo.msgssz)
1133 tlen = msginfo.msgssz;
1134 else
1135 tlen = msgsz - len;
1136 if (next <= -1)
1137 panic("next too low #3");
1138 if (next >= msginfo.msgseg)
1139 panic("next out of range #3");
1191 }
1192 user_msgp = (char *)user_msgp + sizeof(msghdr->msg_type);
1193
1194 /*
1195 * Return the segments to the user
1196 */
1197
1198 next = msghdr->msg_spot;
1199 for (len = 0; len < msgsz; len += msginfo.msgssz) {
1200 size_t tlen;
1201
1202 if (msgsz - len > msginfo.msgssz)
1203 tlen = msginfo.msgssz;
1204 else
1205 tlen = msgsz - len;
1206 if (next <= -1)
1207 panic("next too low #3");
1208 if (next >= msginfo.msgseg)
1209 panic("next out of range #3");
1140 eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz],
1210 error = copyout((caddr_t)&msgpool[next * msginfo.msgssz],
1141 user_msgp, tlen);
1211 user_msgp, tlen);
1142 if (eval != 0) {
1212 if (error != 0) {
1143#ifdef MSG_DEBUG_OK
1144 printf("error (%d) copying out message segment\n",
1213#ifdef MSG_DEBUG_OK
1214 printf("error (%d) copying out message segment\n",
1145 eval);
1215 error);
1146#endif
1147 msg_freehdr(msghdr);
1148 wakeup((caddr_t)msqptr);
1216#endif
1217 msg_freehdr(msghdr);
1218 wakeup((caddr_t)msqptr);
1149 return(eval);
1219 goto done2;
1150 }
1151 user_msgp = (char *)user_msgp + tlen;
1152 next = msgmaps[next].next;
1153 }
1154
1155 /*
1156 * Done, return the actual number of bytes copied out.
1157 */
1158
1159 msg_freehdr(msghdr);
1160 wakeup((caddr_t)msqptr);
1161 p->p_retval[0] = msgsz;
1220 }
1221 user_msgp = (char *)user_msgp + tlen;
1222 next = msgmaps[next].next;
1223 }
1224
1225 /*
1226 * Done, return the actual number of bytes copied out.
1227 */
1228
1229 msg_freehdr(msghdr);
1230 wakeup((caddr_t)msqptr);
1231 p->p_retval[0] = msgsz;
1162 return(0);
1232done2:
1233 mtx_unlock(&Giant);
1234 return (error);
1163}
1164
1165static int
1166sysctl_msqids(SYSCTL_HANDLER_ARGS)
1167{
1168
1169 return (SYSCTL_OUT(req, msqids,
1170 sizeof(struct msqid_ds) * msginfo.msgmni));
1171}
1172
1173SYSCTL_DECL(_kern_ipc);
1174SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, "");
1175SYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RD, &msginfo.msgmni, 0, "");
1176SYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RD, &msginfo.msgmnb, 0, "");
1177SYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RD, &msginfo.msgtql, 0, "");
1178SYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RD, &msginfo.msgssz, 0, "");
1179SYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RD, &msginfo.msgseg, 0, "")
1180SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_RD,
1181 NULL, 0, sysctl_msqids, "", "Message queue IDs");
1235}
1236
1237static int
1238sysctl_msqids(SYSCTL_HANDLER_ARGS)
1239{
1240
1241 return (SYSCTL_OUT(req, msqids,
1242 sizeof(struct msqid_ds) * msginfo.msgmni));
1243}
1244
1245SYSCTL_DECL(_kern_ipc);
1246SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, "");
1247SYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RD, &msginfo.msgmni, 0, "");
1248SYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RD, &msginfo.msgmnb, 0, "");
1249SYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RD, &msginfo.msgtql, 0, "");
1250SYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RD, &msginfo.msgssz, 0, "");
1251SYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RD, &msginfo.msgseg, 0, "")
1252SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_RD,
1253 NULL, 0, sysctl_msqids, "", "Message queue IDs");