19821f1d3SAlan Somers /*- 29821f1d3SAlan Somers * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 39821f1d3SAlan Somers * 49821f1d3SAlan Somers * Copyright (c) 2019 The FreeBSD Foundation 59821f1d3SAlan Somers * 69821f1d3SAlan Somers * This software was developed by BFF Storage Systems, LLC under sponsorship 79821f1d3SAlan Somers * from the FreeBSD Foundation. 89821f1d3SAlan Somers * 99821f1d3SAlan Somers * Redistribution and use in source and binary forms, with or without 109821f1d3SAlan Somers * modification, are permitted provided that the following conditions 119821f1d3SAlan Somers * are met: 129821f1d3SAlan Somers * 1. Redistributions of source code must retain the above copyright 139821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer. 149821f1d3SAlan Somers * 2. Redistributions in binary form must reproduce the above copyright 159821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer in the 169821f1d3SAlan Somers * documentation and/or other materials provided with the distribution. 179821f1d3SAlan Somers * 189821f1d3SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 199821f1d3SAlan Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 209821f1d3SAlan Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 219821f1d3SAlan Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 229821f1d3SAlan Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 239821f1d3SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 249821f1d3SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 259821f1d3SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 269821f1d3SAlan Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 279821f1d3SAlan Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 289821f1d3SAlan Somers * SUCH DAMAGE. 291fa8ebfbSAlan Somers * 301fa8ebfbSAlan Somers * $FreeBSD$ 319821f1d3SAlan Somers */ 329821f1d3SAlan Somers 339821f1d3SAlan Somers extern "C" { 349821f1d3SAlan Somers #include <sys/param.h> 359821f1d3SAlan Somers 369821f1d3SAlan Somers #include <sys/mount.h> 373429092cSAlan Somers #include <sys/select.h> 389821f1d3SAlan Somers #include <sys/stat.h> 399821f1d3SAlan Somers #include <sys/uio.h> 409821f1d3SAlan Somers #include <sys/user.h> 419821f1d3SAlan Somers 429821f1d3SAlan Somers #include <fcntl.h> 439821f1d3SAlan Somers #include <libutil.h> 443429092cSAlan Somers #include <poll.h> 459821f1d3SAlan Somers #include <pthread.h> 469821f1d3SAlan Somers #include <signal.h> 479821f1d3SAlan Somers #include <stdlib.h> 489821f1d3SAlan Somers #include <unistd.h> 499821f1d3SAlan Somers 509821f1d3SAlan Somers #include "mntopts.h" // for build_iovec 519821f1d3SAlan Somers } 529821f1d3SAlan Somers 53cc04566cSAlan Somers #include <cinttypes> 54cc04566cSAlan Somers 559821f1d3SAlan Somers #include <gtest/gtest.h> 569821f1d3SAlan Somers 579821f1d3SAlan Somers #include "mockfs.hh" 589821f1d3SAlan Somers 599821f1d3SAlan Somers using namespace testing; 609821f1d3SAlan Somers 619821f1d3SAlan Somers int verbosity = 0; 629821f1d3SAlan Somers 639821f1d3SAlan Somers const char* opcode2opname(uint32_t opcode) 649821f1d3SAlan Somers { 659821f1d3SAlan Somers const int NUM_OPS = 39; 669821f1d3SAlan Somers const char* table[NUM_OPS] = { 679821f1d3SAlan Somers "Unknown (opcode 0)", 689821f1d3SAlan Somers "LOOKUP", 699821f1d3SAlan Somers "FORGET", 709821f1d3SAlan Somers "GETATTR", 719821f1d3SAlan Somers "SETATTR", 729821f1d3SAlan Somers "READLINK", 739821f1d3SAlan Somers "SYMLINK", 749821f1d3SAlan Somers "Unknown (opcode 7)", 759821f1d3SAlan Somers "MKNOD", 769821f1d3SAlan Somers "MKDIR", 779821f1d3SAlan Somers "UNLINK", 789821f1d3SAlan Somers "RMDIR", 799821f1d3SAlan Somers "RENAME", 809821f1d3SAlan Somers "LINK", 819821f1d3SAlan Somers "OPEN", 829821f1d3SAlan Somers "READ", 839821f1d3SAlan Somers "WRITE", 849821f1d3SAlan Somers "STATFS", 859821f1d3SAlan Somers "RELEASE", 869821f1d3SAlan Somers "Unknown (opcode 19)", 879821f1d3SAlan Somers "FSYNC", 889821f1d3SAlan Somers "SETXATTR", 899821f1d3SAlan Somers "GETXATTR", 909821f1d3SAlan Somers "LISTXATTR", 919821f1d3SAlan Somers "REMOVEXATTR", 929821f1d3SAlan Somers "FLUSH", 939821f1d3SAlan Somers "INIT", 949821f1d3SAlan Somers "OPENDIR", 959821f1d3SAlan Somers "READDIR", 969821f1d3SAlan Somers "RELEASEDIR", 979821f1d3SAlan Somers "FSYNCDIR", 989821f1d3SAlan Somers "GETLK", 999821f1d3SAlan Somers "SETLK", 1009821f1d3SAlan Somers "SETLKW", 1019821f1d3SAlan Somers "ACCESS", 1029821f1d3SAlan Somers "CREATE", 1039821f1d3SAlan Somers "INTERRUPT", 1049821f1d3SAlan Somers "BMAP", 1059821f1d3SAlan Somers "DESTROY" 1069821f1d3SAlan Somers }; 1079821f1d3SAlan Somers if (opcode >= NUM_OPS) 1089821f1d3SAlan Somers return ("Unknown (opcode > max)"); 1099821f1d3SAlan Somers else 1109821f1d3SAlan Somers return (table[opcode]); 1119821f1d3SAlan Somers } 1129821f1d3SAlan Somers 1139821f1d3SAlan Somers ProcessMockerT 1149821f1d3SAlan Somers ReturnErrno(int error) 1159821f1d3SAlan Somers { 1169821f1d3SAlan Somers return([=](auto in, auto &out) { 11729edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 11829edc611SAlan Somers out0->header.unique = in.header.unique; 1199821f1d3SAlan Somers out0->header.error = -error; 1209821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 12129edc611SAlan Somers out.push_back(std::move(out0)); 1229821f1d3SAlan Somers }); 1239821f1d3SAlan Somers } 1249821f1d3SAlan Somers 1259821f1d3SAlan Somers /* Helper function used for returning negative cache entries for LOOKUP */ 1269821f1d3SAlan Somers ProcessMockerT 1279821f1d3SAlan Somers ReturnNegativeCache(const struct timespec *entry_valid) 1289821f1d3SAlan Somers { 1299821f1d3SAlan Somers return([=](auto in, auto &out) { 1309821f1d3SAlan Somers /* nodeid means ENOENT and cache it */ 13129edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 1329821f1d3SAlan Somers out0->body.entry.nodeid = 0; 13329edc611SAlan Somers out0->header.unique = in.header.unique; 1349821f1d3SAlan Somers out0->header.error = 0; 1359821f1d3SAlan Somers out0->body.entry.entry_valid = entry_valid->tv_sec; 1369821f1d3SAlan Somers out0->body.entry.entry_valid_nsec = entry_valid->tv_nsec; 13729edc611SAlan Somers SET_OUT_HEADER_LEN(*out0, entry); 13829edc611SAlan Somers out.push_back(std::move(out0)); 1399821f1d3SAlan Somers }); 1409821f1d3SAlan Somers } 1419821f1d3SAlan Somers 1429821f1d3SAlan Somers ProcessMockerT 14329edc611SAlan Somers ReturnImmediate(std::function<void(const mockfs_buf_in& in, 14429edc611SAlan Somers struct mockfs_buf_out &out)> f) 1459821f1d3SAlan Somers { 14629edc611SAlan Somers return([=](auto& in, auto &out) { 14729edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 14829edc611SAlan Somers out0->header.unique = in.header.unique; 14929edc611SAlan Somers f(in, *out0); 15029edc611SAlan Somers out.push_back(std::move(out0)); 1519821f1d3SAlan Somers }); 1529821f1d3SAlan Somers } 1539821f1d3SAlan Somers 1549821f1d3SAlan Somers void sigint_handler(int __unused sig) { 1558b73a4c5SAlan Somers // Don't do anything except interrupt the daemon's read(2) call 1569821f1d3SAlan Somers } 1579821f1d3SAlan Somers 158c2d70d6eSAlan Somers void MockFS::debug_request(const mockfs_buf_in &in) 1599821f1d3SAlan Somers { 16029edc611SAlan Somers printf("%-11s ino=%2" PRIu64, opcode2opname(in.header.opcode), 16129edc611SAlan Somers in.header.nodeid); 1629821f1d3SAlan Somers if (verbosity > 1) { 163cc04566cSAlan Somers printf(" uid=%5u gid=%5u pid=%5u unique=%" PRIu64 " len=%u", 16429edc611SAlan Somers in.header.uid, in.header.gid, in.header.pid, 16529edc611SAlan Somers in.header.unique, in.header.len); 1669821f1d3SAlan Somers } 16729edc611SAlan Somers switch (in.header.opcode) { 16819ef317dSAlan Somers const char *name, *value; 16919ef317dSAlan Somers 170caf5f57dSAlan Somers case FUSE_ACCESS: 17129edc611SAlan Somers printf(" mask=%#x", in.body.access.mask); 172caf5f57dSAlan Somers break; 173a1c9f4adSAlan Somers case FUSE_BMAP: 17497b0512bSAlan Somers printf(" block=%" PRIx64 " blocksize=%#x", 17597b0512bSAlan Somers in.body.bmap.block, in.body.bmap.blocksize); 176a1c9f4adSAlan Somers break; 17719ef317dSAlan Somers case FUSE_CREATE: 178a4856c96SAlan Somers if (m_kernel_minor_version >= 12) 179a4856c96SAlan Somers name = (const char*)in.body.bytes + 180a4856c96SAlan Somers sizeof(fuse_create_in); 181a4856c96SAlan Somers else 18229edc611SAlan Somers name = (const char*)in.body.bytes + 18319ef317dSAlan Somers sizeof(fuse_open_in); 18419ef317dSAlan Somers printf(" flags=%#x name=%s", 18529edc611SAlan Somers in.body.open.flags, name); 18619ef317dSAlan Somers break; 1879821f1d3SAlan Somers case FUSE_FLUSH: 188cc04566cSAlan Somers printf(" fh=%#" PRIx64 " lock_owner=%" PRIu64, 18929edc611SAlan Somers in.body.flush.fh, 19029edc611SAlan Somers in.body.flush.lock_owner); 1919821f1d3SAlan Somers break; 1929821f1d3SAlan Somers case FUSE_FORGET: 19329edc611SAlan Somers printf(" nlookup=%" PRIu64, in.body.forget.nlookup); 1949821f1d3SAlan Somers break; 1959821f1d3SAlan Somers case FUSE_FSYNC: 19629edc611SAlan Somers printf(" flags=%#x", in.body.fsync.fsync_flags); 1979821f1d3SAlan Somers break; 1989821f1d3SAlan Somers case FUSE_FSYNCDIR: 19929edc611SAlan Somers printf(" flags=%#x", in.body.fsyncdir.fsync_flags); 2009821f1d3SAlan Somers break; 201723c7768SAlan Somers case FUSE_INTERRUPT: 20229edc611SAlan Somers printf(" unique=%" PRIu64, in.body.interrupt.unique); 203723c7768SAlan Somers break; 204002e54b0SAlan Somers case FUSE_LINK: 20529edc611SAlan Somers printf(" oldnodeid=%" PRIu64, in.body.link.oldnodeid); 206002e54b0SAlan Somers break; 2075e633330SAlan Somers case FUSE_LISTXATTR: 2085e633330SAlan Somers printf(" size=%" PRIu32, in.body.listxattr.size); 2095e633330SAlan Somers break; 2109821f1d3SAlan Somers case FUSE_LOOKUP: 21129edc611SAlan Somers printf(" %s", in.body.lookup); 2129821f1d3SAlan Somers break; 21399cf7bffSAlan Somers case FUSE_MKDIR: 21429edc611SAlan Somers name = (const char*)in.body.bytes + 21599cf7bffSAlan Somers sizeof(fuse_mkdir_in); 216a4856c96SAlan Somers printf(" name=%s mode=%#o umask=%#o", name, 217a4856c96SAlan Somers in.body.mkdir.mode, in.body.mkdir.umask); 21899cf7bffSAlan Somers break; 219bf4d7084SAlan Somers case FUSE_MKNOD: 220a4856c96SAlan Somers if (m_kernel_minor_version >= 12) 221a4856c96SAlan Somers name = (const char*)in.body.bytes + 222a4856c96SAlan Somers sizeof(fuse_mknod_in); 223a4856c96SAlan Somers else 224a4856c96SAlan Somers name = (const char*)in.body.bytes + 225a4856c96SAlan Somers FUSE_COMPAT_MKNOD_IN_SIZE; 226a4856c96SAlan Somers printf(" mode=%#o rdev=%x umask=%#o name=%s", 227a4856c96SAlan Somers in.body.mknod.mode, in.body.mknod.rdev, 228a4856c96SAlan Somers in.body.mknod.umask, name); 229bf4d7084SAlan Somers break; 2309821f1d3SAlan Somers case FUSE_OPEN: 231a4856c96SAlan Somers printf(" flags=%#x", in.body.open.flags); 2329821f1d3SAlan Somers break; 2339821f1d3SAlan Somers case FUSE_OPENDIR: 234a4856c96SAlan Somers printf(" flags=%#x", in.body.opendir.flags); 2359821f1d3SAlan Somers break; 2369821f1d3SAlan Somers case FUSE_READ: 237cc04566cSAlan Somers printf(" offset=%" PRIu64 " size=%u", 23829edc611SAlan Somers in.body.read.offset, 23929edc611SAlan Somers in.body.read.size); 240d4fd0c81SAlan Somers if (verbosity > 1) 241d4fd0c81SAlan Somers printf(" flags=%#x", in.body.read.flags); 2429821f1d3SAlan Somers break; 2439821f1d3SAlan Somers case FUSE_READDIR: 244cc04566cSAlan Somers printf(" fh=%#" PRIx64 " offset=%" PRIu64 " size=%u", 24529edc611SAlan Somers in.body.readdir.fh, in.body.readdir.offset, 24629edc611SAlan Somers in.body.readdir.size); 2479821f1d3SAlan Somers break; 2489821f1d3SAlan Somers case FUSE_RELEASE: 249cc04566cSAlan Somers printf(" fh=%#" PRIx64 " flags=%#x lock_owner=%" PRIu64, 25029edc611SAlan Somers in.body.release.fh, 25129edc611SAlan Somers in.body.release.flags, 25229edc611SAlan Somers in.body.release.lock_owner); 2539821f1d3SAlan Somers break; 2549821f1d3SAlan Somers case FUSE_SETATTR: 2559821f1d3SAlan Somers if (verbosity <= 1) { 25629edc611SAlan Somers printf(" valid=%#x", in.body.setattr.valid); 2579821f1d3SAlan Somers break; 2589821f1d3SAlan Somers } 25929edc611SAlan Somers if (in.body.setattr.valid & FATTR_MODE) 26029edc611SAlan Somers printf(" mode=%#o", in.body.setattr.mode); 26129edc611SAlan Somers if (in.body.setattr.valid & FATTR_UID) 26229edc611SAlan Somers printf(" uid=%u", in.body.setattr.uid); 26329edc611SAlan Somers if (in.body.setattr.valid & FATTR_GID) 26429edc611SAlan Somers printf(" gid=%u", in.body.setattr.gid); 26529edc611SAlan Somers if (in.body.setattr.valid & FATTR_SIZE) 26629edc611SAlan Somers printf(" size=%" PRIu64, in.body.setattr.size); 26729edc611SAlan Somers if (in.body.setattr.valid & FATTR_ATIME) 268cc04566cSAlan Somers printf(" atime=%" PRIu64 ".%u", 26929edc611SAlan Somers in.body.setattr.atime, 27029edc611SAlan Somers in.body.setattr.atimensec); 27129edc611SAlan Somers if (in.body.setattr.valid & FATTR_MTIME) 272cc04566cSAlan Somers printf(" mtime=%" PRIu64 ".%u", 27329edc611SAlan Somers in.body.setattr.mtime, 27429edc611SAlan Somers in.body.setattr.mtimensec); 27529edc611SAlan Somers if (in.body.setattr.valid & FATTR_FH) 27629edc611SAlan Somers printf(" fh=%" PRIu64 "", in.body.setattr.fh); 2779821f1d3SAlan Somers break; 278f067b609SAlan Somers case FUSE_SETLK: 279cc04566cSAlan Somers printf(" fh=%#" PRIx64 " owner=%" PRIu64 280cc04566cSAlan Somers " type=%u pid=%u", 28129edc611SAlan Somers in.body.setlk.fh, in.body.setlk.owner, 28229edc611SAlan Somers in.body.setlk.lk.type, 28329edc611SAlan Somers in.body.setlk.lk.pid); 284f067b609SAlan Somers if (verbosity >= 2) { 285cc04566cSAlan Somers printf(" range=[%" PRIu64 "-%" PRIu64 "]", 28629edc611SAlan Somers in.body.setlk.lk.start, 28729edc611SAlan Somers in.body.setlk.lk.end); 288f067b609SAlan Somers } 289f067b609SAlan Somers break; 2909821f1d3SAlan Somers case FUSE_SETXATTR: 2919821f1d3SAlan Somers /* 2929821f1d3SAlan Somers * In theory neither the xattr name and value need be 2939821f1d3SAlan Somers * ASCII, but in this test suite they always are. 2949821f1d3SAlan Somers */ 29529edc611SAlan Somers name = (const char*)in.body.bytes + 2969821f1d3SAlan Somers sizeof(fuse_setxattr_in); 29719ef317dSAlan Somers value = name + strlen(name) + 1; 29819ef317dSAlan Somers printf(" %s=%s", name, value); 2999821f1d3SAlan Somers break; 3009821f1d3SAlan Somers case FUSE_WRITE: 301cc04566cSAlan Somers printf(" fh=%#" PRIx64 " offset=%" PRIu64 302d4fd0c81SAlan Somers " size=%u write_flags=%u", 30329edc611SAlan Somers in.body.write.fh, 30429edc611SAlan Somers in.body.write.offset, in.body.write.size, 30529edc611SAlan Somers in.body.write.write_flags); 306d4fd0c81SAlan Somers if (verbosity > 1) 307d4fd0c81SAlan Somers printf(" flags=%#x", in.body.write.flags); 3089821f1d3SAlan Somers break; 3099821f1d3SAlan Somers default: 3109821f1d3SAlan Somers break; 3119821f1d3SAlan Somers } 3129821f1d3SAlan Somers printf("\n"); 3139821f1d3SAlan Somers } 3149821f1d3SAlan Somers 315c2d70d6eSAlan Somers /* 316c2d70d6eSAlan Somers * Debug a FUSE response. 317c2d70d6eSAlan Somers * 318c2d70d6eSAlan Somers * This is mostly useful for asynchronous notifications, which don't correspond 319c2d70d6eSAlan Somers * to any request 320c2d70d6eSAlan Somers */ 321c2d70d6eSAlan Somers void MockFS::debug_response(const mockfs_buf_out &out) { 322c2d70d6eSAlan Somers const char *name; 323c2d70d6eSAlan Somers 324c2d70d6eSAlan Somers if (verbosity == 0) 325c2d70d6eSAlan Somers return; 326c2d70d6eSAlan Somers 327c2d70d6eSAlan Somers switch (out.header.error) { 328c2d70d6eSAlan Somers case FUSE_NOTIFY_INVAL_ENTRY: 329c2d70d6eSAlan Somers name = (const char*)out.body.bytes + 330c2d70d6eSAlan Somers sizeof(fuse_notify_inval_entry_out); 331c2d70d6eSAlan Somers printf("<- INVAL_ENTRY parent=%" PRIu64 " %s\n", 332c2d70d6eSAlan Somers out.body.inval_entry.parent, name); 333c2d70d6eSAlan Somers break; 334eae1ae13SAlan Somers case FUSE_NOTIFY_INVAL_INODE: 335eae1ae13SAlan Somers printf("<- INVAL_INODE ino=%" PRIu64 " off=%" PRIi64 336eae1ae13SAlan Somers " len=%" PRIi64 "\n", 337eae1ae13SAlan Somers out.body.inval_inode.ino, 338eae1ae13SAlan Somers out.body.inval_inode.off, 339eae1ae13SAlan Somers out.body.inval_inode.len); 340eae1ae13SAlan Somers break; 3417cbb8e8aSAlan Somers case FUSE_NOTIFY_STORE: 3427cbb8e8aSAlan Somers printf("<- STORE ino=%" PRIu64 " off=%" PRIu64 3437cbb8e8aSAlan Somers " size=%" PRIu32 "\n", 3447cbb8e8aSAlan Somers out.body.store.nodeid, 3457cbb8e8aSAlan Somers out.body.store.offset, 3467cbb8e8aSAlan Somers out.body.store.size); 3477cbb8e8aSAlan Somers break; 348c2d70d6eSAlan Somers default: 349c2d70d6eSAlan Somers break; 350c2d70d6eSAlan Somers } 351c2d70d6eSAlan Somers } 352c2d70d6eSAlan Somers 35391ff3a0dSAlan Somers MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions, 35416bd2d47SAlan Somers bool push_symlinks_in, bool ro, enum poll_method pm, uint32_t flags, 355402b609cSAlan Somers uint32_t kernel_minor_version, uint32_t max_write, bool async, 356ed74f781SAlan Somers bool noclusterr, unsigned time_gran, bool nointr) 3579821f1d3SAlan Somers { 3588b73a4c5SAlan Somers struct sigaction sa; 3599821f1d3SAlan Somers struct iovec *iov = NULL; 3609821f1d3SAlan Somers int iovlen = 0; 3619821f1d3SAlan Somers char fdstr[15]; 36291ff3a0dSAlan Somers const bool trueval = true; 3639821f1d3SAlan Somers 3649821f1d3SAlan Somers m_daemon_id = NULL; 36516bd2d47SAlan Somers m_kernel_minor_version = kernel_minor_version; 3669821f1d3SAlan Somers m_maxreadahead = max_readahead; 3678eecd9ceSAlan Somers m_maxwrite = max_write; 3680a7c63e0SAlan Somers m_nready = -1; 3693429092cSAlan Somers m_pm = pm; 370fef46454SAlan Somers m_time_gran = time_gran; 37181a619c4SAlan Somers m_quit = false; 3723429092cSAlan Somers if (m_pm == KQ) 3733429092cSAlan Somers m_kq = kqueue(); 3743429092cSAlan Somers else 3753429092cSAlan Somers m_kq = -1; 3769821f1d3SAlan Somers 3779821f1d3SAlan Somers /* 3789821f1d3SAlan Somers * Kyua sets pwd to a testcase-unique tempdir; no need to use 3799821f1d3SAlan Somers * mkdtemp 3809821f1d3SAlan Somers */ 3819821f1d3SAlan Somers /* 3829821f1d3SAlan Somers * googletest doesn't allow ASSERT_ in constructors, so we must throw 3839821f1d3SAlan Somers * instead. 3849821f1d3SAlan Somers */ 38591ff3a0dSAlan Somers if (mkdir("mountpoint" , 0755) && errno != EEXIST) 3869821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 3879821f1d3SAlan Somers "Couldn't make mountpoint directory")); 3889821f1d3SAlan Somers 3893429092cSAlan Somers switch (m_pm) { 3903429092cSAlan Somers case BLOCKING: 39191ff3a0dSAlan Somers m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR); 3923429092cSAlan Somers break; 3933429092cSAlan Somers default: 3943429092cSAlan Somers m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR | O_NONBLOCK); 3953429092cSAlan Somers break; 3963429092cSAlan Somers } 3979821f1d3SAlan Somers if (m_fuse_fd < 0) 3989821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 3999821f1d3SAlan Somers "Couldn't open /dev/fuse")); 4009821f1d3SAlan Somers 4019821f1d3SAlan Somers m_pid = getpid(); 40291ff3a0dSAlan Somers m_child_pid = -1; 4039821f1d3SAlan Somers 4049821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1); 4059821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fspath", 4069821f1d3SAlan Somers __DECONST(void *, "mountpoint"), -1); 4079821f1d3SAlan Somers build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1); 4083429092cSAlan Somers sprintf(fdstr, "%d", m_fuse_fd); 4099821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fd", fdstr, -1); 41091ff3a0dSAlan Somers if (allow_other) { 41191ff3a0dSAlan Somers build_iovec(&iov, &iovlen, "allow_other", 4129821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 4139821f1d3SAlan Somers } 4149821f1d3SAlan Somers if (default_permissions) { 4159821f1d3SAlan Somers build_iovec(&iov, &iovlen, "default_permissions", 4169821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 4179821f1d3SAlan Somers } 41891ff3a0dSAlan Somers if (push_symlinks_in) { 41991ff3a0dSAlan Somers build_iovec(&iov, &iovlen, "push_symlinks_in", 42091ff3a0dSAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 42191ff3a0dSAlan Somers } 422140bb492SAlan Somers if (ro) { 423140bb492SAlan Somers build_iovec(&iov, &iovlen, "ro", 424140bb492SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 425140bb492SAlan Somers } 4268eecd9ceSAlan Somers if (async) { 4278eecd9ceSAlan Somers build_iovec(&iov, &iovlen, "async", __DECONST(void*, &trueval), 4288eecd9ceSAlan Somers sizeof(bool)); 4298eecd9ceSAlan Somers } 430402b609cSAlan Somers if (noclusterr) { 431402b609cSAlan Somers build_iovec(&iov, &iovlen, "noclusterr", 432402b609cSAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 433402b609cSAlan Somers } 434ed74f781SAlan Somers if (nointr) { 435ed74f781SAlan Somers build_iovec(&iov, &iovlen, "nointr", 436ed74f781SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 437ed74f781SAlan Somers } else { 438ed74f781SAlan Somers build_iovec(&iov, &iovlen, "intr", 439ed74f781SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 440ed74f781SAlan Somers } 4419821f1d3SAlan Somers if (nmount(iov, iovlen, 0)) 4429821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 4439821f1d3SAlan Somers "Couldn't mount filesystem")); 4449821f1d3SAlan Somers 4459821f1d3SAlan Somers // Setup default handler 4469821f1d3SAlan Somers ON_CALL(*this, process(_, _)) 4479821f1d3SAlan Somers .WillByDefault(Invoke(this, &MockFS::process_default)); 4489821f1d3SAlan Somers 4499821f1d3SAlan Somers init(flags); 4508b73a4c5SAlan Somers bzero(&sa, sizeof(sa)); 4518b73a4c5SAlan Somers sa.sa_handler = sigint_handler; 4528b73a4c5SAlan Somers sa.sa_flags = 0; /* Don't set SA_RESTART! */ 4538b73a4c5SAlan Somers if (0 != sigaction(SIGUSR1, &sa, NULL)) 4548b73a4c5SAlan Somers throw(std::system_error(errno, std::system_category(), 4558b73a4c5SAlan Somers "Couldn't handle SIGUSR1")); 4569821f1d3SAlan Somers if (pthread_create(&m_daemon_id, NULL, service, (void*)this)) 4579821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 4589821f1d3SAlan Somers "Couldn't Couldn't start fuse thread")); 4599821f1d3SAlan Somers } 4609821f1d3SAlan Somers 4619821f1d3SAlan Somers MockFS::~MockFS() { 4629821f1d3SAlan Somers kill_daemon(); 4639821f1d3SAlan Somers if (m_daemon_id != NULL) { 4649821f1d3SAlan Somers pthread_join(m_daemon_id, NULL); 4659821f1d3SAlan Somers m_daemon_id = NULL; 4669821f1d3SAlan Somers } 4678b73a4c5SAlan Somers ::unmount("mountpoint", MNT_FORCE); 4689821f1d3SAlan Somers rmdir("mountpoint"); 4693429092cSAlan Somers if (m_kq >= 0) 4703429092cSAlan Somers close(m_kq); 4719821f1d3SAlan Somers } 4729821f1d3SAlan Somers 473bf507497SAlan Somers void MockFS::audit_request(const mockfs_buf_in &in) { 474bf507497SAlan Somers uint32_t inlen = in.header.len; 475bf507497SAlan Somers size_t fih = sizeof(in.header); 476bf507497SAlan Somers switch (in.header.opcode) { 477bf507497SAlan Somers case FUSE_LOOKUP: 478bf507497SAlan Somers case FUSE_RMDIR: 479bf507497SAlan Somers case FUSE_SYMLINK: 480bf507497SAlan Somers case FUSE_UNLINK: 481bf507497SAlan Somers ASSERT_GT(inlen, fih) << "Missing request filename"; 482bf507497SAlan Somers break; 483bf507497SAlan Somers case FUSE_FORGET: 484bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.forget)); 485bf507497SAlan Somers break; 486bf507497SAlan Somers case FUSE_GETATTR: 487bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.getattr)); 488bf507497SAlan Somers break; 489bf507497SAlan Somers case FUSE_SETATTR: 490bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.setattr)); 491bf507497SAlan Somers break; 492bf507497SAlan Somers case FUSE_READLINK: 493bf507497SAlan Somers ASSERT_EQ(inlen, fih) << "Unexpected request body"; 494bf507497SAlan Somers break; 495bf507497SAlan Somers case FUSE_MKNOD: 496bf507497SAlan Somers { 497bf507497SAlan Somers size_t s; 498bf507497SAlan Somers if (m_kernel_minor_version >= 12) 499bf507497SAlan Somers s = sizeof(in.body.mknod); 500bf507497SAlan Somers else 501bf507497SAlan Somers s = FUSE_COMPAT_MKNOD_IN_SIZE; 502bf507497SAlan Somers ASSERT_GE(inlen, fih + s) << "Missing request body"; 503bf507497SAlan Somers ASSERT_GT(inlen, fih + s) << "Missing request filename"; 504bf507497SAlan Somers break; 505bf507497SAlan Somers } 506bf507497SAlan Somers case FUSE_MKDIR: 507bf507497SAlan Somers ASSERT_GE(inlen, fih + sizeof(in.body.mkdir)) << 508bf507497SAlan Somers "Missing request body"; 509bf507497SAlan Somers ASSERT_GT(inlen, fih + sizeof(in.body.mkdir)) << 510bf507497SAlan Somers "Missing request filename"; 511bf507497SAlan Somers break; 512bf507497SAlan Somers case FUSE_RENAME: 513bf507497SAlan Somers ASSERT_GE(inlen, fih + sizeof(in.body.rename)) << 514bf507497SAlan Somers "Missing request body"; 515bf507497SAlan Somers ASSERT_GT(inlen, fih + sizeof(in.body.rename)) << 516bf507497SAlan Somers "Missing request filename"; 517bf507497SAlan Somers break; 518bf507497SAlan Somers case FUSE_LINK: 519bf507497SAlan Somers ASSERT_GE(inlen, fih + sizeof(in.body.link)) << 520bf507497SAlan Somers "Missing request body"; 521bf507497SAlan Somers ASSERT_GT(inlen, fih + sizeof(in.body.link)) << 522bf507497SAlan Somers "Missing request filename"; 523bf507497SAlan Somers break; 524bf507497SAlan Somers case FUSE_OPEN: 525bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.open)); 526bf507497SAlan Somers break; 527bf507497SAlan Somers case FUSE_READ: 528bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.read)); 529bf507497SAlan Somers break; 530bf507497SAlan Somers case FUSE_WRITE: 531bf507497SAlan Somers { 532bf507497SAlan Somers size_t s; 533bf507497SAlan Somers 534bf507497SAlan Somers if (m_kernel_minor_version >= 9) 535bf507497SAlan Somers s = sizeof(in.body.write); 536bf507497SAlan Somers else 537bf507497SAlan Somers s = FUSE_COMPAT_WRITE_IN_SIZE; 538bf507497SAlan Somers ASSERT_GE(inlen, fih + s) << "Missing request body"; 539bf507497SAlan Somers // I suppose a 0-byte write should be allowed 540bf507497SAlan Somers break; 541bf507497SAlan Somers } 542bf507497SAlan Somers case FUSE_DESTROY: 543bf507497SAlan Somers case FUSE_STATFS: 544bf507497SAlan Somers ASSERT_EQ(inlen, fih); 545bf507497SAlan Somers break; 546bf507497SAlan Somers case FUSE_RELEASE: 547bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.release)); 548bf507497SAlan Somers break; 549bf507497SAlan Somers case FUSE_FSYNC: 550bf507497SAlan Somers case FUSE_FSYNCDIR: 551bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.fsync)); 552bf507497SAlan Somers break; 553bf507497SAlan Somers case FUSE_SETXATTR: 554bf507497SAlan Somers ASSERT_GE(inlen, fih + sizeof(in.body.setxattr)) << 555bf507497SAlan Somers "Missing request body"; 556bf507497SAlan Somers ASSERT_GT(inlen, fih + sizeof(in.body.setxattr)) << 557bf507497SAlan Somers "Missing request attribute name"; 558bf507497SAlan Somers break; 559bf507497SAlan Somers case FUSE_GETXATTR: 5603a79e8e7SAlan Somers ASSERT_GE(inlen, fih + sizeof(in.body.getxattr)) << 561bf507497SAlan Somers "Missing request body"; 5623a79e8e7SAlan Somers ASSERT_GT(inlen, fih + sizeof(in.body.getxattr)) << 563bf507497SAlan Somers "Missing request attribute name"; 564bf507497SAlan Somers break; 565bf507497SAlan Somers case FUSE_LISTXATTR: 5663a79e8e7SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.listxattr)); 567bf507497SAlan Somers break; 568bf507497SAlan Somers case FUSE_REMOVEXATTR: 569bf507497SAlan Somers ASSERT_GT(inlen, fih) << "Missing request attribute name"; 570bf507497SAlan Somers break; 571bf507497SAlan Somers case FUSE_FLUSH: 572bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.flush)); 573bf507497SAlan Somers break; 574bf507497SAlan Somers case FUSE_INIT: 575bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.init)); 576bf507497SAlan Somers break; 577bf507497SAlan Somers case FUSE_OPENDIR: 578bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.opendir)); 579bf507497SAlan Somers break; 580bf507497SAlan Somers case FUSE_READDIR: 581bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.readdir)); 582bf507497SAlan Somers break; 583bf507497SAlan Somers case FUSE_RELEASEDIR: 584bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.releasedir)); 585bf507497SAlan Somers break; 586bf507497SAlan Somers case FUSE_GETLK: 587bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.getlk)); 588bf507497SAlan Somers break; 589bf507497SAlan Somers case FUSE_SETLK: 590bf507497SAlan Somers case FUSE_SETLKW: 591bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.setlk)); 592bf507497SAlan Somers break; 593bf507497SAlan Somers case FUSE_ACCESS: 594bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.access)); 595bf507497SAlan Somers break; 596bf507497SAlan Somers case FUSE_CREATE: 597bf507497SAlan Somers ASSERT_GE(inlen, fih + sizeof(in.body.create)) << 598bf507497SAlan Somers "Missing request body"; 599bf507497SAlan Somers ASSERT_GT(inlen, fih + sizeof(in.body.create)) << 600bf507497SAlan Somers "Missing request filename"; 601bf507497SAlan Somers break; 602bf507497SAlan Somers case FUSE_INTERRUPT: 603bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.interrupt)); 604bf507497SAlan Somers break; 605bf507497SAlan Somers case FUSE_BMAP: 606bf507497SAlan Somers ASSERT_EQ(inlen, fih + sizeof(in.body.bmap)); 607bf507497SAlan Somers break; 608bf507497SAlan Somers case FUSE_NOTIFY_REPLY: 609bf507497SAlan Somers case FUSE_BATCH_FORGET: 610bf507497SAlan Somers case FUSE_FALLOCATE: 611bf507497SAlan Somers case FUSE_IOCTL: 612bf507497SAlan Somers case FUSE_POLL: 613bf507497SAlan Somers case FUSE_READDIRPLUS: 614bf507497SAlan Somers FAIL() << "Unsupported opcode?"; 615bf507497SAlan Somers default: 616bf507497SAlan Somers FAIL() << "Unknown opcode " << in.header.opcode; 617bf507497SAlan Somers } 618bf507497SAlan Somers } 619bf507497SAlan Somers 6209821f1d3SAlan Somers void MockFS::init(uint32_t flags) { 62129edc611SAlan Somers std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); 62229edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 6239821f1d3SAlan Somers 62429edc611SAlan Somers read_request(*in); 6259821f1d3SAlan Somers ASSERT_EQ(FUSE_INIT, in->header.opcode); 6269821f1d3SAlan Somers 6279821f1d3SAlan Somers out->header.unique = in->header.unique; 6289821f1d3SAlan Somers out->header.error = 0; 6299821f1d3SAlan Somers out->body.init.major = FUSE_KERNEL_VERSION; 63016bd2d47SAlan Somers out->body.init.minor = m_kernel_minor_version;; 6319821f1d3SAlan Somers out->body.init.flags = in->body.init.flags & flags; 6328eecd9ceSAlan Somers out->body.init.max_write = m_maxwrite; 6339821f1d3SAlan Somers out->body.init.max_readahead = m_maxreadahead; 63487ff949aSAlan Somers 63587ff949aSAlan Somers if (m_kernel_minor_version < 23) { 63687ff949aSAlan Somers SET_OUT_HEADER_LEN(*out, init_7_22); 63787ff949aSAlan Somers } else { 638fef46454SAlan Somers out->body.init.time_gran = m_time_gran; 63929edc611SAlan Somers SET_OUT_HEADER_LEN(*out, init); 64087ff949aSAlan Somers } 64187ff949aSAlan Somers 64229edc611SAlan Somers write(m_fuse_fd, out.get(), out->header.len); 6439821f1d3SAlan Somers } 6449821f1d3SAlan Somers 6459821f1d3SAlan Somers void MockFS::kill_daemon() { 64681a619c4SAlan Somers m_quit = true; 6478b73a4c5SAlan Somers if (m_daemon_id != NULL) 6489821f1d3SAlan Somers pthread_kill(m_daemon_id, SIGUSR1); 6498b73a4c5SAlan Somers // Closing the /dev/fuse file descriptor first allows unmount to 6508b73a4c5SAlan Somers // succeed even if the daemon doesn't correctly respond to commands 6518b73a4c5SAlan Somers // during the unmount sequence. 6529821f1d3SAlan Somers close(m_fuse_fd); 6538b73a4c5SAlan Somers m_fuse_fd = -1; 6549821f1d3SAlan Somers } 6559821f1d3SAlan Somers 6569821f1d3SAlan Somers void MockFS::loop() { 65729edc611SAlan Somers std::vector<std::unique_ptr<mockfs_buf_out>> out; 6589821f1d3SAlan Somers 65929edc611SAlan Somers std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); 6609821f1d3SAlan Somers ASSERT_TRUE(in != NULL); 66181a619c4SAlan Somers while (!m_quit) { 66229edc611SAlan Somers bzero(in.get(), sizeof(*in)); 66329edc611SAlan Somers read_request(*in); 66481a619c4SAlan Somers if (m_quit) 6659821f1d3SAlan Somers break; 6669821f1d3SAlan Somers if (verbosity > 0) 667c2d70d6eSAlan Somers debug_request(*in); 668bf507497SAlan Somers audit_request(*in); 6699821f1d3SAlan Somers if (pid_ok((pid_t)in->header.pid)) { 67029edc611SAlan Somers process(*in, out); 6719821f1d3SAlan Somers } else { 6729821f1d3SAlan Somers /* 6739821f1d3SAlan Somers * Reject any requests from unknown processes. Because 6749821f1d3SAlan Somers * we actually do mount a filesystem, plenty of 6759821f1d3SAlan Somers * unrelated system daemons may try to access it. 6769821f1d3SAlan Somers */ 67799cf7bffSAlan Somers if (verbosity > 1) 67899cf7bffSAlan Somers printf("\tREJECTED (wrong pid %d)\n", 67999cf7bffSAlan Somers in->header.pid); 68029edc611SAlan Somers process_default(*in, out); 6819821f1d3SAlan Somers } 68229edc611SAlan Somers for (auto &it: out) 68329edc611SAlan Somers write_response(*it); 6849821f1d3SAlan Somers out.clear(); 6859821f1d3SAlan Somers } 6869821f1d3SAlan Somers } 6879821f1d3SAlan Somers 688c2d70d6eSAlan Somers int MockFS::notify_inval_entry(ino_t parent, const char *name, size_t namelen) 689c2d70d6eSAlan Somers { 690c2d70d6eSAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 691c2d70d6eSAlan Somers 692c2d70d6eSAlan Somers out->header.unique = 0; /* 0 means asynchronous notification */ 693c2d70d6eSAlan Somers out->header.error = FUSE_NOTIFY_INVAL_ENTRY; 694c2d70d6eSAlan Somers out->body.inval_entry.parent = parent; 695c2d70d6eSAlan Somers out->body.inval_entry.namelen = namelen; 696c2d70d6eSAlan Somers strlcpy((char*)&out->body.bytes + sizeof(out->body.inval_entry), 697c2d70d6eSAlan Somers name, sizeof(out->body.bytes) - sizeof(out->body.inval_entry)); 698c2d70d6eSAlan Somers out->header.len = sizeof(out->header) + sizeof(out->body.inval_entry) + 699c2d70d6eSAlan Somers namelen; 700c2d70d6eSAlan Somers debug_response(*out); 701c2d70d6eSAlan Somers write_response(*out); 702c2d70d6eSAlan Somers return 0; 703c2d70d6eSAlan Somers } 704c2d70d6eSAlan Somers 705eae1ae13SAlan Somers int MockFS::notify_inval_inode(ino_t ino, off_t off, ssize_t len) 706eae1ae13SAlan Somers { 707eae1ae13SAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 708eae1ae13SAlan Somers 709eae1ae13SAlan Somers out->header.unique = 0; /* 0 means asynchronous notification */ 710eae1ae13SAlan Somers out->header.error = FUSE_NOTIFY_INVAL_INODE; 711eae1ae13SAlan Somers out->body.inval_inode.ino = ino; 712eae1ae13SAlan Somers out->body.inval_inode.off = off; 713eae1ae13SAlan Somers out->body.inval_inode.len = len; 714eae1ae13SAlan Somers out->header.len = sizeof(out->header) + sizeof(out->body.inval_inode); 715eae1ae13SAlan Somers debug_response(*out); 716eae1ae13SAlan Somers write_response(*out); 717eae1ae13SAlan Somers return 0; 718eae1ae13SAlan Somers } 719eae1ae13SAlan Somers 7205a0b9a27SAlan Somers int MockFS::notify_store(ino_t ino, off_t off, const void* data, ssize_t size) 7217cbb8e8aSAlan Somers { 7227cbb8e8aSAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 7237cbb8e8aSAlan Somers 7247cbb8e8aSAlan Somers out->header.unique = 0; /* 0 means asynchronous notification */ 7257cbb8e8aSAlan Somers out->header.error = FUSE_NOTIFY_STORE; 7267cbb8e8aSAlan Somers out->body.store.nodeid = ino; 7277cbb8e8aSAlan Somers out->body.store.offset = off; 7287cbb8e8aSAlan Somers out->body.store.size = size; 7297cbb8e8aSAlan Somers bcopy(data, (char*)&out->body.bytes + sizeof(out->body.store), size); 7307cbb8e8aSAlan Somers out->header.len = sizeof(out->header) + sizeof(out->body.store) + size; 7317cbb8e8aSAlan Somers debug_response(*out); 7327cbb8e8aSAlan Somers write_response(*out); 7337cbb8e8aSAlan Somers return 0; 7347cbb8e8aSAlan Somers } 7357cbb8e8aSAlan Somers 7369821f1d3SAlan Somers bool MockFS::pid_ok(pid_t pid) { 7379821f1d3SAlan Somers if (pid == m_pid) { 7389821f1d3SAlan Somers return (true); 73991ff3a0dSAlan Somers } else if (pid == m_child_pid) { 74091ff3a0dSAlan Somers return (true); 7419821f1d3SAlan Somers } else { 7429821f1d3SAlan Somers struct kinfo_proc *ki; 7439821f1d3SAlan Somers bool ok = false; 7449821f1d3SAlan Somers 7459821f1d3SAlan Somers ki = kinfo_getproc(pid); 7469821f1d3SAlan Somers if (ki == NULL) 7479821f1d3SAlan Somers return (false); 7489821f1d3SAlan Somers /* 7499821f1d3SAlan Somers * Allow access by the aio daemon processes so that our tests 7509821f1d3SAlan Somers * can use aio functions 7519821f1d3SAlan Somers */ 7529821f1d3SAlan Somers if (0 == strncmp("aiod", ki->ki_comm, 4)) 7539821f1d3SAlan Somers ok = true; 7549821f1d3SAlan Somers free(ki); 7559821f1d3SAlan Somers return (ok); 7569821f1d3SAlan Somers } 7579821f1d3SAlan Somers } 7589821f1d3SAlan Somers 75929edc611SAlan Somers void MockFS::process_default(const mockfs_buf_in& in, 76029edc611SAlan Somers std::vector<std::unique_ptr<mockfs_buf_out>> &out) 7619821f1d3SAlan Somers { 76229edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 76329edc611SAlan Somers out0->header.unique = in.header.unique; 7649821f1d3SAlan Somers out0->header.error = -EOPNOTSUPP; 7659821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 76629edc611SAlan Somers out.push_back(std::move(out0)); 7679821f1d3SAlan Somers } 7689821f1d3SAlan Somers 76929edc611SAlan Somers void MockFS::read_request(mockfs_buf_in &in) { 7709821f1d3SAlan Somers ssize_t res; 77177fbe694SAlan Somers int nready = 0; 7723429092cSAlan Somers fd_set readfds; 7733429092cSAlan Somers pollfd fds[1]; 7743429092cSAlan Somers struct kevent changes[1]; 7753429092cSAlan Somers struct kevent events[1]; 77677fbe694SAlan Somers struct timespec timeout_ts; 77777fbe694SAlan Somers struct timeval timeout_tv; 77877fbe694SAlan Somers const int timeout_ms = 999; 77977fbe694SAlan Somers int timeout_int, nfds; 7809821f1d3SAlan Somers 7813429092cSAlan Somers switch (m_pm) { 7823429092cSAlan Somers case BLOCKING: 7833429092cSAlan Somers break; 7843429092cSAlan Somers case KQ: 78577fbe694SAlan Somers timeout_ts.tv_sec = 0; 78677fbe694SAlan Somers timeout_ts.tv_nsec = timeout_ms * 1'000'000; 78777fbe694SAlan Somers while (nready == 0) { 78877fbe694SAlan Somers EV_SET(&changes[0], m_fuse_fd, EVFILT_READ, EV_ADD, 0, 78977fbe694SAlan Somers 0, 0); 79077fbe694SAlan Somers nready = kevent(m_kq, &changes[0], 1, &events[0], 1, 79177fbe694SAlan Somers &timeout_ts); 7923429092cSAlan Somers if (m_quit) 7933429092cSAlan Somers return; 79477fbe694SAlan Somers } 7953429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 7963429092cSAlan Somers ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd); 7973429092cSAlan Somers if (events[0].flags & EV_ERROR) 7983429092cSAlan Somers FAIL() << strerror(events[0].data); 7993429092cSAlan Somers else if (events[0].flags & EV_EOF) 8003429092cSAlan Somers FAIL() << strerror(events[0].fflags); 8010a7c63e0SAlan Somers m_nready = events[0].data; 8023429092cSAlan Somers break; 8033429092cSAlan Somers case POLL: 80477fbe694SAlan Somers timeout_int = timeout_ms; 8053429092cSAlan Somers fds[0].fd = m_fuse_fd; 8063429092cSAlan Somers fds[0].events = POLLIN; 80777fbe694SAlan Somers while (nready == 0) { 80877fbe694SAlan Somers nready = poll(fds, 1, timeout_int); 8093429092cSAlan Somers if (m_quit) 8103429092cSAlan Somers return; 81177fbe694SAlan Somers } 8123429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 8133429092cSAlan Somers ASSERT_TRUE(fds[0].revents & POLLIN); 8143429092cSAlan Somers break; 8153429092cSAlan Somers case SELECT: 81677fbe694SAlan Somers timeout_tv.tv_sec = 0; 81777fbe694SAlan Somers timeout_tv.tv_usec = timeout_ms * 1'000; 81877fbe694SAlan Somers nfds = m_fuse_fd + 1; 81977fbe694SAlan Somers while (nready == 0) { 8203429092cSAlan Somers FD_ZERO(&readfds); 8213429092cSAlan Somers FD_SET(m_fuse_fd, &readfds); 82277fbe694SAlan Somers nready = select(nfds, &readfds, NULL, NULL, 82377fbe694SAlan Somers &timeout_tv); 8243429092cSAlan Somers if (m_quit) 8253429092cSAlan Somers return; 82677fbe694SAlan Somers } 8273429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 8283429092cSAlan Somers ASSERT_TRUE(FD_ISSET(m_fuse_fd, &readfds)); 8293429092cSAlan Somers break; 8303429092cSAlan Somers default: 8313429092cSAlan Somers FAIL() << "not yet implemented"; 8323429092cSAlan Somers } 83329edc611SAlan Somers res = read(m_fuse_fd, &in, sizeof(in)); 8343429092cSAlan Somers 835b690d120SAlan Somers if (res < 0 && !m_quit) { 836b690d120SAlan Somers m_quit = true; 837*8e765737SAlan Somers FAIL() << "read: " << strerror(errno); 838b690d120SAlan Somers } 83929edc611SAlan Somers ASSERT_TRUE(res >= static_cast<ssize_t>(sizeof(in.header)) || m_quit); 840bf507497SAlan Somers /* 841bf507497SAlan Somers * Inconsistently, fuse_in_header.len is the size of the entire 842bf507497SAlan Somers * request,including header, even though fuse_out_header.len excludes 843bf507497SAlan Somers * the size of the header. 844bf507497SAlan Somers */ 84538a3e0bdSAlan Somers ASSERT_TRUE(res == static_cast<ssize_t>(in.header.len) || m_quit); 8469821f1d3SAlan Somers } 8479821f1d3SAlan Somers 84829edc611SAlan Somers void MockFS::write_response(const mockfs_buf_out &out) { 8493429092cSAlan Somers fd_set writefds; 8503429092cSAlan Somers pollfd fds[1]; 8513429092cSAlan Somers int nready, nfds; 8523429092cSAlan Somers ssize_t r; 8533429092cSAlan Somers 8543429092cSAlan Somers switch (m_pm) { 8553429092cSAlan Somers case BLOCKING: 8563429092cSAlan Somers case KQ: /* EVFILT_WRITE is not supported */ 8573429092cSAlan Somers break; 8583429092cSAlan Somers case POLL: 8593429092cSAlan Somers fds[0].fd = m_fuse_fd; 8603429092cSAlan Somers fds[0].events = POLLOUT; 8613429092cSAlan Somers nready = poll(fds, 1, INFTIM); 8623429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 8633429092cSAlan Somers ASSERT_EQ(1, nready) << "NULL timeout expired?"; 8643429092cSAlan Somers ASSERT_TRUE(fds[0].revents & POLLOUT); 8653429092cSAlan Somers break; 8663429092cSAlan Somers case SELECT: 8673429092cSAlan Somers FD_ZERO(&writefds); 8683429092cSAlan Somers FD_SET(m_fuse_fd, &writefds); 8693429092cSAlan Somers nfds = m_fuse_fd + 1; 8703429092cSAlan Somers nready = select(nfds, NULL, &writefds, NULL, NULL); 8713429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 8723429092cSAlan Somers ASSERT_EQ(1, nready) << "NULL timeout expired?"; 8733429092cSAlan Somers ASSERT_TRUE(FD_ISSET(m_fuse_fd, &writefds)); 8743429092cSAlan Somers break; 8753429092cSAlan Somers default: 8763429092cSAlan Somers FAIL() << "not yet implemented"; 8773429092cSAlan Somers } 87829edc611SAlan Somers r = write(m_fuse_fd, &out, out.header.len); 8793429092cSAlan Somers ASSERT_TRUE(r > 0 || errno == EAGAIN) << strerror(errno); 8803429092cSAlan Somers } 8813429092cSAlan Somers 8829821f1d3SAlan Somers void* MockFS::service(void *pthr_data) { 8839821f1d3SAlan Somers MockFS *mock_fs = (MockFS*)pthr_data; 8849821f1d3SAlan Somers 8859821f1d3SAlan Somers mock_fs->loop(); 8869821f1d3SAlan Somers 8879821f1d3SAlan Somers return (NULL); 8889821f1d3SAlan Somers } 8899821f1d3SAlan Somers 8909821f1d3SAlan Somers void MockFS::unmount() { 8919821f1d3SAlan Somers ::unmount("mountpoint", 0); 8929821f1d3SAlan Somers } 893