Tue Jul 21 00:23:01 2009 UTC ()
Pull up following revision(s) (requested by rmind in ticket #857):
	sys/kern/sys_mqueue.c: revision 1.21 via patch
mq_send/mq_receive: while permission may allow that, return EBADF if sending
to read-only queue, or receiving from write-only queue.
From Stathis Kamperis, thanks!


(snj)
diff -r1.12.4.3 -r1.12.4.4 src/sys/kern/sys_mqueue.c

cvs diff -r1.12.4.3 -r1.12.4.4 src/sys/kern/sys_mqueue.c (switch to unified diff)

--- src/sys/kern/sys_mqueue.c 2009/05/27 21:32:05 1.12.4.3
+++ src/sys/kern/sys_mqueue.c 2009/07/21 00:23:01 1.12.4.4
@@ -1,1021 +1,1030 @@ @@ -1,1021 +1,1030 @@
1/* $NetBSD: sys_mqueue.c,v 1.12.4.3 2009/05/27 21:32:05 snj Exp $ */ 1/* $NetBSD: sys_mqueue.c,v 1.12.4.4 2009/07/21 00:23:01 snj Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org> 4 * Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org>
5 * All rights reserved. 5 * All rights reserved.
6 *  6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE. 26 * SUCH DAMAGE.
27 */ 27 */
28 28
29/* 29/*
30 * Implementation of POSIX message queues. 30 * Implementation of POSIX message queues.
31 * Defined in the Base Definitions volume of IEEE Std 1003.1-2001. 31 * Defined in the Base Definitions volume of IEEE Std 1003.1-2001.
32 * 32 *
33 * Locking 33 * Locking
34 *  34 *
35 * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt 35 * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt
36 * counter are protected by mqlist_mtx lock. The very message queue and 36 * counter are protected by mqlist_mtx lock. The very message queue and
37 * its members are protected by mqueue::mq_mtx. 37 * its members are protected by mqueue::mq_mtx.
38 *  38 *
39 * Lock order: 39 * Lock order:
40 * mqlist_mtx 40 * mqlist_mtx
41 * -> mqueue::mq_mtx 41 * -> mqueue::mq_mtx
42 */ 42 */
43 43
44#include <sys/cdefs.h> 44#include <sys/cdefs.h>
45__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.12.4.3 2009/05/27 21:32:05 snj Exp $"); 45__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.12.4.4 2009/07/21 00:23:01 snj Exp $");
46 46
47#include <sys/param.h> 47#include <sys/param.h>
48#include <sys/types.h> 48#include <sys/types.h>
49#include <sys/condvar.h> 49#include <sys/condvar.h>
50#include <sys/errno.h> 50#include <sys/errno.h>
51#include <sys/fcntl.h> 51#include <sys/fcntl.h>
52#include <sys/file.h> 52#include <sys/file.h>
53#include <sys/filedesc.h> 53#include <sys/filedesc.h>
54#include <sys/kauth.h> 54#include <sys/kauth.h>
55#include <sys/kernel.h> 55#include <sys/kernel.h>
56#include <sys/kmem.h> 56#include <sys/kmem.h>
57#include <sys/lwp.h> 57#include <sys/lwp.h>
58#include <sys/mqueue.h> 58#include <sys/mqueue.h>
59#include <sys/mutex.h> 59#include <sys/mutex.h>
60#include <sys/pool.h> 60#include <sys/pool.h>
61#include <sys/poll.h> 61#include <sys/poll.h>
62#include <sys/proc.h> 62#include <sys/proc.h>
63#include <sys/queue.h> 63#include <sys/queue.h>
64#include <sys/select.h> 64#include <sys/select.h>
65#include <sys/signal.h> 65#include <sys/signal.h>
66#include <sys/signalvar.h> 66#include <sys/signalvar.h>
67#include <sys/stat.h> 67#include <sys/stat.h>
68#include <sys/sysctl.h> 68#include <sys/sysctl.h>
69#include <sys/syscallargs.h> 69#include <sys/syscallargs.h>
70#include <sys/systm.h> 70#include <sys/systm.h>
71#include <sys/unistd.h> 71#include <sys/unistd.h>
72#include <sys/vnode.h> 72#include <sys/vnode.h>
73 73
74/* System-wide limits. */ 74/* System-wide limits. */
75static u_int mq_open_max = MQ_OPEN_MAX; 75static u_int mq_open_max = MQ_OPEN_MAX;
76static u_int mq_prio_max = MQ_PRIO_MAX; 76static u_int mq_prio_max = MQ_PRIO_MAX;
77 77
78static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE; 78static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE;
79static u_int mq_def_maxmsg = 32; 79static u_int mq_def_maxmsg = 32;
80 80
81static kmutex_t mqlist_mtx; 81static kmutex_t mqlist_mtx;
82static pool_cache_t mqmsg_cache; 82static pool_cache_t mqmsg_cache;
83static LIST_HEAD(, mqueue) mqueue_head = 83static LIST_HEAD(, mqueue) mqueue_head =
84 LIST_HEAD_INITIALIZER(mqueue_head); 84 LIST_HEAD_INITIALIZER(mqueue_head);
85 85
86static int mq_poll_fop(file_t *, int); 86static int mq_poll_fop(file_t *, int);
87static int mq_close_fop(file_t *); 87static int mq_close_fop(file_t *);
88 88
89static const struct fileops mqops = { 89static const struct fileops mqops = {
90 .fo_read = fbadop_read, 90 .fo_read = fbadop_read,
91 .fo_write = fbadop_write, 91 .fo_write = fbadop_write,
92 .fo_ioctl = fbadop_ioctl, 92 .fo_ioctl = fbadop_ioctl,
93 .fo_fcntl = fnullop_fcntl, 93 .fo_fcntl = fnullop_fcntl,
94 .fo_poll = mq_poll_fop, 94 .fo_poll = mq_poll_fop,
95 .fo_stat = fbadop_stat, 95 .fo_stat = fbadop_stat,
96 .fo_close = mq_close_fop, 96 .fo_close = mq_close_fop,
97 .fo_kqfilter = fnullop_kqfilter, 97 .fo_kqfilter = fnullop_kqfilter,
98 .fo_drain = fnullop_drain, 98 .fo_drain = fnullop_drain,
99}; 99};
100 100
101/* 101/*
102 * Initialize POSIX message queue subsystem. 102 * Initialize POSIX message queue subsystem.
103 */ 103 */
104void 104void
105mqueue_sysinit(void) 105mqueue_sysinit(void)
106{ 106{
107 107
108 mqmsg_cache = pool_cache_init(MQ_DEF_MSGSIZE, coherency_unit, 108 mqmsg_cache = pool_cache_init(MQ_DEF_MSGSIZE, coherency_unit,
109 0, 0, "mqmsgpl", NULL, IPL_NONE, NULL, NULL, NULL); 109 0, 0, "mqmsgpl", NULL, IPL_NONE, NULL, NULL, NULL);
110 mutex_init(&mqlist_mtx, MUTEX_DEFAULT, IPL_NONE); 110 mutex_init(&mqlist_mtx, MUTEX_DEFAULT, IPL_NONE);
111} 111}
112 112
113/* 113/*
114 * Free the message. 114 * Free the message.
115 */ 115 */
116static void 116static void
117mqueue_freemsg(struct mq_msg *msg, const size_t size) 117mqueue_freemsg(struct mq_msg *msg, const size_t size)
118{ 118{
119 119
120 if (size > MQ_DEF_MSGSIZE) 120 if (size > MQ_DEF_MSGSIZE)
121 kmem_free(msg, size); 121 kmem_free(msg, size);
122 else 122 else
123 pool_cache_put(mqmsg_cache, msg); 123 pool_cache_put(mqmsg_cache, msg);
124} 124}
125 125
126/* 126/*
127 * Destroy the message queue. 127 * Destroy the message queue.
128 */ 128 */
129static void 129static void
130mqueue_destroy(struct mqueue *mq) 130mqueue_destroy(struct mqueue *mq)
131{ 131{
132 struct mq_msg *msg; 132 struct mq_msg *msg;
133 133
134 while ((msg = TAILQ_FIRST(&mq->mq_head)) != NULL) { 134 while ((msg = TAILQ_FIRST(&mq->mq_head)) != NULL) {
135 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue); 135 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue);
136 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 136 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
137 } 137 }
138 seldestroy(&mq->mq_rsel); 138 seldestroy(&mq->mq_rsel);
139 seldestroy(&mq->mq_wsel); 139 seldestroy(&mq->mq_wsel);
140 cv_destroy(&mq->mq_send_cv); 140 cv_destroy(&mq->mq_send_cv);
141 cv_destroy(&mq->mq_recv_cv); 141 cv_destroy(&mq->mq_recv_cv);
142 mutex_destroy(&mq->mq_mtx); 142 mutex_destroy(&mq->mq_mtx);
143 kmem_free(mq, sizeof(struct mqueue)); 143 kmem_free(mq, sizeof(struct mqueue));
144} 144}
145 145
146/* 146/*
147 * Lookup for file name in general list of message queues. 147 * Lookup for file name in general list of message queues.
148 * => locks the message queue 148 * => locks the message queue
149 */ 149 */
150static void * 150static void *
151mqueue_lookup(char *name) 151mqueue_lookup(char *name)
152{ 152{
153 struct mqueue *mq; 153 struct mqueue *mq;
154 KASSERT(mutex_owned(&mqlist_mtx)); 154 KASSERT(mutex_owned(&mqlist_mtx));
155 155
156 LIST_FOREACH(mq, &mqueue_head, mq_list) { 156 LIST_FOREACH(mq, &mqueue_head, mq_list) {
157 if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) { 157 if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) {
158 mutex_enter(&mq->mq_mtx); 158 mutex_enter(&mq->mq_mtx);
159 return mq; 159 return mq;
160 } 160 }
161 } 161 }
162 162
163 return NULL; 163 return NULL;
164} 164}
165 165
166/* 166/*
167 * mqueue_get: get the mqueue from the descriptor. 167 * mqueue_get: get the mqueue from the descriptor.
168 * => locks the message queue, if found. 168 * => locks the message queue, if found.
169 * => holds a reference on the file descriptor. 169 * => holds a reference on the file descriptor.
170 */ 170 */
171static int 171static int
172mqueue_get(mqd_t mqd, file_t **fpr) 172mqueue_get(mqd_t mqd, file_t **fpr)
173{ 173{
174 struct mqueue *mq; 174 struct mqueue *mq;
175 file_t *fp; 175 file_t *fp;
176 176
177 fp = fd_getfile((int)mqd); 177 fp = fd_getfile((int)mqd);
178 if (__predict_false(fp == NULL)) { 178 if (__predict_false(fp == NULL)) {
179 return EBADF; 179 return EBADF;
180 } 180 }
181 if (__predict_false(fp->f_type != DTYPE_MQUEUE)) { 181 if (__predict_false(fp->f_type != DTYPE_MQUEUE)) {
182 fd_putfile((int)mqd); 182 fd_putfile((int)mqd);
183 return EBADF; 183 return EBADF;
184 } 184 }
185 mq = fp->f_data; 185 mq = fp->f_data;
186 mutex_enter(&mq->mq_mtx); 186 mutex_enter(&mq->mq_mtx);
187 187
188 *fpr = fp; 188 *fpr = fp;
189 return 0; 189 return 0;
190} 190}
191 191
192/* 192/*
193 * Converter from struct timespec to the ticks. 193 * Converter from struct timespec to the ticks.
194 * Used by mq_timedreceive(), mq_timedsend(). 194 * Used by mq_timedreceive(), mq_timedsend().
195 */ 195 */
196static int 196static int
197abstimeout2timo(const void *uaddr, int *timo) 197abstimeout2timo(const void *uaddr, int *timo)
198{ 198{
199 struct timespec ts; 199 struct timespec ts;
200 int error; 200 int error;
201 201
202 error = copyin(uaddr, &ts, sizeof(struct timespec)); 202 error = copyin(uaddr, &ts, sizeof(struct timespec));
203 if (error) 203 if (error)
204 return error; 204 return error;
205 205
206 /* 206 /*
207 * According to POSIX, validation check is needed only in case of 207 * According to POSIX, validation check is needed only in case of
208 * blocking. Thus, set the invalid value right now, and fail latter. 208 * blocking. Thus, set the invalid value right now, and fail latter.
209 */ 209 */
210 error = itimespecfix(&ts); 210 error = itimespecfix(&ts);
211 *timo = (error == 0) ? tstohz(&ts) : -1; 211 *timo = (error == 0) ? tstohz(&ts) : -1;
212 212
213 return 0; 213 return 0;
214} 214}
215 215
216static int 216static int
217mq_poll_fop(file_t *fp, int events) 217mq_poll_fop(file_t *fp, int events)
218{ 218{
219 struct mqueue *mq = fp->f_data; 219 struct mqueue *mq = fp->f_data;
220 int revents = 0; 220 int revents = 0;
221 221
222 mutex_enter(&mq->mq_mtx); 222 mutex_enter(&mq->mq_mtx);
223 if (events & (POLLIN | POLLRDNORM)) { 223 if (events & (POLLIN | POLLRDNORM)) {
224 /* Ready for receiving, if there are messages in the queue */ 224 /* Ready for receiving, if there are messages in the queue */
225 if (mq->mq_attrib.mq_curmsgs) 225 if (mq->mq_attrib.mq_curmsgs)
226 revents |= (POLLIN | POLLRDNORM); 226 revents |= (POLLIN | POLLRDNORM);
227 else 227 else
228 selrecord(curlwp, &mq->mq_rsel); 228 selrecord(curlwp, &mq->mq_rsel);
229 } 229 }
230 if (events & (POLLOUT | POLLWRNORM)) { 230 if (events & (POLLOUT | POLLWRNORM)) {
231 /* Ready for sending, if the message queue is not full */ 231 /* Ready for sending, if the message queue is not full */
232 if (mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg) 232 if (mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg)
233 revents |= (POLLOUT | POLLWRNORM); 233 revents |= (POLLOUT | POLLWRNORM);
234 else 234 else
235 selrecord(curlwp, &mq->mq_wsel); 235 selrecord(curlwp, &mq->mq_wsel);
236 } 236 }
237 mutex_exit(&mq->mq_mtx); 237 mutex_exit(&mq->mq_mtx);
238 238
239 return revents; 239 return revents;
240} 240}
241 241
242static int 242static int
243mq_close_fop(file_t *fp) 243mq_close_fop(file_t *fp)
244{ 244{
245 struct proc *p = curproc; 245 struct proc *p = curproc;
246 struct mqueue *mq = fp->f_data; 246 struct mqueue *mq = fp->f_data;
247 bool destroy; 247 bool destroy;
248 248
249 mutex_enter(&mqlist_mtx); 249 mutex_enter(&mqlist_mtx);
250 mutex_enter(&mq->mq_mtx); 250 mutex_enter(&mq->mq_mtx);
251 251
252 /* Decrease the counters */ 252 /* Decrease the counters */
253 p->p_mqueue_cnt--; 253 p->p_mqueue_cnt--;
254 mq->mq_refcnt--; 254 mq->mq_refcnt--;
255 255
256 /* Remove notification if registered for this process */ 256 /* Remove notification if registered for this process */
257 if (mq->mq_notify_proc == p) 257 if (mq->mq_notify_proc == p)
258 mq->mq_notify_proc = NULL; 258 mq->mq_notify_proc = NULL;
259 259
260 /* 260 /*
261 * If this is the last reference and mqueue is marked for unlink, 261 * If this is the last reference and mqueue is marked for unlink,
262 * remove and later destroy the message queue. 262 * remove and later destroy the message queue.
263 */ 263 */
264 if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 264 if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
265 LIST_REMOVE(mq, mq_list); 265 LIST_REMOVE(mq, mq_list);
266 destroy = true; 266 destroy = true;
267 } else 267 } else
268 destroy = false; 268 destroy = false;
269 269
270 mutex_exit(&mq->mq_mtx); 270 mutex_exit(&mq->mq_mtx);
271 mutex_exit(&mqlist_mtx); 271 mutex_exit(&mqlist_mtx);
272 272
273 if (destroy) 273 if (destroy)
274 mqueue_destroy(mq); 274 mqueue_destroy(mq);
275 275
276 return 0; 276 return 0;
277} 277}
278 278
279/* 279/*
280 * General mqueue system calls. 280 * General mqueue system calls.
281 */ 281 */
282 282
283int 283int
284sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap, 284sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap,
285 register_t *retval) 285 register_t *retval)
286{ 286{
287 /* { 287 /* {
288 syscallarg(const char *) name; 288 syscallarg(const char *) name;
289 syscallarg(int) oflag; 289 syscallarg(int) oflag;
290 syscallarg(mode_t) mode; 290 syscallarg(mode_t) mode;
291 syscallarg(struct mq_attr) attr; 291 syscallarg(struct mq_attr) attr;
292 } */ 292 } */
293 struct proc *p = l->l_proc; 293 struct proc *p = l->l_proc;
294 struct mqueue *mq, *mq_new = NULL; 294 struct mqueue *mq, *mq_new = NULL;
295 file_t *fp; 295 file_t *fp;
296 char *name; 296 char *name;
297 int mqd, error, oflag; 297 int mqd, error, oflag;
298 298
299 oflag = SCARG(uap, oflag); 299 oflag = SCARG(uap, oflag);
300 300
301 /* Get the name from the user-space */ 301 /* Get the name from the user-space */
302 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 302 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP);
303 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 303 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
304 if (error) { 304 if (error) {
305 kmem_free(name, MQ_NAMELEN); 305 kmem_free(name, MQ_NAMELEN);
306 return error; 306 return error;
307 } 307 }
308 308
309 if (oflag & O_CREAT) { 309 if (oflag & O_CREAT) {
310 struct cwdinfo *cwdi = p->p_cwdi; 310 struct cwdinfo *cwdi = p->p_cwdi;
311 struct mq_attr attr; 311 struct mq_attr attr;
312 312
313 /* Check the limit */ 313 /* Check the limit */
314 if (p->p_mqueue_cnt == mq_open_max) { 314 if (p->p_mqueue_cnt == mq_open_max) {
315 kmem_free(name, MQ_NAMELEN); 315 kmem_free(name, MQ_NAMELEN);
316 return EMFILE; 316 return EMFILE;
317 } 317 }
318 318
319 /* Empty name is invalid */ 319 /* Empty name is invalid */
320 if (name[0] == '\0') { 320 if (name[0] == '\0') {
321 kmem_free(name, MQ_NAMELEN); 321 kmem_free(name, MQ_NAMELEN);
322 return EINVAL; 322 return EINVAL;
323 } 323 }
324  324
325 /* Check for mqueue attributes */ 325 /* Check for mqueue attributes */
326 if (SCARG(uap, attr)) { 326 if (SCARG(uap, attr)) {
327 error = copyin(SCARG(uap, attr), &attr, 327 error = copyin(SCARG(uap, attr), &attr,
328 sizeof(struct mq_attr)); 328 sizeof(struct mq_attr));
329 if (error) { 329 if (error) {
330 kmem_free(name, MQ_NAMELEN); 330 kmem_free(name, MQ_NAMELEN);
331 return error; 331 return error;
332 } 332 }
333 if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 || 333 if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 ||
334 attr.mq_msgsize > mq_max_msgsize) { 334 attr.mq_msgsize > mq_max_msgsize) {
335 kmem_free(name, MQ_NAMELEN); 335 kmem_free(name, MQ_NAMELEN);
336 return EINVAL; 336 return EINVAL;
337 } 337 }
338 attr.mq_curmsgs = 0; 338 attr.mq_curmsgs = 0;
339 } else { 339 } else {
340 memset(&attr, 0, sizeof(struct mq_attr)); 340 memset(&attr, 0, sizeof(struct mq_attr));
341 attr.mq_maxmsg = mq_def_maxmsg; 341 attr.mq_maxmsg = mq_def_maxmsg;
342 attr.mq_msgsize = 342 attr.mq_msgsize =
343 MQ_DEF_MSGSIZE - sizeof(struct mq_msg); 343 MQ_DEF_MSGSIZE - sizeof(struct mq_msg);
344 } 344 }
345 345
346 /* 346 /*
347 * Allocate new mqueue, initialize data structures, 347 * Allocate new mqueue, initialize data structures,
348 * copy the name, attributes and set the flag. 348 * copy the name, attributes and set the flag.
349 */ 349 */
350 mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP); 350 mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP);
351 351
352 mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE); 352 mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE);
353 cv_init(&mq_new->mq_send_cv, "mqsendcv"); 353 cv_init(&mq_new->mq_send_cv, "mqsendcv");
354 cv_init(&mq_new->mq_recv_cv, "mqrecvcv"); 354 cv_init(&mq_new->mq_recv_cv, "mqrecvcv");
355 TAILQ_INIT(&mq_new->mq_head); 355 TAILQ_INIT(&mq_new->mq_head);
356 selinit(&mq_new->mq_rsel); 356 selinit(&mq_new->mq_rsel);
357 selinit(&mq_new->mq_wsel); 357 selinit(&mq_new->mq_wsel);
358 358
359 strlcpy(mq_new->mq_name, name, MQ_NAMELEN); 359 strlcpy(mq_new->mq_name, name, MQ_NAMELEN);
360 memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); 360 memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr));
361 361
362 CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0); 362 CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0);
363 mq_new->mq_attrib.mq_flags = (O_MASK & oflag); 363 mq_new->mq_attrib.mq_flags = (O_MASK & oflag);
364 364
365 /* Store mode and effective UID with GID */ 365 /* Store mode and effective UID with GID */
366 mq_new->mq_mode = ((SCARG(uap, mode) & 366 mq_new->mq_mode = ((SCARG(uap, mode) &
367 ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT; 367 ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT;
368 mq_new->mq_euid = kauth_cred_geteuid(l->l_cred); 368 mq_new->mq_euid = kauth_cred_geteuid(l->l_cred);
369 mq_new->mq_egid = kauth_cred_getegid(l->l_cred); 369 mq_new->mq_egid = kauth_cred_getegid(l->l_cred);
370 } 370 }
371 371
372 /* Allocate file structure and descriptor */ 372 /* Allocate file structure and descriptor */
373 error = fd_allocfile(&fp, &mqd); 373 error = fd_allocfile(&fp, &mqd);
374 if (error) { 374 if (error) {
375 if (mq_new) 375 if (mq_new)
376 mqueue_destroy(mq_new); 376 mqueue_destroy(mq_new);
377 kmem_free(name, MQ_NAMELEN); 377 kmem_free(name, MQ_NAMELEN);
378 return error; 378 return error;
379 } 379 }
380 fp->f_type = DTYPE_MQUEUE; 380 fp->f_type = DTYPE_MQUEUE;
381 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE); 381 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE);
382 fp->f_ops = &mqops; 382 fp->f_ops = &mqops;
383 383
384 /* Look up for mqueue with such name */ 384 /* Look up for mqueue with such name */
385 mutex_enter(&mqlist_mtx); 385 mutex_enter(&mqlist_mtx);
386 mq = mqueue_lookup(name); 386 mq = mqueue_lookup(name);
387 if (mq) { 387 if (mq) {
388 mode_t acc_mode; 388 mode_t acc_mode;
389 389
390 KASSERT(mutex_owned(&mq->mq_mtx)); 390 KASSERT(mutex_owned(&mq->mq_mtx));
391 391
392 /* Check if mqueue is not marked as unlinking */ 392 /* Check if mqueue is not marked as unlinking */
393 if (mq->mq_attrib.mq_flags & MQ_UNLINK) { 393 if (mq->mq_attrib.mq_flags & MQ_UNLINK) {
394 error = EACCES; 394 error = EACCES;
395 goto exit; 395 goto exit;
396 } 396 }
397 /* Fail if O_EXCL is set, and mqueue already exists */ 397 /* Fail if O_EXCL is set, and mqueue already exists */
398 if ((oflag & O_CREAT) && (oflag & O_EXCL)) { 398 if ((oflag & O_CREAT) && (oflag & O_EXCL)) {
399 error = EEXIST; 399 error = EEXIST;
400 goto exit; 400 goto exit;
401 } 401 }
402 402
403 /* 403 /*
404 * Check the permissions. Note the difference between 404 * Check the permissions. Note the difference between
405 * VREAD/VWRITE and FREAD/FWRITE. 405 * VREAD/VWRITE and FREAD/FWRITE.
406 */ 406 */
407 acc_mode = 0; 407 acc_mode = 0;
408 if (fp->f_flag & FREAD) { 408 if (fp->f_flag & FREAD) {
409 acc_mode |= VREAD; 409 acc_mode |= VREAD;
410 } 410 }
411 if (fp->f_flag & FWRITE) { 411 if (fp->f_flag & FWRITE) {
412 acc_mode |= VWRITE; 412 acc_mode |= VWRITE;
413 } 413 }
414 if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid, 414 if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid,
415 acc_mode, l->l_cred)) { 415 acc_mode, l->l_cred)) {
416 error = EACCES; 416 error = EACCES;
417 goto exit; 417 goto exit;
418 } 418 }
419 } else { 419 } else {
420 /* Fail if mqueue neither exists, nor we create it */ 420 /* Fail if mqueue neither exists, nor we create it */
421 if ((oflag & O_CREAT) == 0) { 421 if ((oflag & O_CREAT) == 0) {
422 mutex_exit(&mqlist_mtx); 422 mutex_exit(&mqlist_mtx);
423 KASSERT(mq_new == NULL); 423 KASSERT(mq_new == NULL);
424 fd_abort(p, fp, mqd); 424 fd_abort(p, fp, mqd);
425 kmem_free(name, MQ_NAMELEN); 425 kmem_free(name, MQ_NAMELEN);
426 return ENOENT; 426 return ENOENT;
427 } 427 }
428 428
429 /* Check the limit */ 429 /* Check the limit */
430 if (p->p_mqueue_cnt == mq_open_max) { 430 if (p->p_mqueue_cnt == mq_open_max) {
431 error = EMFILE; 431 error = EMFILE;
432 goto exit; 432 goto exit;
433 } 433 }
434 434
435 /* Insert the queue to the list */ 435 /* Insert the queue to the list */
436 mq = mq_new; 436 mq = mq_new;
437 mutex_enter(&mq->mq_mtx); 437 mutex_enter(&mq->mq_mtx);
438 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); 438 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list);
439 mq_new = NULL; 439 mq_new = NULL;
440 } 440 }
441 441
442 /* Increase the counters, and make descriptor ready */ 442 /* Increase the counters, and make descriptor ready */
443 p->p_mqueue_cnt++; 443 p->p_mqueue_cnt++;
444 mq->mq_refcnt++; 444 mq->mq_refcnt++;
445 fp->f_data = mq; 445 fp->f_data = mq;
446exit: 446exit:
447 mutex_exit(&mq->mq_mtx); 447 mutex_exit(&mq->mq_mtx);
448 mutex_exit(&mqlist_mtx); 448 mutex_exit(&mqlist_mtx);
449 449
450 if (mq_new) 450 if (mq_new)
451 mqueue_destroy(mq_new); 451 mqueue_destroy(mq_new);
452 if (error) { 452 if (error) {
453 fd_abort(p, fp, mqd); 453 fd_abort(p, fp, mqd);
454 } else { 454 } else {
455 fd_affix(p, fp, mqd); 455 fd_affix(p, fp, mqd);
456 *retval = mqd; 456 *retval = mqd;
457 } 457 }
458 kmem_free(name, MQ_NAMELEN); 458 kmem_free(name, MQ_NAMELEN);
459 459
460 return error; 460 return error;
461} 461}
462 462
463int 463int
464sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap, 464sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap,
465 register_t *retval) 465 register_t *retval)
466{ 466{
467 467
468 return sys_close(l, (const void *)uap, retval); 468 return sys_close(l, (const void *)uap, retval);
469} 469}
470 470
471/* 471/*
472 * Primary mq_receive1() function. 472 * Primary mq_receive1() function.
473 */ 473 */
474static int 474static int
475mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, 475mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len,
476 unsigned *msg_prio, int t, ssize_t *mlen) 476 unsigned *msg_prio, int t, ssize_t *mlen)
477{ 477{
478 file_t *fp = NULL; 478 file_t *fp = NULL;
479 struct mqueue *mq; 479 struct mqueue *mq;
480 struct mq_msg *msg = NULL; 480 struct mq_msg *msg = NULL;
481 int error; 481 int error;
482 482
483 /* Get the message queue */ 483 /* Get the message queue */
484 error = mqueue_get(mqdes, &fp); 484 error = mqueue_get(mqdes, &fp);
485 if (error) 485 if (error) {
486 return error; 486 return error;
 487 }
487 mq = fp->f_data; 488 mq = fp->f_data;
 489 if ((fp->f_flag & FREAD) == 0) {
 490 error = EBADF;
 491 goto error;
 492 }
488 493
489 /* Check the message size limits */ 494 /* Check the message size limits */
490 if (msg_len < mq->mq_attrib.mq_msgsize) { 495 if (msg_len < mq->mq_attrib.mq_msgsize) {
491 error = EMSGSIZE; 496 error = EMSGSIZE;
492 goto error; 497 goto error;
493 } 498 }
494 499
495 /* Check if queue is empty */ 500 /* Check if queue is empty */
496 while (TAILQ_EMPTY(&mq->mq_head)) { 501 while (TAILQ_EMPTY(&mq->mq_head)) {
497 if (mq->mq_attrib.mq_flags & O_NONBLOCK) { 502 if (mq->mq_attrib.mq_flags & O_NONBLOCK) {
498 error = EAGAIN; 503 error = EAGAIN;
499 goto error; 504 goto error;
500 } 505 }
501 if (t < 0) { 506 if (t < 0) {
502 error = EINVAL; 507 error = EINVAL;
503 goto error; 508 goto error;
504 } 509 }
505 /* 510 /*
506 * Block until someone sends the message. 511 * Block until someone sends the message.
507 * While doing this, notification should not be sent. 512 * While doing this, notification should not be sent.
508 */ 513 */
509 mq->mq_attrib.mq_flags |= MQ_RECEIVE; 514 mq->mq_attrib.mq_flags |= MQ_RECEIVE;
510 error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t); 515 error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t);
511 mq->mq_attrib.mq_flags &= ~MQ_RECEIVE; 516 mq->mq_attrib.mq_flags &= ~MQ_RECEIVE;
512 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 517 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
513 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR; 518 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR;
514 goto error; 519 goto error;
515 } 520 }
516 } 521 }
517 522
518 /* Remove the message from the queue */ 523 /* Remove the message from the queue */
519 msg = TAILQ_FIRST(&mq->mq_head); 524 msg = TAILQ_FIRST(&mq->mq_head);
520 KASSERT(msg != NULL); 525 KASSERT(msg != NULL);
521 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue); 526 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue);
522 527
523 /* Decrement the counter and signal waiter, if any */ 528 /* Decrement the counter and signal waiter, if any */
524 mq->mq_attrib.mq_curmsgs--; 529 mq->mq_attrib.mq_curmsgs--;
525 cv_signal(&mq->mq_recv_cv); 530 cv_signal(&mq->mq_recv_cv);
526 531
527 /* Ready for sending now */ 532 /* Ready for sending now */
528 selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0); 533 selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0);
529error: 534error:
530 mutex_exit(&mq->mq_mtx); 535 mutex_exit(&mq->mq_mtx);
531 fd_putfile((int)mqdes); 536 fd_putfile((int)mqdes);
532 if (error) 537 if (error)
533 return error; 538 return error;
534 539
535 /* 540 /*
536 * Copy the data to the user-space. 541 * Copy the data to the user-space.
537 * Note: According to POSIX, no message should be removed from the 542 * Note: According to POSIX, no message should be removed from the
538 * queue in case of fail - this would be violated. 543 * queue in case of fail - this would be violated.
539 */ 544 */
540 *mlen = msg->msg_len; 545 *mlen = msg->msg_len;
541 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len); 546 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len);
542 if (error == 0 && msg_prio) 547 if (error == 0 && msg_prio)
543 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned)); 548 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned));
544 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 549 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
545 550
546 return error; 551 return error;
547} 552}
548 553
549int 554int
550sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap, 555sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap,
551 register_t *retval) 556 register_t *retval)
552{ 557{
553 /* { 558 /* {
554 syscallarg(mqd_t) mqdes; 559 syscallarg(mqd_t) mqdes;
555 syscallarg(char *) msg_ptr; 560 syscallarg(char *) msg_ptr;
556 syscallarg(size_t) msg_len; 561 syscallarg(size_t) msg_len;
557 syscallarg(unsigned *) msg_prio; 562 syscallarg(unsigned *) msg_prio;
558 } */ 563 } */
559 int error; 564 int error;
560 ssize_t mlen; 565 ssize_t mlen;
561 566
562 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 567 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
563 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen); 568 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen);
564 if (error == 0) 569 if (error == 0)
565 *retval = mlen; 570 *retval = mlen;
566 571
567 return error; 572 return error;
568} 573}
569 574
570int 575int
571sys_mq_timedreceive(struct lwp *l, const struct sys_mq_timedreceive_args *uap, 576sys_mq_timedreceive(struct lwp *l, const struct sys_mq_timedreceive_args *uap,
572 register_t *retval) 577 register_t *retval)
573{ 578{
574 /* { 579 /* {
575 syscallarg(mqd_t) mqdes; 580 syscallarg(mqd_t) mqdes;
576 syscallarg(char *) msg_ptr; 581 syscallarg(char *) msg_ptr;
577 syscallarg(size_t) msg_len; 582 syscallarg(size_t) msg_len;
578 syscallarg(unsigned *) msg_prio; 583 syscallarg(unsigned *) msg_prio;
579 syscallarg(const struct timespec *) abs_timeout; 584 syscallarg(const struct timespec *) abs_timeout;
580 } */ 585 } */
581 int error, t; 586 int error, t;
582 ssize_t mlen; 587 ssize_t mlen;
583 588
584 /* Get and convert time value */ 589 /* Get and convert time value */
585 if (SCARG(uap, abs_timeout)) { 590 if (SCARG(uap, abs_timeout)) {
586 error = abstimeout2timo(SCARG(uap, abs_timeout), &t); 591 error = abstimeout2timo(SCARG(uap, abs_timeout), &t);
587 if (error) 592 if (error)
588 return error; 593 return error;
589 } else 594 } else
590 t = 0; 595 t = 0;
591 596
592 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 597 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
593 SCARG(uap, msg_len), SCARG(uap, msg_prio), t, &mlen); 598 SCARG(uap, msg_len), SCARG(uap, msg_prio), t, &mlen);
594 if (error == 0) 599 if (error == 0)
595 *retval = mlen; 600 *retval = mlen;
596 601
597 return error; 602 return error;
598} 603}
599 604
600/* 605/*
601 * Primary mq_send1() function. 606 * Primary mq_send1() function.
602 */ 607 */
603static int 608static int
604mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len, 609mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len,
605 unsigned msg_prio, int t) 610 unsigned msg_prio, int t)
606{ 611{
607 file_t *fp = NULL; 612 file_t *fp = NULL;
608 struct mqueue *mq; 613 struct mqueue *mq;
609 struct mq_msg *msg, *pos_msg; 614 struct mq_msg *msg, *pos_msg;
610 struct proc *notify = NULL; 615 struct proc *notify = NULL;
611 ksiginfo_t ksi; 616 ksiginfo_t ksi;
612 size_t size; 617 size_t size;
613 int error; 618 int error;
614 619
615 /* Check the priority range */ 620 /* Check the priority range */
616 if (msg_prio >= mq_prio_max) 621 if (msg_prio >= mq_prio_max)
617 return EINVAL; 622 return EINVAL;
618 623
619 /* Allocate a new message */ 624 /* Allocate a new message */
620 size = sizeof(struct mq_msg) + msg_len; 625 size = sizeof(struct mq_msg) + msg_len;
621 if (size > mq_max_msgsize) 626 if (size > mq_max_msgsize)
622 return EMSGSIZE; 627 return EMSGSIZE;
623 628
624 if (size > MQ_DEF_MSGSIZE) 629 if (size > MQ_DEF_MSGSIZE)
625 msg = kmem_alloc(size, KM_SLEEP); 630 msg = kmem_alloc(size, KM_SLEEP);
626 else 631 else
627 msg = pool_cache_get(mqmsg_cache, PR_WAITOK); 632 msg = pool_cache_get(mqmsg_cache, PR_WAITOK);
628 633
629 /* Get the data from user-space */ 634 /* Get the data from user-space */
630 error = copyin(msg_ptr, msg->msg_ptr, msg_len); 635 error = copyin(msg_ptr, msg->msg_ptr, msg_len);
631 if (error) { 636 if (error) {
632 mqueue_freemsg(msg, size); 637 mqueue_freemsg(msg, size);
633 return error; 638 return error;
634 } 639 }
635 msg->msg_len = msg_len; 640 msg->msg_len = msg_len;
636 msg->msg_prio = msg_prio; 641 msg->msg_prio = msg_prio;
637 642
638 /* Get the mqueue */ 643 /* Get the mqueue */
639 error = mqueue_get(mqdes, &fp); 644 error = mqueue_get(mqdes, &fp);
640 if (error) { 645 if (error) {
641 mqueue_freemsg(msg, size); 646 mqueue_freemsg(msg, size);
642 return error; 647 return error;
643 } 648 }
644 mq = fp->f_data; 649 mq = fp->f_data;
 650 if ((fp->f_flag & FWRITE) == 0) {
 651 error = EBADF;
 652 goto error;
 653 }
645 654
646 /* Check the message size limit */ 655 /* Check the message size limit */
647 if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) { 656 if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) {
648 error = EMSGSIZE; 657 error = EMSGSIZE;
649 goto error; 658 goto error;
650 } 659 }
651 660
652 /* Check if queue is full */ 661 /* Check if queue is full */
653 while (mq->mq_attrib.mq_curmsgs >= mq->mq_attrib.mq_maxmsg) { 662 while (mq->mq_attrib.mq_curmsgs >= mq->mq_attrib.mq_maxmsg) {
654 if (mq->mq_attrib.mq_flags & O_NONBLOCK) { 663 if (mq->mq_attrib.mq_flags & O_NONBLOCK) {
655 error = EAGAIN; 664 error = EAGAIN;
656 goto error; 665 goto error;
657 } 666 }
658 if (t < 0) { 667 if (t < 0) {
659 error = EINVAL; 668 error = EINVAL;
660 goto error; 669 goto error;
661 } 670 }
662 /* Block until queue becomes available */ 671 /* Block until queue becomes available */
663 error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t); 672 error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t);
664 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 673 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
665 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error; 674 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error;
666 goto error; 675 goto error;
667 } 676 }
668 } 677 }
669 KASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg); 678 KASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg);
670 679
671 /* Insert message into the queue, according to the priority */ 680 /* Insert message into the queue, according to the priority */
672 TAILQ_FOREACH(pos_msg, &mq->mq_head, msg_queue) 681 TAILQ_FOREACH(pos_msg, &mq->mq_head, msg_queue)
673 if (msg->msg_prio > pos_msg->msg_prio) 682 if (msg->msg_prio > pos_msg->msg_prio)
674 break; 683 break;
675 if (pos_msg == NULL) 684 if (pos_msg == NULL)
676 TAILQ_INSERT_TAIL(&mq->mq_head, msg, msg_queue); 685 TAILQ_INSERT_TAIL(&mq->mq_head, msg, msg_queue);
677 else 686 else
678 TAILQ_INSERT_BEFORE(pos_msg, msg, msg_queue); 687 TAILQ_INSERT_BEFORE(pos_msg, msg, msg_queue);
679 688
680 /* Check for the notify */ 689 /* Check for the notify */
681 if (mq->mq_attrib.mq_curmsgs == 0 && mq->mq_notify_proc && 690 if (mq->mq_attrib.mq_curmsgs == 0 && mq->mq_notify_proc &&
682 (mq->mq_attrib.mq_flags & MQ_RECEIVE) == 0) { 691 (mq->mq_attrib.mq_flags & MQ_RECEIVE) == 0) {
683 /* Initialize the signal */ 692 /* Initialize the signal */
684 KSI_INIT(&ksi); 693 KSI_INIT(&ksi);
685 ksi.ksi_signo = mq->mq_sig_notify.sigev_signo; 694 ksi.ksi_signo = mq->mq_sig_notify.sigev_signo;
686 ksi.ksi_code = SI_MESGQ; 695 ksi.ksi_code = SI_MESGQ;
687 ksi.ksi_value = mq->mq_sig_notify.sigev_value; 696 ksi.ksi_value = mq->mq_sig_notify.sigev_value;
688 /* Unregister the process */ 697 /* Unregister the process */
689 notify = mq->mq_notify_proc; 698 notify = mq->mq_notify_proc;
690 mq->mq_notify_proc = NULL; 699 mq->mq_notify_proc = NULL;
691 } 700 }
692 701
693 /* Increment the counter and signal waiter, if any */ 702 /* Increment the counter and signal waiter, if any */
694 mq->mq_attrib.mq_curmsgs++; 703 mq->mq_attrib.mq_curmsgs++;
695 cv_signal(&mq->mq_send_cv); 704 cv_signal(&mq->mq_send_cv);
696 705
697 /* Ready for receiving now */ 706 /* Ready for receiving now */
698 selnotify(&mq->mq_rsel, POLLIN | POLLRDNORM, 0); 707 selnotify(&mq->mq_rsel, POLLIN | POLLRDNORM, 0);
699error: 708error:
700 mutex_exit(&mq->mq_mtx); 709 mutex_exit(&mq->mq_mtx);
701 fd_putfile((int)mqdes); 710 fd_putfile((int)mqdes);
702 711
703 if (error) { 712 if (error) {
704 mqueue_freemsg(msg, size); 713 mqueue_freemsg(msg, size);
705 } else if (notify) { 714 } else if (notify) {
706 /* Send the notify, if needed */ 715 /* Send the notify, if needed */
707 mutex_enter(proc_lock); 716 mutex_enter(proc_lock);
708 kpsignal(notify, &ksi, NULL); 717 kpsignal(notify, &ksi, NULL);
709 mutex_exit(proc_lock); 718 mutex_exit(proc_lock);
710 } 719 }
711 720
712 return error; 721 return error;
713} 722}
714 723
715int 724int
716sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap, 725sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap,
717 register_t *retval) 726 register_t *retval)
718{ 727{
719 /* { 728 /* {
720 syscallarg(mqd_t) mqdes; 729 syscallarg(mqd_t) mqdes;
721 syscallarg(const char *) msg_ptr; 730 syscallarg(const char *) msg_ptr;
722 syscallarg(size_t) msg_len; 731 syscallarg(size_t) msg_len;
723 syscallarg(unsigned) msg_prio; 732 syscallarg(unsigned) msg_prio;
724 } */ 733 } */
725 734
726 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 735 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
727 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0); 736 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0);
728} 737}
729 738
730int 739int
731sys_mq_timedsend(struct lwp *l, const struct sys_mq_timedsend_args *uap, 740sys_mq_timedsend(struct lwp *l, const struct sys_mq_timedsend_args *uap,
732 register_t *retval) 741 register_t *retval)
733{ 742{
734 /* { 743 /* {
735 syscallarg(mqd_t) mqdes; 744 syscallarg(mqd_t) mqdes;
736 syscallarg(const char *) msg_ptr; 745 syscallarg(const char *) msg_ptr;
737 syscallarg(size_t) msg_len; 746 syscallarg(size_t) msg_len;
738 syscallarg(unsigned) msg_prio; 747 syscallarg(unsigned) msg_prio;
739 syscallarg(const struct timespec *) abs_timeout; 748 syscallarg(const struct timespec *) abs_timeout;
740 } */ 749 } */
741 int t; 750 int t;
742 751
743 /* Get and convert time value */ 752 /* Get and convert time value */
744 if (SCARG(uap, abs_timeout)) { 753 if (SCARG(uap, abs_timeout)) {
745 int error = abstimeout2timo(SCARG(uap, abs_timeout), &t); 754 int error = abstimeout2timo(SCARG(uap, abs_timeout), &t);
746 if (error) 755 if (error)
747 return error; 756 return error;
748 } else 757 } else
749 t = 0; 758 t = 0;
750 759
751 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 760 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
752 SCARG(uap, msg_len), SCARG(uap, msg_prio), t); 761 SCARG(uap, msg_len), SCARG(uap, msg_prio), t);
753} 762}
754 763
755int 764int
756sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap, 765sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap,
757 register_t *retval) 766 register_t *retval)
758{ 767{
759 /* { 768 /* {
760 syscallarg(mqd_t) mqdes; 769 syscallarg(mqd_t) mqdes;
761 syscallarg(const struct sigevent *) notification; 770 syscallarg(const struct sigevent *) notification;
762 } */ 771 } */
763 file_t *fp = NULL; 772 file_t *fp = NULL;
764 struct mqueue *mq; 773 struct mqueue *mq;
765 struct sigevent sig; 774 struct sigevent sig;
766 int error; 775 int error;
767 776
768 if (SCARG(uap, notification)) { 777 if (SCARG(uap, notification)) {
769 /* Get the signal from user-space */ 778 /* Get the signal from user-space */
770 error = copyin(SCARG(uap, notification), &sig, 779 error = copyin(SCARG(uap, notification), &sig,
771 sizeof(struct sigevent)); 780 sizeof(struct sigevent));
772 if (error) 781 if (error)
773 return error; 782 return error;
774 } 783 }
775 784
776 error = mqueue_get(SCARG(uap, mqdes), &fp); 785 error = mqueue_get(SCARG(uap, mqdes), &fp);
777 if (error) 786 if (error)
778 return error; 787 return error;
779 mq = fp->f_data; 788 mq = fp->f_data;
780 789
781 if (SCARG(uap, notification)) { 790 if (SCARG(uap, notification)) {
782 /* Register notification: set the signal and target process */ 791 /* Register notification: set the signal and target process */
783 if (mq->mq_notify_proc == NULL) { 792 if (mq->mq_notify_proc == NULL) {
784 memcpy(&mq->mq_sig_notify, &sig, 793 memcpy(&mq->mq_sig_notify, &sig,
785 sizeof(struct sigevent)); 794 sizeof(struct sigevent));
786 mq->mq_notify_proc = l->l_proc; 795 mq->mq_notify_proc = l->l_proc;
787 } else { 796 } else {
788 /* Fail if someone else already registered */ 797 /* Fail if someone else already registered */
789 error = EBUSY; 798 error = EBUSY;
790 } 799 }
791 } else { 800 } else {
792 /* Unregister the notification */ 801 /* Unregister the notification */
793 mq->mq_notify_proc = NULL; 802 mq->mq_notify_proc = NULL;
794 } 803 }
795 mutex_exit(&mq->mq_mtx); 804 mutex_exit(&mq->mq_mtx);
796 fd_putfile((int)SCARG(uap, mqdes)); 805 fd_putfile((int)SCARG(uap, mqdes));
797 806
798 return error; 807 return error;
799} 808}
800 809
801int 810int
802sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap, 811sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap,
803 register_t *retval) 812 register_t *retval)
804{ 813{
805 /* { 814 /* {
806 syscallarg(mqd_t) mqdes; 815 syscallarg(mqd_t) mqdes;
807 syscallarg(struct mq_attr *) mqstat; 816 syscallarg(struct mq_attr *) mqstat;
808 } */ 817 } */
809 file_t *fp = NULL; 818 file_t *fp = NULL;
810 struct mqueue *mq; 819 struct mqueue *mq;
811 struct mq_attr attr; 820 struct mq_attr attr;
812 int error; 821 int error;
813 822
814 /* Get the message queue */ 823 /* Get the message queue */
815 error = mqueue_get(SCARG(uap, mqdes), &fp); 824 error = mqueue_get(SCARG(uap, mqdes), &fp);
816 if (error) 825 if (error)
817 return error; 826 return error;
818 mq = fp->f_data; 827 mq = fp->f_data;
819 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 828 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
820 mutex_exit(&mq->mq_mtx); 829 mutex_exit(&mq->mq_mtx);
821 fd_putfile((int)SCARG(uap, mqdes)); 830 fd_putfile((int)SCARG(uap, mqdes));
822 831
823 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); 832 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr));
824} 833}
825 834
826int 835int
827sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap, 836sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap,
828 register_t *retval) 837 register_t *retval)
829{ 838{
830 /* { 839 /* {
831 syscallarg(mqd_t) mqdes; 840 syscallarg(mqd_t) mqdes;
832 syscallarg(const struct mq_attr *) mqstat; 841 syscallarg(const struct mq_attr *) mqstat;
833 syscallarg(struct mq_attr *) omqstat; 842 syscallarg(struct mq_attr *) omqstat;
834 } */ 843 } */
835 file_t *fp = NULL; 844 file_t *fp = NULL;
836 struct mqueue *mq; 845 struct mqueue *mq;
837 struct mq_attr attr; 846 struct mq_attr attr;
838 int error, nonblock; 847 int error, nonblock;
839 848
840 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); 849 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr));
841 if (error) 850 if (error)
842 return error; 851 return error;
843 nonblock = (attr.mq_flags & O_NONBLOCK); 852 nonblock = (attr.mq_flags & O_NONBLOCK);
844 853
845 /* Get the message queue */ 854 /* Get the message queue */
846 error = mqueue_get(SCARG(uap, mqdes), &fp); 855 error = mqueue_get(SCARG(uap, mqdes), &fp);
847 if (error) 856 if (error)
848 return error; 857 return error;
849 mq = fp->f_data; 858 mq = fp->f_data;
850 859
851 /* Copy the old attributes, if needed */ 860 /* Copy the old attributes, if needed */
852 if (SCARG(uap, omqstat)) 861 if (SCARG(uap, omqstat))
853 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 862 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
854 863
855 /* Ignore everything, except O_NONBLOCK */ 864 /* Ignore everything, except O_NONBLOCK */
856 if (nonblock) 865 if (nonblock)
857 mq->mq_attrib.mq_flags |= O_NONBLOCK; 866 mq->mq_attrib.mq_flags |= O_NONBLOCK;
858 else 867 else
859 mq->mq_attrib.mq_flags &= ~O_NONBLOCK; 868 mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
860 869
861 mutex_exit(&mq->mq_mtx); 870 mutex_exit(&mq->mq_mtx);
862 fd_putfile((int)SCARG(uap, mqdes)); 871 fd_putfile((int)SCARG(uap, mqdes));
863 872
864 /* 873 /*
865 * Copy the data to the user-space. 874 * Copy the data to the user-space.
866 * Note: According to POSIX, the new attributes should not be set in 875 * Note: According to POSIX, the new attributes should not be set in
867 * case of fail - this would be violated. 876 * case of fail - this would be violated.
868 */ 877 */
869 if (SCARG(uap, omqstat)) 878 if (SCARG(uap, omqstat))
870 error = copyout(&attr, SCARG(uap, omqstat), 879 error = copyout(&attr, SCARG(uap, omqstat),
871 sizeof(struct mq_attr)); 880 sizeof(struct mq_attr));
872 881
873 return error; 882 return error;
874} 883}
875 884
876int 885int
877sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap, 886sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap,
878 register_t *retval) 887 register_t *retval)
879{ 888{
880 /* { 889 /* {
881 syscallarg(const char *) name; 890 syscallarg(const char *) name;
882 } */ 891 } */
883 struct mqueue *mq; 892 struct mqueue *mq;
884 char *name; 893 char *name;
885 int error, refcnt = 0; 894 int error, refcnt = 0;
886 895
887 /* Get the name from the user-space */ 896 /* Get the name from the user-space */
888 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 897 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP);
889 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 898 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
890 if (error) { 899 if (error) {
891 kmem_free(name, MQ_NAMELEN); 900 kmem_free(name, MQ_NAMELEN);
892 return error; 901 return error;
893 } 902 }
894 903
895 /* Lookup for this file */ 904 /* Lookup for this file */
896 mutex_enter(&mqlist_mtx); 905 mutex_enter(&mqlist_mtx);
897 mq = mqueue_lookup(name); 906 mq = mqueue_lookup(name);
898 if (mq == NULL) { 907 if (mq == NULL) {
899 error = ENOENT; 908 error = ENOENT;
900 goto error; 909 goto error;
901 } 910 }
902 911
903 /* Check the permissions */ 912 /* Check the permissions */
904 if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid && 913 if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid &&
905 kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) { 914 kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
906 mutex_exit(&mq->mq_mtx); 915 mutex_exit(&mq->mq_mtx);
907 error = EACCES; 916 error = EACCES;
908 goto error; 917 goto error;
909 } 918 }
910 919
911 /* Mark message queue as unlinking, before leaving the window */ 920 /* Mark message queue as unlinking, before leaving the window */
912 mq->mq_attrib.mq_flags |= MQ_UNLINK; 921 mq->mq_attrib.mq_flags |= MQ_UNLINK;
913 922
914 /* Wake up all waiters, if there are such */ 923 /* Wake up all waiters, if there are such */
915 cv_broadcast(&mq->mq_send_cv); 924 cv_broadcast(&mq->mq_send_cv);
916 cv_broadcast(&mq->mq_recv_cv); 925 cv_broadcast(&mq->mq_recv_cv);
917 926
918 selnotify(&mq->mq_rsel, POLLHUP, 0); 927 selnotify(&mq->mq_rsel, POLLHUP, 0);
919 selnotify(&mq->mq_wsel, POLLHUP, 0); 928 selnotify(&mq->mq_wsel, POLLHUP, 0);
920 929
921 refcnt = mq->mq_refcnt; 930 refcnt = mq->mq_refcnt;
922 if (refcnt == 0) 931 if (refcnt == 0)
923 LIST_REMOVE(mq, mq_list); 932 LIST_REMOVE(mq, mq_list);
924 933
925 mutex_exit(&mq->mq_mtx); 934 mutex_exit(&mq->mq_mtx);
926error: 935error:
927 mutex_exit(&mqlist_mtx); 936 mutex_exit(&mqlist_mtx);
928 937
929 /* 938 /*
930 * If there are no references - destroy the message 939 * If there are no references - destroy the message
931 * queue, otherwise, the last mq_close() will do that. 940 * queue, otherwise, the last mq_close() will do that.
932 */ 941 */
933 if (error == 0 && refcnt == 0) 942 if (error == 0 && refcnt == 0)
934 mqueue_destroy(mq); 943 mqueue_destroy(mq);
935 944
936 kmem_free(name, MQ_NAMELEN); 945 kmem_free(name, MQ_NAMELEN);
937 return error; 946 return error;
938} 947}
939 948
940/* 949/*
941 * SysCtl. 950 * SysCtl.
942 */ 951 */
943 952
944SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup") 953SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup")
945{ 954{
946 const struct sysctlnode *node = NULL; 955 const struct sysctlnode *node = NULL;
947 956
948 sysctl_createv(clog, 0, NULL, NULL, 957 sysctl_createv(clog, 0, NULL, NULL,
949 CTLFLAG_PERMANENT, 958 CTLFLAG_PERMANENT,
950 CTLTYPE_NODE, "kern", NULL, 959 CTLTYPE_NODE, "kern", NULL,
951 NULL, 0, NULL, 0, 960 NULL, 0, NULL, 0,
952 CTL_KERN, CTL_EOL); 961 CTL_KERN, CTL_EOL);
953 sysctl_createv(clog, 0, NULL, NULL, 962 sysctl_createv(clog, 0, NULL, NULL,
954 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 963 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
955 CTLTYPE_INT, "posix_msg", 964 CTLTYPE_INT, "posix_msg",
956 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its " 965 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its "
957 "Message Passing option to which the " 966 "Message Passing option to which the "
958 "system attempts to conform"), 967 "system attempts to conform"),
959 NULL, _POSIX_MESSAGE_PASSING, NULL, 0, 968 NULL, _POSIX_MESSAGE_PASSING, NULL, 0,
960 CTL_KERN, CTL_CREATE, CTL_EOL); 969 CTL_KERN, CTL_CREATE, CTL_EOL);
961 sysctl_createv(clog, 0, NULL, &node, 970 sysctl_createv(clog, 0, NULL, &node,
962 CTLFLAG_PERMANENT, 971 CTLFLAG_PERMANENT,
963 CTLTYPE_NODE, "mqueue", 972 CTLTYPE_NODE, "mqueue",
964 SYSCTL_DESCR("Message queue options"), 973 SYSCTL_DESCR("Message queue options"),
965 NULL, 0, NULL, 0, 974 NULL, 0, NULL, 0,
966 CTL_KERN, CTL_CREATE, CTL_EOL); 975 CTL_KERN, CTL_CREATE, CTL_EOL);
967 976
968 if (node == NULL) 977 if (node == NULL)
969 return; 978 return;
970 979
971 sysctl_createv(clog, 0, &node, NULL, 980 sysctl_createv(clog, 0, &node, NULL,
972 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 981 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
973 CTLTYPE_INT, "mq_open_max", 982 CTLTYPE_INT, "mq_open_max",
974 SYSCTL_DESCR("Maximal number of message queue descriptors " 983 SYSCTL_DESCR("Maximal number of message queue descriptors "
975 "that process could open"), 984 "that process could open"),
976 NULL, 0, &mq_open_max, 0, 985 NULL, 0, &mq_open_max, 0,
977 CTL_CREATE, CTL_EOL); 986 CTL_CREATE, CTL_EOL);
978 sysctl_createv(clog, 0, &node, NULL, 987 sysctl_createv(clog, 0, &node, NULL,
979 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 988 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
980 CTLTYPE_INT, "mq_prio_max", 989 CTLTYPE_INT, "mq_prio_max",
981 SYSCTL_DESCR("Maximal priority of the message"), 990 SYSCTL_DESCR("Maximal priority of the message"),
982 NULL, 0, &mq_prio_max, 0, 991 NULL, 0, &mq_prio_max, 0,
983 CTL_CREATE, CTL_EOL); 992 CTL_CREATE, CTL_EOL);
984 sysctl_createv(clog, 0, &node, NULL, 993 sysctl_createv(clog, 0, &node, NULL,
985 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 994 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
986 CTLTYPE_INT, "mq_max_msgsize", 995 CTLTYPE_INT, "mq_max_msgsize",
987 SYSCTL_DESCR("Maximal allowed size of the message"), 996 SYSCTL_DESCR("Maximal allowed size of the message"),
988 NULL, 0, &mq_max_msgsize, 0, 997 NULL, 0, &mq_max_msgsize, 0,
989 CTL_CREATE, CTL_EOL); 998 CTL_CREATE, CTL_EOL);
990 sysctl_createv(clog, 0, &node, NULL, 999 sysctl_createv(clog, 0, &node, NULL,
991 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1000 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
992 CTLTYPE_INT, "mq_def_maxmsg", 1001 CTLTYPE_INT, "mq_def_maxmsg",
993 SYSCTL_DESCR("Default maximal message count"), 1002 SYSCTL_DESCR("Default maximal message count"),
994 NULL, 0, &mq_def_maxmsg, 0, 1003 NULL, 0, &mq_def_maxmsg, 0,
995 CTL_CREATE, CTL_EOL); 1004 CTL_CREATE, CTL_EOL);
996} 1005}
997 1006
998/* 1007/*
999 * Debugging. 1008 * Debugging.
1000 */ 1009 */
1001#if defined(DDB) 1010#if defined(DDB)
1002 1011
1003void 1012void
1004mqueue_print_list(void (*pr)(const char *, ...)) 1013mqueue_print_list(void (*pr)(const char *, ...))
1005{ 1014{
1006 struct mqueue *mq; 1015 struct mqueue *mq;
1007 1016
1008 (*pr)("Global list of the message queues:\n"); 1017 (*pr)("Global list of the message queues:\n");
1009 (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n", 1018 (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n",
1010 "Name", "Ptr", "Mode", "Flags", "Ref", 1019 "Name", "Ptr", "Mode", "Flags", "Ref",
1011 "MaxMsg", "MsgSze", "CurMsg"); 1020 "MaxMsg", "MsgSze", "CurMsg");
1012 LIST_FOREACH(mq, &mqueue_head, mq_list) { 1021 LIST_FOREACH(mq, &mqueue_head, mq_list) {
1013 (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n", 1022 (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n",
1014 mq->mq_name, mq, mq->mq_mode, 1023 mq->mq_name, mq, mq->mq_mode,
1015 mq->mq_attrib.mq_flags, mq->mq_refcnt, 1024 mq->mq_attrib.mq_flags, mq->mq_refcnt,
1016 mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize, 1025 mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize,
1017 mq->mq_attrib.mq_curmsgs); 1026 mq->mq_attrib.mq_curmsgs);
1018 } 1027 }
1019} 1028}
1020 1029
1021#endif /* defined(DDB) */ 1030#endif /* defined(DDB) */