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