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