xref: /openbsd-src/sys/miscfs/fifofs/fifo_vnops.c (revision fb8aa7497fded39583f40e800732f9c046411717)
1 /*	$OpenBSD: fifo_vnops.c,v 1.51 2016/06/07 06:12:37 deraadt Exp $	*/
2 /*	$NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)fifo_vnops.c	8.4 (Berkeley) 8/10/94
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/time.h>
38 #include <sys/namei.h>
39 #include <sys/vnode.h>
40 #include <sys/lock.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/stat.h>
45 #include <sys/ioctl.h>
46 #include <sys/file.h>
47 #include <sys/event.h>
48 #include <sys/errno.h>
49 #include <sys/malloc.h>
50 #include <sys/poll.h>
51 #include <sys/unpcb.h>
52 #include <sys/unistd.h>
53 
54 #include <miscfs/fifofs/fifo.h>
55 
56 /*
57  * This structure is associated with the FIFO vnode and stores
58  * the state associated with the FIFO.
59  */
60 struct fifoinfo {
61 	struct socket	*fi_readsock;
62 	struct socket	*fi_writesock;
63 	long		fi_readers;
64 	long		fi_writers;
65 };
66 
67 struct vops fifo_vops = {
68 	.vop_lookup	= vop_generic_lookup,
69 	.vop_create	= fifo_badop,
70 	.vop_mknod	= fifo_badop,
71 	.vop_open	= fifo_open,
72 	.vop_close	= fifo_close,
73 	.vop_access	= fifo_ebadf,
74 	.vop_getattr	= fifo_ebadf,
75 	.vop_setattr	= fifo_ebadf,
76 	.vop_read	= fifo_read,
77 	.vop_write	= fifo_write,
78 	.vop_ioctl	= fifo_ioctl,
79 	.vop_poll	= fifo_poll,
80 	.vop_kqfilter	= fifo_kqfilter,
81 	.vop_revoke	= vop_generic_revoke,
82 	.vop_fsync	= nullop,
83 	.vop_remove	= fifo_badop,
84 	.vop_link	= fifo_badop,
85 	.vop_rename	= fifo_badop,
86 	.vop_mkdir	= fifo_badop,
87 	.vop_rmdir	= fifo_badop,
88 	.vop_symlink	= fifo_badop,
89 	.vop_readdir	= fifo_badop,
90 	.vop_readlink	= fifo_badop,
91 	.vop_abortop	= fifo_badop,
92 	.vop_inactive	= fifo_inactive,
93 	.vop_reclaim	= fifo_reclaim,
94 	.vop_lock	= vop_generic_lock,
95 	.vop_unlock	= vop_generic_unlock,
96 	.vop_bmap	= vop_generic_bmap,
97 	.vop_strategy	= fifo_badop,
98 	.vop_print	= fifo_print,
99 	.vop_islocked	= vop_generic_islocked,
100 	.vop_pathconf	= fifo_pathconf,
101 	.vop_advlock	= fifo_advlock,
102 	.vop_bwrite	= nullop
103 };
104 
105 void	filt_fifordetach(struct knote *kn);
106 int	filt_fiforead(struct knote *kn, long hint);
107 void	filt_fifowdetach(struct knote *kn);
108 int	filt_fifowrite(struct knote *kn, long hint);
109 
110 struct filterops fiforead_filtops =
111 	{ 1, NULL, filt_fifordetach, filt_fiforead };
112 struct filterops fifowrite_filtops =
113 	{ 1, NULL, filt_fifowdetach, filt_fifowrite };
114 
115 /*
116  * Open called to set up a new instance of a fifo or
117  * to find an active instance of a fifo.
118  */
119 /* ARGSUSED */
120 int
121 fifo_open(void *v)
122 {
123 	struct vop_open_args *ap = v;
124 	struct vnode *vp = ap->a_vp;
125 	struct fifoinfo *fip;
126 	struct proc *p = ap->a_p;
127 	struct socket *rso, *wso;
128 	int error;
129 
130 	if ((fip = vp->v_fifoinfo) == NULL) {
131 		fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK);
132 		vp->v_fifoinfo = fip;
133 		if ((error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) != 0) {
134 			free(fip, M_VNODE, sizeof *fip);
135 			vp->v_fifoinfo = NULL;
136 			return (error);
137 		}
138 		fip->fi_readsock = rso;
139 		if ((error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) != 0) {
140 			(void)soclose(rso);
141 			free(fip, M_VNODE, sizeof *fip);
142 			vp->v_fifoinfo = NULL;
143 			return (error);
144 		}
145 		fip->fi_writesock = wso;
146 		if ((error = unp_connect2(wso, rso)) != 0) {
147 			(void)soclose(wso);
148 			(void)soclose(rso);
149 			free(fip, M_VNODE, sizeof *fip);
150 			vp->v_fifoinfo = NULL;
151 			return (error);
152 		}
153 		fip->fi_readers = fip->fi_writers = 0;
154 		wso->so_state |= SS_CANTSENDMORE;
155 		wso->so_snd.sb_lowat = PIPE_BUF;
156 	}
157 	if (ap->a_mode & FREAD) {
158 		fip->fi_readers++;
159 		if (fip->fi_readers == 1) {
160 			fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
161 			if (fip->fi_writers > 0)
162 				wakeup(&fip->fi_writers);
163 		}
164 	}
165 	if (ap->a_mode & FWRITE) {
166 		fip->fi_writers++;
167 		if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
168 			error = ENXIO;
169 			goto bad;
170 		}
171 		if (fip->fi_writers == 1) {
172 			fip->fi_readsock->so_state &= ~(SS_CANTRCVMORE|SS_ISDISCONNECTED);
173 			if (fip->fi_readers > 0)
174 				wakeup(&fip->fi_readers);
175 		}
176 	}
177 	if ((ap->a_mode & O_NONBLOCK) == 0) {
178 		if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
179 			VOP_UNLOCK(vp, p);
180 			error = tsleep(&fip->fi_readers,
181 			    PCATCH | PSOCK, "fifor", 0);
182 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
183 			if (error)
184 				goto bad;
185 		}
186 		if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
187 			VOP_UNLOCK(vp, p);
188 			error = tsleep(&fip->fi_writers,
189 			    PCATCH | PSOCK, "fifow", 0);
190 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
191 			if (error)
192 				goto bad;
193 		}
194 	}
195 	return (0);
196 bad:
197 	VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p);
198 	return (error);
199 }
200 
201 /*
202  * Vnode op for read
203  */
204 /* ARGSUSED */
205 int
206 fifo_read(void *v)
207 {
208 	struct vop_read_args *ap = v;
209 	struct uio *uio = ap->a_uio;
210 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
211 	struct proc *p = uio->uio_procp;
212 	int error;
213 
214 #ifdef DIAGNOSTIC
215 	if (uio->uio_rw != UIO_READ)
216 		panic("fifo_read mode");
217 #endif
218 	if (uio->uio_resid == 0)
219 		return (0);
220 	if (ap->a_ioflag & IO_NDELAY)
221 		rso->so_state |= SS_NBIO;
222 	VOP_UNLOCK(ap->a_vp, p);
223 	error = soreceive(rso, NULL, uio, NULL, NULL, NULL, 0);
224 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
225 	if (ap->a_ioflag & IO_NDELAY) {
226 		rso->so_state &= ~SS_NBIO;
227 		if (error == EWOULDBLOCK &&
228 		    ap->a_vp->v_fifoinfo->fi_writers == 0)
229 			error = 0;
230 	}
231 	return (error);
232 }
233 
234 /*
235  * Vnode op for write
236  */
237 /* ARGSUSED */
238 int
239 fifo_write(void *v)
240 {
241 	struct vop_write_args *ap = v;
242 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
243 	struct proc *p = ap->a_uio->uio_procp;
244 	int error;
245 
246 #ifdef DIAGNOSTIC
247 	if (ap->a_uio->uio_rw != UIO_WRITE)
248 		panic("fifo_write mode");
249 #endif
250 	if (ap->a_ioflag & IO_NDELAY)
251 		wso->so_state |= SS_NBIO;
252 	VOP_UNLOCK(ap->a_vp, p);
253 	error = sosend(wso, NULL, ap->a_uio, NULL, NULL, 0);
254 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
255 	if (ap->a_ioflag & IO_NDELAY)
256 		wso->so_state &= ~SS_NBIO;
257 	return (error);
258 }
259 
260 /*
261  * Device ioctl operation.
262  */
263 /* ARGSUSED */
264 int
265 fifo_ioctl(void *v)
266 {
267 	struct vop_ioctl_args *ap = v;
268 	struct file filetmp;
269 	int error;
270 
271 	if (ap->a_command == FIONBIO)
272 		return (0);
273 	if (ap->a_fflag & FREAD) {
274 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
275 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
276 		if (error)
277 			return (error);
278 	}
279 	if (ap->a_fflag & FWRITE) {
280 		filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
281 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
282 		if (error)
283 			return (error);
284 	}
285 	return (0);
286 }
287 
288 /* ARGSUSED */
289 int
290 fifo_poll(void *v)
291 {
292 	struct vop_poll_args *ap = v;
293 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
294 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
295 	int events = 0;
296 	int revents = 0;
297 
298 	/*
299 	 * FIFOs don't support out-of-band or high priority data.
300 	 */
301 	if (ap->a_fflag & FREAD)
302 		events |= ap->a_events & (POLLIN | POLLRDNORM);
303 	if (ap->a_fflag & FWRITE)
304 		events |= ap->a_events & (POLLOUT | POLLWRNORM);
305 
306 	if (events & (POLLIN | POLLRDNORM)) {
307 		if (soreadable(rso))
308 			revents |= events & (POLLIN | POLLRDNORM);
309 	}
310 	/* NOTE: POLLHUP and POLLOUT/POLLWRNORM are mutually exclusive */
311 	if ((rso->so_state & SS_ISDISCONNECTED) && !(ap->a_events & POLL_NOHUP)) {
312 		revents |= POLLHUP;
313 	} else if (events & (POLLOUT | POLLWRNORM)) {
314 		if (sowriteable(wso))
315 			revents |= events & (POLLOUT | POLLWRNORM);
316 	}
317 	if (revents == 0) {
318 		/* We want to return POLLHUP even if no valid events set. */
319 		if (events == 0 && !(ap->a_events & POLL_NOHUP))
320 			events = POLLIN;
321 		if (events & (POLLIN | POLLRDNORM)) {
322 			selrecord(ap->a_p, &rso->so_rcv.sb_sel);
323 			rso->so_rcv.sb_flagsintr |= SB_SEL;
324 		}
325 		if (events & (POLLOUT | POLLWRNORM)) {
326 			selrecord(ap->a_p, &wso->so_snd.sb_sel);
327 			wso->so_snd.sb_flagsintr |= SB_SEL;
328 		}
329 	}
330 	return (revents);
331 }
332 
333 int
334 fifo_inactive(void *v)
335 {
336 	struct vop_inactive_args *ap = v;
337 
338 	VOP_UNLOCK(ap->a_vp, ap->a_p);
339 	return (0);
340 }
341 
342 
343 /*
344  * Device close routine
345  */
346 /* ARGSUSED */
347 int
348 fifo_close(void *v)
349 {
350 	struct vop_close_args *ap = v;
351 	struct vnode *vp = ap->a_vp;
352 	struct fifoinfo *fip = vp->v_fifoinfo;
353 	int error1 = 0, error2 = 0;
354 
355 	if (fip == NULL)
356 		return (0);
357 
358 	if (ap->a_fflag & FREAD) {
359 		if (--fip->fi_readers == 0)
360 			socantsendmore(fip->fi_writesock);
361 	}
362 	if (ap->a_fflag & FWRITE) {
363 		if (--fip->fi_writers == 0) {
364 			/* SS_ISDISCONNECTED will result in POLLHUP */
365 			fip->fi_readsock->so_state |= SS_ISDISCONNECTED;
366 			socantrcvmore(fip->fi_readsock);
367 		}
368 	}
369 	if (fip->fi_readers == 0 && fip->fi_writers == 0) {
370 		error1 = soclose(fip->fi_readsock);
371 		error2 = soclose(fip->fi_writesock);
372 		free(fip, M_VNODE, sizeof *fip);
373 		vp->v_fifoinfo = NULL;
374 	}
375 	return (error1 ? error1 : error2);
376 }
377 
378 int
379 fifo_reclaim(void *v)
380 {
381 	struct vop_reclaim_args *ap = v;
382 	struct vnode *vp = ap->a_vp;
383 	struct fifoinfo *fip = vp->v_fifoinfo;
384 
385 	if (fip == NULL)
386 		return (0);
387 
388 	soclose(fip->fi_readsock);
389 	soclose(fip->fi_writesock);
390 	free(fip, M_VNODE, sizeof *fip);
391 	vp->v_fifoinfo = NULL;
392 
393 	return (0);
394 }
395 
396 /*
397  * Print out the contents of a fifo vnode.
398  */
399 int
400 fifo_print(void *v)
401 {
402 	struct vop_print_args *ap = v;
403 
404 	printf("tag VT_NON");
405 	fifo_printinfo(ap->a_vp);
406 	printf("\n");
407 	return 0;
408 }
409 
410 /*
411  * Print out internal contents of a fifo vnode.
412  */
413 void
414 fifo_printinfo(struct vnode *vp)
415 {
416 	struct fifoinfo *fip = vp->v_fifoinfo;
417 
418 	printf(", fifo with %ld readers and %ld writers",
419 		fip->fi_readers, fip->fi_writers);
420 }
421 
422 /*
423  * Return POSIX pathconf information applicable to fifo's.
424  */
425 int
426 fifo_pathconf(void *v)
427 {
428 	struct vop_pathconf_args *ap = v;
429 	int error = 0;
430 
431 	switch (ap->a_name) {
432 	case _PC_LINK_MAX:
433 		*ap->a_retval = LINK_MAX;
434 		break;
435 	case _PC_CHOWN_RESTRICTED:
436 		*ap->a_retval = 1;
437 		break;
438 	case _PC_TIMESTAMP_RESOLUTION:
439 		*ap->a_retval = 1;
440 		break;
441 	default:
442 		error = EINVAL;
443 		break;
444 	}
445 
446 	return (error);
447 }
448 
449 /*
450  * Fifo failed operation
451  */
452 /*ARGSUSED*/
453 int
454 fifo_ebadf(void *v)
455 {
456 
457 	return (EBADF);
458 }
459 
460 /*
461  * Fifo advisory byte-level locks.
462  */
463 /* ARGSUSED */
464 int
465 fifo_advlock(void *v)
466 {
467 	return (EOPNOTSUPP);
468 }
469 
470 /*
471  * Fifo bad operation
472  */
473 /*ARGSUSED*/
474 int
475 fifo_badop(void *v)
476 {
477 
478 	panic("fifo_badop called");
479 	/* NOTREACHED */
480 	return(0);
481 }
482 
483 
484 int
485 fifo_kqfilter(void *v)
486 {
487 	struct vop_kqfilter_args *ap = v;
488 	struct socket *so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock;
489 	struct sockbuf *sb;
490 
491 	switch (ap->a_kn->kn_filter) {
492 	case EVFILT_READ:
493 		ap->a_kn->kn_fop = &fiforead_filtops;
494 		sb = &so->so_rcv;
495 		break;
496 	case EVFILT_WRITE:
497 		ap->a_kn->kn_fop = &fifowrite_filtops;
498 		sb = &so->so_snd;
499 		break;
500 	default:
501 		return (EINVAL);
502 	}
503 
504 	ap->a_kn->kn_hook = so;
505 
506 	SLIST_INSERT_HEAD(&sb->sb_sel.si_note, ap->a_kn, kn_selnext);
507 	sb->sb_flags |= SB_KNOTE;
508 
509 	return (0);
510 }
511 
512 void
513 filt_fifordetach(struct knote *kn)
514 {
515 	struct socket *so = (struct socket *)kn->kn_hook;
516 
517 	SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
518 	if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
519 		so->so_rcv.sb_flags &= ~SB_KNOTE;
520 }
521 
522 int
523 filt_fiforead(struct knote *kn, long hint)
524 {
525 	struct socket *so = (struct socket *)kn->kn_hook;
526 
527 	kn->kn_data = so->so_rcv.sb_cc;
528 	if (so->so_state & SS_CANTRCVMORE) {
529 		kn->kn_flags |= EV_EOF;
530 		return (1);
531 	}
532 	kn->kn_flags &= ~EV_EOF;
533 	return (kn->kn_data > 0);
534 }
535 
536 void
537 filt_fifowdetach(struct knote *kn)
538 {
539 	struct socket *so = (struct socket *)kn->kn_hook;
540 
541 	SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
542 	if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
543 		so->so_snd.sb_flags &= ~SB_KNOTE;
544 }
545 
546 int
547 filt_fifowrite(struct knote *kn, long hint)
548 {
549 	struct socket *so = (struct socket *)kn->kn_hook;
550 
551 	kn->kn_data = sbspace(&so->so_snd);
552 	if (so->so_state & SS_CANTSENDMORE) {
553 		kn->kn_flags |= EV_EOF;
554 		return (1);
555 	}
556 	kn->kn_flags &= ~EV_EOF;
557 	return (kn->kn_data >= so->so_snd.sb_lowat);
558 }
559