1 /* $NetBSD: msg.c,v 1.13 2011/05/30 14:50:08 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->uid = (uid_t)-1; 207 fih->gid = (gid_t)-1; 208 fih->pid = 0; 209 if (cred != NULL) { 210 (void)puffs_cred_getuid(cred, &fih->uid); 211 (void)puffs_cred_getgid(cred, &fih->gid); 212 } 213 if ((pcc = puffs_cc_getcc(pu)) != NULL) 214 (void)puffs_cc_getcaller(pcc, (pid_t *)&fih->pid, NULL); 215 216 return (perfuse_msg_t *)(void *)pb; 217 } 218 219 /* 220 * framebuf send/receive primitives based on pcc are 221 * not available until puffs mainloop is entered. 222 * This xchg_pb_inloop() variant allow early communication. 223 */ 224 static int 225 xchg_pb_early(pu, pb, fd, reply) 226 struct puffs_usermount *pu; 227 struct puffs_framebuf *pb; 228 int fd; 229 enum perfuse_xchg_pb_reply reply; 230 { 231 int done; 232 int error; 233 234 done = 0; 235 while (done == 0) { 236 if ((error = perfuse_writeframe(pu, pb, fd, &done)) != 0) 237 return error; 238 } 239 240 if (reply == no_reply) { 241 puffs_framebuf_destroy(pb); 242 return 0; 243 } else { 244 puffs_framebuf_recycle(pb); 245 } 246 247 done = 0; 248 while (done == 0) { 249 if ((error = perfuse_readframe(pu, pb, fd, &done)) != 0) 250 return error; 251 } 252 253 return 0; 254 } 255 256 static int 257 xchg_pb_inloop(pu, pb, fd, reply) 258 struct puffs_usermount *pu; 259 struct puffs_framebuf *pb; 260 int fd; 261 enum perfuse_xchg_pb_reply reply; 262 { 263 struct puffs_cc *pcc; 264 int error; 265 266 if (reply == no_reply) { 267 error = puffs_framev_enqueue_justsend(pu, fd, pb, 0, 0); 268 } else { 269 pcc = puffs_cc_getcc(pu); 270 error = puffs_framev_enqueue_cc(pcc, fd, pb, 0); 271 } 272 273 return error; 274 } 275 276 int 277 perfuse_xchg_pb(pu, pm, expected_len, reply) 278 struct puffs_usermount *pu; 279 perfuse_msg_t *pm; 280 size_t expected_len; 281 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 = perfuse_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 perfuse_hexdump((char *)fih, fih->len); 306 307 #endif /* PERFUSE_DEBUG */ 308 309 fd = (int)(long)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 = perfuse_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 perfuse_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 foh->error = -foh->error; 361 362 return foh->error; 363 } 364 365 366 struct fuse_in_header * 367 perfuse_get_inhdr(pm) 368 perfuse_msg_t *pm; 369 { 370 struct puffs_framebuf *pb; 371 struct fuse_in_header *fih; 372 void *hdr; 373 size_t len; 374 375 pb = (struct puffs_framebuf *)(void *)pm; 376 len = sizeof(*fih); 377 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 378 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 379 if (len != sizeof(*fih)) 380 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 381 382 fih = (struct fuse_in_header *)hdr; 383 384 return fih; 385 } 386 387 struct fuse_out_header * 388 perfuse_get_outhdr(pm) 389 perfuse_msg_t *pm; 390 { 391 struct puffs_framebuf *pb; 392 struct fuse_out_header *foh; 393 void *hdr; 394 size_t len; 395 396 pb = (struct puffs_framebuf *)(void *)pm; 397 len = sizeof(*foh); 398 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 399 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 400 if (len != sizeof(*foh)) 401 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 402 403 foh = (struct fuse_out_header *)hdr; 404 405 return foh; 406 } 407 408 char * 409 perfuse_get_inpayload(pm) 410 perfuse_msg_t *pm; 411 { 412 struct puffs_framebuf *pb; 413 struct fuse_in_header *fih; 414 void *hdr; 415 void *payload; 416 size_t len; 417 418 pb = (struct puffs_framebuf *)(void *)pm; 419 len = sizeof(*fih); 420 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 421 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 422 if (len != sizeof(*fih)) 423 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 424 425 fih = (struct fuse_in_header *)hdr; 426 427 len = fih->len - sizeof(*fih); 428 if (puffs_framebuf_getwindow(pb, sizeof(*fih), &payload, &len) != 0) 429 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 430 if (len != fih->len - sizeof(*fih)) 431 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 432 433 return (char *)payload; 434 } 435 436 char * 437 perfuse_get_outpayload(pm) 438 perfuse_msg_t *pm; 439 { 440 struct puffs_framebuf *pb; 441 struct fuse_out_header *foh; 442 void *hdr; 443 void *payload; 444 size_t len; 445 446 pb = (struct puffs_framebuf *)(void *)pm; 447 len = sizeof(*foh); 448 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 449 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 450 if (len != sizeof(*foh)) 451 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 452 453 foh = (struct fuse_out_header *)hdr; 454 455 len = foh->len - sizeof(*foh); 456 if (puffs_framebuf_getwindow(pb, sizeof(*foh), &payload, &len) != 0) 457 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 458 if (len != foh->len - sizeof(*foh)) 459 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 460 461 return (char *)payload; 462 } 463 464 #define PUFFS_FRAMEBUF_GETWINDOW(pb, offset, data, len) \ 465 do { \ 466 int pfg_error; \ 467 size_t pfg_len = *(len); \ 468 \ 469 pfg_error = puffs_framebuf_getwindow(pb, offset, data, len); \ 470 if (pfg_error != 0) \ 471 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");\ 472 \ 473 if (*(len) != pfg_len) \ 474 DERRX(EX_SOFTWARE, "puffs_framebuf_getwindow size"); \ 475 } while (0 /* CONSTCOND */); 476 477 /* ARGSUSED0 */ 478 int 479 perfuse_readframe(pu, pufbuf, fd, done) 480 struct puffs_usermount *pu; 481 struct puffs_framebuf *pufbuf; 482 int fd; 483 int *done; 484 { 485 struct fuse_out_header foh; 486 size_t len; 487 ssize_t readen; 488 void *data; 489 490 /* 491 * Read the header 492 */ 493 len = sizeof(foh); 494 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 495 496 switch (readen = recv(fd, data, len, MSG_NOSIGNAL|MSG_PEEK)) { 497 case 0: 498 DWARNX("%s: recv retunred 0", __func__); 499 return ECONNRESET; 500 /* NOTREACHED */ 501 break; 502 case -1: 503 if (errno == EAGAIN) 504 return 0; 505 DWARN("%s: recv retunred -1", __func__); 506 return errno; 507 /* NOTREACHED */ 508 break; 509 default: 510 break; 511 } 512 513 #ifdef PERFUSE_DEBUG 514 if (readen != (ssize_t)len) 515 DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd", 516 __func__, readen, len); 517 #endif 518 519 /* 520 * We have a header, get remaing length to read 521 */ 522 if (puffs_framebuf_getdata_atoff(pufbuf, 0, &foh, sizeof(foh)) != 0) 523 DERR(EX_SOFTWARE, "puffs_framebuf_getdata_atoff failed"); 524 525 len = foh.len; 526 527 #ifdef PERFUSE_DEBUG 528 if (len > FUSE_BUFSIZE) 529 DERRX(EX_SOFTWARE, "%s: foh.len = %zu", __func__, len); 530 #endif 531 532 /* 533 * This is time to reserve space. 534 */ 535 if (puffs_framebuf_reserve_space(pufbuf, len) == -1) 536 DERR(EX_OSERR, "puffs_framebuf_reserve_space failed"); 537 538 /* 539 * And read the remaining data 540 */ 541 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 542 543 switch (readen = recv(fd, data, len, MSG_NOSIGNAL)) { 544 case 0: 545 DWARNX("%s: recv retunred 0", __func__); 546 return ECONNRESET; 547 /* NOTREACHED */ 548 break; 549 case -1: 550 if (errno == EAGAIN) 551 return 0; 552 DWARN("%s: recv retunred -1", __func__); 553 return errno; 554 /* NOTREACHED */ 555 break; 556 default: 557 break; 558 } 559 560 #ifdef PERFUSE_DEBUG 561 if (readen != (ssize_t)len) 562 DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd", 563 __func__, readen, len); 564 #endif 565 566 *done = 1; 567 return 0; 568 } 569 570 /* ARGSUSED0 */ 571 int 572 perfuse_writeframe(pu, pufbuf, fd, done) 573 struct puffs_usermount *pu; 574 struct puffs_framebuf *pufbuf; 575 int fd; 576 int *done; 577 { 578 size_t len; 579 ssize_t written; 580 void *data; 581 582 len = puffs_framebuf_tellsize(pufbuf); 583 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 584 585 switch (written = send(fd, data, len, MSG_NOSIGNAL)) { 586 case 0: 587 DWARNX("%s: send retunred 0", __func__); 588 return ECONNRESET; 589 /* NOTREACHED */ 590 break; 591 case -1: 592 DWARN("%s: send retunred -1, errno = %d", __func__, errno); 593 switch(errno) { 594 case EAGAIN: 595 case ENOBUFS: 596 case EMSGSIZE: 597 return 0; 598 break; 599 default: 600 return errno; 601 break; 602 } 603 /* NOTREACHED */ 604 break; 605 default: 606 break; 607 } 608 609 #ifdef PERFUSE_DEBUG 610 if (written != (ssize_t)len) 611 DERRX(EX_SOFTWARE, "%s: short send %zd/%zd", 612 __func__, written, len); 613 #endif 614 615 *done = 1; 616 return 0; 617 } 618 619 /* ARGSUSED0 */ 620 int 621 perfuse_cmpframe(pu, pb1, pb2, match) 622 struct puffs_usermount *pu; 623 struct puffs_framebuf *pb1; 624 struct puffs_framebuf *pb2; 625 int *match; 626 { 627 struct fuse_in_header *fih; 628 struct fuse_out_header *foh; 629 uint64_t unique_in; 630 uint64_t unique_out; 631 size_t len; 632 633 len = sizeof(*fih); 634 PUFFS_FRAMEBUF_GETWINDOW(pb1, 0, (void **)(void *)&fih, &len); 635 unique_in = fih->unique; 636 637 len = sizeof(*foh); 638 PUFFS_FRAMEBUF_GETWINDOW(pb2, 0, (void **)(void *)&foh, &len); 639 unique_out = foh->unique; 640 641 return unique_in != unique_out; 642 } 643 644 /* ARGSUSED0 */ 645 void 646 perfuse_gotframe(pu, pb) 647 struct puffs_usermount *pu; 648 struct puffs_framebuf *pb; 649 { 650 struct fuse_out_header *foh; 651 size_t len; 652 653 len = sizeof(*foh); 654 PUFFS_FRAMEBUF_GETWINDOW(pb, 0, (void **)(void *)&foh, &len); 655 656 DWARNX("Unexpected frame: unique = %"PRId64", error = %d", 657 foh->unique, foh->error); 658 #ifdef PERFUSE_DEBUG 659 perfuse_hexdump((char *)(void *)foh, foh->len); 660 #endif 661 662 return; 663 } 664 665 void 666 perfuse_fdnotify(pu, fd, what) 667 struct puffs_usermount *pu; 668 int fd; 669 int what; 670 { 671 if (fd != (int)(long)perfuse_getspecific(pu)) 672 DERRX(EX_SOFTWARE, "%s: unexpected notification for fd = %d", 673 __func__, fd); 674 675 if ((what != PUFFS_FBIO_READ) && (what != PUFFS_FBIO_WRITE)) 676 DERRX(EX_SOFTWARE, "%s: unexpected notification what = 0x%x", 677 __func__, what); 678 679 if (perfuse_unmount(pu) != 0) 680 DWARN("unmount() failed"); 681 682 if (shutdown(fd, SHUT_RDWR) != 0) 683 DWARN("shutdown() failed"); 684 685 if (perfuse_diagflags & PDF_MISC) 686 DPRINTF("Exit"); 687 688 exit(0); 689 690 /* NOTREACHED */ 691 return; 692 } 693 694 void 695 perfuse_umount(pu) 696 struct puffs_usermount *pu; 697 { 698 int fd; 699 700 fd = (int)(long)perfuse_getspecific(pu); 701 702 if (shutdown(fd, SHUT_RDWR) != 0) 703 DWARN("shutdown() failed"); 704 705 if (perfuse_diagflags & PDF_MISC) 706 DPRINTF("unmount"); 707 708 return; 709 } 710