1 /* $NetBSD: netbsd32_mqueue.c,v 1.7 2019/01/27 02:08:40 pgoyette Exp $ */
2
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software developed for The NetBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_mqueue.c,v 1.7 2019/01/27 02:08:40 pgoyette Exp $");
33
34 #if defined(_KERNEL_OPT)
35 #include "opt_compat_netbsd.h"
36 #endif
37
38 #include <sys/param.h>
39 #include <sys/dirent.h>
40 #include <sys/filedesc.h>
41 #include <sys/fcntl.h>
42 #include <sys/module.h>
43 #include <sys/syscallvar.h>
44
45 #include <compat/netbsd32/netbsd32.h>
46 #include <compat/netbsd32/netbsd32_syscall.h>
47 #include <compat/netbsd32/netbsd32_syscallargs.h>
48 #include <compat/netbsd32/netbsd32_conv.h>
49
50 int
netbsd32_mq_open(struct lwp * l,const struct netbsd32_mq_open_args * uap,register_t * retval)51 netbsd32_mq_open(struct lwp *l, const struct netbsd32_mq_open_args *uap,
52 register_t *retval)
53 {
54 /* {
55 syscallarg(const netbsd32_charp) name;
56 syscallarg(int) oflag;
57 syscallarg(mode_t) mode;
58 syscallarg(struct netbsd32_mq_attrp_t) attr;
59 } */
60 struct netbsd32_mq_attr attr32;
61 struct mq_attr *attr = NULL, a;
62 int error;
63
64 if ((SCARG(uap, oflag) & O_CREAT) && SCARG_P32(uap, attr) != NULL) {
65 error = copyin(SCARG_P32(uap, attr), &attr32, sizeof(attr32));
66 if (error)
67 return error;
68 netbsd32_to_mq_attr(&attr32, &a);
69 attr = &a;
70 }
71
72 return mq_handle_open(l, SCARG_P32(uap, name), SCARG(uap, oflag),
73 SCARG(uap, mode), attr, retval);
74 }
75
76 int
netbsd32_mq_close(struct lwp * l,const struct netbsd32_mq_close_args * uap,register_t * retval)77 netbsd32_mq_close(struct lwp *l, const struct netbsd32_mq_close_args *uap,
78 register_t *retval)
79 {
80 /* {
81 syscallarg(mqd_t) mqdes;
82 } */
83
84 return netbsd32_close(l, (const void*)uap, retval);
85 }
86
87 int
netbsd32_mq_unlink(struct lwp * l,const struct netbsd32_mq_unlink_args * uap,register_t * retval)88 netbsd32_mq_unlink(struct lwp *l, const struct netbsd32_mq_unlink_args *uap,
89 register_t *retval)
90 {
91 /* {
92 syscallarg(const netbsd32_charp) name;
93 } */
94 struct sys_mq_unlink_args ua;
95
96 NETBSD32TOP_UAP(name, const char);
97 return sys_mq_unlink(l, &ua, retval);
98 }
99
100 int
netbsd32_mq_getattr(struct lwp * l,const struct netbsd32_mq_getattr_args * uap,register_t * retval)101 netbsd32_mq_getattr(struct lwp *l, const struct netbsd32_mq_getattr_args *uap,
102 register_t *retval)
103 {
104 /* {
105 syscallarg(mqd_t) mqdes;
106 syscallarg(netbsd32_mq_attrp_t) mqstat;
107 } */
108 struct mqueue *mq;
109 struct mq_attr attr;
110 struct netbsd32_mq_attr a32;
111 int error;
112
113 error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
114 if (error)
115 return error;
116
117 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
118 mutex_exit(&mq->mq_mtx);
119 fd_putfile((int)SCARG(uap, mqdes));
120 netbsd32_from_mq_attr(&attr, &a32);
121 return copyout(&a32, SCARG_P32(uap,mqstat), sizeof(a32));
122 }
123
124 int
netbsd32_mq_setattr(struct lwp * l,const struct netbsd32_mq_setattr_args * uap,register_t * retval)125 netbsd32_mq_setattr(struct lwp *l, const struct netbsd32_mq_setattr_args *uap,
126 register_t *retval)
127 {
128 /* {
129 syscallarg(mqd_t) mqdes;
130 syscallarg(const netbsd32_mq_attrp_t) mqstat;
131 syscallarg(netbsd32_mq_attrp_t) omqstat;
132 } */
133 struct mqueue *mq;
134 struct netbsd32_mq_attr attr32;
135 struct mq_attr attr;
136 int error, nonblock;
137
138 error = copyin(SCARG_P32(uap, mqstat), &attr32, sizeof(attr32));
139 if (error)
140 return error;
141 netbsd32_to_mq_attr(&attr32, &attr);
142 nonblock = (attr.mq_flags & O_NONBLOCK);
143
144 error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
145 if (error)
146 return error;
147
148 /* Copy the old attributes, if needed */
149 if (SCARG_P32(uap, omqstat))
150 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
151
152 /* Ignore everything, except O_NONBLOCK */
153 if (nonblock)
154 mq->mq_attrib.mq_flags |= O_NONBLOCK;
155 else
156 mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
157
158 mutex_exit(&mq->mq_mtx);
159 fd_putfile((int)SCARG(uap, mqdes));
160
161 /*
162 * Copy the data to the user-space.
163 * Note: According to POSIX, the new attributes should not be set in
164 * case of fail - this would be violated.
165 */
166 if (SCARG_P32(uap, omqstat)) {
167 netbsd32_from_mq_attr(&attr, &attr32);
168 error = copyout(&attr32, SCARG_P32(uap, omqstat),
169 sizeof(attr32));
170 }
171
172 return error;
173 }
174
175 int
netbsd32_mq_notify(struct lwp * l,const struct netbsd32_mq_notify_args * uap,register_t * result)176 netbsd32_mq_notify(struct lwp *l, const struct netbsd32_mq_notify_args *uap,
177 register_t *result)
178 {
179 /* {
180 syscallarg(mqd_t) mqdes;
181 syscallarg(const netbsd32_sigeventp_t) notification;
182 } */
183 struct mqueue *mq;
184 struct netbsd32_sigevent sig32;
185 int error;
186
187 if (SCARG_P32(uap, notification)) {
188 /* Get the signal from user-space */
189 error = copyin(SCARG_P32(uap, notification), &sig32,
190 sizeof(sig32));
191 if (error)
192 return error;
193 if (sig32.sigev_notify == SIGEV_SIGNAL &&
194 (sig32.sigev_signo <=0 || sig32.sigev_signo >= NSIG))
195 return EINVAL;
196 }
197
198 error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
199 if (error) {
200 return error;
201 }
202 if (SCARG_P32(uap, notification)) {
203 /* Register notification: set the signal and target process */
204 if (mq->mq_notify_proc == NULL) {
205 netbsd32_to_sigevent(&sig32, &mq->mq_sig_notify);
206 mq->mq_notify_proc = l->l_proc;
207 } else {
208 /* Fail if someone else already registered */
209 error = EBUSY;
210 }
211 } else {
212 /* Unregister the notification */
213 mq->mq_notify_proc = NULL;
214 }
215 mutex_exit(&mq->mq_mtx);
216 fd_putfile((int)SCARG(uap, mqdes));
217
218 return error;
219 }
220
221 int
netbsd32_mq_send(struct lwp * l,const struct netbsd32_mq_send_args * uap,register_t * result)222 netbsd32_mq_send(struct lwp *l, const struct netbsd32_mq_send_args *uap,
223 register_t *result)
224 {
225 /* {
226 syscallarg(mqd_t) mqdes;
227 syscallarg(const netbsd32_charp) msg_ptr;
228 syscallarg(netbsd32_size_t) msg_len;
229 syscallarg(unsigned) msg_prio;
230 } */
231
232
233 return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
234 SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL);
235 }
236
237 int
netbsd32_mq_receive(struct lwp * l,const struct netbsd32_mq_receive_args * uap,register_t * retval)238 netbsd32_mq_receive(struct lwp *l, const struct netbsd32_mq_receive_args *uap,
239 register_t *retval)
240 {
241 /* {
242 syscallarg(mqd_t) mqdes;
243 syscallarg(netbsd32_charp) msg_ptr;
244 syscallarg(netbsd32_size_t) msg_len;
245 syscallarg(netbsd32_uintp) msg_prio;
246 } */
247 ssize_t mlen;
248 int error;
249
250 error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
251 SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), NULL, &mlen);
252 if (error == 0)
253 *retval = mlen;
254
255 return error;
256 }
257
258 int
netbsd32___mq_timedsend50(struct lwp * l,const struct netbsd32___mq_timedsend50_args * uap,register_t * retval)259 netbsd32___mq_timedsend50(struct lwp *l,
260 const struct netbsd32___mq_timedsend50_args *uap, register_t *retval)
261 {
262 /* {
263 syscallarg(mqd_t) mqdes;
264 syscallarg(const netbsd32_charp) msg_ptr;
265 syscallarg(netbsd32_size_t) msg_len;
266 syscallarg(unsigned) msg_prio;
267 syscallarg(const netbsd32_timespecp_t) abs_timeout;
268 } */
269 struct timespec ts, *tsp;
270 struct netbsd32_timespec ts32;
271 int error;
272
273 /* Get and convert time value */
274 if (SCARG_P32(uap, abs_timeout)) {
275 error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
276 sizeof(ts32));
277 if (error)
278 return error;
279 netbsd32_to_timespec(&ts32, &ts);
280 tsp = &ts;
281 } else {
282 tsp = NULL;
283 }
284
285 return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
286 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
287 }
288
289 int
netbsd32___mq_timedreceive50(struct lwp * l,const struct netbsd32___mq_timedreceive50_args * uap,register_t * retval)290 netbsd32___mq_timedreceive50(struct lwp *l,
291 const struct netbsd32___mq_timedreceive50_args *uap, register_t *retval)
292 {
293 /* {
294 syscallarg(mqd_t) mqdes;
295 syscallarg(netbsd32_charp) msg_ptr;
296 syscallarg(netbsd32_size_t) msg_len;
297 syscallarg(netbsd32_uintp) msg_prio;
298 syscallarg(const netbsd32_timespecp_t) abs_timeout;
299 } */
300 struct timespec ts, *tsp;
301 struct netbsd32_timespec ts32;
302 ssize_t mlen;
303 int error;
304
305 /* Get and convert time value */
306 if (SCARG_P32(uap, abs_timeout)) {
307 error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
308 sizeof(ts32));
309 if (error)
310 return error;
311 netbsd32_to_timespec(&ts32, &ts);
312 tsp = &ts;
313 } else {
314 tsp = NULL;
315 }
316
317 error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
318 SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen);
319 if (error == 0)
320 *retval = mlen;
321
322 return error;
323 }
324
325 #ifdef COMPAT_50
326
327 int
compat_50_netbsd32_mq_timedsend(struct lwp * l,const struct compat_50_netbsd32_mq_timedsend_args * uap,register_t * retval)328 compat_50_netbsd32_mq_timedsend(struct lwp *l,
329 const struct compat_50_netbsd32_mq_timedsend_args *uap,
330 register_t *retval)
331 {
332 /* {
333 syscallarg(mqd_t) mqdes;
334 syscallarg(const netbsd32_charp) msg_ptr;
335 syscallarg(netbsd32_size_t) msg_len;
336 syscallarg(unsigned) msg_prio;
337 syscallarg(const netbsd32_timespec50p_t) abs_timeout;
338 } */
339 struct timespec ts, *tsp;
340 struct netbsd32_timespec50 ts32;
341 int error;
342
343 /* Get and convert time value */
344 if (SCARG_P32(uap, abs_timeout)) {
345 error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
346 sizeof(ts32));
347 if (error)
348 return error;
349 netbsd32_to_timespec50(&ts32, &ts);
350 tsp = &ts;
351 } else {
352 tsp = NULL;
353 }
354
355 return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
356 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
357 }
358
359 int
compat_50_netbsd32_mq_timedreceive(struct lwp * l,const struct compat_50_netbsd32_mq_timedreceive_args * uap,register_t * retval)360 compat_50_netbsd32_mq_timedreceive(struct lwp *l,
361 const struct compat_50_netbsd32_mq_timedreceive_args *uap,
362 register_t *retval)
363 {
364 /* {
365 syscallarg(mqd_t) mqdes;
366 syscallarg(netbsd32_charp) msg_ptr;
367 syscallarg(netbsd32_size_t) msg_len;
368 syscallarg(netbsd32_uintp) msg_prio;
369 syscallarg(const netbsd32_timespec50p_t) abs_timeout;
370 } */
371 struct timespec ts, *tsp;
372 struct netbsd32_timespec50 ts32;
373 ssize_t mlen;
374 int error;
375
376 /* Get and convert time value */
377 if (SCARG_P32(uap, abs_timeout)) {
378 error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
379 sizeof(ts32));
380 if (error)
381 return error;
382 netbsd32_to_timespec50(&ts32, &ts);
383 tsp = &ts;
384 } else {
385 tsp = NULL;
386 }
387
388 error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
389 SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen);
390 if (error == 0)
391 *retval = mlen;
392
393 return error;
394 }
395
396 #endif /* COMPAT_50 */
397
398 #define _PKG_ENTRY(name) \
399 { NETBSD32_SYS_ ## name, 0, (sy_call_t *)name }
400
401 static const struct syscall_package compat_mqueue_syscalls[] = {
402 _PKG_ENTRY(netbsd32_mq_open),
403 _PKG_ENTRY(netbsd32_mq_close),
404 _PKG_ENTRY(netbsd32_mq_unlink),
405 _PKG_ENTRY(netbsd32_mq_getattr),
406 _PKG_ENTRY(netbsd32_mq_setattr),
407 _PKG_ENTRY(netbsd32_mq_notify),
408 _PKG_ENTRY(netbsd32_mq_send),
409 _PKG_ENTRY(netbsd32_mq_receive),
410 _PKG_ENTRY(netbsd32___mq_timedsend50),
411 _PKG_ENTRY(netbsd32___mq_timedreceive50),
412 #ifdef COMPAT_50
413 _PKG_ENTRY(compat_50_netbsd32_mq_timedsend),
414 _PKG_ENTRY(compat_50_netbsd32_mq_timedreceive),
415 #endif
416 {0, 0, NULL}
417 };
418
419 MODULE(MODULE_CLASS_EXEC, compat_netbsd32_mqueue, "mqueue,compat_netbsd32");
420
421 static int
compat_netbsd32_mqueue_modcmd(modcmd_t cmd,void * arg)422 compat_netbsd32_mqueue_modcmd(modcmd_t cmd, void *arg)
423 {
424 int error;
425
426 switch (cmd) {
427 case MODULE_CMD_INIT:
428 error = syscall_establish(&emul_netbsd32,
429 compat_mqueue_syscalls);
430 break;
431 case MODULE_CMD_FINI:
432 error = syscall_disestablish(&emul_netbsd32,
433 compat_mqueue_syscalls);
434 break;
435 default:
436 error = ENOTTY;
437 break;
438 }
439 return error;
440 }
441