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