Home | History | Annotate | Line # | Download | only in netbsd32
      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