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