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