xref: /openbsd/usr.bin/sndiod/fdpass.c (revision 36355b88)
1*36355b88Sratchov /*	$OpenBSD: fdpass.c,v 1.11 2021/11/01 14:43:25 ratchov Exp $	*/
2395f8c55Sratchov /*
3395f8c55Sratchov  * Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
4395f8c55Sratchov  *
5395f8c55Sratchov  * Permission to use, copy, modify, and distribute this software for any
6395f8c55Sratchov  * purpose with or without fee is hereby granted, provided that the above
7395f8c55Sratchov  * copyright notice and this permission notice appear in all copies.
8395f8c55Sratchov  *
9395f8c55Sratchov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10395f8c55Sratchov  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11395f8c55Sratchov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12395f8c55Sratchov  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13395f8c55Sratchov  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14395f8c55Sratchov  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15395f8c55Sratchov  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16395f8c55Sratchov  */
17395f8c55Sratchov #include <sys/socket.h>
18395f8c55Sratchov #include <errno.h>
19395f8c55Sratchov #include <fcntl.h>
20395f8c55Sratchov #include <poll.h>
21395f8c55Sratchov #include <sndio.h>
22395f8c55Sratchov #include <string.h>
23395f8c55Sratchov #include <unistd.h>
24395f8c55Sratchov #include "dev.h"
25395f8c55Sratchov #include "fdpass.h"
26395f8c55Sratchov #include "file.h"
27395f8c55Sratchov #include "listen.h"
28395f8c55Sratchov #include "midi.h"
29395f8c55Sratchov #include "sock.h"
30395f8c55Sratchov #include "utils.h"
31395f8c55Sratchov 
32395f8c55Sratchov struct fdpass_msg {
33395f8c55Sratchov #define FDPASS_OPEN_SND		0	/* open an audio device */
34395f8c55Sratchov #define FDPASS_OPEN_MIDI	1	/* open a midi port */
35d07fece6Sratchov #define FDPASS_OPEN_CTL		2	/* open an audio control device */
36395f8c55Sratchov #define FDPASS_RETURN		3	/* return after above commands */
37395f8c55Sratchov 	unsigned int cmd;		/* one of above */
38395f8c55Sratchov 	unsigned int num;		/* audio device or midi port number */
39395f8c55Sratchov 	unsigned int mode;		/* SIO_PLAY, SIO_REC, MIO_IN, ... */
40395f8c55Sratchov };
41395f8c55Sratchov 
42395f8c55Sratchov int fdpass_pollfd(void *, struct pollfd *);
43395f8c55Sratchov int fdpass_revents(void *, struct pollfd *);
44395f8c55Sratchov void fdpass_in_worker(void *);
45395f8c55Sratchov void fdpass_in_helper(void *);
46395f8c55Sratchov void fdpass_out(void *);
47395f8c55Sratchov void fdpass_hup(void *);
48395f8c55Sratchov 
49395f8c55Sratchov struct fileops worker_fileops = {
50395f8c55Sratchov 	"worker",
51395f8c55Sratchov 	fdpass_pollfd,
52395f8c55Sratchov 	fdpass_revents,
53395f8c55Sratchov 	fdpass_in_worker,
54395f8c55Sratchov 	fdpass_out,
55395f8c55Sratchov 	fdpass_hup
56395f8c55Sratchov };
57395f8c55Sratchov 
58395f8c55Sratchov struct fileops helper_fileops = {
59395f8c55Sratchov 	"helper",
60395f8c55Sratchov 	fdpass_pollfd,
61395f8c55Sratchov 	fdpass_revents,
62395f8c55Sratchov 	fdpass_in_helper,
63395f8c55Sratchov 	fdpass_out,
64395f8c55Sratchov 	fdpass_hup
65395f8c55Sratchov };
66395f8c55Sratchov 
67395f8c55Sratchov struct fdpass {
68395f8c55Sratchov 	struct file *file;
69395f8c55Sratchov 	int fd;
70395f8c55Sratchov } *fdpass_peer = NULL;
71395f8c55Sratchov 
72395f8c55Sratchov static void
fdpass_log(struct fdpass * f)73395f8c55Sratchov fdpass_log(struct fdpass *f)
74395f8c55Sratchov {
75395f8c55Sratchov 	log_puts(f->file->name);
76395f8c55Sratchov }
77395f8c55Sratchov 
78395f8c55Sratchov static int
fdpass_send(struct fdpass * f,int cmd,int num,int mode,int fd)79*36355b88Sratchov fdpass_send(struct fdpass *f, int cmd, int num, int mode, int fd)
80395f8c55Sratchov {
81395f8c55Sratchov 	struct fdpass_msg data;
82395f8c55Sratchov 	struct msghdr msg;
83395f8c55Sratchov 	struct cmsghdr *cmsg;
84395f8c55Sratchov 	union {
85395f8c55Sratchov 		struct cmsghdr hdr;
86395f8c55Sratchov 		unsigned char buf[CMSG_SPACE(sizeof(int))];
87395f8c55Sratchov 	} cmsgbuf;
88395f8c55Sratchov 	struct iovec iov;
89395f8c55Sratchov 	ssize_t n;
90395f8c55Sratchov 
91395f8c55Sratchov 	data.cmd = cmd;
92395f8c55Sratchov 	data.num = num;
93395f8c55Sratchov 	data.mode = mode;
94395f8c55Sratchov 	iov.iov_base = &data;
95395f8c55Sratchov 	iov.iov_len = sizeof(struct fdpass_msg);
96395f8c55Sratchov 	memset(&msg, 0, sizeof(msg));
97395f8c55Sratchov 	msg.msg_iov = &iov;
98395f8c55Sratchov 	msg.msg_iovlen = 1;
99395f8c55Sratchov 	if (fd >= 0) {
100395f8c55Sratchov 		msg.msg_control = &cmsgbuf.buf;
101395f8c55Sratchov 		msg.msg_controllen = sizeof(cmsgbuf.buf);
102395f8c55Sratchov 		cmsg = CMSG_FIRSTHDR(&msg);
103395f8c55Sratchov 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
104395f8c55Sratchov 		cmsg->cmsg_level = SOL_SOCKET;
105395f8c55Sratchov 		cmsg->cmsg_type = SCM_RIGHTS;
106395f8c55Sratchov 		*(int *)CMSG_DATA(cmsg) = fd;
107395f8c55Sratchov 	}
108395f8c55Sratchov 	n = sendmsg(f->fd, &msg, 0);
1093aaa63ebSderaadt 	if (n == -1) {
110395f8c55Sratchov 		if (log_level >= 1) {
111395f8c55Sratchov 			fdpass_log(f);
112395f8c55Sratchov 			log_puts(": sendmsg failed\n");
113395f8c55Sratchov 		}
114395f8c55Sratchov 		fdpass_close(f);
115395f8c55Sratchov 		return 0;
116395f8c55Sratchov 	}
117395f8c55Sratchov 	if (n != sizeof(struct fdpass_msg)) {
118395f8c55Sratchov 		if (log_level >= 1) {
119395f8c55Sratchov 			fdpass_log(f);
120395f8c55Sratchov 			log_puts(": short write\n");
121395f8c55Sratchov 		}
122395f8c55Sratchov 		fdpass_close(f);
123395f8c55Sratchov 		return 0;
124395f8c55Sratchov 	}
125395f8c55Sratchov #ifdef DEBUG
126395f8c55Sratchov 	if (log_level >= 3) {
127395f8c55Sratchov 		fdpass_log(f);
128395f8c55Sratchov 		log_puts(": send: cmd = ");
129395f8c55Sratchov 		log_puti(cmd);
130395f8c55Sratchov 		log_puts(", num = ");
131395f8c55Sratchov 		log_puti(num);
132395f8c55Sratchov 		log_puts(", mode = ");
133395f8c55Sratchov 		log_puti(mode);
134395f8c55Sratchov 		log_puts(", fd = ");
135395f8c55Sratchov 		log_puti(fd);
136395f8c55Sratchov 		log_puts("\n");
137395f8c55Sratchov 	}
138395f8c55Sratchov #endif
139395f8c55Sratchov 	if (fd >= 0)
140395f8c55Sratchov 		close(fd);
141395f8c55Sratchov 	return 1;
142395f8c55Sratchov }
143395f8c55Sratchov 
144395f8c55Sratchov static int
fdpass_recv(struct fdpass * f,int * cmd,int * num,int * mode,int * fd)145*36355b88Sratchov fdpass_recv(struct fdpass *f, int *cmd, int *num, int *mode, int *fd)
146395f8c55Sratchov {
147395f8c55Sratchov 	struct fdpass_msg data;
148395f8c55Sratchov 	struct msghdr msg;
149395f8c55Sratchov 	struct cmsghdr *cmsg;
150395f8c55Sratchov 	union {
151395f8c55Sratchov 		struct cmsghdr hdr;
152395f8c55Sratchov 		unsigned char buf[CMSG_SPACE(sizeof(int))];
153395f8c55Sratchov 	} cmsgbuf;
154395f8c55Sratchov 	struct iovec iov;
155395f8c55Sratchov 	ssize_t n;
156395f8c55Sratchov 
157395f8c55Sratchov 	iov.iov_base = &data;
158395f8c55Sratchov 	iov.iov_len = sizeof(struct fdpass_msg);
159395f8c55Sratchov 	memset(&msg, 0, sizeof(msg));
160395f8c55Sratchov 	msg.msg_control = &cmsgbuf.buf;
161395f8c55Sratchov 	msg.msg_controllen = sizeof(cmsgbuf.buf);
162395f8c55Sratchov 	msg.msg_iov = &iov;
163395f8c55Sratchov 	msg.msg_iovlen = 1;
164395f8c55Sratchov 	n = recvmsg(f->fd, &msg, MSG_WAITALL);
1653aaa63ebSderaadt 	if (n == -1 && errno == EMSGSIZE) {
166395f8c55Sratchov 		if (log_level >= 1) {
167395f8c55Sratchov 			fdpass_log(f);
168395f8c55Sratchov 			log_puts(": out of fds\n");
169395f8c55Sratchov 		}
170395f8c55Sratchov 		/*
171395f8c55Sratchov 		 * ancillary data (ie the fd) is discarded,
172395f8c55Sratchov 		 * retrieve the message
173395f8c55Sratchov 		 */
174395f8c55Sratchov 		n = recvmsg(f->fd, &msg, MSG_WAITALL);
175395f8c55Sratchov 	}
1763aaa63ebSderaadt 	if (n == -1) {
177395f8c55Sratchov 		if (log_level >= 1) {
178395f8c55Sratchov 			fdpass_log(f);
179395f8c55Sratchov 			log_puts(": recvmsg failed\n");
180395f8c55Sratchov 		}
181395f8c55Sratchov 		fdpass_close(f);
182395f8c55Sratchov 		return 0;
183395f8c55Sratchov 	}
184395f8c55Sratchov 	if (n == 0) {
185c28c4b14Sratchov 		if (log_level >= 3) {
186395f8c55Sratchov 			fdpass_log(f);
187395f8c55Sratchov 			log_puts(": recvmsg eof\n");
188395f8c55Sratchov 		}
189395f8c55Sratchov 		fdpass_close(f);
190395f8c55Sratchov 		return 0;
191395f8c55Sratchov 	}
192395f8c55Sratchov 	if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
193395f8c55Sratchov 		if (log_level >= 1) {
194395f8c55Sratchov 			fdpass_log(f);
195395f8c55Sratchov 			log_puts(": truncated\n");
196395f8c55Sratchov 		}
197395f8c55Sratchov 		fdpass_close(f);
198395f8c55Sratchov 		return 0;
199395f8c55Sratchov 	}
200395f8c55Sratchov 	cmsg = CMSG_FIRSTHDR(&msg);
201395f8c55Sratchov 	for (;;) {
202395f8c55Sratchov 		if (cmsg == NULL) {
203395f8c55Sratchov 			*fd = -1;
204395f8c55Sratchov 			break;
205395f8c55Sratchov 		}
206395f8c55Sratchov 		if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
207395f8c55Sratchov 		    cmsg->cmsg_level == SOL_SOCKET &&
208395f8c55Sratchov 		    cmsg->cmsg_type == SCM_RIGHTS) {
209395f8c55Sratchov 			*fd = *(int *)CMSG_DATA(cmsg);
210395f8c55Sratchov 			break;
211395f8c55Sratchov 		}
212395f8c55Sratchov 		cmsg = CMSG_NXTHDR(&msg, cmsg);
213395f8c55Sratchov 	}
214395f8c55Sratchov 	*cmd = data.cmd;
215395f8c55Sratchov 	*num = data.num;
216395f8c55Sratchov 	*mode = data.mode;
217395f8c55Sratchov #ifdef DEBUG
218395f8c55Sratchov 	if (log_level >= 3) {
219395f8c55Sratchov 		fdpass_log(f);
220395f8c55Sratchov 		log_puts(": recv: cmd = ");
221395f8c55Sratchov 		log_puti(*cmd);
222395f8c55Sratchov 		log_puts(", num = ");
223395f8c55Sratchov 		log_puti(*num);
224395f8c55Sratchov 		log_puts(", mode = ");
225395f8c55Sratchov 		log_puti(*mode);
226395f8c55Sratchov 		log_puts(", fd = ");
227395f8c55Sratchov 		log_puti(*fd);
228395f8c55Sratchov 		log_puts("\n");
229395f8c55Sratchov 	}
230395f8c55Sratchov #endif
231395f8c55Sratchov 	return 1;
232395f8c55Sratchov }
233395f8c55Sratchov 
234395f8c55Sratchov static int
fdpass_waitret(struct fdpass * f,int * retfd)235395f8c55Sratchov fdpass_waitret(struct fdpass *f, int *retfd)
236395f8c55Sratchov {
237395f8c55Sratchov 	int cmd, unused;
238395f8c55Sratchov 
239*36355b88Sratchov 	if (!fdpass_recv(fdpass_peer, &cmd, &unused, &unused, retfd))
240395f8c55Sratchov 		return 0;
241395f8c55Sratchov 	if (cmd != FDPASS_RETURN) {
242395f8c55Sratchov 		if (log_level >= 1) {
243395f8c55Sratchov 			fdpass_log(f);
244395f8c55Sratchov 			log_puts(": expected RETURN message\n");
245395f8c55Sratchov 		}
246395f8c55Sratchov 		fdpass_close(f);
247395f8c55Sratchov 		return 0;
248395f8c55Sratchov 	}
249395f8c55Sratchov 	return 1;
250395f8c55Sratchov }
251395f8c55Sratchov 
252395f8c55Sratchov struct sio_hdl *
fdpass_sio_open(int num,unsigned int mode)253*36355b88Sratchov fdpass_sio_open(int num, unsigned int mode)
254395f8c55Sratchov {
255395f8c55Sratchov 	int fd;
256395f8c55Sratchov 
25716a99293Sratchov 	if (fdpass_peer == NULL)
25816a99293Sratchov 		return NULL;
259*36355b88Sratchov 	if (!fdpass_send(fdpass_peer, FDPASS_OPEN_SND, num, mode, -1))
260395f8c55Sratchov 		return NULL;
261395f8c55Sratchov 	if (!fdpass_waitret(fdpass_peer, &fd))
262395f8c55Sratchov 		return NULL;
263395f8c55Sratchov 	if (fd < 0)
264395f8c55Sratchov 		return NULL;
265395f8c55Sratchov 	return sio_sun_fdopen(fd, mode, 1);
266395f8c55Sratchov }
267395f8c55Sratchov 
268395f8c55Sratchov struct mio_hdl *
fdpass_mio_open(int num,unsigned int mode)269*36355b88Sratchov fdpass_mio_open(int num, unsigned int mode)
270395f8c55Sratchov {
271395f8c55Sratchov 	int fd;
272395f8c55Sratchov 
27316a99293Sratchov 	if (fdpass_peer == NULL)
27416a99293Sratchov 		return NULL;
275*36355b88Sratchov 	if (!fdpass_send(fdpass_peer, FDPASS_OPEN_MIDI, num, mode, -1))
276395f8c55Sratchov 		return NULL;
277395f8c55Sratchov 	if (!fdpass_waitret(fdpass_peer, &fd))
278395f8c55Sratchov 		return NULL;
279395f8c55Sratchov 	if (fd < 0)
280395f8c55Sratchov 		return NULL;
281395f8c55Sratchov 	return mio_rmidi_fdopen(fd, mode, 1);
282395f8c55Sratchov }
283395f8c55Sratchov 
284d07fece6Sratchov struct sioctl_hdl *
fdpass_sioctl_open(int num,unsigned int mode)285*36355b88Sratchov fdpass_sioctl_open(int num, unsigned int mode)
286d07fece6Sratchov {
287d07fece6Sratchov 	int fd;
288d07fece6Sratchov 
289d07fece6Sratchov 	if (fdpass_peer == NULL)
290d07fece6Sratchov 		return NULL;
291*36355b88Sratchov 	if (!fdpass_send(fdpass_peer, FDPASS_OPEN_CTL, num, mode, -1))
292d07fece6Sratchov 		return NULL;
293d07fece6Sratchov 	if (!fdpass_waitret(fdpass_peer, &fd))
294d07fece6Sratchov 		return NULL;
295d07fece6Sratchov 	if (fd < 0)
296d07fece6Sratchov 		return NULL;
297d07fece6Sratchov 	return sioctl_sun_fdopen(fd, mode, 1);
298d07fece6Sratchov }
299d07fece6Sratchov 
300395f8c55Sratchov void
fdpass_in_worker(void * arg)301395f8c55Sratchov fdpass_in_worker(void *arg)
302395f8c55Sratchov {
303395f8c55Sratchov 	struct fdpass *f = arg;
304395f8c55Sratchov 
305c28c4b14Sratchov 	if (log_level >= 3) {
306395f8c55Sratchov 		fdpass_log(f);
307395f8c55Sratchov 		log_puts(": exit\n");
308395f8c55Sratchov 	}
309395f8c55Sratchov 	fdpass_close(f);
310395f8c55Sratchov 	return;
311395f8c55Sratchov }
312395f8c55Sratchov 
313395f8c55Sratchov void
fdpass_in_helper(void * arg)314395f8c55Sratchov fdpass_in_helper(void *arg)
315395f8c55Sratchov {
316*36355b88Sratchov 	int cmd, num, mode, fd;
317395f8c55Sratchov 	struct fdpass *f = arg;
318395f8c55Sratchov 	struct dev *d;
319395f8c55Sratchov 	struct port *p;
320395f8c55Sratchov 
321*36355b88Sratchov 	if (!fdpass_recv(f, &cmd, &num, &mode, &fd))
322395f8c55Sratchov 		return;
323395f8c55Sratchov 	switch (cmd) {
324395f8c55Sratchov 	case FDPASS_OPEN_SND:
325395f8c55Sratchov 		d = dev_bynum(num);
326395f8c55Sratchov 		if (d == NULL || !(mode & (SIO_PLAY | SIO_REC))) {
327395f8c55Sratchov 			if (log_level >= 1) {
328395f8c55Sratchov 				fdpass_log(f);
329395f8c55Sratchov 				log_puts(": bad audio device or mode\n");
330395f8c55Sratchov 			}
331395f8c55Sratchov 			fdpass_close(f);
332395f8c55Sratchov 			return;
333395f8c55Sratchov 		}
334*36355b88Sratchov 		fd = sio_sun_getfd(d->path, mode, 1);
335395f8c55Sratchov 		break;
336395f8c55Sratchov 	case FDPASS_OPEN_MIDI:
337395f8c55Sratchov 		p = port_bynum(num);
338395f8c55Sratchov 		if (p == NULL || !(mode & (MIO_IN | MIO_OUT))) {
339395f8c55Sratchov 			if (log_level >= 1) {
340395f8c55Sratchov 				fdpass_log(f);
341395f8c55Sratchov 				log_puts(": bad midi port or mode\n");
342395f8c55Sratchov 			}
343395f8c55Sratchov 			fdpass_close(f);
344395f8c55Sratchov 			return;
345395f8c55Sratchov 		}
346*36355b88Sratchov 		fd = mio_rmidi_getfd(p->path, mode, 1);
347395f8c55Sratchov 		break;
348d07fece6Sratchov 	case FDPASS_OPEN_CTL:
349d07fece6Sratchov 		d = dev_bynum(num);
350d07fece6Sratchov 		if (d == NULL || !(mode & (SIOCTL_READ | SIOCTL_WRITE))) {
351d07fece6Sratchov 			if (log_level >= 1) {
352d07fece6Sratchov 				fdpass_log(f);
353d07fece6Sratchov 				log_puts(": bad audio control device\n");
354d07fece6Sratchov 			}
355d07fece6Sratchov 			fdpass_close(f);
356d07fece6Sratchov 			return;
357d07fece6Sratchov 		}
358*36355b88Sratchov 		fd = sioctl_sun_getfd(d->path, mode, 1);
359d07fece6Sratchov 		break;
360395f8c55Sratchov 	default:
361395f8c55Sratchov 		fdpass_close(f);
362395f8c55Sratchov 		return;
363395f8c55Sratchov 	}
364*36355b88Sratchov 	fdpass_send(f, FDPASS_RETURN, 0, 0, fd);
365395f8c55Sratchov }
366395f8c55Sratchov 
367395f8c55Sratchov void
fdpass_out(void * arg)368395f8c55Sratchov fdpass_out(void *arg)
369395f8c55Sratchov {
370395f8c55Sratchov }
371395f8c55Sratchov 
372395f8c55Sratchov void
fdpass_hup(void * arg)373395f8c55Sratchov fdpass_hup(void *arg)
374395f8c55Sratchov {
375395f8c55Sratchov 	struct fdpass *f = arg;
376395f8c55Sratchov 
377c28c4b14Sratchov 	if (log_level >= 3) {
378395f8c55Sratchov 		fdpass_log(f);
379395f8c55Sratchov 		log_puts(": hup\n");
380395f8c55Sratchov 	}
381395f8c55Sratchov 	fdpass_close(f);
382395f8c55Sratchov }
383395f8c55Sratchov 
384395f8c55Sratchov struct fdpass *
fdpass_new(int sock,struct fileops * ops)385395f8c55Sratchov fdpass_new(int sock, struct fileops *ops)
386395f8c55Sratchov {
387395f8c55Sratchov 	struct fdpass *f;
388395f8c55Sratchov 
389395f8c55Sratchov 	f = xmalloc(sizeof(struct fdpass));
390395f8c55Sratchov 	f->file = file_new(ops, f, ops->name, 1);
391395f8c55Sratchov 	if (f->file == NULL) {
392395f8c55Sratchov 		close(sock);
393c699f4b9Sratchov 		xfree(f);
394395f8c55Sratchov 		return NULL;
395395f8c55Sratchov 	}
396395f8c55Sratchov 	f->fd = sock;
397395f8c55Sratchov 	fdpass_peer = f;
398395f8c55Sratchov 	return f;
399395f8c55Sratchov }
400395f8c55Sratchov 
401395f8c55Sratchov void
fdpass_close(struct fdpass * f)402395f8c55Sratchov fdpass_close(struct fdpass *f)
403395f8c55Sratchov {
404395f8c55Sratchov 	fdpass_peer = NULL;
405395f8c55Sratchov 	file_del(f->file);
406395f8c55Sratchov 	close(f->fd);
407395f8c55Sratchov 	xfree(f);
408395f8c55Sratchov }
409395f8c55Sratchov 
410395f8c55Sratchov int
fdpass_pollfd(void * arg,struct pollfd * pfd)411395f8c55Sratchov fdpass_pollfd(void *arg, struct pollfd *pfd)
412395f8c55Sratchov {
413395f8c55Sratchov 	struct fdpass *f = arg;
414395f8c55Sratchov 
415395f8c55Sratchov 	pfd->fd = f->fd;
416395f8c55Sratchov 	pfd->events = POLLIN;
417395f8c55Sratchov 	return 1;
418395f8c55Sratchov }
419395f8c55Sratchov 
420395f8c55Sratchov int
fdpass_revents(void * arg,struct pollfd * pfd)421395f8c55Sratchov fdpass_revents(void *arg, struct pollfd *pfd)
422395f8c55Sratchov {
423395f8c55Sratchov 	return pfd->revents;
424395f8c55Sratchov }
425