Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: sys_descrip.c,v 1.54 2026/01/04 01:32:23 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * Copyright (c) 1982, 1986, 1989, 1991, 1993
     31  *	The Regents of the University of California.  All rights reserved.
     32  * (c) UNIX System Laboratories, Inc.
     33  * All or some portions of this file are derived from material licensed
     34  * to the University of California by American Telephone and Telegraph
     35  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     36  * the permission of UNIX System Laboratories, Inc.
     37  *
     38  * Redistribution and use in source and binary forms, with or without
     39  * modification, are permitted provided that the following conditions
     40  * are met:
     41  * 1. Redistributions of source code must retain the above copyright
     42  *    notice, this list of conditions and the following disclaimer.
     43  * 2. Redistributions in binary form must reproduce the above copyright
     44  *    notice, this list of conditions and the following disclaimer in the
     45  *    documentation and/or other materials provided with the distribution.
     46  * 3. Neither the name of the University nor the names of its contributors
     47  *    may be used to endorse or promote products derived from this software
     48  *    without specific prior written permission.
     49  *
     50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     60  * SUCH DAMAGE.
     61  *
     62  *	@(#)kern_descrip.c	8.8 (Berkeley) 2/14/95
     63  */
     64 
     65 /*
     66  * System calls on descriptors.
     67  */
     68 
     69 #include <sys/cdefs.h>
     70 __KERNEL_RCSID(0, "$NetBSD: sys_descrip.c,v 1.54 2026/01/04 01:32:23 riastradh Exp $");
     71 
     72 #include <sys/param.h>
     73 #include <sys/types.h>
     74 
     75 #include <sys/atomic.h>
     76 #include <sys/conf.h>
     77 #include <sys/event.h>
     78 #include <sys/fcntl.h>
     79 #include <sys/file.h>
     80 #include <sys/filedesc.h>
     81 #include <sys/ioctl.h>
     82 #include <sys/kauth.h>
     83 #include <sys/kernel.h>
     84 #include <sys/kmem.h>
     85 #include <sys/mount.h>
     86 #include <sys/namei.h>
     87 #include <sys/pool.h>
     88 #include <sys/proc.h>
     89 #include <sys/resourcevar.h>
     90 #include <sys/sdt.h>
     91 #include <sys/socket.h>
     92 #include <sys/socketvar.h>
     93 #include <sys/stat.h>
     94 #include <sys/syscallargs.h>
     95 #include <sys/syslog.h>
     96 #include <sys/systm.h>
     97 #include <sys/unistd.h>
     98 #include <sys/vnode.h>
     99 
    100 #include <uvm/uvm_readahead.h>
    101 
    102 /*
    103  * Duplicate a file descriptor.
    104  */
    105 int
    106 sys_dup(struct lwp *l, const struct sys_dup_args *uap, register_t *retval)
    107 {
    108 	/* {
    109 		syscallarg(int)	fd;
    110 	} */
    111 	int error, newfd, oldfd;
    112 	file_t *fp;
    113 
    114 	oldfd = SCARG(uap, fd);
    115 
    116 	if ((fp = fd_getfile(oldfd)) == NULL) {
    117 		return SET_ERROR(EBADF);
    118 	}
    119 	error = fd_dup(fp, 0, &newfd, false, false);
    120 	fd_putfile(oldfd);
    121 	*retval = newfd;
    122 	return error;
    123 }
    124 
    125 /*
    126  * Duplicate a file descriptor to a particular value.
    127  */
    128 int
    129 dodup(struct lwp *l, int from, int to, int flags, register_t *retval)
    130 {
    131 	int error;
    132 	file_t *fp;
    133 
    134 	if ((fp = fd_getfile(from)) == NULL)
    135 		return SET_ERROR(EBADF);
    136 	mutex_enter(&fp->f_lock);
    137 	fp->f_count++;
    138 	mutex_exit(&fp->f_lock);
    139 	fd_putfile(from);
    140 
    141 	if ((u_int)to >= curproc->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
    142 	    (u_int)to >= maxfiles)
    143 		error = SET_ERROR(EBADF);
    144 	else if (from == to)
    145 		error = 0;
    146 	else
    147 		error = fd_dup2(fp, to, flags);
    148 	closef(fp);
    149 	*retval = to;
    150 
    151 	return error;
    152 }
    153 
    154 int
    155 sys___dup3100(struct lwp *l, const struct sys___dup3100_args *uap, register_t *retval)
    156 {
    157 	/* {
    158 		syscallarg(int)	from;
    159 		syscallarg(int)	to;
    160 		syscallarg(int)	flags;
    161 	} */
    162 	if (SCARG(uap, from) == SCARG(uap, to))
    163 		return SET_ERROR(EINVAL);
    164 	return dodup(l, SCARG(uap, from), SCARG(uap, to), SCARG(uap, flags),
    165 	    retval);
    166 }
    167 
    168 int
    169 sys_dup2(struct lwp *l, const struct sys_dup2_args *uap, register_t *retval)
    170 {
    171 	/* {
    172 		syscallarg(int)	from;
    173 		syscallarg(int)	to;
    174 	} */
    175 	return dodup(l, SCARG(uap, from), SCARG(uap, to), 0, retval);
    176 }
    177 
    178 /*
    179  * fcntl call which is being passed to the file's fs.
    180  */
    181 static int
    182 fcntl_forfs(int fd, file_t *fp, int cmd, void *arg)
    183 {
    184 	int		error;
    185 	u_int		size;
    186 	void		*data, *memp;
    187 #define STK_PARAMS	128
    188 	char		stkbuf[STK_PARAMS];
    189 
    190 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
    191 		return SET_ERROR(EBADF);
    192 
    193 	/*
    194 	 * Interpret high order word to find amount of data to be
    195 	 * copied to/from the user's address space.
    196 	 */
    197 	size = (size_t)F_PARAM_LEN(cmd);
    198 	if (size > F_PARAM_MAX)
    199 		return SET_ERROR(EINVAL);
    200 	memp = NULL;
    201 	if (size > sizeof(stkbuf)) {
    202 		memp = kmem_alloc(size, KM_SLEEP);
    203 		data = memp;
    204 	} else
    205 		data = stkbuf;
    206 	if (cmd & F_FSIN) {
    207 		if (size) {
    208 			error = copyin(arg, data, size);
    209 			if (error) {
    210 				if (memp)
    211 					kmem_free(memp, size);
    212 				return (error);
    213 			}
    214 		} else
    215 			*(void **)data = arg;
    216 	} else if ((cmd & F_FSOUT) != 0 && size != 0) {
    217 		/*
    218 		 * Zero the buffer so the user always
    219 		 * gets back something deterministic.
    220 		 */
    221 		memset(data, 0, size);
    222 	} else if (cmd & F_FSVOID)
    223 		*(void **)data = arg;
    224 
    225 
    226 	error = (*fp->f_ops->fo_fcntl)(fp, cmd, data);
    227 
    228 	/*
    229 	 * Copy any data to user, size was
    230 	 * already set and checked above.
    231 	 */
    232 	if (error == 0 && (cmd & F_FSOUT) && size)
    233 		error = copyout(data, arg, size);
    234 	if (memp)
    235 		kmem_free(memp, size);
    236 	return (error);
    237 }
    238 
    239 int
    240 do_fcntl_lock(int fd, int cmd, struct flock *fl)
    241 {
    242 	struct file *fp = NULL;
    243 	proc_t *p;
    244 	int (*fo_advlock)(struct file *, void *, int, struct flock *, int);
    245 	int error, flg;
    246 
    247 	if ((fp = fd_getfile(fd)) == NULL) {
    248 		error = SET_ERROR(EBADF);
    249 		goto out;
    250 	}
    251 	if ((fo_advlock = fp->f_ops->fo_advlock) == NULL) {
    252 		error = SET_ERROR(EINVAL);
    253 		goto out;
    254 	}
    255 
    256 	flg = F_POSIX;
    257 	p = curproc;
    258 
    259 	switch (cmd) {
    260 	case F_SETLKW:
    261 		flg |= F_WAIT;
    262 		/* Fall into F_SETLK */
    263 
    264 		/* FALLTHROUGH */
    265 	case F_SETLK:
    266 		switch (fl->l_type) {
    267 		case F_RDLCK:
    268 			if ((fp->f_flag & FREAD) == 0) {
    269 				error = SET_ERROR(EBADF);
    270 				break;
    271 			}
    272 			if ((p->p_flag & PK_ADVLOCK) == 0) {
    273 				mutex_enter(p->p_lock);
    274 				p->p_flag |= PK_ADVLOCK;
    275 				mutex_exit(p->p_lock);
    276 			}
    277 			error = (*fo_advlock)(fp, p, F_SETLK, fl, flg);
    278 			break;
    279 
    280 		case F_WRLCK:
    281 			if ((fp->f_flag & FWRITE) == 0) {
    282 				error = SET_ERROR(EBADF);
    283 				break;
    284 			}
    285 			if ((p->p_flag & PK_ADVLOCK) == 0) {
    286 				mutex_enter(p->p_lock);
    287 				p->p_flag |= PK_ADVLOCK;
    288 				mutex_exit(p->p_lock);
    289 			}
    290 			error = (*fo_advlock)(fp, p, F_SETLK, fl, flg);
    291 			break;
    292 
    293 		case F_UNLCK:
    294 			error = (*fo_advlock)(fp, p, F_UNLCK, fl, F_POSIX);
    295 			break;
    296 
    297 		default:
    298 			error = SET_ERROR(EINVAL);
    299 			break;
    300 		}
    301 		break;
    302 
    303 	case F_GETLK:
    304 		if (fl->l_type != F_RDLCK &&
    305 		    fl->l_type != F_WRLCK &&
    306 		    fl->l_type != F_UNLCK) {
    307 			error = SET_ERROR(EINVAL);
    308 			break;
    309 		}
    310 		error = (*fo_advlock)(fp, p, F_GETLK, fl, F_POSIX);
    311 		break;
    312 
    313 	default:
    314 		error = SET_ERROR(EINVAL);
    315 		break;
    316 	}
    317 
    318 out:	if (fp)
    319 		fd_putfile(fd);
    320 	return error;
    321 }
    322 
    323 /*
    324  * The file control system call.
    325  */
    326 int
    327 sys_fcntl(struct lwp *l, const struct sys_fcntl_args *uap, register_t *retval)
    328 {
    329 	/* {
    330 		syscallarg(int)		fd;
    331 		syscallarg(int)		cmd;
    332 		syscallarg(void *)	arg;
    333 	} */
    334 	int fd, i, tmp, error, cmd, newmin;
    335 	filedesc_t *fdp;
    336 	fdtab_t *dt;
    337 	file_t *fp;
    338 	char *kpath;
    339 	struct flock fl;
    340 	bool cloexec = false;
    341 	bool clofork = false;
    342 
    343 	fd = SCARG(uap, fd);
    344 	cmd = SCARG(uap, cmd);
    345 	fdp = l->l_fd;
    346 	error = 0;
    347 
    348 	switch (cmd) {
    349 	case F_CLOSEM:
    350 		if (fd < 0)
    351 			return SET_ERROR(EBADF);
    352 		while ((i = fdp->fd_lastfile) >= fd) {
    353 			if (fd_getfile(i) == NULL) {
    354 				/* Another thread has updated. */
    355 				continue;
    356 			}
    357 			fd_close(i);
    358 		}
    359 		return 0;
    360 
    361 	case F_MAXFD:
    362 		*retval = fdp->fd_lastfile;
    363 		return 0;
    364 
    365 	case F_SETLKW:
    366 	case F_SETLK:
    367 	case F_GETLK:
    368 		error = copyin(SCARG(uap, arg), &fl, sizeof(fl));
    369 		if (error)
    370 			return error;
    371 		error = do_fcntl_lock(fd, cmd, &fl);
    372 		if (cmd == F_GETLK && error == 0)
    373 			error = copyout(&fl, SCARG(uap, arg), sizeof(fl));
    374 		return error;
    375 
    376 	default:
    377 		/* Handled below */
    378 		break;
    379 	}
    380 
    381 	if ((fp = fd_getfile(fd)) == NULL)
    382 		return SET_ERROR(EBADF);
    383 
    384 	if ((cmd & F_FSCTL)) {
    385 		error = fcntl_forfs(fd, fp, cmd, SCARG(uap, arg));
    386 		fd_putfile(fd);
    387 		return error;
    388 	}
    389 
    390 	switch (cmd) {
    391 	case F_DUPFD_CLOFORK:
    392 		clofork = true;
    393 		goto f_dupfd;
    394 	case F_DUPFD_CLOBOTH:
    395 		clofork = true;
    396 		/*FALLTHROUGH*/
    397 	case F_DUPFD_CLOEXEC:
    398 		cloexec = true;
    399 		/*FALLTHROUGH*/
    400 	case F_DUPFD:
    401 	f_dupfd:;
    402 		newmin = (long)SCARG(uap, arg);
    403 		if ((u_int)newmin >=
    404 		    l->l_proc->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
    405 		    (u_int)newmin >= maxfiles) {
    406 			fd_putfile(fd);
    407 			return SET_ERROR(EINVAL);
    408 		}
    409 		error = fd_dup(fp, newmin, &i, cloexec, clofork);
    410 		*retval = i;
    411 		break;
    412 
    413 	case F_GETFD:
    414 		dt = atomic_load_consume(&fdp->fd_dt);
    415 		*retval = (dt->dt_ff[fd]->ff_exclose ? FD_CLOEXEC : 0) |
    416 		    (dt->dt_ff[fd]->ff_foclose ? FD_CLOFORK: 0);
    417 		break;
    418 
    419 	case F_SETFD:
    420 		tmp = (intptr_t)SCARG(uap, arg);
    421 		fd_set_exclose(l, fd, (tmp & FD_CLOEXEC) != 0);
    422 		fd_set_foclose(l, fd, (tmp & FD_CLOFORK) != 0);
    423 		break;
    424 
    425 	case F_GETNOSIGPIPE:
    426 		*retval = (fp->f_flag & FNOSIGPIPE) != 0;
    427 		break;
    428 
    429 	case F_SETNOSIGPIPE:
    430 		if (SCARG(uap, arg))
    431 			atomic_or_uint(&fp->f_flag, FNOSIGPIPE);
    432 		else
    433 			atomic_and_uint(&fp->f_flag, ~FNOSIGPIPE);
    434 		*retval = 0;
    435 		break;
    436 
    437 	case F_GETFL:
    438 		*retval = OFLAGS(fp->f_flag);
    439 		break;
    440 
    441 	case F_SETFL:
    442 		/* XXX not guaranteed to be atomic. */
    443 		tmp = FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
    444 		error = (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &tmp);
    445 		if (error)
    446 			break;
    447 		i = tmp ^ fp->f_flag;
    448 		if (i & FNONBLOCK) {
    449 			int flgs = tmp & FNONBLOCK;
    450 			error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, &flgs);
    451 			if (error) {
    452 				(*fp->f_ops->fo_fcntl)(fp, F_SETFL,
    453 				    &fp->f_flag);
    454 				break;
    455 			}
    456 		}
    457 		if (i & FASYNC) {
    458 			int flgs = tmp & FASYNC;
    459 			error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, &flgs);
    460 			if (error) {
    461 				if (i & FNONBLOCK) {
    462 					tmp = fp->f_flag & FNONBLOCK;
    463 					(void)(*fp->f_ops->fo_ioctl)(fp,
    464 						FIONBIO, &tmp);
    465 				}
    466 				(*fp->f_ops->fo_fcntl)(fp, F_SETFL,
    467 				    &fp->f_flag);
    468 				break;
    469 			}
    470 		}
    471 		fp->f_flag = (fp->f_flag & ~FCNTLFLAGS) | tmp;
    472 		break;
    473 
    474 	case F_GETOWN:
    475 		error = (*fp->f_ops->fo_ioctl)(fp, FIOGETOWN, &tmp);
    476 		*retval = tmp;
    477 		break;
    478 
    479 	case F_SETOWN:
    480 		tmp = (int)(uintptr_t) SCARG(uap, arg);
    481 		error = (*fp->f_ops->fo_ioctl)(fp, FIOSETOWN, &tmp);
    482 		break;
    483 
    484 	case F_GETPATH:
    485 		kpath = PNBUF_GET();
    486 
    487 		/* vnodes need extra context, so are handled separately */
    488 		if (fp->f_type == DTYPE_VNODE)
    489 			error = vnode_to_path(kpath, MAXPATHLEN, fp->f_vnode,
    490 			    l, l->l_proc);
    491 		else
    492 			error = (*fp->f_ops->fo_fcntl)(fp, F_GETPATH, kpath);
    493 
    494 		if (error == 0)
    495 			error = copyoutstr(kpath, SCARG(uap, arg), MAXPATHLEN,
    496 			    NULL);
    497 
    498 		PNBUF_PUT(kpath);
    499 		break;
    500 
    501 	case F_ADD_SEALS:
    502 		tmp = (int)(uintptr_t) SCARG(uap, arg);
    503 		error = (*fp->f_ops->fo_fcntl)(fp, F_ADD_SEALS, &tmp);
    504 		break;
    505 
    506 	case F_GET_SEALS:
    507 		error = (*fp->f_ops->fo_fcntl)(fp, F_GET_SEALS, &tmp);
    508 		*retval = tmp;
    509 		break;
    510 
    511 	default:
    512 		error = SET_ERROR(EINVAL);
    513 	}
    514 
    515 	fd_putfile(fd);
    516 	return (error);
    517 }
    518 
    519 /*
    520  * Close a file descriptor.
    521  */
    522 int
    523 sys_close(struct lwp *l, const struct sys_close_args *uap, register_t *retval)
    524 {
    525 	/* {
    526 		syscallarg(int)	fd;
    527 	} */
    528 	int error;
    529 	int fd = SCARG(uap, fd);
    530 
    531 	if (fd_getfile(fd) == NULL) {
    532 		return SET_ERROR(EBADF);
    533 	}
    534 
    535 	error = fd_close(fd);
    536 	if (error == ERESTART) {
    537 #ifdef DIAGNOSTIC
    538 		printf("%s[%d]: close(%d) returned ERESTART\n",
    539 		    l->l_proc->p_comm, (int)l->l_proc->p_pid, fd);
    540 #endif
    541 		error = SET_ERROR(EINTR);
    542 	}
    543 
    544 	return error;
    545 }
    546 
    547 /*
    548  * Return status information about a file descriptor.
    549  * Common function for compat code.
    550  */
    551 int
    552 do_sys_fstat(int fd, struct stat *sb)
    553 {
    554 	file_t *fp;
    555 	int error;
    556 
    557 	if ((fp = fd_getfile(fd)) == NULL) {
    558 		return SET_ERROR(EBADF);
    559 	}
    560 	error = (*fp->f_ops->fo_stat)(fp, sb);
    561 	fd_putfile(fd);
    562 
    563 	return error;
    564 }
    565 
    566 /*
    567  * Return status information about a file descriptor.
    568  */
    569 int
    570 sys___fstat50(struct lwp *l, const struct sys___fstat50_args *uap,
    571 	      register_t *retval)
    572 {
    573 	/* {
    574 		syscallarg(int)			fd;
    575 		syscallarg(struct stat *)	sb;
    576 	} */
    577 	struct stat sb;
    578 	int error;
    579 
    580 	error = do_sys_fstat(SCARG(uap, fd), &sb);
    581 	if (error == 0) {
    582 		error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
    583 	}
    584 	return error;
    585 }
    586 
    587 /*
    588  * Return pathconf information about a file descriptor.
    589  */
    590 int
    591 sys_fpathconf(struct lwp *l, const struct sys_fpathconf_args *uap,
    592 	      register_t *retval)
    593 {
    594 	/* {
    595 		syscallarg(int)	fd;
    596 		syscallarg(int)	name;
    597 	} */
    598 	int fd, name, error;
    599 	file_t *fp;
    600 
    601 	fd = SCARG(uap, fd);
    602 	name = SCARG(uap, name);
    603 	error = 0;
    604 
    605 	if ((fp = fd_getfile(fd)) == NULL)
    606 		return SET_ERROR(EBADF);
    607 	if (fp->f_ops->fo_fpathconf == NULL)
    608 		error = SET_ERROR(EOPNOTSUPP);
    609 	else
    610 		error = (*fp->f_ops->fo_fpathconf)(fp, name, retval);
    611 	fd_putfile(fd);
    612 	return error;
    613 }
    614 
    615 /*
    616  * Apply an advisory lock on a file descriptor.
    617  *
    618  * Just attempt to get a record lock of the requested type on
    619  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
    620  */
    621 /* ARGSUSED */
    622 int
    623 sys_flock(struct lwp *l, const struct sys_flock_args *uap, register_t *retval)
    624 {
    625 	/* {
    626 		syscallarg(int)	fd;
    627 		syscallarg(int)	how;
    628 	} */
    629 	int fd, how, error;
    630 	struct file *fp = NULL;
    631 	int (*fo_advlock)(struct file *, void *, int, struct flock *, int);
    632 	struct flock lf;
    633 
    634 	fd = SCARG(uap, fd);
    635 	how = SCARG(uap, how);
    636 
    637 	if ((fp = fd_getfile(fd)) == NULL) {
    638 		error = SET_ERROR(EBADF);
    639 		goto out;
    640 	}
    641 	if ((fo_advlock = fp->f_ops->fo_advlock) == NULL) {
    642 		KASSERT((atomic_load_relaxed(&fp->f_flag) & FHASLOCK) == 0);
    643 		error = SET_ERROR(EOPNOTSUPP);
    644 		goto out;
    645 	}
    646 
    647 	lf.l_whence = SEEK_SET;
    648 	lf.l_start = 0;
    649 	lf.l_len = 0;
    650 
    651 	switch (how & ~LOCK_NB) {
    652 	case LOCK_UN:
    653 		lf.l_type = F_UNLCK;
    654 		atomic_and_uint(&fp->f_flag, ~FHASLOCK);
    655 		error = (*fo_advlock)(fp, fp, F_UNLCK, &lf, F_FLOCK);
    656 		goto out;
    657 	case LOCK_EX:
    658 		lf.l_type = F_WRLCK;
    659 		break;
    660 	case LOCK_SH:
    661 		lf.l_type = F_RDLCK;
    662 		break;
    663 	default:
    664 		error = SET_ERROR(EINVAL);
    665 		goto out;
    666 	}
    667 
    668 	atomic_or_uint(&fp->f_flag, FHASLOCK);
    669 	if (how & LOCK_NB) {
    670 		error = (*fo_advlock)(fp, fp, F_SETLK, &lf, F_FLOCK);
    671 	} else {
    672 		error = (*fo_advlock)(fp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT);
    673 	}
    674 out:	if (fp)
    675 		fd_putfile(fd);
    676 	return error;
    677 }
    678 
    679 int
    680 do_posix_fadvise(int fd, off_t offset, off_t len, int advice)
    681 {
    682 	file_t *fp;
    683 	int error;
    684 
    685 	if ((fp = fd_getfile(fd)) == NULL)
    686 		return SET_ERROR(EBADF);
    687 	if (fp->f_ops->fo_posix_fadvise == NULL) {
    688 		error = SET_ERROR(EOPNOTSUPP);
    689 	} else {
    690 		error = (*fp->f_ops->fo_posix_fadvise)(fp, offset, len,
    691 		    advice);
    692 	}
    693 	fd_putfile(fd);
    694 	return error;
    695 }
    696 
    697 int
    698 sys___posix_fadvise50(struct lwp *l,
    699 		      const struct sys___posix_fadvise50_args *uap,
    700 		      register_t *retval)
    701 {
    702 	/* {
    703 		syscallarg(int) fd;
    704 		syscallarg(int) pad;
    705 		syscallarg(off_t) offset;
    706 		syscallarg(off_t) len;
    707 		syscallarg(int) advice;
    708 	} */
    709 
    710 	*retval = do_posix_fadvise(SCARG(uap, fd), SCARG(uap, offset),
    711 	    SCARG(uap, len), SCARG(uap, advice));
    712 
    713 	return 0;
    714 }
    715 
    716 int
    717 sys_pipe(struct lwp *l, const void *v, register_t *retval)
    718 {
    719 	int fd[2], error;
    720 
    721 	if ((error = pipe1(l, fd, 0)) != 0)
    722 		return error;
    723 
    724 	retval[0] = fd[0];
    725 	retval[1] = fd[1];
    726 
    727 	return 0;
    728 }
    729 
    730 int
    731 sys_pipe2(struct lwp *l, const struct sys_pipe2_args *uap, register_t *retval)
    732 {
    733 	/* {
    734 		syscallarg(int[2]) fildes;
    735 		syscallarg(int) flags;
    736 	} */
    737 	int fd[2], error;
    738 
    739 	if ((error = pipe1(l, fd, SCARG(uap, flags))) != 0)
    740 		return error;
    741 
    742 	if ((error = copyout(fd, SCARG(uap, fildes), sizeof(fd))) != 0)
    743 		return error;
    744 	retval[0] = 0;
    745 	return 0;
    746 }
    747