1 1.27 andvar /* $NetBSD: msg.c,v 1.27 2025/01/07 17:39:45 andvar Exp $ */ 2 1.1 manu 3 1.1 manu /*- 4 1.1 manu * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. 5 1.1 manu * 6 1.1 manu * Redistribution and use in source and binary forms, with or without 7 1.1 manu * modification, are permitted provided that the following conditions 8 1.1 manu * are met: 9 1.1 manu * 1. Redistributions of source code must retain the above copyright 10 1.1 manu * notice, this list of conditions and the following disclaimer. 11 1.1 manu * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 manu * notice, this list of conditions and the following disclaimer in the 13 1.1 manu * documentation and/or other materials provided with the distribution. 14 1.1 manu * 15 1.1 manu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 1.1 manu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 1.1 manu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 1.1 manu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 1.1 manu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 1.1 manu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 1.1 manu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 1.1 manu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 1.1 manu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 1.1 manu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 manu * POSSIBILITY OF SUCH DAMAGE. 26 1.1 manu */ 27 1.1 manu 28 1.1 manu #include <stdio.h> 29 1.1 manu #include <stdlib.h> 30 1.1 manu #include <unistd.h> 31 1.1 manu #include <err.h> 32 1.1 manu #include <errno.h> 33 1.1 manu #include <string.h> 34 1.1 manu #include <sysexits.h> 35 1.1 manu #include <syslog.h> 36 1.1 manu #include <paths.h> 37 1.1 manu #include <puffs.h> 38 1.6 manu #include <limits.h> 39 1.6 manu #include <sys/types.h> 40 1.1 manu #include <sys/socket.h> 41 1.1 manu #include <sys/un.h> 42 1.1 manu #include <machine/vmparam.h> 43 1.1 manu 44 1.1 manu #include "perfused.h" 45 1.1 manu 46 1.1 manu static int xchg_pb_inloop(struct puffs_usermount *a, struct puffs_framebuf *, 47 1.1 manu int, enum perfuse_xchg_pb_reply); 48 1.1 manu static int xchg_pb_early(struct puffs_usermount *a, struct puffs_framebuf *, 49 1.1 manu int, enum perfuse_xchg_pb_reply); 50 1.1 manu 51 1.1 manu int 52 1.18 christos perfused_open_sock(void) 53 1.1 manu { 54 1.1 manu int s; 55 1.1 manu struct sockaddr_un sun; 56 1.1 manu const struct sockaddr *sa; 57 1.6 manu uint32_t opt; 58 1.13 manu int sock_type = SOCK_SEQPACKET; 59 1.1 manu 60 1.1 manu (void)unlink(_PATH_FUSE); 61 1.1 manu 62 1.13 manu /* 63 1.13 manu * Try SOCK_SEQPACKET and fallback to SOCK_DGRAM 64 1.13 manu * if unavaible 65 1.13 manu */ 66 1.13 manu if ((s = socket(PF_LOCAL, SOCK_SEQPACKET, 0)) == -1) { 67 1.13 manu warnx("SEQPACKET local sockets unavailable, using less " 68 1.13 manu "reliable DGRAM sockets. Expect file operation hangs."); 69 1.13 manu 70 1.13 manu sock_type = SOCK_DGRAM; 71 1.13 manu if ((s = socket(PF_LOCAL, SOCK_DGRAM, 0)) == -1) 72 1.13 manu err(EX_OSERR, "socket failed"); 73 1.13 manu } 74 1.1 manu 75 1.1 manu sa = (const struct sockaddr *)(void *)&sun; 76 1.1 manu sun.sun_len = sizeof(sun); 77 1.1 manu sun.sun_family = AF_LOCAL; 78 1.1 manu (void)strcpy(sun.sun_path, _PATH_FUSE); 79 1.6 manu 80 1.6 manu /* 81 1.25 maya * Set a buffer length large enough so that a few FUSE packets 82 1.8 manu * will fit. 83 1.6 manu */ 84 1.24 christos opt = perfuse_bufvar_from_env("PERFUSE_BUFSIZE", 16 * FUSE_BUFSIZE); 85 1.6 manu if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) != 0) 86 1.23 manu DWARN("%s: setsockopt SO_SNDBUF = %d failed", __func__, opt); 87 1.6 manu 88 1.6 manu if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) != 0) 89 1.23 manu DWARN("%s: setsockopt SO_RCVBUF = %d failed", __func__, opt); 90 1.6 manu 91 1.6 manu /* 92 1.6 manu * Request peer credentials 93 1.6 manu */ 94 1.6 manu opt = 1; 95 1.26 nia if (setsockopt(s, SOL_LOCAL, LOCAL_CREDS, &opt, sizeof(opt)) != 0) 96 1.6 manu DWARN("%s: setsockopt LOCAL_CREDS failed", __func__); 97 1.1 manu 98 1.1 manu if (bind(s, sa, (socklen_t )sun.sun_len) == -1) 99 1.1 manu err(EX_OSERR, "cannot open \"%s\" socket", _PATH_FUSE); 100 1.1 manu 101 1.13 manu if (sock_type == SOCK_DGRAM) { 102 1.13 manu if (connect(s, sa, (socklen_t )sun.sun_len) == -1) 103 1.13 manu err(EX_OSERR, "cannot open \"%s\" socket", _PATH_FUSE); 104 1.13 manu } 105 1.1 manu 106 1.1 manu return s; 107 1.1 manu } 108 1.1 manu 109 1.1 manu 110 1.1 manu void * 111 1.18 christos perfused_recv_early(int fd, struct sockcred *sockcred, size_t sockcred_len) 112 1.6 manu { 113 1.6 manu struct fuse_out_header foh; 114 1.1 manu size_t len; 115 1.1 manu char *buf; 116 1.6 manu struct msghdr msg; 117 1.6 manu char cmsg_buf[sizeof(struct cmsghdr) + SOCKCREDSIZE(NGROUPS_MAX)]; 118 1.6 manu struct cmsghdr *cmsg = (struct cmsghdr *)(void *)&cmsg_buf; 119 1.6 manu struct sockcred *sc = (struct sockcred *)(void *)(cmsg + 1); 120 1.6 manu struct iovec iov; 121 1.6 manu 122 1.6 manu len = sizeof(foh); 123 1.6 manu 124 1.6 manu /* 125 1.6 manu * We use the complicated recvmsg because we want peer creds. 126 1.6 manu */ 127 1.6 manu iov.iov_base = &foh; 128 1.6 manu iov.iov_len = len; 129 1.6 manu msg.msg_name = NULL; 130 1.6 manu msg.msg_namelen = 0; 131 1.6 manu msg.msg_iov = &iov; 132 1.6 manu msg.msg_iovlen = 1; 133 1.6 manu msg.msg_control = cmsg; 134 1.6 manu msg.msg_controllen = sizeof(cmsg_buf); 135 1.6 manu msg.msg_flags = 0; 136 1.1 manu 137 1.6 manu if (recvmsg(fd, &msg, MSG_NOSIGNAL|MSG_PEEK) != (ssize_t)len) { 138 1.6 manu DWARN("short recv (header)"); 139 1.1 manu return NULL; 140 1.6 manu } 141 1.6 manu 142 1.6 manu if (cmsg->cmsg_type != SCM_CREDS) { 143 1.6 manu DWARNX("No SCM_CREDS"); 144 1.6 manu return NULL; 145 1.6 manu } 146 1.6 manu 147 1.6 manu if (sockcred != NULL) 148 1.6 manu (void)memcpy(sockcred, sc, 149 1.6 manu MIN(cmsg->cmsg_len - sizeof(*cmsg), sockcred_len)); 150 1.6 manu 151 1.1 manu 152 1.6 manu len = foh.len; 153 1.6 manu if ((buf = malloc(len)) == NULL) 154 1.3 manu err(EX_OSERR, "malloc(%zd) failed", len); 155 1.1 manu 156 1.6 manu if (recv(fd, buf, len, MSG_NOSIGNAL) != (ssize_t)len) { 157 1.6 manu DWARN("short recv (frame)"); 158 1.1 manu return NULL; 159 1.1 manu } 160 1.1 manu 161 1.1 manu return buf; 162 1.1 manu } 163 1.1 manu 164 1.1 manu 165 1.1 manu perfuse_msg_t * 166 1.18 christos perfused_new_pb (struct puffs_usermount *pu, puffs_cookie_t opc, int opcode, 167 1.16 joerg size_t payload_len, const struct puffs_cred *cred) 168 1.1 manu { 169 1.1 manu struct puffs_framebuf *pb; 170 1.1 manu struct fuse_in_header *fih; 171 1.1 manu struct puffs_cc *pcc; 172 1.1 manu uint64_t nodeid; 173 1.1 manu void *data; 174 1.1 manu size_t len; 175 1.1 manu 176 1.1 manu if ((pb = puffs_framebuf_make()) == NULL) 177 1.1 manu DERR(EX_OSERR, "puffs_framebuf_make failed"); 178 1.1 manu 179 1.1 manu len = payload_len + sizeof(*fih); 180 1.17 manu if (opc != 0) 181 1.17 manu nodeid = perfuse_get_nodeid(pu, opc); 182 1.17 manu else 183 1.17 manu nodeid = PERFUSE_UNKNOWN_NODEID; 184 1.1 manu 185 1.1 manu if (puffs_framebuf_reserve_space(pb, len) != 0) 186 1.1 manu DERR(EX_OSERR, "puffs_framebuf_reserve_space failed"); 187 1.1 manu 188 1.1 manu if (puffs_framebuf_getwindow(pb, 0, &data, &len) != 0) 189 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 190 1.1 manu if (len != payload_len + sizeof(*fih)) 191 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short len"); 192 1.1 manu 193 1.1 manu (void)memset(data, 0, len); 194 1.1 manu fih = (struct fuse_in_header *)data; 195 1.4 manu fih->len = (uint32_t)len; 196 1.1 manu fih->opcode = opcode; 197 1.1 manu fih->unique = perfuse_next_unique(pu); 198 1.1 manu fih->nodeid = nodeid; 199 1.1 manu fih->pid = 0; 200 1.14 manu 201 1.14 manu /* 202 1.14 manu * NULL creds is taken as FUSE root. This currently happens for: 203 1.14 manu * - mount root cred assumed 204 1.14 manu * - umount root cred assumed 205 1.14 manu * - inactive kernel cred used 206 1.14 manu * - statvfs root cred assumed 207 1.14 manu * - poll checks have been done at open() time 208 1.14 manu * - addvlock checks have been done at open() time 209 1.14 manu */ 210 1.14 manu if ((cred != NULL) && !puffs_cred_isjuggernaut(cred)) { 211 1.14 manu if (puffs_cred_getuid(cred, &fih->uid) != 0) 212 1.14 manu DERRX(EX_SOFTWARE, "puffs_cred_getuid failed"); 213 1.14 manu if (puffs_cred_getgid(cred, &fih->gid) != 0) 214 1.14 manu DERRX(EX_SOFTWARE, "puffs_cred_getgid failed"); 215 1.14 manu } else { 216 1.14 manu fih->uid = (uid_t)0; 217 1.14 manu fih->gid = (gid_t)0; 218 1.1 manu } 219 1.14 manu 220 1.1 manu if ((pcc = puffs_cc_getcc(pu)) != NULL) 221 1.1 manu (void)puffs_cc_getcaller(pcc, (pid_t *)&fih->pid, NULL); 222 1.1 manu 223 1.1 manu return (perfuse_msg_t *)(void *)pb; 224 1.1 manu } 225 1.1 manu 226 1.1 manu /* 227 1.1 manu * framebuf send/receive primitives based on pcc are 228 1.1 manu * not available until puffs mainloop is entered. 229 1.1 manu * This xchg_pb_inloop() variant allow early communication. 230 1.1 manu */ 231 1.1 manu static int 232 1.16 joerg xchg_pb_early(struct puffs_usermount *pu, struct puffs_framebuf *pb, int fd, 233 1.16 joerg enum perfuse_xchg_pb_reply reply) 234 1.1 manu { 235 1.1 manu int done; 236 1.1 manu int error; 237 1.1 manu 238 1.1 manu done = 0; 239 1.1 manu while (done == 0) { 240 1.18 christos if ((error = perfused_writeframe(pu, pb, fd, &done)) != 0) 241 1.1 manu return error; 242 1.1 manu } 243 1.1 manu 244 1.1 manu if (reply == no_reply) { 245 1.1 manu puffs_framebuf_destroy(pb); 246 1.1 manu return 0; 247 1.1 manu } else { 248 1.1 manu puffs_framebuf_recycle(pb); 249 1.1 manu } 250 1.1 manu 251 1.1 manu done = 0; 252 1.1 manu while (done == 0) { 253 1.18 christos if ((error = perfused_readframe(pu, pb, fd, &done)) != 0) 254 1.1 manu return error; 255 1.1 manu } 256 1.1 manu 257 1.1 manu return 0; 258 1.1 manu } 259 1.1 manu 260 1.1 manu static int 261 1.16 joerg xchg_pb_inloop(struct puffs_usermount *pu, struct puffs_framebuf *pb, int fd, 262 1.16 joerg enum perfuse_xchg_pb_reply reply) 263 1.1 manu { 264 1.1 manu struct puffs_cc *pcc; 265 1.1 manu int error; 266 1.1 manu 267 1.1 manu if (reply == no_reply) { 268 1.1 manu error = puffs_framev_enqueue_justsend(pu, fd, pb, 0, 0); 269 1.1 manu } else { 270 1.1 manu pcc = puffs_cc_getcc(pu); 271 1.1 manu error = puffs_framev_enqueue_cc(pcc, fd, pb, 0); 272 1.1 manu } 273 1.1 manu 274 1.1 manu return error; 275 1.1 manu } 276 1.1 manu 277 1.1 manu int 278 1.18 christos perfused_xchg_pb(struct puffs_usermount *pu, perfuse_msg_t *pm, 279 1.16 joerg size_t expected_len, enum perfuse_xchg_pb_reply reply) 280 1.1 manu { 281 1.1 manu struct puffs_framebuf *pb = (struct puffs_framebuf *)(void *)pm; 282 1.1 manu int fd; 283 1.1 manu int error; 284 1.1 manu struct fuse_out_header *foh; 285 1.1 manu #ifdef PERFUSE_DEBUG 286 1.1 manu struct fuse_in_header *fih; 287 1.1 manu uint64_t nodeid; 288 1.1 manu int opcode; 289 1.1 manu uint64_t unique_in; 290 1.1 manu uint64_t unique_out; 291 1.1 manu 292 1.18 christos fih = perfused_get_inhdr(pm); 293 1.1 manu unique_in = fih->unique; 294 1.1 manu nodeid = fih->nodeid; 295 1.1 manu opcode = fih->opcode; 296 1.1 manu 297 1.1 manu if (perfuse_diagflags & PDF_FUSE) 298 1.3 manu DPRINTF("> unique = %"PRId64", nodeid = %"PRId64", " 299 1.3 manu "opcode = %s (%d)\n", 300 1.1 manu unique_in, nodeid, perfuse_opname(opcode), opcode); 301 1.1 manu 302 1.1 manu if (perfuse_diagflags & PDF_DUMP) 303 1.18 christos perfused_hexdump((char *)fih, fih->len); 304 1.1 manu 305 1.1 manu #endif /* PERFUSE_DEBUG */ 306 1.1 manu 307 1.18 christos fd = (int)(intptr_t)perfuse_getspecific(pu); 308 1.1 manu 309 1.1 manu if (perfuse_inloop(pu)) 310 1.1 manu error = xchg_pb_inloop(pu, pb, fd, reply); 311 1.1 manu else 312 1.1 manu error = xchg_pb_early(pu, pb, fd, reply); 313 1.1 manu 314 1.1 manu if (error) 315 1.1 manu DERR(EX_SOFTWARE, "xchg_pb failed"); 316 1.1 manu 317 1.1 manu if (reply == no_reply) 318 1.1 manu return 0; 319 1.1 manu 320 1.18 christos foh = perfused_get_outhdr((perfuse_msg_t *)(void *)pb); 321 1.1 manu #ifdef PERFUSE_DEBUG 322 1.1 manu unique_out = foh->unique; 323 1.1 manu 324 1.1 manu if (perfuse_diagflags & PDF_FUSE) 325 1.3 manu DPRINTF("< unique = %"PRId64", nodeid = %"PRId64", " 326 1.3 manu "opcode = %s (%d), " 327 1.1 manu "error = %d\n", unique_out, nodeid, 328 1.11 manu perfuse_opname(opcode), opcode, foh->error); 329 1.1 manu 330 1.1 manu if (perfuse_diagflags & PDF_DUMP) 331 1.18 christos perfused_hexdump((char *)foh, foh->len); 332 1.1 manu 333 1.1 manu if (unique_in != unique_out) { 334 1.3 manu printf("%s: packet mismatch unique %"PRId64" vs %"PRId64"\n", 335 1.1 manu __func__, unique_in, unique_out); 336 1.1 manu abort(); 337 1.3 manu errx(EX_SOFTWARE, "%s: packet mismatch unique " 338 1.3 manu "%"PRId64" vs %"PRId64"\n", 339 1.1 manu __func__, unique_in, unique_out); 340 1.1 manu } 341 1.1 manu #endif /* PERFUSE_DEBUG */ 342 1.1 manu 343 1.1 manu if ((expected_len != PERFUSE_UNSPEC_REPLY_LEN) && 344 1.1 manu (foh->len - sizeof(*foh) < expected_len) && 345 1.1 manu (foh->error == 0)) { 346 1.1 manu DERRX(EX_PROTOCOL, 347 1.3 manu "Unexpected short reply: received %zd bytes, expected %zd", 348 1.1 manu foh->len - sizeof(*foh), expected_len); 349 1.1 manu } 350 1.1 manu 351 1.1 manu if ((expected_len != 0) && 352 1.1 manu (foh->len - sizeof(*foh) > expected_len)) 353 1.1 manu DWARNX("Unexpected long reply"); 354 1.1 manu 355 1.1 manu /* 356 1.1 manu * Negative Linux errno... 357 1.1 manu */ 358 1.21 manu if (foh->error <= 0) { 359 1.21 manu foh->error = -foh->error; 360 1.21 manu } else { 361 1.21 manu DWARNX("FUSE resturns positive errno %d", foh->error); 362 1.21 manu foh->error = 0; 363 1.21 manu } 364 1.1 manu 365 1.1 manu return foh->error; 366 1.1 manu } 367 1.1 manu 368 1.1 manu 369 1.1 manu struct fuse_in_header * 370 1.18 christos perfused_get_inhdr(perfuse_msg_t *pm) 371 1.1 manu { 372 1.1 manu struct puffs_framebuf *pb; 373 1.1 manu struct fuse_in_header *fih; 374 1.1 manu void *hdr; 375 1.1 manu size_t len; 376 1.1 manu 377 1.1 manu pb = (struct puffs_framebuf *)(void *)pm; 378 1.1 manu len = sizeof(*fih); 379 1.1 manu if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 380 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 381 1.1 manu if (len != sizeof(*fih)) 382 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 383 1.1 manu 384 1.1 manu fih = (struct fuse_in_header *)hdr; 385 1.1 manu 386 1.1 manu return fih; 387 1.1 manu } 388 1.1 manu 389 1.1 manu struct fuse_out_header * 390 1.18 christos perfused_get_outhdr(perfuse_msg_t *pm) 391 1.1 manu { 392 1.1 manu struct puffs_framebuf *pb; 393 1.1 manu struct fuse_out_header *foh; 394 1.1 manu void *hdr; 395 1.1 manu size_t len; 396 1.1 manu 397 1.1 manu pb = (struct puffs_framebuf *)(void *)pm; 398 1.1 manu len = sizeof(*foh); 399 1.1 manu if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 400 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 401 1.1 manu if (len != sizeof(*foh)) 402 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 403 1.1 manu 404 1.1 manu foh = (struct fuse_out_header *)hdr; 405 1.1 manu 406 1.1 manu return foh; 407 1.1 manu } 408 1.1 manu 409 1.1 manu char * 410 1.18 christos perfused_get_inpayload(perfuse_msg_t *pm) 411 1.1 manu { 412 1.1 manu struct puffs_framebuf *pb; 413 1.1 manu struct fuse_in_header *fih; 414 1.1 manu void *hdr; 415 1.1 manu void *payload; 416 1.1 manu size_t len; 417 1.1 manu 418 1.1 manu pb = (struct puffs_framebuf *)(void *)pm; 419 1.1 manu len = sizeof(*fih); 420 1.1 manu if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 421 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 422 1.1 manu if (len != sizeof(*fih)) 423 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 424 1.1 manu 425 1.1 manu fih = (struct fuse_in_header *)hdr; 426 1.1 manu 427 1.1 manu len = fih->len - sizeof(*fih); 428 1.1 manu if (puffs_framebuf_getwindow(pb, sizeof(*fih), &payload, &len) != 0) 429 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 430 1.1 manu if (len != fih->len - sizeof(*fih)) 431 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 432 1.1 manu 433 1.1 manu return (char *)payload; 434 1.1 manu } 435 1.1 manu 436 1.1 manu char * 437 1.18 christos perfused_get_outpayload(perfuse_msg_t *pm) 438 1.1 manu { 439 1.1 manu struct puffs_framebuf *pb; 440 1.1 manu struct fuse_out_header *foh; 441 1.1 manu void *hdr; 442 1.1 manu void *payload; 443 1.1 manu size_t len; 444 1.1 manu 445 1.1 manu pb = (struct puffs_framebuf *)(void *)pm; 446 1.1 manu len = sizeof(*foh); 447 1.1 manu if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0) 448 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 449 1.1 manu if (len != sizeof(*foh)) 450 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 451 1.1 manu 452 1.1 manu foh = (struct fuse_out_header *)hdr; 453 1.1 manu 454 1.1 manu len = foh->len - sizeof(*foh); 455 1.1 manu if (puffs_framebuf_getwindow(pb, sizeof(*foh), &payload, &len) != 0) 456 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed"); 457 1.1 manu if (len != foh->len - sizeof(*foh)) 458 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header"); 459 1.1 manu 460 1.1 manu return (char *)payload; 461 1.1 manu } 462 1.1 manu 463 1.1 manu #define PUFFS_FRAMEBUF_GETWINDOW(pb, offset, data, len) \ 464 1.1 manu do { \ 465 1.1 manu int pfg_error; \ 466 1.1 manu size_t pfg_len = *(len); \ 467 1.1 manu \ 468 1.1 manu pfg_error = puffs_framebuf_getwindow(pb, offset, data, len); \ 469 1.1 manu if (pfg_error != 0) \ 470 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");\ 471 1.1 manu \ 472 1.1 manu if (*(len) != pfg_len) \ 473 1.1 manu DERRX(EX_SOFTWARE, "puffs_framebuf_getwindow size"); \ 474 1.1 manu } while (0 /* CONSTCOND */); 475 1.1 manu 476 1.1 manu /* ARGSUSED0 */ 477 1.1 manu int 478 1.18 christos perfused_readframe(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, 479 1.16 joerg int fd, int *done) 480 1.1 manu { 481 1.1 manu struct fuse_out_header foh; 482 1.9 manu size_t len; 483 1.1 manu ssize_t readen; 484 1.1 manu void *data; 485 1.1 manu 486 1.1 manu /* 487 1.1 manu * Read the header 488 1.1 manu */ 489 1.9 manu len = sizeof(foh); 490 1.9 manu PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 491 1.1 manu 492 1.9 manu switch (readen = recv(fd, data, len, MSG_NOSIGNAL|MSG_PEEK)) { 493 1.9 manu case 0: 494 1.22 manu DPRINTF("Filesystem exit\n"); 495 1.22 manu /* NOTREACHED */ 496 1.22 manu exit(0); 497 1.22 manu break; 498 1.9 manu case -1: 499 1.9 manu if (errno == EAGAIN) 500 1.9 manu return 0; 501 1.19 manu DWARN("%s: recv returned -1", __func__); 502 1.9 manu return errno; 503 1.9 manu /* NOTREACHED */ 504 1.9 manu break; 505 1.9 manu default: 506 1.9 manu break; 507 1.1 manu } 508 1.1 manu 509 1.9 manu #ifdef PERFUSE_DEBUG 510 1.10 manu if (readen != (ssize_t)len) 511 1.9 manu DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd", 512 1.9 manu __func__, readen, len); 513 1.6 manu #endif 514 1.9 manu 515 1.1 manu /* 516 1.27 andvar * We have a header, get remaining length to read 517 1.1 manu */ 518 1.1 manu if (puffs_framebuf_getdata_atoff(pufbuf, 0, &foh, sizeof(foh)) != 0) 519 1.1 manu DERR(EX_SOFTWARE, "puffs_framebuf_getdata_atoff failed"); 520 1.9 manu 521 1.9 manu len = foh.len; 522 1.9 manu 523 1.1 manu #ifdef PERFUSE_DEBUG 524 1.15 manu if (len > (size_t)FUSE_BUFSIZE) 525 1.10 manu DERRX(EX_SOFTWARE, "%s: foh.len = %zu", __func__, len); 526 1.1 manu #endif 527 1.1 manu 528 1.1 manu /* 529 1.9 manu * This is time to reserve space. 530 1.1 manu */ 531 1.9 manu if (puffs_framebuf_reserve_space(pufbuf, len) == -1) 532 1.9 manu DERR(EX_OSERR, "puffs_framebuf_reserve_space failed"); 533 1.1 manu 534 1.1 manu /* 535 1.1 manu * And read the remaining data 536 1.1 manu */ 537 1.9 manu PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 538 1.9 manu 539 1.9 manu switch (readen = recv(fd, data, len, MSG_NOSIGNAL)) { 540 1.9 manu case 0: 541 1.19 manu DWARNX("%s: recv returned 0", __func__); 542 1.19 manu perfused_panic(); 543 1.9 manu case -1: 544 1.9 manu if (errno == EAGAIN) 545 1.9 manu return 0; 546 1.19 manu DWARN("%s: recv returned -1", __func__); 547 1.9 manu return errno; 548 1.9 manu default: 549 1.9 manu break; 550 1.9 manu } 551 1.1 manu 552 1.9 manu #ifdef PERFUSE_DEBUG 553 1.10 manu if (readen != (ssize_t)len) 554 1.9 manu DERRX(EX_SOFTWARE, "%s: short recv %zd/%zd", 555 1.9 manu __func__, readen, len); 556 1.7 manu #endif 557 1.1 manu 558 1.1 manu *done = 1; 559 1.1 manu return 0; 560 1.1 manu } 561 1.1 manu 562 1.1 manu /* ARGSUSED0 */ 563 1.1 manu int 564 1.18 christos perfused_writeframe(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, 565 1.16 joerg int fd, int *done) 566 1.1 manu { 567 1.1 manu size_t len; 568 1.1 manu ssize_t written; 569 1.1 manu void *data; 570 1.1 manu 571 1.9 manu len = puffs_framebuf_tellsize(pufbuf); 572 1.9 manu PUFFS_FRAMEBUF_GETWINDOW(pufbuf, 0, &data, &len); 573 1.1 manu 574 1.9 manu switch (written = send(fd, data, len, MSG_NOSIGNAL)) { 575 1.9 manu case 0: 576 1.19 manu #ifdef PERFUSE_DEBUG 577 1.19 manu DERRX(EX_SOFTWARE, "%s: send returned 0", __func__); 578 1.19 manu #else 579 1.9 manu return ECONNRESET; 580 1.19 manu #endif 581 1.9 manu /* NOTREACHED */ 582 1.9 manu break; 583 1.9 manu case -1: 584 1.19 manu DWARN("%s: send returned -1, errno = %d", __func__, errno); 585 1.10 manu switch(errno) { 586 1.10 manu case EAGAIN: 587 1.10 manu case ENOBUFS: 588 1.13 manu case EMSGSIZE: 589 1.9 manu return 0; 590 1.10 manu break; 591 1.19 manu case EPIPE: 592 1.19 manu perfused_panic(); 593 1.19 manu /* NOTREACHED */ 594 1.19 manu break; 595 1.10 manu default: 596 1.10 manu return errno; 597 1.10 manu break; 598 1.10 manu } 599 1.9 manu /* NOTREACHED */ 600 1.9 manu break; 601 1.9 manu default: 602 1.9 manu break; 603 1.9 manu } 604 1.1 manu 605 1.9 manu #ifdef PERFUSE_DEBUG 606 1.10 manu if (written != (ssize_t)len) 607 1.9 manu DERRX(EX_SOFTWARE, "%s: short send %zd/%zd", 608 1.9 manu __func__, written, len); 609 1.9 manu #endif 610 1.1 manu 611 1.1 manu *done = 1; 612 1.1 manu return 0; 613 1.1 manu } 614 1.1 manu 615 1.1 manu /* ARGSUSED0 */ 616 1.1 manu int 617 1.18 christos perfused_cmpframe(struct puffs_usermount *pu, struct puffs_framebuf *pb1, 618 1.16 joerg struct puffs_framebuf *pb2, int *match) 619 1.1 manu { 620 1.1 manu struct fuse_in_header *fih; 621 1.1 manu struct fuse_out_header *foh; 622 1.1 manu uint64_t unique_in; 623 1.1 manu uint64_t unique_out; 624 1.1 manu size_t len; 625 1.1 manu 626 1.1 manu len = sizeof(*fih); 627 1.12 manu PUFFS_FRAMEBUF_GETWINDOW(pb1, 0, (void **)(void *)&fih, &len); 628 1.1 manu unique_in = fih->unique; 629 1.1 manu 630 1.1 manu len = sizeof(*foh); 631 1.12 manu PUFFS_FRAMEBUF_GETWINDOW(pb2, 0, (void **)(void *)&foh, &len); 632 1.1 manu unique_out = foh->unique; 633 1.1 manu 634 1.1 manu return unique_in != unique_out; 635 1.1 manu } 636 1.1 manu 637 1.1 manu /* ARGSUSED0 */ 638 1.1 manu void 639 1.18 christos perfused_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb) 640 1.1 manu { 641 1.1 manu struct fuse_out_header *foh; 642 1.1 manu size_t len; 643 1.1 manu 644 1.1 manu len = sizeof(*foh); 645 1.12 manu PUFFS_FRAMEBUF_GETWINDOW(pb, 0, (void **)(void *)&foh, &len); 646 1.1 manu 647 1.3 manu DWARNX("Unexpected frame: unique = %"PRId64", error = %d", 648 1.1 manu foh->unique, foh->error); 649 1.1 manu #ifdef PERFUSE_DEBUG 650 1.18 christos perfused_hexdump((char *)(void *)foh, foh->len); 651 1.1 manu #endif 652 1.1 manu 653 1.1 manu return; 654 1.1 manu } 655 1.1 manu 656 1.2 manu void 657 1.18 christos perfused_fdnotify(struct puffs_usermount *pu, int fd, int what) 658 1.2 manu { 659 1.18 christos if (fd != (int)(intptr_t)perfuse_getspecific(pu)) 660 1.2 manu DERRX(EX_SOFTWARE, "%s: unexpected notification for fd = %d", 661 1.2 manu __func__, fd); 662 1.2 manu 663 1.2 manu if ((what != PUFFS_FBIO_READ) && (what != PUFFS_FBIO_WRITE)) 664 1.2 manu DERRX(EX_SOFTWARE, "%s: unexpected notification what = 0x%x", 665 1.2 manu __func__, what); 666 1.2 manu 667 1.2 manu if (perfuse_unmount(pu) != 0) 668 1.2 manu DWARN("unmount() failed"); 669 1.2 manu 670 1.2 manu if (shutdown(fd, SHUT_RDWR) != 0) 671 1.2 manu DWARN("shutdown() failed"); 672 1.2 manu 673 1.2 manu if (perfuse_diagflags & PDF_MISC) 674 1.2 manu DPRINTF("Exit"); 675 1.2 manu 676 1.2 manu exit(0); 677 1.2 manu } 678 1.13 manu 679 1.13 manu void 680 1.18 christos perfused_umount(struct puffs_usermount *pu) 681 1.13 manu { 682 1.13 manu int fd; 683 1.13 manu 684 1.18 christos fd = (int)(intptr_t)perfuse_getspecific(pu); 685 1.13 manu 686 1.13 manu if (shutdown(fd, SHUT_RDWR) != 0) 687 1.13 manu DWARN("shutdown() failed"); 688 1.13 manu 689 1.13 manu if (perfuse_diagflags & PDF_MISC) 690 1.13 manu DPRINTF("unmount"); 691 1.13 manu 692 1.13 manu return; 693 1.13 manu } 694