jcs's openbsd hax
openbsd
at jcs 698 lines 15 kB view raw
1/* $OpenBSD: fuse_session.c,v 1.1 2026/01/22 11:53:31 helg Exp $ */ 2/* 3 * Copyright (c) 2025 Helg Bredow <helg@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/uio.h> 19#include <errno.h> 20#include <err.h> 21#include <stdlib.h> 22#include <stdio.h> 23#include <string.h> 24#include <unistd.h> 25 26#include "debug.h" 27#include "fuse_private.h" 28 29void 30fuse_session_destroy(struct fuse_session *se) 31{ 32 if (se->init && se->llops.destroy) 33 se->llops.destroy(se->userdata); 34 35 free(se->chan); 36 free(se); 37} 38DEF(fuse_session_destroy); 39 40void 41fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) 42{ 43 if (se->chan == NULL && ch->se == NULL) { 44 se->chan = ch; 45 ch->se = se; 46 } 47} 48DEF(fuse_session_add_chan); 49 50void 51fuse_session_remove_chan(struct fuse_chan *ch) 52{ 53 if (ch->se->chan == ch) { 54 ch->se->chan = NULL; 55 ch->se = NULL; 56 } 57} 58DEF(fuse_session_remove_chan); 59 60void 61fuse_session_exit(struct fuse_session *se) 62{ 63 se->exit = 1; 64} 65DEF(fuse_session_exit); 66 67int 68fuse_session_exited(const struct fuse_session *se) 69{ 70 return (se->exit); 71} 72DEF(fuse_session_exited); 73 74void 75fuse_session_reset(struct fuse_session *se) 76{ 77 if (se != NULL) 78 se->exit = 0; 79} 80DEF(fuse_session_reset); 81 82int 83fuse_session_loop(struct fuse_session *se) 84{ 85 struct fuse_chan *ch; 86 struct fusebuf fbuf; 87 char *buf = (char *)&fbuf; 88 size_t bufsize; 89 int err; 90 91 if (se == NULL) 92 return (-1); 93 94 ch = se->chan; 95 if (ch == NULL) 96 return (-1); 97 98 /* prepare the read and write data buffer */ 99 fbuf.fb_dat = calloc(1, FUSEBUFMAXSIZE); 100 if (fbuf.fb_dat == NULL) { 101 DPERROR(__func__); 102 return (-1); 103 } 104 105 bufsize = sizeof(fbuf.fb_hdr) + sizeof(fbuf.FD) + FUSEBUFMAXSIZE; 106 107 while (!fuse_session_exited(se)) { 108 err = fuse_chan_recv(&ch, buf, bufsize); 109 if (err == -EINTR || err == -ENODEV) { 110 fuse_session_exit(se); 111 continue; 112 } else if (err <= 0) { 113 DPERROR(__func__); 114 break; 115 } 116 117 fuse_session_process(se, buf, bufsize, ch); 118 } 119 120 free(fbuf.fb_dat); 121 fuse_session_reset(se); 122 123 return (err == 0 ? 0 : -1); 124} 125DEF(fuse_session_loop); 126 127static void 128iprocess_init(fuse_req_t req) 129{ 130 struct fuse_session *se = req->se; 131 struct fuse_conn_info fci; 132 133 DPRINTF("%-11s", "init"); 134 135 if (se->llops.init) { 136 memset(&fci, 0, sizeof(fci)); 137 fci.proto_minor = FUSE_MINOR_VERSION; 138 fci.proto_major = FUSE_MAJOR_VERSION; 139 140 se->llops.init(se->userdata, &fci); 141 } 142 143 fuse_reply_err(req, 0); 144 145 se->init = 1; 146} 147 148static void 149iprocess_destroy(fuse_req_t req) 150{ 151 struct fuse_session *se = req->se; 152 153 DPRINTF("%-11s", "destroy"); 154 155 se->chan->dead = 1; 156 fuse_session_exit(se); 157 fuse_reply_err(req, 0); 158} 159 160static void 161iprocess_lookup(fuse_req_t req) 162{ 163 struct fusebuf *fbuf = req->fbuf; 164 struct fuse_session *se = req->se; 165 const char *name = fbuf->fb_dat; 166 167 DPRINTF("%-11s", "lookup"); 168 DPRINTF("inode: %llu\t", fbuf->fb_ino); 169 DPRINTF("name: %s\t", name); 170 171 if (se->llops.lookup) 172 se->llops.lookup(req, fbuf->fb_ino, name); 173 else 174 fuse_reply_err(req, ENOSYS); 175} 176 177static void 178iprocess_getattr(fuse_req_t req) 179{ 180 struct fusebuf *fbuf = req->fbuf; 181 struct fuse_session *se = req->se; 182 struct fuse_file_info ffi; 183 184 DPRINTF("%-11s", "getattr"); 185 DPRINTF("inode: %llu\t", fbuf->fb_ino); 186 187 if (se->llops.getattr) { 188 memset(&ffi, 0, sizeof(ffi)); 189 ffi.fh = fbuf->fb_io_fd; 190 ffi.fh_old = ffi.fh; 191 192 se->llops.getattr(req, fbuf->fb_ino, &ffi); 193 } else 194 fuse_reply_err(req, ENOSYS); 195} 196 197static void 198iprocess_setattr(fuse_req_t req) 199{ 200 struct fusebuf *fbuf = req->fbuf; 201 struct fuse_session *se = req->se; 202 struct fuse_file_info ffi; 203 struct stat *stbuf = &fbuf->fb_attr; 204 struct fb_io *io = fbtod(fbuf, struct fb_io *); 205 206 DPRINTF("%-11s", "setattr"); 207 DPRINTF("inode: %llu\t", fbuf->fb_ino); 208 209 if (se->llops.setattr) { 210 memset(&ffi, 0, sizeof(ffi)); 211 ffi.fh = fbuf->fb_io_fd; 212 ffi.fh_old = ffi.fh; 213 214 se->llops.setattr(req, fbuf->fb_ino, stbuf, io->fi_flags, &ffi); 215 } else 216 fuse_reply_err(req, ENOSYS); 217} 218 219static void 220iprocess_opendir(fuse_req_t req) 221{ 222 struct fusebuf *fbuf = req->fbuf; 223 struct fuse_session *se = req->se; 224 struct fuse_file_info ffi; 225 226 DPRINTF("%-11s", "opendir"); 227 DPRINTF("inode: %llu\t", fbuf->fb_ino); 228 229 memset(&ffi, 0, sizeof(ffi)); 230 ffi.flags = fbuf->fb_io_flags; 231 232 if (se->llops.opendir) 233 se->llops.opendir(req, fbuf->fb_ino, &ffi); 234 else 235 fuse_reply_open(req, &ffi); 236} 237 238static void 239iprocess_readdir(fuse_req_t req) 240{ 241 struct fusebuf *fbuf = req->fbuf; 242 struct fuse_session *se = req->se; 243 struct fuse_file_info ffi; 244 245 DPRINTF("%-11s", "readdir"); 246 DPRINTF("inode: %llu\t", fbuf->fb_ino); 247 DPRINTF("size: %lu\t", fbuf->fb_io_len); 248 DPRINTF("offset: %llu\t", fbuf->fb_io_off); 249 250 if (se->llops.readdir) { 251 memset(&ffi, 0, sizeof(ffi)); 252 ffi.fh = fbuf->fb_io_fd; 253 ffi.fh_old = ffi.fh; 254 255 se->llops.readdir(req, fbuf->fb_ino, fbuf->fb_io_len, 256 fbuf->fb_io_off, &ffi); 257 } else 258 fuse_reply_err(req, ENOSYS); 259} 260 261static void 262iprocess_releasedir(fuse_req_t req) 263{ 264 struct fusebuf *fbuf = req->fbuf; 265 struct fuse_session *se = req->se; 266 struct fuse_file_info ffi; 267 268 DPRINTF("%-11s", "releasedir"); 269 DPRINTF("inode: %llu\t", fbuf->fb_ino); 270 271 if (se->llops.releasedir) { 272 memset(&ffi, 0, sizeof(ffi)); 273 ffi.fh = fbuf->fb_io_fd; 274 ffi.fh_old = ffi.fh; 275 ffi.flags = fbuf->fb_io_flags; 276 277 se->llops.releasedir(req, fbuf->fb_ino, &ffi); 278 } else 279 fuse_reply_err(req, 0); 280} 281 282static void 283iprocess_mkdir(fuse_req_t req) 284{ 285 struct fusebuf *fbuf = req->fbuf; 286 struct fuse_session *se = req->se; 287 288 DPRINTF("%-11s", "mkdir"); 289 DPRINTF("inode: %llu\t", fbuf->fb_ino); 290 DPRINTF("mode: %#6o\t", fbuf->fb_io_mode); 291 DPRINTF("name: %s\t", fbuf->fb_dat); 292 293 if (se->llops.mkdir) 294 se->llops.mkdir(req, fbuf->fb_ino, fbuf->fb_dat, 295 fbuf->fb_io_mode); 296 else 297 fuse_reply_err(req, ENOSYS); 298} 299 300static void 301iprocess_rmdir(fuse_req_t req) 302{ 303 struct fusebuf *fbuf = req->fbuf; 304 struct fuse_session *se = req->se; 305 306 DPRINTF("%-11s", "rmdir"); 307 DPRINTF("inode: %llu\t", fbuf->fb_ino); 308 DPRINTF("name: %s\t", fbuf->fb_dat); 309 310 if (se->llops.rmdir) 311 se->llops.rmdir(req, fbuf->fb_ino, fbuf->fb_dat); 312 else 313 fuse_reply_err(req, ENOSYS); 314} 315 316static void 317iprocess_mknod(fuse_req_t req) 318{ 319 struct fusebuf *fbuf = req->fbuf; 320 struct fuse_session *se = req->se; 321 322 DPRINTF("%-11s", "mknod"); 323 DPRINTF("inode: %llu\t", fbuf->fb_ino); 324 DPRINTF("mode: %#6o\t", fbuf->fb_io_mode); 325 DPRINTF("name: %s\t", fbuf->fb_dat); 326 327 if (se->llops.mknod) 328 se->llops.mknod(req, fbuf->fb_ino, fbuf->fb_dat, 329 fbuf->fb_io_mode, fbuf->fb_io_rdev); 330 else 331 fuse_reply_err(req, ENOSYS); 332} 333 334static void 335iprocess_open(fuse_req_t req) 336{ 337 struct fusebuf *fbuf = req->fbuf; 338 struct fuse_session *se = req->se; 339 struct fuse_file_info ffi; 340 341 DPRINTF("%-11s", "open"); 342 DPRINTF("inode: %llu\t", fbuf->fb_ino); 343 344 memset(&ffi, 0, sizeof(ffi)); 345 ffi.flags = fbuf->fb_io_flags; 346 347 if (se->llops.open) 348 se->llops.open(req, fbuf->fb_ino, &ffi); 349 else 350 fuse_reply_open(req, &ffi); 351} 352 353static void 354iprocess_read(fuse_req_t req) 355{ 356 struct fusebuf *fbuf = req->fbuf; 357 struct fuse_session *se = req->se; 358 struct fuse_file_info ffi; 359 360 DPRINTF("%-11s", "read"); 361 DPRINTF("inode: %llu\t", fbuf->fb_ino); 362 DPRINTF("size: %lu\t", fbuf->fb_io_len); 363 DPRINTF("offset: %llu\t", fbuf->fb_io_off); 364 365 if (se->llops.read) { 366 memset(&ffi, 0, sizeof(ffi)); 367 ffi.fh = fbuf->fb_io_fd; 368 ffi.fh_old = ffi.fh; 369 ffi.flags = fbuf->fb_io_flags; 370 371 se->llops.read(req, fbuf->fb_ino, fbuf->fb_io_len, 372 fbuf->fb_io_off, &ffi); 373 } else 374 fuse_reply_err(req, ENOSYS); 375} 376 377static void 378iprocess_write(fuse_req_t req) 379{ 380 struct fusebuf *fbuf = req->fbuf; 381 struct fuse_session *se = req->se; 382 struct fuse_file_info ffi; 383 384 DPRINTF("%-11s", "write"); 385 DPRINTF("inode: %llu\t", fbuf->fb_ino); 386 DPRINTF("size: %lu\t", fbuf->fb_io_len); 387 DPRINTF("offset: %llu\t", fbuf->fb_io_off); 388 389 if (se->llops.write) { 390 memset(&ffi, 0, sizeof(ffi)); 391 ffi.fh = fbuf->fb_io_fd; 392 ffi.fh_old = ffi.fh; 393 ffi.writepage = fbuf->fb_io_flags & 1; // XXX 394 395 se->llops.write(req, fbuf->fb_ino, fbuf->fb_dat, 396 fbuf->fb_io_len, fbuf->fb_io_off, &ffi); 397 } else 398 fuse_reply_err(req, ENOSYS); 399} 400 401static void 402iprocess_fsync(fuse_req_t req) 403{ 404 struct fusebuf *fbuf = req->fbuf; 405 struct fuse_session *se = req->se; 406 struct fuse_file_info ffi; 407 408 DPRINTF("%-11s", "fsync"); 409 DPRINTF("inode: %llu\t", fbuf->fb_ino); 410 411 if (se->llops.fsync) { 412 memset(&ffi, 0, sizeof(ffi)); 413 ffi.fh = fbuf->fb_io_fd; 414 ffi.fh_old = ffi.fh; 415 416 /* 417 * fdatasync(2) is just a wrapper around fsync(2) so datasync 418 * is always false. 419 */ 420 se->llops.fsync(req, fbuf->fb_ino, 0 /* datasync */, &ffi); 421 } else 422 fuse_reply_err(req, ENOSYS); 423} 424 425static void 426iprocess_flush(fuse_req_t req) 427{ 428 struct fusebuf *fbuf = req->fbuf; 429 struct fuse_session *se = req->se; 430 struct fuse_file_info ffi; 431 432 DPRINTF("%-11s", "flush"); 433 DPRINTF("inode: %llu\t", fbuf->fb_ino); 434 435 if (se->llops.flush) { 436 memset(&ffi, 0, sizeof(ffi)); 437 ffi.fh = fbuf->fb_io_fd; 438 ffi.fh_old = ffi.fh; 439 ffi.flush = 1; 440 441 se->llops.flush(req, fbuf->fb_ino, &ffi); 442 } else 443 fuse_reply_err(req, ENOSYS); 444} 445 446static void 447iprocess_release(fuse_req_t req) 448{ 449 struct fusebuf *fbuf = req->fbuf; 450 struct fuse_session *se = req->se; 451 struct fuse_file_info ffi; 452 453 DPRINTF("%-11s", "release"); 454 DPRINTF("inode: %llu\t", fbuf->fb_ino); 455 456 if (se->llops.release) { 457 memset(&ffi, 0, sizeof(ffi)); 458 ffi.fh = fbuf->fb_io_fd; 459 ffi.fh_old = ffi.fh; 460 ffi.flags = fbuf->fb_io_flags; 461 462 se->llops.release(req, fbuf->fb_ino, &ffi); 463 } else 464 fuse_reply_err(req, 0); 465} 466 467static void 468iprocess_forget(fuse_req_t req) 469{ 470 struct fusebuf *fbuf = req->fbuf; 471 struct fuse_session *se = req->se; 472 473 DPRINTF("%-11s", "forget"); 474 DPRINTF("inode: %llu\t", fbuf->fb_ino); 475 476 if (se->llops.forget) 477 se->llops.forget(req, fbuf->fb_ino, 1 /* TODO */); 478 else 479 fuse_reply_err(req, 0); 480} 481 482static void 483iprocess_symlink(fuse_req_t req) 484{ 485 struct fusebuf *fbuf = req->fbuf; 486 struct fuse_session *se = req->se; 487 const char *target; 488 const char *name; 489 int len; 490 491 name = fbuf->fb_dat; 492 len = strnlen(name, fbuf->fb_len); 493 target = &fbuf->fb_dat[len + 1]; 494 495 DPRINTF("%-11s", "symlink"); 496 DPRINTF("inode: %llu\t", fbuf->fb_ino); 497 DPRINTF("name: %s\t", name); 498 DPRINTF("target: %s\t", target); 499 500 if (se->llops.symlink) 501 se->llops.symlink(req, target, fbuf->fb_ino, name); 502 else 503 fuse_reply_err(req, ENOSYS); 504} 505 506static void 507iprocess_readlink(fuse_req_t req) 508{ 509 struct fusebuf *fbuf = req->fbuf; 510 struct fuse_session *se = req->se; 511 512 DPRINTF("%-11s", "readlink"); 513 DPRINTF("inode: %llu\t", fbuf->fb_ino); 514 515 if (se->llops.readlink) 516 se->llops.readlink(req, fbuf->fb_ino); 517 else 518 fuse_reply_err(req, ENOSYS); 519} 520 521static void 522iprocess_link(fuse_req_t req) 523{ 524 struct fusebuf *fbuf = req->fbuf; 525 struct fuse_session *se = req->se; 526 const char *name = fbuf->fb_dat; 527 528 DPRINTF("%-11s", "link"); 529 DPRINTF("inode: %llu\t", fbuf->fb_ino); 530 DPRINTF("inode: %llu\t", fbuf->fb_io_ino); 531 DPRINTF("name: %s\t", name); 532 533 if (se->llops.link) 534 se->llops.link(req, fbuf->fb_io_ino, fbuf->fb_ino, name); 535 else 536 fuse_reply_err(req, ENOSYS); 537} 538 539static void 540iprocess_unlink(fuse_req_t req) 541{ 542 struct fusebuf *fbuf = req->fbuf; 543 struct fuse_session *se = req->se; 544 545 DPRINTF("%-11s", "unlink"); 546 DPRINTF("inode: %llu\t", fbuf->fb_ino); 547 DPRINTF("name: %s\t", fbuf->fb_dat); 548 549 if (se->llops.unlink) 550 se->llops.unlink(req, fbuf->fb_ino, fbuf->fb_dat); 551 else 552 fuse_reply_err(req, ENOSYS); 553} 554 555static void 556iprocess_rename(fuse_req_t req) 557{ 558 struct fusebuf *fbuf = req->fbuf; 559 struct fuse_session *se = req->se; 560 const char *target; 561 const char *name; 562 int len; 563 564 name = fbuf->fb_dat; 565 len = strnlen(name, fbuf->fb_len); 566 target = &fbuf->fb_dat[len + 1]; 567 568 DPRINTF("%-11s", "rename"); 569 DPRINTF("inode: %llu\t", fbuf->fb_ino); 570 DPRINTF("name: %s\t", name); 571 DPRINTF("inode: %llu\t", fbuf->fb_io_ino); 572 DPRINTF("target: %s\t", target); 573 574 if (se->llops.rename) 575 se->llops.rename(req, fbuf->fb_ino, name, fbuf->fb_io_ino, 576 target); 577 else 578 fuse_reply_err(req, ENOSYS); 579} 580 581static void 582iprocess_statfs(fuse_req_t req) 583{ 584 struct fusebuf *fbuf = req->fbuf; 585 struct fuse_session *se = req->se; 586 587 DPRINTF("%-11s", "statfs"); 588 DPRINTF("inode: %llu\t", fbuf->fb_ino); 589 590 if (se->llops.statfs) 591 se->llops.statfs(req, fbuf->fb_ino); 592 else 593 fuse_reply_err(req, ENOSYS); 594} 595 596void 597fuse_session_process(struct fuse_session *se, const char *buf, size_t len, 598 struct fuse_chan *ch) 599{ 600 struct fusebuf *fbuf; 601 struct fuse_req req; 602 603 fbuf = (struct fusebuf *)buf; 604 req.fbuf = fbuf; 605 req.se = se; 606 req.ch = (ch == NULL) ? se->chan : ch; 607 req.ctx.uid = fbuf->fb_uid; 608 req.ctx.gid = fbuf->fb_gid; 609 req.ctx.pid = fbuf->fb_tid; 610 req.ctx.umask = fbuf->fb_umask; 611 612 /* need to at least have the header for the next check */ 613 if (len < sizeof(fbuf->fb_hdr)) 614 return; 615 616 if (len < sizeof(fbuf->fb_hdr) + sizeof(fbuf->FD) + fbuf->fb_len) 617 return; 618 619 switch (fbuf->fb_type) { 620 case FBT_INIT: 621 iprocess_init(&req); 622 break; 623 case FBT_DESTROY: 624 iprocess_destroy(&req); 625 break; 626 case FBT_LOOKUP: 627 iprocess_lookup(&req); 628 break; 629 case FBT_GETATTR: 630 iprocess_getattr(&req); 631 break; 632 case FBT_SETATTR: 633 iprocess_setattr(&req); 634 break; 635 case FBT_OPENDIR: 636 iprocess_opendir(&req); 637 break; 638 case FBT_READDIR: 639 iprocess_readdir(&req); 640 break; 641 case FBT_RELEASEDIR: 642 iprocess_releasedir(&req); 643 break; 644 case FBT_MKDIR: 645 iprocess_mkdir(&req); 646 break; 647 case FBT_RMDIR: 648 iprocess_rmdir(&req); 649 break; 650 case FBT_MKNOD: 651 iprocess_mknod(&req); 652 break; 653 case FBT_OPEN: 654 iprocess_open(&req); 655 break; 656 case FBT_READ: 657 iprocess_read(&req); 658 break; 659 case FBT_WRITE: 660 iprocess_write(&req); 661 break; 662 case FBT_FSYNC: 663 iprocess_fsync(&req); 664 break; 665 case FBT_FLUSH: 666 iprocess_flush(&req); 667 break; 668 case FBT_RELEASE: 669 iprocess_release(&req); 670 break; 671 case FBT_RECLAIM: 672 iprocess_forget(&req); 673 break; 674 case FBT_SYMLINK: 675 iprocess_symlink(&req); 676 break; 677 case FBT_READLINK: 678 iprocess_readlink(&req); 679 break; 680 case FBT_LINK: 681 iprocess_link(&req); 682 break; 683 case FBT_UNLINK: 684 iprocess_unlink(&req); 685 break; 686 case FBT_RENAME: 687 iprocess_rename(&req); 688 break; 689 case FBT_STATFS: 690 iprocess_statfs(&req); 691 break; 692 default: 693 DPRINTF("Opcode: %i not supported\t", fbuf->fb_type); 694 fuse_reply_err(&req, ENOSYS); 695 } 696 DPRINTF("\n"); 697} 698DEF(fuse_session_process);