1 | /* $NetBSD: netbsd32_mqueue.c,v 1.6 2015/12/01 23:56:43 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.6 2015/12/01 23:56:43 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 | extern struct emul emul_netbsd32; |
51 | |
52 | int |
53 | netbsd32_mq_open(struct lwp *l, const struct netbsd32_mq_open_args *uap, |
54 | register_t *retval) |
55 | { |
56 | /* { |
57 | syscallarg(const netbsd32_charp) name; |
58 | syscallarg(int) oflag; |
59 | syscallarg(mode_t) mode; |
60 | syscallarg(struct netbsd32_mq_attrp_t) attr; |
61 | } */ |
62 | struct netbsd32_mq_attr attr32; |
63 | struct mq_attr *attr = NULL, a; |
64 | int error; |
65 | |
66 | if ((SCARG(uap, oflag) & O_CREAT) && SCARG_P32(uap, attr) != NULL) { |
67 | error = copyin(SCARG_P32(uap, attr), &attr32, sizeof(attr32)); |
68 | if (error) |
69 | return error; |
70 | netbsd32_to_mq_attr(&attr32, &a); |
71 | attr = &a; |
72 | } |
73 | |
74 | return mq_handle_open(l, SCARG_P32(uap, name), SCARG(uap, oflag), |
75 | SCARG(uap, mode), attr, retval); |
76 | } |
77 | |
78 | int |
79 | netbsd32_mq_close(struct lwp *l, const struct netbsd32_mq_close_args *uap, |
80 | register_t *retval) |
81 | { |
82 | /* { |
83 | syscallarg(mqd_t) mqdes; |
84 | } */ |
85 | |
86 | return netbsd32_close(l, (const void*)uap, retval); |
87 | } |
88 | |
89 | int |
90 | netbsd32_mq_unlink(struct lwp *l, const struct netbsd32_mq_unlink_args *uap, |
91 | register_t *retval) |
92 | { |
93 | /* { |
94 | syscallarg(const netbsd32_charp) name; |
95 | } */ |
96 | struct sys_mq_unlink_args ua; |
97 | |
98 | NETBSD32TOP_UAP(name, const char); |
99 | return sys_mq_unlink(l, &ua, retval); |
100 | } |
101 | |
102 | int |
103 | netbsd32_mq_getattr(struct lwp *l, const struct netbsd32_mq_getattr_args *uap, |
104 | register_t *retval) |
105 | { |
106 | /* { |
107 | syscallarg(mqd_t) mqdes; |
108 | syscallarg(netbsd32_mq_attrp_t) mqstat; |
109 | } */ |
110 | struct mqueue *mq; |
111 | struct mq_attr attr; |
112 | struct netbsd32_mq_attr a32; |
113 | int error; |
114 | |
115 | error = mqueue_get(SCARG(uap, mqdes), 0, &mq); |
116 | if (error) |
117 | return error; |
118 | |
119 | memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); |
120 | mutex_exit(&mq->mq_mtx); |
121 | fd_putfile((int)SCARG(uap, mqdes)); |
122 | netbsd32_from_mq_attr(&attr, &a32); |
123 | return copyout(&a32, SCARG_P32(uap,mqstat), sizeof(a32)); |
124 | } |
125 | |
126 | int |
127 | netbsd32_mq_setattr(struct lwp *l, const struct netbsd32_mq_setattr_args *uap, |
128 | register_t *retval) |
129 | { |
130 | /* { |
131 | syscallarg(mqd_t) mqdes; |
132 | syscallarg(const netbsd32_mq_attrp_t) mqstat; |
133 | syscallarg(netbsd32_mq_attrp_t) omqstat; |
134 | } */ |
135 | struct mqueue *mq; |
136 | struct netbsd32_mq_attr attr32; |
137 | struct mq_attr attr; |
138 | int error, nonblock; |
139 | |
140 | error = copyin(SCARG_P32(uap, mqstat), &attr32, sizeof(attr32)); |
141 | if (error) |
142 | return error; |
143 | netbsd32_to_mq_attr(&attr32, &attr); |
144 | nonblock = (attr.mq_flags & O_NONBLOCK); |
145 | |
146 | error = mqueue_get(SCARG(uap, mqdes), 0, &mq); |
147 | if (error) |
148 | return error; |
149 | |
150 | /* Copy the old attributes, if needed */ |
151 | if (SCARG_P32(uap, omqstat)) |
152 | memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); |
153 | |
154 | /* Ignore everything, except O_NONBLOCK */ |
155 | if (nonblock) |
156 | mq->mq_attrib.mq_flags |= O_NONBLOCK; |
157 | else |
158 | mq->mq_attrib.mq_flags &= ~O_NONBLOCK; |
159 | |
160 | mutex_exit(&mq->mq_mtx); |
161 | fd_putfile((int)SCARG(uap, mqdes)); |
162 | |
163 | /* |
164 | * Copy the data to the user-space. |
165 | * Note: According to POSIX, the new attributes should not be set in |
166 | * case of fail - this would be violated. |
167 | */ |
168 | if (SCARG_P32(uap, omqstat)) { |
169 | netbsd32_from_mq_attr(&attr, &attr32); |
170 | error = copyout(&attr32, SCARG_P32(uap, omqstat), |
171 | sizeof(attr32)); |
172 | } |
173 | |
174 | return error; |
175 | } |
176 | |
177 | int |
178 | netbsd32_mq_notify(struct lwp *l, const struct netbsd32_mq_notify_args *uap, |
179 | register_t *result) |
180 | { |
181 | /* { |
182 | syscallarg(mqd_t) mqdes; |
183 | syscallarg(const netbsd32_sigeventp_t) notification; |
184 | } */ |
185 | struct mqueue *mq; |
186 | struct netbsd32_sigevent sig32; |
187 | int error; |
188 | |
189 | if (SCARG_P32(uap, notification)) { |
190 | /* Get the signal from user-space */ |
191 | error = copyin(SCARG_P32(uap, notification), &sig32, |
192 | sizeof(sig32)); |
193 | if (error) |
194 | return error; |
195 | if (sig32.sigev_notify == SIGEV_SIGNAL && |
196 | (sig32.sigev_signo <=0 || sig32.sigev_signo >= NSIG)) |
197 | return EINVAL; |
198 | } |
199 | |
200 | error = mqueue_get(SCARG(uap, mqdes), 0, &mq); |
201 | if (error) { |
202 | return error; |
203 | } |
204 | if (SCARG_P32(uap, notification)) { |
205 | /* Register notification: set the signal and target process */ |
206 | if (mq->mq_notify_proc == NULL) { |
207 | netbsd32_to_sigevent(&sig32, &mq->mq_sig_notify); |
208 | mq->mq_notify_proc = l->l_proc; |
209 | } else { |
210 | /* Fail if someone else already registered */ |
211 | error = EBUSY; |
212 | } |
213 | } else { |
214 | /* Unregister the notification */ |
215 | mq->mq_notify_proc = NULL; |
216 | } |
217 | mutex_exit(&mq->mq_mtx); |
218 | fd_putfile((int)SCARG(uap, mqdes)); |
219 | |
220 | return error; |
221 | } |
222 | |
223 | int |
224 | netbsd32_mq_send(struct lwp *l, const struct netbsd32_mq_send_args *uap, |
225 | register_t *result) |
226 | { |
227 | /* { |
228 | syscallarg(mqd_t) mqdes; |
229 | syscallarg(const netbsd32_charp) msg_ptr; |
230 | syscallarg(netbsd32_size_t) msg_len; |
231 | syscallarg(unsigned) msg_prio; |
232 | } */ |
233 | |
234 | |
235 | return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr), |
236 | SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL); |
237 | } |
238 | |
239 | int |
240 | netbsd32_mq_receive(struct lwp *l, const struct netbsd32_mq_receive_args *uap, |
241 | register_t *retval) |
242 | { |
243 | /* { |
244 | syscallarg(mqd_t) mqdes; |
245 | syscallarg(netbsd32_charp) msg_ptr; |
246 | syscallarg(netbsd32_size_t) msg_len; |
247 | syscallarg(netbsd32_uintp) msg_prio; |
248 | } */ |
249 | ssize_t mlen; |
250 | int error; |
251 | |
252 | error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr), |
253 | SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), NULL, &mlen); |
254 | if (error == 0) |
255 | *retval = mlen; |
256 | |
257 | return error; |
258 | } |
259 | |
260 | int |
261 | netbsd32___mq_timedsend50(struct lwp *l, |
262 | const struct netbsd32___mq_timedsend50_args *uap, register_t *retval) |
263 | { |
264 | /* { |
265 | syscallarg(mqd_t) mqdes; |
266 | syscallarg(const netbsd32_charp) msg_ptr; |
267 | syscallarg(netbsd32_size_t) msg_len; |
268 | syscallarg(unsigned) msg_prio; |
269 | syscallarg(const netbsd32_timespecp_t) abs_timeout; |
270 | } */ |
271 | struct timespec ts, *tsp; |
272 | struct netbsd32_timespec ts32; |
273 | int error; |
274 | |
275 | /* Get and convert time value */ |
276 | if (SCARG_P32(uap, abs_timeout)) { |
277 | error = copyin(SCARG_P32(uap, abs_timeout), &ts32, |
278 | sizeof(ts32)); |
279 | if (error) |
280 | return error; |
281 | netbsd32_to_timespec(&ts32, &ts); |
282 | tsp = &ts; |
283 | } else { |
284 | tsp = NULL; |
285 | } |
286 | |
287 | return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr), |
288 | SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); |
289 | } |
290 | |
291 | int |
292 | netbsd32___mq_timedreceive50(struct lwp *l, |
293 | const struct netbsd32___mq_timedreceive50_args *uap, register_t *retval) |
294 | { |
295 | /* { |
296 | syscallarg(mqd_t) mqdes; |
297 | syscallarg(netbsd32_charp) msg_ptr; |
298 | syscallarg(netbsd32_size_t) msg_len; |
299 | syscallarg(netbsd32_uintp) msg_prio; |
300 | syscallarg(const netbsd32_timespecp_t) abs_timeout; |
301 | } */ |
302 | struct timespec ts, *tsp; |
303 | struct netbsd32_timespec ts32; |
304 | ssize_t mlen; |
305 | int error; |
306 | |
307 | /* Get and convert time value */ |
308 | if (SCARG_P32(uap, abs_timeout)) { |
309 | error = copyin(SCARG_P32(uap, abs_timeout), &ts32, |
310 | sizeof(ts32)); |
311 | if (error) |
312 | return error; |
313 | netbsd32_to_timespec(&ts32, &ts); |
314 | tsp = &ts; |
315 | } else { |
316 | tsp = NULL; |
317 | } |
318 | |
319 | error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr), |
320 | SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen); |
321 | if (error == 0) |
322 | *retval = mlen; |
323 | |
324 | return error; |
325 | } |
326 | |
327 | #ifdef COMPAT_50 |
328 | |
329 | int |
330 | compat_50_netbsd32_mq_timedsend(struct lwp *l, |
331 | const struct compat_50_netbsd32_mq_timedsend_args *uap, |
332 | register_t *retval) |
333 | { |
334 | /* { |
335 | syscallarg(mqd_t) mqdes; |
336 | syscallarg(const netbsd32_charp) msg_ptr; |
337 | syscallarg(netbsd32_size_t) msg_len; |
338 | syscallarg(unsigned) msg_prio; |
339 | syscallarg(const netbsd32_timespec50p_t) abs_timeout; |
340 | } */ |
341 | struct timespec ts, *tsp; |
342 | struct netbsd32_timespec50 ts32; |
343 | int error; |
344 | |
345 | /* Get and convert time value */ |
346 | if (SCARG_P32(uap, abs_timeout)) { |
347 | error = copyin(SCARG_P32(uap, abs_timeout), &ts32, |
348 | sizeof(ts32)); |
349 | if (error) |
350 | return error; |
351 | netbsd32_to_timespec50(&ts32, &ts); |
352 | tsp = &ts; |
353 | } else { |
354 | tsp = NULL; |
355 | } |
356 | |
357 | return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr), |
358 | SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); |
359 | } |
360 | |
361 | int |
362 | compat_50_netbsd32_mq_timedreceive(struct lwp *l, |
363 | const struct compat_50_netbsd32_mq_timedreceive_args *uap, |
364 | register_t *retval) |
365 | { |
366 | /* { |
367 | syscallarg(mqd_t) mqdes; |
368 | syscallarg(netbsd32_charp) msg_ptr; |
369 | syscallarg(netbsd32_size_t) msg_len; |
370 | syscallarg(netbsd32_uintp) msg_prio; |
371 | syscallarg(const netbsd32_timespec50p_t) abs_timeout; |
372 | } */ |
373 | struct timespec ts, *tsp; |
374 | struct netbsd32_timespec50 ts32; |
375 | ssize_t mlen; |
376 | int error; |
377 | |
378 | /* Get and convert time value */ |
379 | if (SCARG_P32(uap, abs_timeout)) { |
380 | error = copyin(SCARG_P32(uap, abs_timeout), &ts32, |
381 | sizeof(ts32)); |
382 | if (error) |
383 | return error; |
384 | netbsd32_to_timespec50(&ts32, &ts); |
385 | tsp = &ts; |
386 | } else { |
387 | tsp = NULL; |
388 | } |
389 | |
390 | error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr), |
391 | SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen); |
392 | if (error == 0) |
393 | *retval = mlen; |
394 | |
395 | return error; |
396 | } |
397 | |
398 | #endif /* COMPAT_50 */ |
399 | |
400 | #define _PKG_ENTRY(name) \ |
401 | { NETBSD32_SYS_ ## name, 0, (sy_call_t *)name } |
402 | |
403 | static const struct syscall_package compat_mqueue_syscalls[] = { |
404 | _PKG_ENTRY(netbsd32_mq_open), |
405 | _PKG_ENTRY(netbsd32_mq_close), |
406 | _PKG_ENTRY(netbsd32_mq_unlink), |
407 | _PKG_ENTRY(netbsd32_mq_getattr), |
408 | _PKG_ENTRY(netbsd32_mq_setattr), |
409 | _PKG_ENTRY(netbsd32_mq_notify), |
410 | _PKG_ENTRY(netbsd32_mq_send), |
411 | _PKG_ENTRY(netbsd32_mq_receive), |
412 | _PKG_ENTRY(netbsd32___mq_timedsend50), |
413 | _PKG_ENTRY(netbsd32___mq_timedreceive50), |
414 | #ifdef COMPAT_50 |
415 | _PKG_ENTRY(compat_50_netbsd32_mq_timedsend), |
416 | _PKG_ENTRY(compat_50_netbsd32_mq_timedreceive), |
417 | #endif |
418 | {0, 0, NULL} |
419 | }; |
420 | |
421 | MODULE(MODULE_CLASS_EXEC, compat_netbsd32_mqueue, "mqueue,compat_netbsd32" ); |
422 | |
423 | static int |
424 | compat_netbsd32_mqueue_modcmd(modcmd_t cmd, void *arg) |
425 | { |
426 | int error; |
427 | |
428 | switch (cmd) { |
429 | case MODULE_CMD_INIT: |
430 | error = syscall_establish(&emul_netbsd32, |
431 | compat_mqueue_syscalls); |
432 | break; |
433 | case MODULE_CMD_FINI: |
434 | error = syscall_disestablish(&emul_netbsd32, |
435 | compat_mqueue_syscalls); |
436 | break; |
437 | default: |
438 | error = ENOTTY; |
439 | break; |
440 | } |
441 | return error; |
442 | } |
443 | |