1 /* $NetBSD: msg.c,v 1.17 2011/10/30 05:17:41 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(int fd, struct sockcred *sockcred, size_t sockcred_len) 115 { 116 struct fuse_out_header foh; 117 size_t len; 118 char *buf; 119 struct msghdr msg; 120 char cmsg_buf[sizeof(struct cmsghdr) + SOCKCREDSIZE(NGROUPS_MAX)]; 121 struct cmsghdr *cmsg = (struct cmsghdr *)(void *)&cmsg_buf; 122 struct sockcred *sc = (struct sockcred *)(void *)(cmsg + 1); 123 struct iovec iov; 124 125 len = sizeof(foh); 126 127 /* 128 * We use the complicated recvmsg because we want peer creds. 129 */ 130 iov.iov_base = &foh; 131 iov.iov_len = len; 132 msg.msg_name = NULL; 133 msg.msg_namelen = 0; 134 msg.msg_iov = &iov; 135 msg.msg_iovlen = 1; 136 msg.msg_control = cmsg; 137 msg.msg_controllen = sizeof(cmsg_buf); 138 msg.msg_flags = 0; 139 140 if (recvmsg(fd, &msg, MSG_NOSIGNAL|MSG_PEEK) != (ssize_t)len) { 141 DWARN("short recv (header)"); 142 return NULL; 143 } 144 145 if (cmsg->cmsg_type != SCM_CREDS) { 146 DWARNX("No SCM_CREDS"); 147 return NULL; 148 } 149 150 if (sockcred != NULL) 151 (void)memcpy(sockcred, sc, 152 MIN(cmsg->cmsg_len - sizeof(*cmsg), sockcred_len)); 153 154 155 len = foh.len; 156 if ((buf = malloc(len)) == NULL) 157 err(EX_OSERR, "malloc(%zd) failed", len); 158 159 if (recv(fd, buf, len, MSG_NOSIGNAL) != (ssize_t)len) { 160 DWARN("short recv (frame)"); 161 return NULL; 162 } 163 164 return buf; 165 } 166 167 168 perfuse_msg_t * 169 perfuse_new_pb (struct puffs_usermount *pu, puffs_cookie_t opc, int opcode, 170 size_t payload_len, const struct puffs_cred *cred) 171 { 172 struct puffs_framebuf *pb; 173 struct fuse_in_header *fih; 174 struct puffs_cc *pcc; 175 uint64_t nodeid; 176 void *data; 177 size_t len; 178 179 if ((pb = puffs_framebuf_make()) == NULL) 180 DERR(EX_OSERR, "puffs_framebuf_make failed"); 181 182 len = payload_len + sizeof(*fih); 183 if (opc != 0) 184 nodeid = perfuse_get_nodeid(pu, opc); 185 else 186 nodeid = PERFUSE_UNKNOWN_NODEID; 187 188 if (puffs_framebuf_reserve_space(pb, len) != 0) 189 DERR(EX_OSERR, "puffs_framebuf_reserve_space failed"); 190 191 if (puffs_framebuf_getwindow(pb, 0, &data, &len) != 0) 192 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 193 if (len != payload_len + sizeof(*fih)) 194 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short len"); 195 196 (void)memset(data, 0, len); 197 fih = (struct fuse_in_header *)data; 198 fih->len = (uint32_t)len; 199 fih->opcode = opcode; 200 fih->unique = perfuse_next_unique(pu); 201 fih->nodeid = nodeid; 202 fih->pid = 0; 203 204 /* 205 * NULL creds is taken as FUSE root. This currently happens for: 206 * - mount root cred assumed 207 * - umount root cred assumed 208 * - inactive kernel cred used 209 * - statvfs root cred assumed 210 * - poll checks have been done at open() time 211 * - addvlock checks have been done at open() time 212 */ 213 if ((cred != NULL) && !puffs_cred_isjuggernaut(cred)) { 214 if (puffs_cred_getuid(cred, &fih->uid) != 0) 215 DERRX(EX_SOFTWARE, "puffs_cred_getuid failed"); 216 if (puffs_cred_getgid(cred, &fih->gid) != 0) 217 DERRX(EX_SOFTWARE, "puffs_cred_getgid failed"); 218 } else { 219 fih->uid = (uid_t)0; 220 fih->gid = (gid_t)0; 221 } 222 223 if ((pcc = puffs_cc_getcc(pu)) != NULL) 224 (void)puffs_cc_getcaller(pcc, (pid_t *)&fih->pid, NULL); 225 226 return (perfuse_msg_t *)(void *)pb; 227 } 228 229 /* 230 * framebuf send/receive primitives based on pcc are 231 * not available until puffs mainloop is entered. 232 * This xchg_pb_inloop() variant allow early communication. 233 */ 234 static int 235 xchg_pb_early(struct puffs_usermount *pu, struct puffs_framebuf *pb, int fd, 236 enum perfuse_xchg_pb_reply reply) 237 { 238 int done; 239 int error; 240 241 done = 0; 242 while (done == 0) { 243 if ((error = perfuse_writeframe(pu, pb, fd, &done)) != 0) 244 return error; 245 } 246 247 if (reply == no_reply) { 248 puffs_framebuf_destroy(pb); 249 return 0; 250 } else { 251 puffs_framebuf_recycle(pb); 252 } 253 254 done = 0; 255 while (done == 0) { 256 if ((error = perfuse_readframe(pu, pb, fd, &done)) != 0) 257 return error; 258 } 259 260 return 0; 261 } 262 263 static int 264 xchg_pb_inloop(struct puffs_usermount *pu, struct puffs_framebuf *pb, int fd, 265 enum perfuse_xchg_pb_reply reply) 266 { 267 struct puffs_cc *pcc; 268 int error; 269 270 if (reply == no_reply) { 271 error = puffs_framev_enqueue_justsend(pu, fd, pb, 0, 0); 272 } else { 273 pcc = puffs_cc_getcc(pu); 274 error = puffs_framev_enqueue_cc(pcc, fd, pb, 0); 275 } 276 277 return error; 278 } 279 280 int 281 perfuse_xchg_pb(struct puffs_usermount *pu, perfuse_msg_t *pm, 282 size_t expected_len, enum perfuse_xchg_pb_reply reply) 283 { 284 struct puffs_framebuf *pb = (struct puffs_framebuf *)(void *)pm; 285 int fd; 286 int error; 287 struct fuse_out_header *foh; 288 #ifdef PERFUSE_DEBUG 289 struct fuse_in_header *fih; 290 uint64_t nodeid; 291 int opcode; 292 uint64_t unique_in; 293 uint64_t unique_out; 294 295 fih = perfuse_get_inhdr(pm); 296 unique_in = fih->unique; 297 nodeid = fih->nodeid; 298 opcode = fih->opcode; 299 300 if (perfuse_diagflags & PDF_FUSE) 301 DPRINTF("> unique = %"PRId64", nodeid = %"PRId64", " 302 "opcode = %s (%d)\n", 303 unique_in, nodeid, perfuse_opname(opcode), opcode); 304 305 if (perfuse_diagflags & PDF_DUMP) 306 perfuse_hexdump((char *)fih, fih->len); 307 308 #endif /* PERFUSE_DEBUG */ 309 310 fd = (int)(long)perfuse_getspecific(pu); 311 312 if (perfuse_inloop(pu)) 313 error = xchg_pb_inloop(pu, pb, fd, reply); 314 else 315 error = xchg_pb_early(pu, pb, fd, reply); 316 317 if (error) 318 DERR(EX_SOFTWARE, "xchg_pb failed"); 319 320 if (reply == no_reply) 321 return 0; 322 323 foh = perfuse_get_outhdr((perfuse_msg_t *)(void *)pb); 324 #ifdef PERFUSE_DEBUG 325 unique_out = foh->unique; 326 327 if (perfuse_diagflags & PDF_FUSE) 328 DPRINTF("< unique = %"PRId64", nodeid = %"PRId64", " 329 "opcode = %s (%d), " 330 "error = %d\n", unique_out, nodeid, 331 perfuse_opname(opcode), opcode, foh->error); 332 333 if (perfuse_diagflags & PDF_DUMP) 334 perfuse_hexdump((char *)foh, foh->len); 335 336 if (unique_in != unique_out) { 337 printf("%s: packet mismatch unique %"PRId64" vs %"PRId64"\n", 338 __func__, unique_in, unique_out); 339 abort(); 340 errx(EX_SOFTWARE, "%s: packet mismatch unique " 341 "%"PRId64" vs %"PRId64"\n", 342 __func__, unique_in, unique_out); 343 } 344 #endif /* PERFUSE_DEBUG */ 345 346 if ((expected_len != PERFUSE_UNSPEC_REPLY_LEN) && 347 (foh->len - sizeof(*foh) < expected_len) && 348 (foh->error == 0)) { 349 DERRX(EX_PROTOCOL, 350 "Unexpected short reply: received %zd bytes, expected %zd", 351 foh->len - sizeof(*foh), expected_len); 352 } 353 354 if ((expected_len != 0) && 355 (foh->len - sizeof(*foh) > expected_len)) 356 DWARNX("Unexpected long reply"); 357 358 /* 359 * Negative Linux errno... 360 */ 361 foh->error = -foh->error; 362 363 return foh->error; 364 } 365 366 367 struct fuse_in_header * 368 perfuse_get_inhdr(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(perfuse_msg_t *pm) 389 { 390 struct puffs_framebuf *pb; 391 struct fuse_out_header *foh; 392 void *hdr; 393 size_t len; 394 395 pb = (struct puffs_framebuf *)(void *)pm; 396 len = sizeof(*foh); 397 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 398 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 399 if (len != sizeof(*foh)) 400 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 401 402 foh = (struct fuse_out_header *)hdr; 403 404 return foh; 405 } 406 407 char * 408 perfuse_get_inpayload(perfuse_msg_t *pm) 409 { 410 struct puffs_framebuf *pb; 411 struct fuse_in_header *fih; 412 void *hdr; 413 void *payload; 414 size_t len; 415 416 pb = (struct puffs_framebuf *)(void *)pm; 417 len = sizeof(*fih); 418 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 419 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 420 if (len != sizeof(*fih)) 421 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 422 423 fih = (struct fuse_in_header *)hdr; 424 425 len = fih->len - sizeof(*fih); 426 if (puffs_framebuf_getwindow(pb, sizeof(*fih), &payload, &len) != 0) 427 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 428 if (len != fih->len - sizeof(*fih)) 429 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 430 431 return (char *)payload; 432 } 433 434 char * 435 perfuse_get_outpayload(perfuse_msg_t *pm) 436 { 437 struct puffs_framebuf *pb; 438 struct fuse_out_header *foh; 439 void *hdr; 440 void *payload; 441 size_t len; 442 443 pb = (struct puffs_framebuf *)(void *)pm; 444 len = sizeof(*foh); 445 if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 446 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 447 if (len != sizeof(*foh)) 448 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 449 450 foh = (struct fuse_out_header *)hdr; 451 452 len = foh->len - sizeof(*foh); 453 if (puffs_framebuf_getwindow(pb, sizeof(*foh), &payload, &len) != 0) 454 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 455 if (len != foh->len - sizeof(*foh)) 456 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 457 458 return (char *)payload; 459 } 460 461 #define PUFFS_FRAMEBUF_GETWINDOW(pb, offset, data, len) \ 462 do { \ 463 int pfg_error; \ 464 size_t pfg_len = *(len); \ 465 \ 466 pfg_error = puffs_framebuf_getwindow(pb, offset, data, len); \ 467 if (pfg_error != 0) \ 468 DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");\ 469 \ 470 if (*(len) != pfg_len) \ 471 DERRX(EX_SOFTWARE, "puffs_framebuf_getwindow size"); \ 472 } while (0 /* CONSTCOND */); 473 474 /* ARGSUSED0 */ 475 int 476 perfuse_readframe(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, 477 int fd, int *done) 478 { 479 struct fuse_out_header foh; 480 size_t len; 481 ssize_t readen; 482 void *data; 483 484 /* 485 * Read the header 486 */ 487 len = sizeof(foh); 488 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 489 490 switch (readen = recv(fd, data, len, MSG_NOSIGNAL|MSG_PEEK)) { 491 case 0: 492 DWARNX("%s: recv retunred 0", __func__); 493 return ECONNRESET; 494 /* NOTREACHED */ 495 break; 496 case -1: 497 if (errno == EAGAIN) 498 return 0; 499 DWARN("%s: recv retunred -1", __func__); 500 return errno; 501 /* NOTREACHED */ 502 break; 503 default: 504 break; 505 } 506 507 #ifdef PERFUSE_DEBUG 508 if (readen != (ssize_t)len) 509 DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd", 510 __func__, readen, len); 511 #endif 512 513 /* 514 * We have a header, get remaing length to read 515 */ 516 if (puffs_framebuf_getdata_atoff(pufbuf, 0, &foh, sizeof(foh)) != 0) 517 DERR(EX_SOFTWARE, "puffs_framebuf_getdata_atoff failed"); 518 519 len = foh.len; 520 521 #ifdef PERFUSE_DEBUG 522 if (len > (size_t)FUSE_BUFSIZE) 523 DERRX(EX_SOFTWARE, "%s: foh.len = %zu", __func__, len); 524 #endif 525 526 /* 527 * This is time to reserve space. 528 */ 529 if (puffs_framebuf_reserve_space(pufbuf, len) == -1) 530 DERR(EX_OSERR, "puffs_framebuf_reserve_space failed"); 531 532 /* 533 * And read the remaining data 534 */ 535 PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 536 537 switch (readen = recv(fd, data, len, MSG_NOSIGNAL)) { 538 case 0: 539 DWARNX("%s: recv retunred 0", __func__); 540 return ECONNRESET; 541 /* NOTREACHED */ 542 break; 543 case -1: 544 if (errno == EAGAIN) 545 return 0; 546 DWARN("%s: recv retunred -1", __func__); 547 return errno; 548 /* NOTREACHED */ 549 break; 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 perfuse_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 DWARNX("%s: send retunred 0", __func__); 579 return ECONNRESET; 580 /* NOTREACHED */ 581 break; 582 case -1: 583 DWARN("%s: send retunred -1, errno = %d", __func__, errno); 584 switch(errno) { 585 case EAGAIN: 586 case ENOBUFS: 587 case EMSGSIZE: 588 return 0; 589 break; 590 default: 591 return errno; 592 break; 593 } 594 /* NOTREACHED */ 595 break; 596 default: 597 break; 598 } 599 600 #ifdef PERFUSE_DEBUG 601 if (written != (ssize_t)len) 602 DERRX(EX_SOFTWARE, "%s: short send %zd/%zd", 603 __func__, written, len); 604 #endif 605 606 *done = 1; 607 return 0; 608 } 609 610 /* ARGSUSED0 */ 611 int 612 perfuse_cmpframe(struct puffs_usermount *pu, struct puffs_framebuf *pb1, 613 struct puffs_framebuf *pb2, int *match) 614 { 615 struct fuse_in_header *fih; 616 struct fuse_out_header *foh; 617 uint64_t unique_in; 618 uint64_t unique_out; 619 size_t len; 620 621 len = sizeof(*fih); 622 PUFFS_FRAMEBUF_GETWINDOW(pb1, 0, (void **)(void *)&fih, &len); 623 unique_in = fih->unique; 624 625 len = sizeof(*foh); 626 PUFFS_FRAMEBUF_GETWINDOW(pb2, 0, (void **)(void *)&foh, &len); 627 unique_out = foh->unique; 628 629 return unique_in != unique_out; 630 } 631 632 /* ARGSUSED0 */ 633 void 634 perfuse_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb) 635 { 636 struct fuse_out_header *foh; 637 size_t len; 638 639 len = sizeof(*foh); 640 PUFFS_FRAMEBUF_GETWINDOW(pb, 0, (void **)(void *)&foh, &len); 641 642 DWARNX("Unexpected frame: unique = %"PRId64", error = %d", 643 foh->unique, foh->error); 644 #ifdef PERFUSE_DEBUG 645 perfuse_hexdump((char *)(void *)foh, foh->len); 646 #endif 647 648 return; 649 } 650 651 void 652 perfuse_fdnotify(struct puffs_usermount *pu, int fd, int what) 653 { 654 if (fd != (int)(long)perfuse_getspecific(pu)) 655 DERRX(EX_SOFTWARE, "%s: unexpected notification for fd = %d", 656 __func__, fd); 657 658 if ((what != PUFFS_FBIO_READ) && (what != PUFFS_FBIO_WRITE)) 659 DERRX(EX_SOFTWARE, "%s: unexpected notification what = 0x%x", 660 __func__, what); 661 662 if (perfuse_unmount(pu) != 0) 663 DWARN("unmount() failed"); 664 665 if (shutdown(fd, SHUT_RDWR) != 0) 666 DWARN("shutdown() failed"); 667 668 if (perfuse_diagflags & PDF_MISC) 669 DPRINTF("Exit"); 670 671 exit(0); 672 } 673 674 void 675 perfuse_umount(struct puffs_usermount *pu) 676 { 677 int fd; 678 679 fd = (int)(long)perfuse_getspecific(pu); 680 681 if (shutdown(fd, SHUT_RDWR) != 0) 682 DWARN("shutdown() failed"); 683 684 if (perfuse_diagflags & PDF_MISC) 685 DPRINTF("unmount"); 686 687 return; 688 } 689