xref: /netbsd-src/usr.sbin/perfused/msg.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*  $NetBSD: msg.c,v 1.22 2014/08/16 16:32:04 manu Exp $ */
2 
3 /*-
4  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions
8  *  are met:
9  *  1. Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16  *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19  *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  *  POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <sysexits.h>
35 #include <syslog.h>
36 #include <paths.h>
37 #include <puffs.h>
38 #include <limits.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/un.h>
42 #include <machine/vmparam.h>
43 
44 #include "perfused.h"
45 
46 static int xchg_pb_inloop(struct puffs_usermount *a, struct puffs_framebuf *,
47 	int, enum perfuse_xchg_pb_reply);
48 static int xchg_pb_early(struct puffs_usermount *a, struct puffs_framebuf *,
49 	int, enum perfuse_xchg_pb_reply);
50 
51 int
52 perfused_open_sock(void)
53 {
54 	int s;
55 	struct sockaddr_un sun;
56 	const struct sockaddr *sa;
57 	uint32_t opt;
58 	int sock_type = SOCK_SEQPACKET;
59 
60 	(void)unlink(_PATH_FUSE);
61 
62 	/*
63 	 * Try SOCK_SEQPACKET and fallback to SOCK_DGRAM
64 	 * if unavaible
65 	 */
66 	if ((s = socket(PF_LOCAL, SOCK_SEQPACKET, 0)) == -1) {
67 		warnx("SEQPACKET local sockets unavailable, using less "
68 		      "reliable DGRAM sockets. Expect file operation hangs.");
69 
70 		sock_type = SOCK_DGRAM;
71 		if ((s = socket(PF_LOCAL, SOCK_DGRAM, 0)) == -1)
72 			err(EX_OSERR, "socket failed");
73 	}
74 
75 	sa = (const struct sockaddr *)(void *)&sun;
76 	sun.sun_len = sizeof(sun);
77 	sun.sun_family = AF_LOCAL;
78 	(void)strcpy(sun.sun_path, _PATH_FUSE);
79 
80 	/*
81 	 * Set a buffer lentgh large enough so that a few FUSE packets
82 	 * will fit.
83 	 * XXX We will have to find how many packets we need
84 	 */
85 	opt = 4 * FUSE_BUFSIZE;
86 	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) != 0)
87 		DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt);
88 
89 	opt = 4 * FUSE_BUFSIZE;
90 	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) != 0)
91 		DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt);
92 
93 	/*
94 	 * Request peer credentials
95 	 */
96 	opt = 1;
97 	if (setsockopt(s, 0, LOCAL_CREDS, &opt, sizeof(opt)) != 0)
98 		DWARN("%s: setsockopt LOCAL_CREDS failed", __func__);
99 
100 	if (bind(s, sa, (socklen_t )sun.sun_len) == -1)
101 		err(EX_OSERR, "cannot open \"%s\" socket", _PATH_FUSE);
102 
103 	if (sock_type == SOCK_DGRAM) {
104 		if (connect(s, sa, (socklen_t )sun.sun_len) == -1)
105 			err(EX_OSERR, "cannot open \"%s\" socket", _PATH_FUSE);
106 	}
107 
108 	return s;
109 }
110 
111 
112 void *
113 perfused_recv_early(int fd, struct sockcred *sockcred, size_t sockcred_len)
114 {
115 	struct fuse_out_header foh;
116 	size_t len;
117 	char *buf;
118 	struct msghdr msg;
119 	char cmsg_buf[sizeof(struct cmsghdr) + SOCKCREDSIZE(NGROUPS_MAX)];
120 	struct cmsghdr *cmsg = (struct cmsghdr *)(void *)&cmsg_buf;
121 	struct sockcred *sc = (struct sockcred *)(void *)(cmsg + 1);
122 	struct iovec iov;
123 
124 	len = sizeof(foh);
125 
126 	/*
127 	 * We use the complicated recvmsg because we want peer creds.
128 	 */
129 	iov.iov_base = &foh;
130 	iov.iov_len = len;
131 	msg.msg_name = NULL;
132 	msg.msg_namelen = 0;
133 	msg.msg_iov = &iov;
134 	msg.msg_iovlen = 1;
135 	msg.msg_control = cmsg;
136 	msg.msg_controllen = sizeof(cmsg_buf);
137 	msg.msg_flags = 0;
138 
139 	if (recvmsg(fd, &msg, MSG_NOSIGNAL|MSG_PEEK) != (ssize_t)len) {
140 		DWARN("short recv (header)");
141 		return NULL;
142 	}
143 
144 	if (cmsg->cmsg_type != SCM_CREDS) {
145 		DWARNX("No SCM_CREDS");
146 		return NULL;
147 	}
148 
149 	if (sockcred != NULL)
150 		(void)memcpy(sockcred, sc,
151 			     MIN(cmsg->cmsg_len - sizeof(*cmsg), sockcred_len));
152 
153 
154 	len = foh.len;
155 	if ((buf = malloc(len)) == NULL)
156 		err(EX_OSERR, "malloc(%zd) failed", len);
157 
158 	if (recv(fd, buf, len, MSG_NOSIGNAL) != (ssize_t)len) {
159 		DWARN("short recv (frame)");
160 		return NULL;
161 	}
162 
163 	return buf;
164 }
165 
166 
167 perfuse_msg_t *
168 perfused_new_pb (struct puffs_usermount *pu, puffs_cookie_t opc, int opcode,
169     size_t payload_len, const struct puffs_cred *cred)
170 {
171 	struct puffs_framebuf *pb;
172 	struct fuse_in_header *fih;
173 	struct puffs_cc *pcc;
174 	uint64_t nodeid;
175 	void *data;
176 	size_t len;
177 
178 	if ((pb = puffs_framebuf_make()) == NULL)
179 		DERR(EX_OSERR, "puffs_framebuf_make failed");
180 
181 	len = payload_len + sizeof(*fih);
182 	if (opc != 0)
183 		nodeid = perfuse_get_nodeid(pu, opc);
184 	else
185 		nodeid = PERFUSE_UNKNOWN_NODEID;
186 
187 	if (puffs_framebuf_reserve_space(pb, len) != 0)
188 		DERR(EX_OSERR, "puffs_framebuf_reserve_space failed");
189 
190 	if (puffs_framebuf_getwindow(pb, 0, &data, &len) != 0)
191 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
192 	if (len != payload_len + sizeof(*fih))
193 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short len");
194 
195 	(void)memset(data, 0, len);
196 	fih = (struct fuse_in_header *)data;
197 	fih->len = (uint32_t)len;
198 	fih->opcode = opcode;
199 	fih->unique = perfuse_next_unique(pu);
200 	fih->nodeid = nodeid;
201 	fih->pid = 0;
202 
203 	/*
204 	 * NULL creds is taken as FUSE root. This currently happens for:
205 	 * - mount	root cred assumed
206 	 * - umount	root cred assumed
207 	 * - inactive	kernel cred used
208 	 * - statvfs	root cred assumed
209 	 * - poll	checks have been done at open() time
210 	 * - addvlock	checks have been done at open() time
211 	 */
212 	if ((cred != NULL) && !puffs_cred_isjuggernaut(cred)) {
213 		if (puffs_cred_getuid(cred, &fih->uid) != 0)
214 			DERRX(EX_SOFTWARE, "puffs_cred_getuid failed");
215 		if (puffs_cred_getgid(cred, &fih->gid) != 0)
216 			DERRX(EX_SOFTWARE, "puffs_cred_getgid failed");
217 	} else {
218 		fih->uid = (uid_t)0;
219 		fih->gid = (gid_t)0;
220 	}
221 
222 	if ((pcc = puffs_cc_getcc(pu)) != NULL)
223 		(void)puffs_cc_getcaller(pcc, (pid_t *)&fih->pid, NULL);
224 
225 	return (perfuse_msg_t *)(void *)pb;
226 }
227 
228 /*
229  * framebuf send/receive primitives based on pcc are
230  * not available until puffs mainloop is entered.
231  * This xchg_pb_inloop() variant allow early communication.
232  */
233 static int
234 xchg_pb_early(struct puffs_usermount *pu, struct puffs_framebuf *pb, int fd,
235     enum perfuse_xchg_pb_reply reply)
236 {
237 	int done;
238 	int error;
239 
240 	done = 0;
241 	while (done == 0) {
242 		if ((error = perfused_writeframe(pu, pb, fd, &done)) != 0)
243 			return error;
244 	}
245 
246 	if (reply == no_reply) {
247 		puffs_framebuf_destroy(pb);
248 		return 0;
249 	} else {
250 		puffs_framebuf_recycle(pb);
251 	}
252 
253 	done = 0;
254 	while (done == 0) {
255 		if ((error = perfused_readframe(pu, pb, fd, &done)) != 0)
256 			return error;
257 	}
258 
259 	return 0;
260 }
261 
262 static int
263 xchg_pb_inloop(struct puffs_usermount *pu, struct puffs_framebuf *pb, int fd,
264     enum perfuse_xchg_pb_reply reply)
265 {
266 	struct puffs_cc *pcc;
267 	int error;
268 
269 	if (reply == no_reply) {
270 		error = puffs_framev_enqueue_justsend(pu, fd, pb, 0, 0);
271 	} else {
272 		pcc = puffs_cc_getcc(pu);
273 		error = puffs_framev_enqueue_cc(pcc, fd, pb, 0);
274 	}
275 
276 	return error;
277 }
278 
279 int
280 perfused_xchg_pb(struct puffs_usermount *pu, perfuse_msg_t *pm,
281     size_t expected_len, enum perfuse_xchg_pb_reply reply)
282 {
283 	struct puffs_framebuf *pb = (struct puffs_framebuf *)(void *)pm;
284 	int fd;
285 	int error;
286 	struct fuse_out_header *foh;
287 #ifdef PERFUSE_DEBUG
288 	struct fuse_in_header *fih;
289 	uint64_t nodeid;
290 	int opcode;
291 	uint64_t unique_in;
292 	uint64_t unique_out;
293 
294 	fih = perfused_get_inhdr(pm);
295 	unique_in = fih->unique;
296 	nodeid = fih->nodeid;
297 	opcode = fih->opcode;
298 
299 	if (perfuse_diagflags & PDF_FUSE)
300 		DPRINTF("> unique = %"PRId64", nodeid = %"PRId64", "
301 			"opcode = %s (%d)\n",
302 			unique_in, nodeid, perfuse_opname(opcode), opcode);
303 
304 	if (perfuse_diagflags & PDF_DUMP)
305 		perfused_hexdump((char *)fih, fih->len);
306 
307 #endif /* PERFUSE_DEBUG */
308 
309 	fd = (int)(intptr_t)perfuse_getspecific(pu);
310 
311 	if (perfuse_inloop(pu))
312 		error = xchg_pb_inloop(pu, pb, fd, reply);
313 	else
314 		error = xchg_pb_early(pu, pb, fd, reply);
315 
316 	if (error)
317 		DERR(EX_SOFTWARE, "xchg_pb failed");
318 
319 	if (reply == no_reply)
320 		return 0;
321 
322 	foh = perfused_get_outhdr((perfuse_msg_t *)(void *)pb);
323 #ifdef PERFUSE_DEBUG
324 	unique_out = foh->unique;
325 
326 	if (perfuse_diagflags & PDF_FUSE)
327 		DPRINTF("< unique = %"PRId64", nodeid = %"PRId64", "
328 			"opcode = %s (%d), "
329 			"error = %d\n", unique_out, nodeid,
330 			perfuse_opname(opcode), opcode, foh->error);
331 
332 	if (perfuse_diagflags & PDF_DUMP)
333 		perfused_hexdump((char *)foh, foh->len);
334 
335 	if (unique_in != unique_out) {
336 		printf("%s: packet mismatch unique %"PRId64" vs %"PRId64"\n",
337 		     __func__, unique_in, unique_out);
338 		abort();
339 		errx(EX_SOFTWARE, "%s: packet mismatch unique "
340 		     "%"PRId64" vs %"PRId64"\n",
341 		     __func__, unique_in, unique_out);
342 	}
343 #endif /* PERFUSE_DEBUG */
344 
345 	if ((expected_len != PERFUSE_UNSPEC_REPLY_LEN) &&
346 	    (foh->len - sizeof(*foh) < expected_len) &&
347 	    (foh->error == 0)) {
348 		DERRX(EX_PROTOCOL,
349 		     "Unexpected short reply: received %zd bytes, expected %zd",
350 		     foh->len - sizeof(*foh), expected_len);
351 	}
352 
353 	if ((expected_len != 0) &&
354 	    (foh->len - sizeof(*foh) > expected_len))
355 		DWARNX("Unexpected long reply");
356 
357 	/*
358 	 * Negative Linux errno...
359 	 */
360 	if (foh->error <= 0) {
361 		foh->error = -foh->error;
362 	} else {
363 		DWARNX("FUSE resturns positive errno %d", foh->error);
364 		foh->error = 0;
365 	}
366 
367 	return foh->error;
368 }
369 
370 
371 struct fuse_in_header *
372 perfused_get_inhdr(perfuse_msg_t *pm)
373 {
374 	struct puffs_framebuf *pb;
375 	struct fuse_in_header *fih;
376 	void *hdr;
377 	size_t len;
378 
379 	pb = (struct puffs_framebuf *)(void *)pm;
380 	len = sizeof(*fih);
381 	if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
382 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
383 	if (len != sizeof(*fih))
384 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
385 
386 	fih = (struct fuse_in_header *)hdr;
387 
388 	return fih;
389 }
390 
391 struct fuse_out_header *
392 perfused_get_outhdr(perfuse_msg_t *pm)
393 {
394 	struct puffs_framebuf *pb;
395 	struct fuse_out_header *foh;
396 	void *hdr;
397 	size_t len;
398 
399 	pb = (struct puffs_framebuf *)(void *)pm;
400 	len = sizeof(*foh);
401 	if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
402 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
403 	if (len != sizeof(*foh))
404 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
405 
406 	foh = (struct fuse_out_header *)hdr;
407 
408 	return foh;
409 }
410 
411 char *
412 perfused_get_inpayload(perfuse_msg_t *pm)
413 {
414 	struct puffs_framebuf *pb;
415 	struct fuse_in_header *fih;
416 	void *hdr;
417 	void *payload;
418 	size_t len;
419 
420 	pb = (struct puffs_framebuf *)(void *)pm;
421 	len = sizeof(*fih);
422 	if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
423 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
424 	if (len != sizeof(*fih))
425 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
426 
427 	fih = (struct fuse_in_header *)hdr;
428 
429 	len = fih->len - sizeof(*fih);
430 	if (puffs_framebuf_getwindow(pb, sizeof(*fih), &payload, &len) != 0)
431 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
432 	if (len != fih->len - sizeof(*fih))
433 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
434 
435 	return (char *)payload;
436 }
437 
438 char *
439 perfused_get_outpayload(perfuse_msg_t *pm)
440 {
441 	struct puffs_framebuf *pb;
442 	struct fuse_out_header *foh;
443 	void *hdr;
444 	void *payload;
445 	size_t len;
446 
447 	pb = (struct puffs_framebuf *)(void *)pm;
448 	len = sizeof(*foh);
449 	if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
450 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
451 	if (len != sizeof(*foh))
452 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
453 
454 	foh = (struct fuse_out_header *)hdr;
455 
456 	len = foh->len - sizeof(*foh);
457 	if (puffs_framebuf_getwindow(pb, sizeof(*foh), &payload, &len) != 0)
458 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
459 	if (len != foh->len - sizeof(*foh))
460 		DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
461 
462 	return (char *)payload;
463 }
464 
465 #define PUFFS_FRAMEBUF_GETWINDOW(pb, offset, data, len) 		     \
466 	do {								     \
467 		int pfg_error;						     \
468 		size_t pfg_len = *(len);				     \
469 									     \
470 		pfg_error = puffs_framebuf_getwindow(pb, offset, data, len); \
471 		if (pfg_error != 0)					     \
472 			DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");\
473 									     \
474 		if (*(len) != pfg_len)					     \
475 			DERRX(EX_SOFTWARE, "puffs_framebuf_getwindow size"); \
476 	} while (0 /* CONSTCOND */);
477 
478 /* ARGSUSED0 */
479 int
480 perfused_readframe(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf,
481     int fd, int *done)
482 {
483 	struct fuse_out_header foh;
484 	size_t len;
485 	ssize_t readen;
486 	void *data;
487 
488 	/*
489 	 * Read the header
490 	 */
491 	len = sizeof(foh);
492 	PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len);
493 
494 	switch (readen = recv(fd, data, len, MSG_NOSIGNAL|MSG_PEEK)) {
495 	case 0:
496 		DPRINTF("Filesystem exit\n");
497 		/* NOTREACHED */
498 		exit(0);
499 		break;
500 	case -1:
501 		if (errno == EAGAIN)
502 			return 0;
503 		DWARN("%s: recv returned -1", __func__);
504 		return errno;
505 		/* NOTREACHED */
506 		break;
507 	default:
508 		break;
509 	}
510 
511 #ifdef PERFUSE_DEBUG
512 	if (readen != (ssize_t)len)
513 		DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd",
514 		      __func__, readen, len);
515 #endif
516 
517 	/*
518 	 * We have a header, get remaing length to read
519 	 */
520 	if (puffs_framebuf_getdata_atoff(pufbuf, 0, &foh, sizeof(foh)) != 0)
521 		DERR(EX_SOFTWARE, "puffs_framebuf_getdata_atoff failed");
522 
523 	len = foh.len;
524 
525 #ifdef PERFUSE_DEBUG
526 	if (len > (size_t)FUSE_BUFSIZE)
527 		DERRX(EX_SOFTWARE, "%s: foh.len = %zu", __func__, len);
528 #endif
529 
530 	/*
531 	 * This is time to reserve space.
532 	 */
533 	if (puffs_framebuf_reserve_space(pufbuf, len) == -1)
534 		DERR(EX_OSERR, "puffs_framebuf_reserve_space failed");
535 
536 	/*
537 	 * And read the remaining data
538 	 */
539 	PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len);
540 
541 	switch (readen = recv(fd, data, len, MSG_NOSIGNAL)) {
542 	case 0:
543 		DWARNX("%s: recv returned 0", __func__);
544 		perfused_panic();
545 	case -1:
546 		if (errno == EAGAIN)
547 			return 0;
548 		DWARN("%s: recv returned -1", __func__);
549 		return errno;
550 	default:
551 		break;
552 	}
553 
554 #ifdef PERFUSE_DEBUG
555 	if (readen != (ssize_t)len)
556 		DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd",
557 		      __func__, readen, len);
558 #endif
559 
560 	*done = 1;
561 	return 0;
562 }
563 
564 /* ARGSUSED0 */
565 int
566 perfused_writeframe(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf,
567     int fd, int *done)
568 {
569 	size_t len;
570 	ssize_t written;
571 	void *data;
572 
573 	len = puffs_framebuf_tellsize(pufbuf);
574 	PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len);
575 
576 	switch (written = send(fd, data, len, MSG_NOSIGNAL)) {
577 	case 0:
578 #ifdef PERFUSE_DEBUG
579 		DERRX(EX_SOFTWARE, "%s: send returned 0", __func__);
580 #else
581 		return ECONNRESET;
582 #endif
583 		/* NOTREACHED */
584 		break;
585 	case -1:
586 		DWARN("%s: send returned -1, errno = %d", __func__, errno);
587 		switch(errno) {
588 		case EAGAIN:
589 		case ENOBUFS:
590 		case EMSGSIZE:
591 			return 0;
592 			break;
593 		case EPIPE:
594 			perfused_panic();
595 			/* NOTREACHED */
596 			break;
597 		default:
598 			return errno;
599 			break;
600 		}
601 		/* NOTREACHED */
602 		break;
603 	default:
604 		break;
605 	}
606 
607 #ifdef PERFUSE_DEBUG
608 	if (written != (ssize_t)len)
609 		DERRX(EX_SOFTWARE, "%s: short send %zd/%zd",
610 		      __func__, written, len);
611 #endif
612 
613 	*done = 1;
614 	return 0;
615 }
616 
617 /* ARGSUSED0 */
618 int
619 perfused_cmpframe(struct puffs_usermount *pu, struct puffs_framebuf *pb1,
620     struct puffs_framebuf *pb2, int *match)
621 {
622 	struct fuse_in_header *fih;
623 	struct fuse_out_header *foh;
624 	uint64_t unique_in;
625 	uint64_t unique_out;
626 	size_t len;
627 
628 	len = sizeof(*fih);
629 	PUFFS_FRAMEBUF_GETWINDOW(pb1, 0, (void **)(void *)&fih, &len);
630 	unique_in = fih->unique;
631 
632 	len = sizeof(*foh);
633 	PUFFS_FRAMEBUF_GETWINDOW(pb2, 0, (void **)(void *)&foh, &len);
634 	unique_out = foh->unique;
635 
636 	return unique_in != unique_out;
637 }
638 
639 /* ARGSUSED0 */
640 void
641 perfused_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
642 {
643 	struct fuse_out_header *foh;
644 	size_t len;
645 
646 	len = sizeof(*foh);
647 	PUFFS_FRAMEBUF_GETWINDOW(pb, 0, (void **)(void *)&foh, &len);
648 
649 	DWARNX("Unexpected frame: unique = %"PRId64", error = %d",
650 	       foh->unique, foh->error);
651 #ifdef PERFUSE_DEBUG
652 	perfused_hexdump((char *)(void *)foh, foh->len);
653 #endif
654 
655 	return;
656 }
657 
658 void
659 perfused_fdnotify(struct puffs_usermount *pu, int fd, int what)
660 {
661 	if (fd != (int)(intptr_t)perfuse_getspecific(pu))
662 		DERRX(EX_SOFTWARE, "%s: unexpected notification for fd = %d",
663 		      __func__, fd);
664 
665 	if ((what != PUFFS_FBIO_READ) && (what != PUFFS_FBIO_WRITE))
666 		DERRX(EX_SOFTWARE, "%s: unexpected notification what = 0x%x",
667 		      __func__, what);
668 
669 	if (perfuse_unmount(pu) != 0)
670 		DWARN("unmount() failed");
671 
672 	if (shutdown(fd, SHUT_RDWR) != 0)
673 		DWARN("shutdown() failed");
674 
675 	if (perfuse_diagflags & PDF_MISC)
676 		DPRINTF("Exit");
677 
678 	exit(0);
679 }
680 
681 void
682 perfused_umount(struct puffs_usermount *pu)
683 {
684 	int fd;
685 
686 	fd = (int)(intptr_t)perfuse_getspecific(pu);
687 
688 	if (shutdown(fd, SHUT_RDWR) != 0)
689 		DWARN("shutdown() failed");
690 
691 	if (perfuse_diagflags & PDF_MISC)
692 		DPRINTF("unmount");
693 
694 	return;
695 }
696