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