msg.c revision 1.7 1 /* $NetBSD: msg.c,v 1.7 2010/09/20 06:45:38 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 "../../lib/libperfuse/perfuse_if.h"
45 #include "perfused.h"
46
47 static int xchg_pb_inloop(struct puffs_usermount *a, struct puffs_framebuf *,
48 int, enum perfuse_xchg_pb_reply);
49 static int xchg_pb_early(struct puffs_usermount *a, struct puffs_framebuf *,
50 int, enum perfuse_xchg_pb_reply);
51
52 int
53 perfuse_open_sock(void)
54 {
55 int s;
56 struct sockaddr_un sun;
57 const struct sockaddr *sa;
58 uint32_t opt;
59
60 (void)unlink(_PATH_FUSE);
61
62 if ((s = socket(AF_LOCAL, PERFUSE_SOCKTYPE, 0)) == -1)
63 err(EX_OSERR, "socket failed");
64
65 sa = (const struct sockaddr *)(void *)&sun;
66 sun.sun_len = sizeof(sun);
67 sun.sun_family = AF_LOCAL;
68 (void)strcpy(sun.sun_path, _PATH_FUSE);
69
70 /*
71 * Set a buffer lentgh large enough so that any FUSE packet
72 * will fit.
73 */
74 opt = FUSE_BUFSIZE;
75 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) != 0)
76 DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt);
77
78 opt = FUSE_BUFSIZE;
79 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) != 0)
80 DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt);
81
82 /*
83 * Request peer credentials
84 */
85 opt = 1;
86 if (setsockopt(s, 0, LOCAL_CREDS, &opt, sizeof(opt)) != 0)
87 DWARN("%s: setsockopt LOCAL_CREDS failed", __func__);
88
89 if (bind(s, sa, (socklen_t )sun.sun_len) == -1)
90 err(EX_OSERR, "cannot open \"%s\" socket", _PATH_FUSE);
91
92 #if (PERFUSE_SOCKTYPE == SOCK_DGRAM)
93 if (connect(s, sa, (socklen_t )sun.sun_len) == -1)
94 err(EX_OSERR, "cannot open \"%s\" socket", _PATH_FUSE);
95 #else
96 if (listen(s, 1) == -1)
97 err(EX_OSERR, "listen failed");
98 #endif
99
100 return s;
101 }
102
103
104 void *
105 perfuse_recv_early(fd, sockcred, sockcred_len)
106 int fd;
107 struct sockcred *sockcred;
108 size_t sockcred_len;
109 {
110 struct fuse_out_header foh;
111 size_t len;
112 char *buf;
113 struct msghdr msg;
114 char cmsg_buf[sizeof(struct cmsghdr) + SOCKCREDSIZE(NGROUPS_MAX)];
115 struct cmsghdr *cmsg = (struct cmsghdr *)(void *)&cmsg_buf;
116 struct sockcred *sc = (struct sockcred *)(void *)(cmsg + 1);
117 struct iovec iov;
118
119 len = sizeof(foh);
120
121 /*
122 * We use the complicated recvmsg because we want peer creds.
123 */
124 iov.iov_base = &foh;
125 iov.iov_len = len;
126 msg.msg_name = NULL;
127 msg.msg_namelen = 0;
128 msg.msg_iov = &iov;
129 msg.msg_iovlen = 1;
130 msg.msg_control = cmsg;
131 msg.msg_controllen = sizeof(cmsg_buf);
132 msg.msg_flags = 0;
133
134 if (recvmsg(fd, &msg, MSG_NOSIGNAL|MSG_PEEK) != (ssize_t)len) {
135 DWARN("short recv (header)");
136 return NULL;
137 }
138
139 if (cmsg->cmsg_type != SCM_CREDS) {
140 DWARNX("No SCM_CREDS");
141 return NULL;
142 }
143
144 if (sockcred != NULL)
145 (void)memcpy(sockcred, sc,
146 MIN(cmsg->cmsg_len - sizeof(*cmsg), sockcred_len));
147
148
149 len = foh.len;
150 if ((buf = malloc(len)) == NULL)
151 err(EX_OSERR, "malloc(%zd) failed", len);
152
153 if (recv(fd, buf, len, MSG_NOSIGNAL) != (ssize_t)len) {
154 DWARN("short recv (frame)");
155 return NULL;
156 }
157
158 return buf;
159 }
160
161
162 perfuse_msg_t *
163 perfuse_new_pb (pu, opc, opcode, payload_len, cred)
164 struct puffs_usermount *pu;
165 puffs_cookie_t opc;
166 int opcode;
167 size_t payload_len;
168 const struct puffs_cred *cred;
169 {
170 struct puffs_framebuf *pb;
171 struct fuse_in_header *fih;
172 struct puffs_cc *pcc;
173 uint64_t nodeid;
174 void *data;
175 size_t len;
176
177 if ((pb = puffs_framebuf_make()) == NULL)
178 DERR(EX_OSERR, "puffs_framebuf_make failed");
179
180 len = payload_len + sizeof(*fih);
181 nodeid = (opc != 0) ? perfuse_get_ino(pu, opc) : PERFUSE_UNKNOWN_INO;
182
183 if (puffs_framebuf_reserve_space(pb, len) != 0)
184 DERR(EX_OSERR, "puffs_framebuf_reserve_space failed");
185
186 if (puffs_framebuf_getwindow(pb, 0, &data, &len) != 0)
187 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
188 if (len != payload_len + sizeof(*fih))
189 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short len");
190
191 (void)memset(data, 0, len);
192 fih = (struct fuse_in_header *)data;
193 fih->len = (uint32_t)len;
194 fih->opcode = opcode;
195 fih->unique = perfuse_next_unique(pu);
196 fih->nodeid = nodeid;
197 fih->uid = (uid_t)-1;
198 fih->gid = (gid_t)-1;
199 fih->pid = 0;
200 if (cred != NULL) {
201 (void)puffs_cred_getuid(cred, &fih->uid);
202 (void)puffs_cred_getgid(cred, &fih->gid);
203 }
204 if ((pcc = puffs_cc_getcc(pu)) != NULL)
205 (void)puffs_cc_getcaller(pcc, (pid_t *)&fih->pid, NULL);
206
207 return (perfuse_msg_t *)(void *)pb;
208 }
209
210 /*
211 * framebuf send/receive primitives based on pcc are
212 * not available until puffs mainloop is entered.
213 * This xchg_pb_inloop() variant allow early communication.
214 */
215 static int
216 xchg_pb_early(pu, pb, fd, reply)
217 struct puffs_usermount *pu;
218 struct puffs_framebuf *pb;
219 int fd;
220 enum perfuse_xchg_pb_reply reply;
221 {
222 int done;
223 int error;
224
225 done = 0;
226 while (done == 0) {
227 if ((error = perfuse_writeframe(pu, pb, fd, &done)) != 0)
228 return error;
229 }
230
231 if (reply == no_reply) {
232 puffs_framebuf_destroy(pb);
233 return 0;
234 } else {
235 puffs_framebuf_recycle(pb);
236 }
237
238 done = 0;
239 while (done == 0) {
240 if ((error = perfuse_readframe(pu, pb, fd, &done)) != 0)
241 return error;
242 }
243
244 return 0;
245 }
246
247 static int
248 xchg_pb_inloop(pu, pb, fd, reply)
249 struct puffs_usermount *pu;
250 struct puffs_framebuf *pb;
251 int fd;
252 enum perfuse_xchg_pb_reply reply;
253 {
254 struct puffs_cc *pcc;
255 int error;
256
257 if (reply == no_reply) {
258 error = puffs_framev_enqueue_justsend(pu, fd, pb, 0, 0);
259 } else {
260 pcc = puffs_cc_getcc(pu);
261 error = puffs_framev_enqueue_cc(pcc, fd, pb, 0);
262 }
263
264 return error;
265 }
266
267 int
268 perfuse_xchg_pb(pu, pm, expected_len, reply)
269 struct puffs_usermount *pu;
270 perfuse_msg_t *pm;
271 size_t expected_len;
272 enum perfuse_xchg_pb_reply reply;
273 {
274 struct puffs_framebuf *pb = (struct puffs_framebuf *)(void *)pm;
275 int fd;
276 int error;
277 struct fuse_out_header *foh;
278 #ifdef PERFUSE_DEBUG
279 struct fuse_in_header *fih;
280 uint64_t nodeid;
281 int opcode;
282 uint64_t unique_in;
283 uint64_t unique_out;
284
285 fih = perfuse_get_inhdr(pm);
286 unique_in = fih->unique;
287 nodeid = fih->nodeid;
288 opcode = fih->opcode;
289
290 if (perfuse_diagflags & PDF_FUSE)
291 DPRINTF("> unique = %"PRId64", nodeid = %"PRId64", "
292 "opcode = %s (%d)\n",
293 unique_in, nodeid, perfuse_opname(opcode), opcode);
294
295 if (perfuse_diagflags & PDF_DUMP)
296 perfuse_hexdump((char *)fih, fih->len);
297
298 #endif /* PERFUSE_DEBUG */
299
300 fd = (int)(long)perfuse_getspecific(pu);
301
302 if (perfuse_inloop(pu))
303 error = xchg_pb_inloop(pu, pb, fd, reply);
304 else
305 error = xchg_pb_early(pu, pb, fd, reply);
306
307 if (error)
308 DERR(EX_SOFTWARE, "xchg_pb failed");
309
310 if (reply == no_reply)
311 return 0;
312
313 foh = perfuse_get_outhdr((perfuse_msg_t *)(void *)pb);
314 #ifdef PERFUSE_DEBUG
315 unique_out = foh->unique;
316
317 if (perfuse_diagflags & PDF_FUSE)
318 DPRINTF("< unique = %"PRId64", nodeid = %"PRId64", "
319 "opcode = %s (%d), "
320 "error = %d\n", unique_out, nodeid,
321 perfuse_opname(opcode), opcode, error);
322
323 if (perfuse_diagflags & PDF_DUMP)
324 perfuse_hexdump((char *)foh, foh->len);
325
326 if (unique_in != unique_out) {
327 printf("%s: packet mismatch unique %"PRId64" vs %"PRId64"\n",
328 __func__, unique_in, unique_out);
329 abort();
330 errx(EX_SOFTWARE, "%s: packet mismatch unique "
331 "%"PRId64" vs %"PRId64"\n",
332 __func__, unique_in, unique_out);
333 }
334 #endif /* PERFUSE_DEBUG */
335
336 if ((expected_len != PERFUSE_UNSPEC_REPLY_LEN) &&
337 (foh->len - sizeof(*foh) < expected_len) &&
338 (foh->error == 0)) {
339 DERRX(EX_PROTOCOL,
340 "Unexpected short reply: received %zd bytes, expected %zd",
341 foh->len - sizeof(*foh), expected_len);
342 }
343
344 if ((expected_len != 0) &&
345 (foh->len - sizeof(*foh) > expected_len))
346 DWARNX("Unexpected long reply");
347
348 /*
349 * Negative Linux errno...
350 */
351 foh->error = -foh->error;
352
353 return foh->error;
354 }
355
356
357 struct fuse_in_header *
358 perfuse_get_inhdr(pm)
359 perfuse_msg_t *pm;
360 {
361 struct puffs_framebuf *pb;
362 struct fuse_in_header *fih;
363 void *hdr;
364 size_t len;
365
366 pb = (struct puffs_framebuf *)(void *)pm;
367 len = sizeof(*fih);
368 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
369 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
370 if (len != sizeof(*fih))
371 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
372
373 fih = (struct fuse_in_header *)hdr;
374
375 return fih;
376 }
377
378 struct fuse_out_header *
379 perfuse_get_outhdr(pm)
380 perfuse_msg_t *pm;
381 {
382 struct puffs_framebuf *pb;
383 struct fuse_out_header *foh;
384 void *hdr;
385 size_t len;
386
387 pb = (struct puffs_framebuf *)(void *)pm;
388 len = sizeof(*foh);
389 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
390 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
391 if (len != sizeof(*foh))
392 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
393
394 foh = (struct fuse_out_header *)hdr;
395
396 return foh;
397 }
398
399 char *
400 perfuse_get_inpayload(pm)
401 perfuse_msg_t *pm;
402 {
403 struct puffs_framebuf *pb;
404 struct fuse_in_header *fih;
405 void *hdr;
406 void *payload;
407 size_t len;
408
409 pb = (struct puffs_framebuf *)(void *)pm;
410 len = sizeof(*fih);
411 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
412 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
413 if (len != sizeof(*fih))
414 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
415
416 fih = (struct fuse_in_header *)hdr;
417
418 len = fih->len - sizeof(*fih);
419 if (puffs_framebuf_getwindow(pb, sizeof(*fih), &payload, &len) != 0)
420 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
421 if (len != fih->len - sizeof(*fih))
422 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
423
424 return (char *)payload;
425 }
426
427 char *
428 perfuse_get_outpayload(pm)
429 perfuse_msg_t *pm;
430 {
431 struct puffs_framebuf *pb;
432 struct fuse_out_header *foh;
433 void *hdr;
434 void *payload;
435 size_t len;
436
437 pb = (struct puffs_framebuf *)(void *)pm;
438 len = sizeof(*foh);
439 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
440 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
441 if (len != sizeof(*foh))
442 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
443
444 foh = (struct fuse_out_header *)hdr;
445
446 len = foh->len - sizeof(*foh);
447 if (puffs_framebuf_getwindow(pb, sizeof(*foh), &payload, &len) != 0)
448 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
449 if (len != foh->len - sizeof(*foh))
450 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
451
452 return (char *)payload;
453 }
454
455 #define PUFFS_FRAMEBUF_GETWINDOW(pb, offset, data, len) \
456 do { \
457 int pfg_error; \
458 size_t pfg_len = *(len); \
459 \
460 pfg_error = puffs_framebuf_getwindow(pb, offset, data, len); \
461 if (pfg_error != 0) \
462 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");\
463 \
464 if (*(len) != pfg_len) \
465 DERRX(EX_SOFTWARE, "puffs_framebuf_getwindow size"); \
466 } while (0 /* CONSTCOND */);
467
468 /* ARGSUSED0 */
469 int
470 perfuse_readframe(pu, pufbuf, fd, done)
471 struct puffs_usermount *pu;
472 struct puffs_framebuf *pufbuf;
473 int fd;
474 int *done;
475 {
476 struct fuse_out_header foh;
477 size_t offset;
478 size_t remain;
479 ssize_t readen;
480 void *data;
481 int peek = 0;
482
483 #if (PERFUSE_SOCKTYPE == SOCK_DGRAM)
484 peek = MSG_PEEK;
485 #endif
486 offset = puffs_framebuf_telloff(pufbuf);
487
488 /*
489 * Read the header
490 * MSG_PEEK is used so that this code works for SOCK_DGRAM
491 * socket. The loop is only needed to work with SOCK_STREAM.
492 */
493 while (offset < sizeof(foh)) {
494 remain = sizeof(foh) - offset;
495 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, offset, &data, &remain);
496
497 switch (readen = recv(fd, data, remain, MSG_NOSIGNAL|peek)) {
498 case 0:
499 DWARNX("%s: recv retunred 0", __func__);
500 return ECONNRESET;
501 /* NOTREACHED */
502 break;
503 case -1:
504 if (errno == EAGAIN)
505 return 0;
506 DWARN("%s: recv retunred -1", __func__);
507 return errno;
508 /* NOTREACHED */
509 break;
510 default:
511 #if defined(PERFUSE_DEBUG) && (PERFUSE_SOCKTYPE == SOCK_DGRAM)
512 if (readen != remain)
513 DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd",
514 __func__, readen, remain);
515 #endif
516 break;
517 }
518
519 offset += readen;
520 if (puffs_framebuf_seekset(pufbuf, offset) == -1)
521 DERR(EX_OSERR, "puffs_framebuf_seekset failed");
522 }
523
524 #if (PERFUSE_SOCKTYPE == SOCK_DGRAM)
525 /*
526 * We had a peek at the header, now really read it.
527 */
528 offset = 0;
529 #endif
530
531 /*
532 * We have a header, get remaing length to read
533 */
534 if (puffs_framebuf_getdata_atoff(pufbuf, 0, &foh, sizeof(foh)) != 0)
535 DERR(EX_SOFTWARE, "puffs_framebuf_getdata_atoff failed");
536 ;
537 #ifdef PERFUSE_DEBUG
538 if (foh.len > FUSE_BUFSIZE)
539 DERRX(EX_SOFTWARE, "%s: foh.len = %d (this is huge!)",
540 __func__, foh.len);
541 #endif
542
543 /*
544 * If we have only readen the header so far,
545 * this is time to reserve space.
546 */
547 remain = foh.len - offset;
548 if (offset == sizeof(foh))
549 if (puffs_framebuf_reserve_space(pufbuf, remain) == -1)
550 DERR(EX_OSERR, "puffs_framebuf_reserve_space failed");
551
552
553 /*
554 * And read the remaining data
555 */
556 while (remain != 0) {
557 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, offset, &data, &remain);
558
559 switch (readen = recv(fd, data, remain, MSG_NOSIGNAL)) {
560 case 0:
561 DWARNX("%s: recv retunred 0", __func__);
562 return ECONNRESET;
563 /* NOTREACHED */
564 break;
565 case -1:
566 if (errno == EAGAIN)
567 return 0;
568 DWARN("%s: recv retunred -1", __func__);
569 return errno;
570 /* NOTREACHED */
571 break;
572 default:
573 #if defined(PERFUSE_DEBUG) && (PERFUSE_SOCKTYPE == SOCK_DGRAM)
574 if (readen != remain)
575 DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd",
576 __func__, readen, remain);
577 #endif
578 break;
579 }
580
581 offset += readen;
582 remain -= readen;
583
584 if (puffs_framebuf_seekset(pufbuf, offset) == -1)
585 DERR(EX_OSERR, "puffs_framebuf_seekset failed");
586 }
587
588 *done = 1;
589 return 0;
590 }
591
592 /* ARGSUSED0 */
593 int
594 perfuse_writeframe(pu, pufbuf, fd, done)
595 struct puffs_usermount *pu;
596 struct puffs_framebuf *pufbuf;
597 int fd;
598 int *done;
599 {
600 size_t offset;
601 size_t len;
602 ssize_t written;
603 size_t remain;
604 void *data;
605
606 offset = puffs_framebuf_telloff(pufbuf);
607 len = puffs_framebuf_tellsize(pufbuf) - offset;
608 remain = len;
609
610 while (remain != 0) {
611 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, offset, &data, &len);
612
613 switch (written = send(fd, data, remain, MSG_NOSIGNAL)) {
614 case 0:
615 DWARNX("%s: send retunred 0", __func__);
616 return ECONNRESET;
617 /* NOTREACHED */
618 break;
619 case -1:
620 if (errno == EAGAIN)
621 return 0;
622 DWARN("%s: send retunred -1", __func__);
623 return errno;
624 /* NOTREACHED */
625 break;
626 default:
627 #if defined(PERFUSE_DEBUG) && (PERFUSE_SOCKTYPE == SOCK_DGRAM)
628 if (written != remain)
629 DERRX(EX_SOFTWARE, "%s: short send %zd/%zd",
630 __func__, written, remain);
631 #endif
632 break;
633 }
634
635 remain -= written;
636 offset += written;
637
638 if (puffs_framebuf_seekset(pufbuf, offset) == -1)
639 DERR(EX_OSERR, "puffs_framebuf_seekset failed");
640 }
641
642 *done = 1;
643 return 0;
644 }
645
646 /* ARGSUSED0 */
647 int
648 perfuse_cmpframe(pu, pb1, pb2, match)
649 struct puffs_usermount *pu;
650 struct puffs_framebuf *pb1;
651 struct puffs_framebuf *pb2;
652 int *match;
653 {
654 struct fuse_in_header *fih;
655 struct fuse_out_header *foh;
656 uint64_t unique_in;
657 uint64_t unique_out;
658 size_t len;
659
660 len = sizeof(*fih);
661 PUFFS_FRAMEBUF_GETWINDOW(pb1, 0, (void **)&fih, &len);
662 unique_in = fih->unique;
663
664 len = sizeof(*foh);
665 PUFFS_FRAMEBUF_GETWINDOW(pb2, 0, (void **)&foh, &len);
666 unique_out = foh->unique;
667
668 return unique_in != unique_out;
669 }
670
671 /* ARGSUSED0 */
672 void
673 perfuse_gotframe(pu, pb)
674 struct puffs_usermount *pu;
675 struct puffs_framebuf *pb;
676 {
677 struct fuse_out_header *foh;
678 size_t len;
679
680 len = sizeof(*foh);
681 PUFFS_FRAMEBUF_GETWINDOW(pb, 0, (void **)&foh, &len);
682
683 DWARNX("Unexpected frame: unique = %"PRId64", error = %d",
684 foh->unique, foh->error);
685 #ifdef PERFUSE_DEBUG
686 perfuse_hexdump((char *)(void *)foh, foh->len);
687 #endif
688
689 return;
690 }
691
692 void
693 perfuse_fdnotify(pu, fd, what)
694 struct puffs_usermount *pu;
695 int fd;
696 int what;
697 {
698 if (fd != (int)(long)perfuse_getspecific(pu))
699 DERRX(EX_SOFTWARE, "%s: unexpected notification for fd = %d",
700 __func__, fd);
701
702 if ((what != PUFFS_FBIO_READ) && (what != PUFFS_FBIO_WRITE))
703 DERRX(EX_SOFTWARE, "%s: unexpected notification what = 0x%x",
704 __func__, what);
705
706 if (perfuse_unmount(pu) != 0)
707 DWARN("unmount() failed");
708
709 if (shutdown(fd, SHUT_RDWR) != 0)
710 DWARN("shutdown() failed");
711
712 if (perfuse_diagflags & PDF_MISC)
713 DPRINTF("Exit");
714
715 exit(0);
716
717 /* NOTREACHED */
718 return;
719 }
720