1152179Sgrehan/* $OpenBSD: fuse.c,v 1.51 2019/06/28 13:32:42 deraadt Exp $ */ 2152179Sgrehan/* 3152179Sgrehan * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> 4152179Sgrehan * 5152179Sgrehan * Permission to use, copy, modify, and distribute this software for any 6152179Sgrehan * purpose with or without fee is hereby granted, provided that the above 7152179Sgrehan * copyright notice and this permission notice appear in all copies. 8152179Sgrehan * 9152179Sgrehan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10152179Sgrehan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11152179Sgrehan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12152179Sgrehan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13152179Sgrehan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14152179Sgrehan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15152179Sgrehan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16152179Sgrehan */ 17152179Sgrehan 18152179Sgrehan#include <sys/wait.h> 19152179Sgrehan#include <sys/types.h> 20152179Sgrehan#include <sys/ioctl.h> 21152179Sgrehan 22152179Sgrehan#include <miscfs/fuse/fusefs.h> 23152179Sgrehan 24152179Sgrehan#include <errno.h> 25152179Sgrehan#include <signal.h> 26152179Sgrehan#include <stddef.h> 27152179Sgrehan#include <stdlib.h> 28152179Sgrehan#include <string.h> 29152179Sgrehan#include <unistd.h> 30152179Sgrehan 31152179Sgrehan#include "fuse_opt.h" 32152179Sgrehan#include "fuse_private.h" 33152179Sgrehan#include "debug.h" 34152179Sgrehan 35152179Sgrehanstatic struct fuse_context *ictx = NULL; 36152179Sgrehan 37152179Sgrehanenum { 38152179Sgrehan KEY_DEBUG, 39152179Sgrehan KEY_FOREGROUND, 40152179Sgrehan KEY_HELP, 41152179Sgrehan KEY_HELP_WITHOUT_HEADER, 42152179Sgrehan KEY_VERSION, 43152179Sgrehan KEY_MAXREAD, 44152179Sgrehan KEY_STUB 45152179Sgrehan}; 46152179Sgrehan 47152179Sgrehan/* options supported by fuse_parse_cmdline */ 48152179Sgrehanstatic struct fuse_opt fuse_core_opts[] = { 49152179Sgrehan FUSE_OPT_KEY("-d", KEY_DEBUG), 50152179Sgrehan FUSE_OPT_KEY("debug", KEY_DEBUG), 51152179Sgrehan FUSE_OPT_KEY("-f", KEY_FOREGROUND), 52152179Sgrehan FUSE_OPT_KEY("-h", KEY_HELP), 53152179Sgrehan FUSE_OPT_KEY("--help", KEY_HELP), 54152179Sgrehan FUSE_OPT_KEY("-ho", KEY_HELP_WITHOUT_HEADER), 55152179Sgrehan FUSE_OPT_KEY("-s", KEY_STUB), 56152179Sgrehan FUSE_OPT_KEY("-V", KEY_VERSION), 57152179Sgrehan FUSE_OPT_KEY("--version", KEY_VERSION), 58152179Sgrehan FUSE_OPT_END 59152179Sgrehan}; 60152179Sgrehan 61152179Sgrehan/* options supported by fuse_new */ 62152179Sgrehan#define FUSE_LIB_OPT(o, m) {o, offsetof(struct fuse_config, m), 1} 63152179Sgrehanstatic struct fuse_opt fuse_lib_opts[] = { 64152179Sgrehan FUSE_OPT_KEY("ac_attr_timeout=", KEY_STUB), 65152179Sgrehan FUSE_OPT_KEY("attr_timeout=", KEY_STUB), 66152179Sgrehan FUSE_OPT_KEY("auto_cache", KEY_STUB), 67152179Sgrehan FUSE_OPT_KEY("noauto_cache", KEY_STUB), 68152179Sgrehan FUSE_OPT_KEY("big_writes", KEY_STUB), 69152179Sgrehan FUSE_OPT_KEY("debug", KEY_DEBUG), 70152179Sgrehan FUSE_OPT_KEY("-d", KEY_DEBUG), 71152179Sgrehan FUSE_OPT_KEY("entry_timeout=", KEY_STUB), 72152179Sgrehan FUSE_LIB_OPT("gid=", set_gid), 73152179Sgrehan FUSE_LIB_OPT("gid=%u", gid), 74152179Sgrehan FUSE_OPT_KEY("hard_remove", KEY_STUB), 75152179Sgrehan FUSE_OPT_KEY("intr_signal", KEY_STUB), 76152179Sgrehan FUSE_OPT_KEY("kernel_cache", KEY_STUB), 77152179Sgrehan FUSE_OPT_KEY("large_read", KEY_STUB), 78152179Sgrehan FUSE_OPT_KEY("modules=", KEY_STUB), 79152179Sgrehan FUSE_OPT_KEY("negative_timeout=", KEY_STUB), 80152179Sgrehan FUSE_OPT_KEY("readdir_ino", KEY_STUB), 81152179Sgrehan FUSE_OPT_KEY("relatime", KEY_STUB), 82152179Sgrehan FUSE_OPT_KEY("subtype=", KEY_STUB), 83152179Sgrehan FUSE_LIB_OPT("uid=", set_uid), 84152179Sgrehan FUSE_LIB_OPT("uid=%u", uid), 85152179Sgrehan FUSE_LIB_OPT("use_ino", use_ino), 86152179Sgrehan FUSE_OPT_KEY("dmask=%o", KEY_STUB), 87152179Sgrehan FUSE_OPT_KEY("fmask=%o", KEY_STUB), 88157443Speter FUSE_LIB_OPT("umask=", set_mode), 89152179Sgrehan FUSE_LIB_OPT("umask=%o", umask), 90152179Sgrehan FUSE_OPT_END 91152179Sgrehan}; 92152179Sgrehan 93208504Salc/* options supported by fuse_mount */ 94208504Salc#define FUSE_MOUNT_OPT(o, m) {o, offsetof(struct fuse_mount_opts, m), 1} 95152179Sgrehanstatic struct fuse_opt fuse_mount_opts[] = { 96152179Sgrehan FUSE_MOUNT_OPT("allow_other", allow_other), 97152179Sgrehan FUSE_OPT_KEY("allow_root", KEY_STUB), 98152179Sgrehan FUSE_OPT_KEY("async_read", KEY_STUB), 99152179Sgrehan FUSE_OPT_KEY("blkdev", KEY_STUB), 100152179Sgrehan FUSE_OPT_KEY("blksize=", KEY_STUB), 101152179Sgrehan FUSE_MOUNT_OPT("default_permissions", def_perms), 102152179Sgrehan FUSE_OPT_KEY("direct_io", KEY_STUB), 103152179Sgrehan FUSE_MOUNT_OPT("fsname=%s", fsname), 104179081Salc FUSE_MOUNT_OPT("max_read=%u", max_read), 105179081Salc FUSE_OPT_KEY("max_readahead", KEY_STUB), 106152179Sgrehan FUSE_OPT_KEY("max_write", KEY_STUB), 107179081Salc FUSE_MOUNT_OPT("noatime", noatime), 108152179Sgrehan FUSE_MOUNT_OPT("nonempty", nonempty), 109190684Smarcel FUSE_MOUNT_OPT("-r", rdonly), 110190684Smarcel FUSE_MOUNT_OPT("ro", rdonly), 111190684Smarcel FUSE_OPT_KEY("ro_fallback", KEY_STUB), 112190684Smarcel FUSE_OPT_KEY("sync_read", KEY_STUB), 113190684Smarcel FUSE_OPT_END 114213307Snwhitehorn}; 115213307Snwhitehorn 116213307Snwhitehornstatic void 117213307Snwhitehornifuse_try_unmount(struct fuse *f) 118213307Snwhitehorn{ 119213307Snwhitehorn pid_t child; 120213307Snwhitehorn 121213307Snwhitehorn /* unmount in another thread so fuse_loop() doesn't deadlock */ 122213307Snwhitehorn child = fork(); 123213307Snwhitehorn 124213307Snwhitehorn if (child == -1) { 125213307Snwhitehorn DPERROR(__func__); 126213307Snwhitehorn return; 127213307Snwhitehorn } 128213307Snwhitehorn 129213307Snwhitehorn if (child == 0) { 130213307Snwhitehorn fuse_remove_signal_handlers(fuse_get_session(f)); 131213307Snwhitehorn errno = 0; 132152179Sgrehan fuse_unmount(f->fc->dir, f->fc); 133152179Sgrehan _exit(errno); 134152179Sgrehan } 135152179Sgrehan} 136255028Salc 137255028Salcstatic void 138255028Salcifuse_child_exit(const struct fuse *f) 139255028Salc{ 140255028Salc int status; 141255028Salc 142255028Salc if (waitpid(WAIT_ANY, &status, WNOHANG) == -1) 143255028Salc fprintf(stderr, "fuse: %s\n", strerror(errno)); 144255028Salc 145255028Salc if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) 146255028Salc fprintf(stderr, "fuse: %s: %s\n", 147255028Salc f->fc->dir, strerror(WEXITSTATUS(status))); 148255028Salc 149255028Salc return; 150255028Salc} 151255028Salc 152255028Salcint 153255028Salcfuse_loop(struct fuse *fuse) 154255028Salc{ 155152179Sgrehan struct fusebuf fbuf; 156152179Sgrehan struct fuse_context ctx; 157152179Sgrehan struct fb_ioctl_xch ioexch; 158152179Sgrehan struct kevent event[5]; 159152179Sgrehan struct kevent ev; 160152179Sgrehan ssize_t n; 161152179Sgrehan int ret; 162152179Sgrehan 163152179Sgrehan if (fuse == NULL) 164152179Sgrehan return (-1); 165152179Sgrehan 166160889Salc fuse->fc->kq = kqueue(); 167160889Salc if (fuse->fc->kq == -1) 168160889Salc return (-1); 169160889Salc 170160889Salc EV_SET(&event[0], fuse->fc->fd, EVFILT_READ, EV_ADD | 171160889Salc EV_ENABLE, 0, 0, 0); 172160889Salc 173160889Salc /* signal events */ 174160889Salc EV_SET(&event[1], SIGCHLD, EVFILT_SIGNAL, EV_ADD | 175160889Salc EV_ENABLE, 0, 0, 0); 176160889Salc EV_SET(&event[2], SIGHUP, EVFILT_SIGNAL, EV_ADD | 177160889Salc EV_ENABLE, 0, 0, 0); 178152179Sgrehan EV_SET(&event[3], SIGINT, EVFILT_SIGNAL, EV_ADD | 179152179Sgrehan EV_ENABLE, 0, 0, 0); 180152179Sgrehan EV_SET(&event[4], SIGTERM, EVFILT_SIGNAL, EV_ADD | 181152179Sgrehan EV_ENABLE, 0, 0, 0); 182152179Sgrehan 183152179Sgrehan while (!fuse->fc->dead) { 184152179Sgrehan ret = kevent(fuse->fc->kq, &event[0], 5, &ev, 1, NULL); 185152179Sgrehan if (ret == -1) { 186152179Sgrehan if (errno != EINTR) 187152179Sgrehan DPERROR(__func__); 188152179Sgrehan } else if (ret > 0 && ev.filter == EVFILT_SIGNAL) { 189152179Sgrehan int signum = ev.ident; 190152179Sgrehan switch (signum) { 191152179Sgrehan case SIGCHLD: 192152179Sgrehan ifuse_child_exit(fuse); 193152179Sgrehan break; 194152179Sgrehan case SIGHUP: 195152179Sgrehan case SIGINT: 196152179Sgrehan case SIGTERM: 197152179Sgrehan ifuse_try_unmount(fuse); 198152179Sgrehan break; 199152179Sgrehan default: 200152179Sgrehan fprintf(stderr, "%s: %s\n", __func__, 201152179Sgrehan strsignal(signum)); 202152179Sgrehan } 203152179Sgrehan } else if (ret > 0) { 204152179Sgrehan n = read(fuse->fc->fd, &fbuf, sizeof(fbuf)); 205152179Sgrehan if (n != sizeof(fbuf)) { 206152179Sgrehan fprintf(stderr, "%s: bad fusebuf read\n", 207152179Sgrehan __func__); 208152179Sgrehan return (-1); 209152179Sgrehan } 210248280Skib 211248280Skib /* check if there is data something present */ 212248280Skib if (fbuf.fb_len) { 213248280Skib fbuf.fb_dat = malloc(fbuf.fb_len); 214248280Skib if (fbuf.fb_dat == NULL) 215248280Skib return (-1); 216248280Skib ioexch.fbxch_uuid = fbuf.fb_uuid; 217248280Skib ioexch.fbxch_len = fbuf.fb_len; 218152179Sgrehan ioexch.fbxch_data = fbuf.fb_dat; 219152179Sgrehan 220152179Sgrehan if (ioctl(fuse->fc->fd, FIOCGETFBDAT, 221152179Sgrehan &ioexch) == -1) { 222152179Sgrehan free(fbuf.fb_dat); 223152179Sgrehan return (-1); 224152179Sgrehan } 225152179Sgrehan } 226152179Sgrehan 227270439Skib ctx.fuse = fuse; 228270439Skib ctx.uid = fbuf.fb_uid; 229152179Sgrehan ctx.gid = fbuf.fb_gid; 230270439Skib ctx.pid = fbuf.fb_tid; 231152179Sgrehan ctx.umask = fbuf.fb_umask; 232152179Sgrehan ctx.private_data = fuse->private_data; 233152179Sgrehan ictx = &ctx; 234152179Sgrehan 235152179Sgrehan ret = ifuse_exec_opcode(fuse, &fbuf); 236270439Skib if (ret) { 237270439Skib ictx = NULL; 238152179Sgrehan return (-1); 239152179Sgrehan } 240152179Sgrehan 241152179Sgrehan n = write(fuse->fc->fd, &fbuf, sizeof(fbuf)); 242159303Salc if (fbuf.fb_len) { 243159303Salc if (fbuf.fb_dat == NULL) { 244159303Salc fprintf(stderr, "%s: fb_dat is Null\n", 245159303Salc __func__); 246159303Salc return (-1); 247159303Salc } 248159303Salc ioexch.fbxch_uuid = fbuf.fb_uuid; 249159303Salc ioexch.fbxch_len = fbuf.fb_len; 250159303Salc ioexch.fbxch_data = fbuf.fb_dat; 251159303Salc 252159303Salc if (ioctl(fuse->fc->fd, FIOCSETFBDAT, &ioexch) == -1) { 253159303Salc free(fbuf.fb_dat); 254159303Salc return (-1); 255159303Salc } 256159303Salc free(fbuf.fb_dat); 257159303Salc } 258159303Salc ictx = NULL; 259159303Salc 260159303Salc if (n != FUSEBUFSIZE) { 261152179Sgrehan errno = EINVAL; 262152179Sgrehan return (-1); 263152179Sgrehan } 264152179Sgrehan } 265152179Sgrehan } 266152179Sgrehan 267152179Sgrehan return (0); 268152179Sgrehan} 269159627SupsDEF(fuse_loop); 270152179Sgrehan 271152179Sgrehanstruct fuse_chan * 272152179Sgrehanfuse_mount(const char *dir, struct fuse_args *args) 273152179Sgrehan{ 274152179Sgrehan struct fusefs_args fargs; 275152179Sgrehan struct fuse_mount_opts opts; 276152179Sgrehan struct fuse_chan *fc; 277152179Sgrehan const char *errcause; 278152179Sgrehan int mnt_flags; 279152179Sgrehan 280152179Sgrehan if (dir == NULL) 281152179Sgrehan return (NULL); 282152179Sgrehan 283152179Sgrehan fc = calloc(1, sizeof(*fc)); 284152179Sgrehan if (fc == NULL) 285152179Sgrehan return (NULL); 286152179Sgrehan 287152179Sgrehan fc->dir = realpath(dir, NULL); 288152179Sgrehan if (fc->dir == NULL) 289152179Sgrehan goto bad; 290152179Sgrehan 291152179Sgrehan if ((fc->fd = open("/dev/fuse0", O_RDWR)) == -1) { 292152179Sgrehan perror(__func__); 293152179Sgrehan goto bad; 294152179Sgrehan } 295152179Sgrehan 296152179Sgrehan memset(&opts, 0, sizeof(opts)); 297152179Sgrehan if (fuse_opt_parse(args, &opts, fuse_mount_opts, NULL) == -1) 298152179Sgrehan goto bad; 299152179Sgrehan 300152179Sgrehan mnt_flags = 0; 301152179Sgrehan if (opts.rdonly) 302152179Sgrehan mnt_flags |= MNT_RDONLY; 303152179Sgrehan if (opts.noatime) 304152179Sgrehan mnt_flags |= MNT_NOATIME; 305152179Sgrehan 306152179Sgrehan if (opts.max_read > FUSEBUFMAXSIZE) { 307152179Sgrehan fprintf(stderr, "fuse: invalid max_read (%d > %d)\n", 308152179Sgrehan opts.max_read, FUSEBUFMAXSIZE); 309152179Sgrehan goto bad; 310152179Sgrehan } 311152179Sgrehan 312152179Sgrehan memset(&fargs, 0, sizeof(fargs)); 313152179Sgrehan fargs.fd = fc->fd; 314152179Sgrehan fargs.max_read = opts.max_read; 315152179Sgrehan fargs.allow_other = opts.allow_other; 316152179Sgrehan 317152179Sgrehan if (mount(MOUNT_FUSEFS, fc->dir, mnt_flags, &fargs)) { 318152179Sgrehan switch (errno) { 319152179Sgrehan case EMFILE: 320152179Sgrehan errcause = "mount table full"; 321152179Sgrehan break; 322152179Sgrehan case EOPNOTSUPP: 323152179Sgrehan errcause = "filesystem not supported by kernel"; 324152179Sgrehan break; 325152179Sgrehan default: 326152179Sgrehan errcause = strerror(errno); 327152179Sgrehan break; 328152179Sgrehan } 329152179Sgrehan fprintf(stderr, "%s on %s: %s\n", __func__, dir, errcause); 330152179Sgrehan goto bad; 331152179Sgrehan } 332152179Sgrehan 333152179Sgrehan return (fc); 334152179Sgrehanbad: 335152179Sgrehan if (fc->fd != -1) 336152179Sgrehan close(fc->fd); 337152179Sgrehan free(fc->dir); 338152179Sgrehan free(fc); 339152179Sgrehan return (NULL); 340152179Sgrehan} 341152179SgrehanDEF(fuse_mount); 342152179Sgrehan 343152179Sgrehanvoid 344152179Sgrehanfuse_unmount(const char *dir, struct fuse_chan *ch) 345152179Sgrehan{ 346152179Sgrehan if (ch == NULL || ch->dead) 347152179Sgrehan return; 348152179Sgrehan 349152179Sgrehan if (unmount(dir, MNT_UPDATE) == -1) 350152179Sgrehan DPERROR(__func__); 351152179Sgrehan} 352152179SgrehanDEF(fuse_unmount); 353152179Sgrehan 354152179Sgrehanint 355152179Sgrehanfuse_is_lib_option(const char *opt) 356152179Sgrehan{ 357152179Sgrehan return (fuse_opt_match(fuse_lib_opts, opt)); 358152179Sgrehan} 359152179Sgrehan 360152179Sgrehanint 361152179Sgrehanfuse_chan_fd(struct fuse_chan *ch) 362152179Sgrehan{ 363152179Sgrehan if (ch == NULL) 364152179Sgrehan return (-1); 365152179Sgrehan 366152179Sgrehan return (ch->fd); 367152179Sgrehan} 368152179Sgrehan 369152179Sgrehanstruct fuse_session * 370207155Salcfuse_get_session(struct fuse *f) 371207155Salc{ 372207155Salc return (&f->se); 373207155Salc} 374207155SalcDEF(fuse_get_session); 375207155Salc 376207155Salcint 377207155Salcfuse_loop_mt(unused struct fuse *fuse) 378207155Salc{ 379207155Salc return (-1); 380207155Salc} 381207155Salc 382207155Salcstatic int 383207155Salcifuse_lib_opt_proc(void *data, const char *arg, int key, 384152179Sgrehan unused struct fuse_args *args) 385152179Sgrehan{ 386152179Sgrehan switch (key) { 387152179Sgrehan case KEY_STUB: 388152179Sgrehan return (0); 389152179Sgrehan case KEY_DEBUG: 390152179Sgrehan ifuse_debug_init(); 391152179Sgrehan break; 392238357Salc default: 393152179Sgrehan fprintf(stderr, "fuse: unrecognised option %s\n", arg); 394152179Sgrehan return (-1); 395152179Sgrehan } 396152179Sgrehan 397152179Sgrehan /* Keep unknown options. */ 398152179Sgrehan return (1); 399152179Sgrehan} 400152179Sgrehan 401152179Sgrehanstruct fuse * 402152179Sgrehanfuse_new(struct fuse_chan *fc, struct fuse_args *args, 403152179Sgrehan const struct fuse_operations *ops, unused size_t size, 404152179Sgrehan void *userdata) 405152179Sgrehan{ 406152179Sgrehan struct fuse *fuse; 407152179Sgrehan struct fuse_vnode *root; 408152179Sgrehan 409152179Sgrehan if (fc == NULL || ops == NULL) 410152179Sgrehan return (NULL); 411152179Sgrehan 412152179Sgrehan if ((fuse = calloc(1, sizeof(*fuse))) == NULL) 413152179Sgrehan return (NULL); 414152179Sgrehan 415152179Sgrehan /* copy fuse ops to their own structure */ 416152179Sgrehan memcpy(&fuse->op, ops, sizeof(fuse->op)); 417152179Sgrehan 418152179Sgrehan if (fuse_opt_parse(args, &fuse->conf, fuse_lib_opts, 419152179Sgrehan ifuse_lib_opt_proc) == -1) { 420152179Sgrehan free(fuse); 421152179Sgrehan return (NULL); 422152179Sgrehan } 423152179Sgrehan 424152179Sgrehan fuse->fc = fc; 425152179Sgrehan fuse->max_ino = FUSE_ROOT_INO; 426152179Sgrehan fuse->se.args = fuse; 427152179Sgrehan fuse->private_data = userdata; 428152179Sgrehan 429152179Sgrehan if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) { 430152179Sgrehan free(fuse); 431152179Sgrehan return (NULL); 432152179Sgrehan } 433152179Sgrehan 434152179Sgrehan tree_init(&fuse->vnode_tree); 435152179Sgrehan tree_init(&fuse->name_tree); 436152179Sgrehan if (!set_vn(fuse, root)) { 437152179Sgrehan free(fuse); 438152179Sgrehan return (NULL); 439152179Sgrehan } 440152179Sgrehan 441152179Sgrehan return (fuse); 442152179Sgrehan} 443152179SgrehanDEF(fuse_new); 444152179Sgrehan 445152179Sgrehanint 446152179Sgrehanfuse_daemonize(int foreground) 447152179Sgrehan{ 448152179Sgrehan if (foreground) 449152179Sgrehan return (0); 450152179Sgrehan 451152179Sgrehan return (daemon(0, 0)); 452152179Sgrehan} 453152179SgrehanDEF(fuse_daemonize); 454152179Sgrehan 455152179Sgrehanvoid 456152179Sgrehanfuse_destroy(struct fuse *f) 457152179Sgrehan{ 458152179Sgrehan if (f == NULL) 459152179Sgrehan return; 460152179Sgrehan 461152179Sgrehan /* 462152179Sgrehan * Even though these were allocated in fuse_mount(), we can't free them 463152179Sgrehan * in fuse_unmount() since fuse_loop() will not have terminated yet so 464152179Sgrehan * we free them here. 465152179Sgrehan */ 466152179Sgrehan close(f->fc->fd); 467152179Sgrehan free(f->fc->dir); 468152179Sgrehan free(f->fc); 469152179Sgrehan free(f); 470152179Sgrehan} 471152179SgrehanDEF(fuse_destroy); 472152179Sgrehan 473152179Sgrehanvoid 474173708Salcfuse_remove_signal_handlers(unused struct fuse_session *se) 475173708Salc{ 476173708Salc struct sigaction old_sa; 477173708Salc 478173708Salc if (sigaction(SIGHUP, NULL, &old_sa) == 0) 479173708Salc if (old_sa.sa_handler == SIG_IGN) 480173708Salc signal(SIGHUP, SIG_DFL); 481173708Salc 482173708Salc if (sigaction(SIGINT, NULL, &old_sa) == 0) 483173708Salc if (old_sa.sa_handler == SIG_IGN) 484173708Salc signal(SIGINT, SIG_DFL); 485173708Salc 486173708Salc if (sigaction(SIGTERM, NULL, &old_sa) == 0) 487173708Salc if (old_sa.sa_handler == SIG_IGN) 488173708Salc signal(SIGTERM, SIG_DFL); 489152179Sgrehan 490152179Sgrehan if (sigaction(SIGPIPE, NULL, &old_sa) == 0) 491152179Sgrehan if (old_sa.sa_handler == SIG_IGN) 492152179Sgrehan signal(SIGPIPE, SIG_DFL); 493152179Sgrehan 494152179Sgrehan if (sigaction(SIGCHLD, NULL, &old_sa) == 0) 495152179Sgrehan if (old_sa.sa_handler == SIG_IGN) 496152179Sgrehan signal(SIGCHLD, SIG_DFL); 497152179Sgrehan} 498152179SgrehanDEF(fuse_remove_signal_handlers); 499152179Sgrehan 500152179Sgrehanint 501152179Sgrehanfuse_set_signal_handlers(unused struct fuse_session *se) 502152179Sgrehan{ 503152179Sgrehan struct sigaction old_sa; 504152179Sgrehan 505152179Sgrehan if (sigaction(SIGHUP, NULL, &old_sa) == -1) 506152179Sgrehan return (-1); 507152179Sgrehan if (old_sa.sa_handler == SIG_DFL) 508152179Sgrehan signal(SIGHUP, SIG_IGN); 509152179Sgrehan 510152179Sgrehan if (sigaction(SIGINT, NULL, &old_sa) == -1) 511152179Sgrehan return (-1); 512152179Sgrehan if (old_sa.sa_handler == SIG_DFL) 513152179Sgrehan signal(SIGINT, SIG_IGN); 514152179Sgrehan 515152179Sgrehan if (sigaction(SIGTERM, NULL, &old_sa) == -1) 516152179Sgrehan return (-1); 517152179Sgrehan if (old_sa.sa_handler == SIG_DFL) 518152179Sgrehan signal(SIGTERM, SIG_IGN); 519152179Sgrehan 520152179Sgrehan if (sigaction(SIGPIPE, NULL, &old_sa) == -1) 521152179Sgrehan return (-1); 522152179Sgrehan if (old_sa.sa_handler == SIG_DFL) 523152179Sgrehan signal(SIGPIPE, SIG_IGN); 524152179Sgrehan 525152179Sgrehan if (sigaction(SIGCHLD, NULL, &old_sa) == -1) 526152179Sgrehan return (-1); 527152179Sgrehan if (old_sa.sa_handler == SIG_DFL) 528152179Sgrehan signal(SIGCHLD, SIG_IGN); 529152179Sgrehan 530152179Sgrehan return (0); 531152179Sgrehan} 532152179Sgrehan 533152179Sgrehanstatic void 534152179Sgrehandump_help(void) 535152179Sgrehan{ 536152179Sgrehan fprintf(stderr, "FUSE options:\n" 537152179Sgrehan " -d -o debug enable debug output (implies -f)\n" 538152179Sgrehan " -f run in foreground\n" 539152179Sgrehan " -V --version print fuse version\n" 540152179Sgrehan "\n"); 541152179Sgrehan} 542152179Sgrehan 543152179Sgrehanstatic void 544152179Sgrehandump_version(void) 545152179Sgrehan{ 546152179Sgrehan fprintf(stderr, "FUSE library version: %d.%d\n", FUSE_MAJOR_VERSION, 547152179Sgrehan FUSE_MINOR_VERSION); 548152179Sgrehan} 549152179Sgrehan 550152179Sgrehanstatic int 551152179Sgrehanifuse_process_opt(void *data, const char *arg, int key, 552152179Sgrehan unused struct fuse_args *args) 553152179Sgrehan{ 554152179Sgrehan struct fuse_core_opts *opt = data; 555152179Sgrehan struct stat st; 556152179Sgrehan int res; 557152179Sgrehan 558152179Sgrehan switch (key) { 559152179Sgrehan case KEY_STUB: 560152179Sgrehan return (0); 561152179Sgrehan case KEY_DEBUG: 562152179Sgrehan ifuse_debug_init(); 563152179Sgrehan /* falls through */ 564152179Sgrehan case KEY_FOREGROUND: 565152179Sgrehan opt->foreground = 1; 566152179Sgrehan return (0); 567152179Sgrehan case KEY_HELP: 568152179Sgrehan case KEY_HELP_WITHOUT_HEADER: 569152179Sgrehan dump_help(); 570152179Sgrehan return (-1); 571152179Sgrehan case KEY_VERSION: 572152179Sgrehan dump_version(); 573152179Sgrehan return (-1); 574152179Sgrehan case FUSE_OPT_KEY_NONOPT: 575152179Sgrehan if (opt->mp == NULL) { 576152179Sgrehan opt->mp = realpath(arg, opt->mp); 577152179Sgrehan if (opt->mp == NULL) { 578152179Sgrehan fprintf(stderr, "fuse: realpath: " 579152179Sgrehan "%s : %s\n", arg, strerror(errno)); 580152179Sgrehan return (-1); 581152179Sgrehan } 582152179Sgrehan 583152179Sgrehan res = stat(opt->mp, &st); 584152179Sgrehan if (res == -1) { 585152179Sgrehan fprintf(stderr, "fuse: bad mount point " 586152179Sgrehan "%s : %s\n", arg, strerror(errno)); 587152179Sgrehan return (-1); 588152179Sgrehan } 589225418Skib 590152179Sgrehan if (!S_ISDIR(st.st_mode)) { 591152179Sgrehan fprintf(stderr, "fuse: bad mount point " 592152179Sgrehan "%s : %s\n", arg, strerror(ENOTDIR)); 593152179Sgrehan return (-1); 594152179Sgrehan } 595152179Sgrehan } 596152179Sgrehan return (0); 597152179Sgrehan } 598152179Sgrehan 599152179Sgrehan /* Pass through unknown options. */ 600152179Sgrehan return (1); 601152179Sgrehan} 602152179Sgrehan 603152179Sgrehanint 604152179Sgrehanfuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, int *fg) 605152179Sgrehan{ 606152179Sgrehan struct fuse_core_opts opt; 607152179Sgrehan 608152179Sgrehan memset(&opt, 0, sizeof(opt)); 609152179Sgrehan if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1) 610152179Sgrehan return (-1); 611152179Sgrehan 612152179Sgrehan if (opt.mp == NULL) { 613152179Sgrehan fprintf(stderr, "fuse: missing mountpoint parameter\n"); 614152179Sgrehan return (-1); 615152179Sgrehan } 616152179Sgrehan 617270920Skib if (mp != NULL) { 618270920Skib *mp = strdup(opt.mp); 619270920Skib if (*mp == NULL) 620270920Skib return (-1); 621270920Skib } 622270920Skib 623270920Skib if (mt != NULL) 624270920Skib *mt = 0; 625270920Skib 626270920Skib if (fg != NULL) 627270920Skib *fg = opt.foreground; 628270920Skib 629270920Skib return (0); 630270920Skib} 631270920SkibDEF(fuse_parse_cmdline); 632270920Skib 633152179Sgrehanstruct fuse_context * 634152179Sgrehanfuse_get_context(void) 635152179Sgrehan{ 636152179Sgrehan return (ictx); 637152179Sgrehan} 638152179SgrehanDEF(fuse_get_context); 639152179Sgrehan 640152179Sgrehanint 641152179Sgrehanfuse_version(void) 642152179Sgrehan{ 643152179Sgrehan return (FUSE_VERSION); 644152179Sgrehan} 645152179Sgrehan 646152179Sgrehanvoid 647152179Sgrehanfuse_teardown(struct fuse *fuse, char *mp) 648152179Sgrehan{ 649152179Sgrehan if (fuse == NULL || mp == NULL) 650152179Sgrehan return; 651152179Sgrehan 652152179Sgrehan fuse_remove_signal_handlers(fuse_get_session(fuse)); 653152179Sgrehan fuse_unmount(mp, fuse->fc); 654152179Sgrehan fuse_destroy(fuse); 655152179Sgrehan} 656152179Sgrehan 657152179Sgrehanint 658152179Sgrehanfuse_invalidate(unused struct fuse *f, unused const char *path) 659152179Sgrehan{ 660152179Sgrehan return (EINVAL); 661152179Sgrehan} 662152179Sgrehan 663152179Sgrehanstruct fuse * 664152179Sgrehanfuse_setup(int argc, char **argv, const struct fuse_operations *ops, 665152179Sgrehan size_t size, char **mp, int *mt, void *data) 666152179Sgrehan{ 667152179Sgrehan struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 668152179Sgrehan struct fuse_chan *fc; 669152179Sgrehan struct fuse *fuse; 670152179Sgrehan char *dir; 671152179Sgrehan int fg; 672152179Sgrehan 673208504Salc dir = NULL; 674152179Sgrehan if (fuse_parse_cmdline(&args, &dir, mt, &fg)) 675152179Sgrehan goto err; 676152179Sgrehan 677208504Salc fuse_daemonize(fg); 678152179Sgrehan 679152179Sgrehan if ((fc = fuse_mount(dir, &args)) == NULL) 680152179Sgrehan goto err; 681152179Sgrehan 682152179Sgrehan if ((fuse = fuse_new(fc, &args, ops, size, data)) == NULL) { 683152179Sgrehan fuse_unmount(dir, fc); 684152179Sgrehan close(fc->fd); 685152179Sgrehan free(fc->dir); 686208504Salc free(fc); 687152179Sgrehan goto err; 688152179Sgrehan } 689152179Sgrehan 690152179Sgrehan /* args are no longer needed */ 691152179Sgrehan fuse_opt_free_args(&args); 692152179Sgrehan 693152179Sgrehan if (fuse_set_signal_handlers(fuse_get_session(fuse)) == -1) { 694152179Sgrehan fuse_unmount(dir, fc); 695152179Sgrehan fuse_destroy(fuse); 696152179Sgrehan goto err; 697152179Sgrehan } 698152179Sgrehan 699152179Sgrehan /* the caller frees dir, but we do it if the caller doesn't want it */ 700152179Sgrehan if (mp == NULL) 701152179Sgrehan free(dir); 702152179Sgrehan else 703152179Sgrehan *mp = dir; 704152179Sgrehan 705152179Sgrehan return (fuse); 706152179Sgrehanerr: 707152179Sgrehan free(dir); 708152179Sgrehan return (NULL); 709152179Sgrehan} 710152179SgrehanDEF(fuse_setup); 711152179Sgrehan 712152179Sgrehanint 713152179Sgrehanfuse_main(int argc, char **argv, const struct fuse_operations *ops, void *data) 714152179Sgrehan{ 715152179Sgrehan struct fuse *fuse; 716152179Sgrehan 717152179Sgrehan fuse = fuse_setup(argc, argv, ops, sizeof(*ops), NULL, NULL, data); 718179081Salc if (fuse == NULL) 719152179Sgrehan return (-1); 720152179Sgrehan 721152179Sgrehan return (fuse_loop(fuse)); 722179081Salc} 723152179Sgrehan