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 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 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 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 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 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 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 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 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 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 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 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 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 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